diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c144c06ec..c70982081 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -7,7 +7,7 @@ - [ ] Only relevant files were touched - [ ] Only one feature/fix was added per PR and the code change compiles without warnings - [ ] The code change is tested and works with Tasmota core ESP8266 V.2.7.4.9 - - [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.11 + - [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.14 - [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla). _NOTE: The code change must pass CI tests. **Your PR cannot be merged unless tests pass**_ diff --git a/.github/workflows/Tasmota_build_devel.yml b/.github/workflows/Tasmota_build_devel.yml index 1d7d24852..6b087e613 100644 --- a/.github/workflows/Tasmota_build_devel.yml +++ b/.github/workflows/Tasmota_build_devel.yml @@ -90,6 +90,9 @@ jobs: - tasmota32s2cdc-safeboot - tasmota32s3-safeboot - tasmota32s3cdc-safeboot + - tasmota32c2-safeboot + - tasmota32c6-safeboot + - tasmota32c6cdc-safeboot steps: - uses: actions/checkout@v3 with: @@ -102,6 +105,7 @@ jobs: run: | pip install wheel pip install -U platformio + cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} - name: Upload safeboot firmware artifacts diff --git a/.github/workflows/Tasmota_build_master.yml b/.github/workflows/Tasmota_build_master.yml index fa944eede..96b4db262 100644 --- a/.github/workflows/Tasmota_build_master.yml +++ b/.github/workflows/Tasmota_build_master.yml @@ -29,6 +29,9 @@ jobs: - tasmota32s2cdc-safeboot - tasmota32s3-safeboot - tasmota32s3cdc-safeboot + - tasmota32c2-safeboot + - tasmota32c6-safeboot + - tasmota32c6cdc-safeboot steps: - uses: actions/checkout@v3 with: @@ -41,6 +44,7 @@ jobs: run: | pip install wheel pip install -U platformio + cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} - name: Upload safeboot firmware artifacts diff --git a/.github/workflows/build_all_the_things.yml b/.github/workflows/build_all_the_things.yml index 3f89214e3..bcaddcfc3 100644 --- a/.github/workflows/build_all_the_things.yml +++ b/.github/workflows/build_all_the_things.yml @@ -112,6 +112,9 @@ jobs: - tasmota32s2cdc-safeboot - tasmota32s3-safeboot - tasmota32s3cdc-safeboot + - tasmota32c2-safeboot + - tasmota32c6-safeboot + - tasmota32c6cdc-safeboot steps: - uses: actions/checkout@v3 - name: Set up Python @@ -125,6 +128,7 @@ jobs: pip install -U platformio #platformio upgrade --dev #platformio update + cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini - name: Run PlatformIO run: platformio run -e ${{ matrix.variant }} - uses: actions/upload-artifact@v3 diff --git a/.gitignore b/.gitignore index 82c56687b..78c2cfe2f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ tasmota/tasmota.ino.cpp platformio_override.ini platformio_tasmota_cenv.ini platformio_tasmota_user_env.ini +platformio_tasmota_core3_env.ini lib/libesp32/berry/generate/* lib/libesp32/berry/berry diff --git a/BUILDS.md b/BUILDS.md index 7cfe5a568..d8d325b6e 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -32,8 +32,8 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up | USE_SUNRISE | x | x / x | x | x | x | x | | USE_RULES | x | x / x | x | x | x | x | | USE_SCRIPT | - | - / - | - | - | - | - | -| USE_EXPRESSION | - | - / - | - | - | - | - | -| SUPPORT_IF_STATEMENT | - | - / - | - | - | - | - | +| USE_EXPRESSION | - | - / x | - | - | - | - | Every ESP32 + ESP8266 > 1MB +| SUPPORT_IF_STATEMENT | - | - / x | - | - | - | - | Every ESP32 + ESP8266 > 1MB | USE_HOTPLUG | - | - / - | - | - | - | - | | USE_PROMETHEUS | - | - / - | - | - | - | - | | USE_PING | - | - / - | - | - | - | - | @@ -132,6 +132,8 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up | USE_MPR121 | - | - / - | - | - | - | - | | USE_CCS811 | - | - / - | - | x | - | - | | USE_CCS811_V2 | - | - / x | - | - | - | - | +| USE_ENS16x | - | - / - | - | - | - | - | +| USE_ENS210 | - | - / - | - | - | - | - | | USE_MPU6050 | - | - / - | - | - | - | - | | USE_DS3231 | - | - / - | - | - | - | - | | USE_MGC3130 | - | - / - | - | - | - | - | diff --git a/CHANGELOG.md b/CHANGELOG.md index ffffcc0ce..ac5670b0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,92 @@ # Changelog All notable changes to this project will be documented in this file. -## [Released] - Development +## [Released] + +## [13.2.0] 20231018 +- Release Quincy + +## [13.1.0.4] 20231018 +### Added +- Support for HC8 CO2 sensor (#19714) +- ESP32 commands ``Ds18Rescan`` and ``Ds18RetryRead`` (#19700) + +### Breaking Changed +- Removed support for Homekit in favour of Matter (#19738) + +### Changed +- ESP32 Framework (Arduino Core) from v2.0.13 to v2.0.14 +- MAX31855/MAX6675 sensors driver support up to 6 (#19329) +- ESP32 analog from `analogRead()` to calibrated `analogReadMilliVolts()` (#19732) +- I2S refactoring in preparation for core 3 (#19749) +- Teleinfo use Apparent Power as Active Power approximation (#19756) + +### Fixed +- ESP32 shutter frequency (#19717) +- ModbusBridge write memory leak (#19758) + +### Removed +- WiFiClientSecure in favour of WiFiClientSecureLightBearSSL (#19725) + +## [13.1.0.3] 20231003 +### Added +- Support for Shelly PlusPMMini, Plus1Mini and Plus1PMMini +- Matter support for Virtual Devices controllable via Rules or Berry (#19520) +- Berry read and write Counters (#19558) +- ESP32 support for influxdb access using https (#19582) +- Support for ENS16x (air quality) and ENS210 (temp & RH) sensors (#19479) +- Support for non-persistent ``WebButton17`` to ``WebButton32`` (#19580) +- Command ``Mi32Name`` (#19619) + +### Changed +- ESP32 Framework (Arduino Core) from v2.0.12 to v2.0.13 +- ESP32 LVGL library from v8.3.9 to v8.3.10 (no functional change) +- Consolidate SGP40 and SGP41 into SGP4x driver (#19560) +- ESP32 Audio preparation for Arduino Core v3 (#19637) +- ESP32 LittleFS updated to version with grow option (#19635) +- ESP32 Partition Wizard grow filesystem support (#19645) + +### Fixed +- ESP32 DS18x20 driver support extended over GPIO33 +- ESP32 Shutter button quad press (#19589) +- Compile error with new email lib (#19608) +- ESP32 Arduino Core v2 wifi client flush (#19642) + +## [13.1.0.2] 20230914 +### Added +- Support for HDMI CEC protocol (#19434) +- Support different baudrates on BL0942 + +### Breaking Changed +- `Sendmail` upgraded to ESP-Mail-Client v3.4.9 from v1.2.0, using BearSSL instead of MbedTLS (#19460) + +### Changed +- Berry fast_loop is now called every 5ms whatever the Sleep value (#19436) +- Reduce IRAM consumption of HDMI CEC to 1453 bytes (#19452) +- ESP32 Framework (Arduino Core) from v2.0.11 to v2.0.12 +- ESP32 LVGL library from v8.3.8 to v8.3.9 (no functional change) + +### Fixed +- PCF8574 mode 1 with base relays exception 3/28 regression from v12.4.0.4 (#19408) +- Berry make mdns compatible with non-IPv6 builds +- ESP32 Shutter migration (#19454) +- ESP32 Shutter multi press button events (#19465) +- Support for IPv6 link-local zones for esp-idf 5.1 (necessary for Matter) +- ESP32C3 relay click on restart + +## [13.1.0.1] 20230831 +### Added +- Commands to allow setting of timeprop parameters (#19310) +- Variables ``%power<1..28>%`` and ``%switch<1..28>%`` to rules (#19331) +- Experimental support for ESP32-C2 and ESP32-C6 using Arduino core v3.0 + +### Changed +- Display invert setting after tasmota start in uDisplay driver (#19337) + +### Fixed +- Shutter invert (#19341, #19374) +- Teleinfo power (#19381) +- Exception 3 in IRHVAC (#19389) ## [13.1.0] 20230815 - Release Quentin diff --git a/I2CDEVICES.md b/I2CDEVICES.md index 9bba8962e..fcda37377 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -120,3 +120,6 @@ Index | Define | Driver | Device | Address(es) | Description 81 | USE_PCA9557 | xdrv_69 | PCA95xx | 0x18 - 0x1F | 8-bit I/O expander as virtual button/switch/relay 82 | USE_SGP4X | xsns_109 | SGP4X | 0x59 | Gas (TVOC/NOx index) 83 | USE_MAX17043 | xsns_110 | MAX17043 | 0x36 | Fuel-gauge for 3.7 Volt Lipo battery + 84 | USE_ENS16x | xsns_111 | ENS16x | 0x52 - 0x53 | Gas (TVOC, eCO2) and air quality sensor + 85 | USE_ENS210 | xsns_112 | ENS210 | 0x43 - 0x44 | Temperature and humidity sensor + diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0dcabefa6..ef792642f 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -36,9 +36,9 @@ While fallback or downgrading is common practice it was never supported due to S This release will be supported from ESP8266/Arduino library Core version **2.7.4.9** due to reported security and stability issues on previous Core version. This will also support gzipped binaries. -This release will be supported from ESP32/Arduino library Core version **2.0.11**. +This release will be supported from ESP32/Arduino library Core version **2.0.14**. -Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.11 have been removed. +Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.14 have been removed. ## Support of TLS @@ -75,12 +75,12 @@ Latest released binaries can be downloaded from - http://ota.tasmota.com/tasmota/release Historical binaries can be downloaded from -- http://ota.tasmota.com/tasmota/release-13.1.0 +- http://ota.tasmota.com/tasmota/release-13.2.0 The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz`` ### ESP32, ESP32-C3, ESP32-S2 and ESP32-S3 based -The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.11**. +The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.14**. - **tasmota32.bin** = The Tasmota version with most drivers including additional sensors and KNX for 4M+ flash. **RECOMMENDED RELEASE BINARY** - **tasmota32xy.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C3/S2/S3 and 4M+ flash. @@ -100,7 +100,7 @@ Latest released binaries can be downloaded from - https://ota.tasmota.com/tasmota32/release Historical binaries can be downloaded from -- https://ota.tasmota.com/tasmota32/release-13.1.0 +- https://ota.tasmota.com/tasmota32/release-13.2.0 The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasmota.com/tasmota32/release/tasmota32.bin`` @@ -110,66 +110,54 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm [Complete list](BUILDS.md) of available feature and sensors. -## Changelog v13.1.0 Quentin +## Changelog v13.2.0 Quincy ### Added -- Command ``BrRestart`` to restart the Berry VM (experimental) [#19003](https://github.com/arendst/Tasmota/issues/19003) -- Command ``Delay -1`` to wait until next second [#18984](https://github.com/arendst/Tasmota/issues/18984) -- Command ``Restart 9`` to save all changes and go into deepsleep waiting for a reset [#19024](https://github.com/arendst/Tasmota/issues/19024) -- Support for MAX17043 fuel-gauge systems Lipo batteries [#18788](https://github.com/arendst/Tasmota/issues/18788) -- Support for multiple PCA9685 with extended functionality [#18805](https://github.com/arendst/Tasmota/issues/18805) -- Support for SGP41 TVOC/NOx Sensor [#18880](https://github.com/arendst/Tasmota/issues/18880) -- Support for DeepSleep battery level percentage [#19134](https://github.com/arendst/Tasmota/issues/19134) -- Zigbee decode Aqara 0000/FF01 attribute 03 as Temperature [#19210](https://github.com/arendst/Tasmota/issues/19210) -- ESP32 prepare for Arduino Core v3 and esp-idf v5 [#19264](https://github.com/arendst/Tasmota/issues/19264) -- Berry `getgbl` performance counter to `debug.counters()` [#19070](https://github.com/arendst/Tasmota/issues/19070) -- Berry `_class` can be used in `static var` initialization code [#19088](https://github.com/arendst/Tasmota/issues/19088) -- Berry `energy.update_total()` to call `EnergyUpdateTotal()` from energy driver [#19117](https://github.com/arendst/Tasmota/issues/19117) -- Berry `tasmota.loglevel()` and `tasmota.rtc_utc()` for faster performance [#19152](https://github.com/arendst/Tasmota/issues/19152) -- Berry metrics for memory allocation/deallocation/reallocation [#19150](https://github.com/arendst/Tasmota/issues/19150) -- Berry AES CCM decrypting in a single call to avoid any object allocation [#19153](https://github.com/arendst/Tasmota/issues/19153) -- Berry bytes `get` and `set` work for 3 bytes values [#19225](https://github.com/arendst/Tasmota/issues/19225) -- Partition Wizard is now able to convert to safeboot from Shelly partition layout [#19034](https://github.com/arendst/Tasmota/issues/19034) -- Matter option to disable bridge mode [#18992](https://github.com/arendst/Tasmota/issues/18992) -- Matter mini-profiler [#19075](https://github.com/arendst/Tasmota/issues/19075) -- Matter support for fabric_filtered request (for Google compatibility) [#19249](https://github.com/arendst/Tasmota/issues/19249) +- Experimental support for ESP32-C2 and ESP32-C6 using Arduino core v3 +- Commands to allow setting of timeprop parameters [#19310](https://github.com/arendst/Tasmota/issues/19310) +- Command ``Mi32Name`` [#19619](https://github.com/arendst/Tasmota/issues/19619) +- Variables ``%power<1..28>%`` and ``%switch<1..28>%`` to rules [#19331](https://github.com/arendst/Tasmota/issues/19331) +- Support different baudrates on BL0942 +- Support for Shelly PlusPMMini, Plus1Mini and Plus1PMMini +- Support for HDMI CEC protocol [#19434](https://github.com/arendst/Tasmota/issues/19434) +- Support for ENS16x (air quality) and ENS210 (temp & RH) sensors [#19479](https://github.com/arendst/Tasmota/issues/19479) +- Support for HC8 CO2 sensor [#19714](https://github.com/arendst/Tasmota/issues/19714) +- Support for non-persistent ``WebButton17`` to ``WebButton32`` [#19580](https://github.com/arendst/Tasmota/issues/19580) +- ESP32 commands ``Ds18Rescan`` and ``Ds18RetryRead`` [#19700](https://github.com/arendst/Tasmota/issues/19700) +- ESP32 support for influxdb access using https [#19582](https://github.com/arendst/Tasmota/issues/19582) +- Berry read and write Counters [#19558](https://github.com/arendst/Tasmota/issues/19558) +- Matter support for Virtual Devices controllable via Rules or Berry [#19520](https://github.com/arendst/Tasmota/issues/19520) ### Breaking Changed -- Berry `bool( [] )` and `bool( {} )` now evaluate as `false` [#18986](https://github.com/arendst/Tasmota/issues/18986) -- Berry `import strict` now detects useless expression without side effects [#18997](https://github.com/arendst/Tasmota/issues/18997) +- `Sendmail` upgraded to ESP-Mail-Client v3.4.9 from v1.2.0, using BearSSL instead of MbedTLS [#19460](https://github.com/arendst/Tasmota/issues/19460) +- Removed support for Homekit in favour of Matter [#19738](https://github.com/arendst/Tasmota/issues/19738) ### Changed -- IRremoteESP8266 library from v2.8.5 to v2.8.6 -- ESP32 Framework (Arduino Core) from v2.0.10 to v2.0.11 -- ESP32 LVGL library from v8.3.7 to v8.3.8 (no functional change) -- Initial ``DisplayMode`` from 1 to 0 and ``DisplayDimmmer`` from 10% to 50% [#19138](https://github.com/arendst/Tasmota/issues/19138) -- Configuration backup and restore now supports ``.xdrvsetXXX`` files too [#18295](https://github.com/arendst/Tasmota/issues/18295) -- Reduced log level for TeleInfo [#19216](https://github.com/arendst/Tasmota/issues/19216) -- Console height from default 318 pixels to viewport [#19241](https://github.com/arendst/Tasmota/issues/19241) -- Shutter button hold behaviour with grouptopic [#19263](https://github.com/arendst/Tasmota/issues/19263) -- Thermostat improvements [#19279](https://github.com/arendst/Tasmota/issues/19279) -- PID controller improvements [#19285](https://github.com/arendst/Tasmota/issues/19285) -- HDC1080 detect device offline [#19298](https://github.com/arendst/Tasmota/issues/19298) -- ADE7953 lowered no load threshold [#19302](https://github.com/arendst/Tasmota/issues/19302) -- ESP32 shutter driver support up to 16 shutters [#18295](https://github.com/arendst/Tasmota/issues/18295) -- ESP32 autodetect flashsize and adjust filesystem [#19215](https://github.com/arendst/Tasmota/issues/19215) -- Berry extend `range(lower, upper, incr)` to arbitrary increment [#19120](https://github.com/arendst/Tasmota/issues/19120) -- Berry updated syntax highlighting plugin for VSCode [#19123](https://github.com/arendst/Tasmota/issues/19123) -- Berry `mqtt.publish` now distinguishes between `string` and `bytes` [#19196](https://github.com/arendst/Tasmota/issues/19196) -- Matter support for temperature in Fahrenheit (`SetOption8 1`) [#18987](https://github.com/arendst/Tasmota/issues/18987) -- Matter improve responsiveness [#19002](https://github.com/arendst/Tasmota/issues/19002) -- Matter improve latency for remote commands [#19072](https://github.com/arendst/Tasmota/issues/19072) -- Matter improve latency for single attribute reads and single commands [#19158](https://github.com/arendst/Tasmota/issues/19158) -- Matter increased polling frequency for local switches/occupancy [#19242](https://github.com/arendst/Tasmota/issues/19242) +- ESP32 Framework (Arduino Core) from v2.0.11 to v2.0.14 +- ESP32 LVGL library from v8.3.8 to v8.3.10 (no functional change) +- Display invert setting after tasmota start in uDisplay driver [#19337](https://github.com/arendst/Tasmota/issues/19337) +- Consolidate SGP40 and SGP41 into SGP4x driver [#19560](https://github.com/arendst/Tasmota/issues/19560) +- MAX31855/MAX6675 sensors driver support up to 6 [#19329](https://github.com/arendst/Tasmota/issues/19329) +- Teleinfo use Apparent Power as Active Power approximation [#19756](https://github.com/arendst/Tasmota/issues/19756) +- ESP32 LittleFS updated to version with grow option [#19635](https://github.com/arendst/Tasmota/issues/19635) +- ESP32 I2S audio preparation for Arduino Core v3 [#19637](https://github.com/arendst/Tasmota/issues/19637) +- ESP32 analog from `analogRead()` to calibrated `analogReadMilliVolts()` [#19732](https://github.com/arendst/Tasmota/issues/19732) ### Fixed -- Berry Walrus Operator [#18982](https://github.com/arendst/Tasmota/issues/18982) -- MiElHVAC power commands regression from v12.4.0.1 [#18923](https://github.com/arendst/Tasmota/issues/18923) -- Zero cross dimmer minimum interrupt time [#19211](https://github.com/arendst/Tasmota/issues/19211) -- Fade would fail when the difference between start and target would be too small [#19248](https://github.com/arendst/Tasmota/issues/19248) -- Inverted shutter [#19243](https://github.com/arendst/Tasmota/issues/19243) -- ESP8266 SPI initialization for scripter, filesystem and MFRC522 [#19209](https://github.com/arendst/Tasmota/issues/19209) -- Matter support for large atribute responses [#19252](https://github.com/arendst/Tasmota/issues/19252) -- Matter auto-configuration Relay indices [#19255](https://github.com/arendst/Tasmota/issues/19255) +- Shutter invert [#19341](https://github.com/arendst/Tasmota/issues/19341) and [#19374](https://github.com/arendst/Tasmota/issues/19374) +- Teleinfo power [#19381](https://github.com/arendst/Tasmota/issues/19381) +- Exception 3 in IRHVAC [#19389](https://github.com/arendst/Tasmota/issues/19389) +- PCF8574 mode 1 with base relays exception 3/28 regression from v12.4.0.4 [#19408](https://github.com/arendst/Tasmota/issues/19408) +- ModbusBridge write memory leak [#19758](https://github.com/arendst/Tasmota/issues/19758) +- ESP32 DS18x20 driver support extended over GPIO33 +- ESP32 Support for IPv6 link-local zones for esp-idf 5.1 (necessary for Matter) +- ESP32 Shutter migration [#19454](https://github.com/arendst/Tasmota/issues/19454) +- ESP32 Shutter multi press button events [#19465](https://github.com/arendst/Tasmota/issues/19465) +- ESP32 Shutter button quad press [#19589](https://github.com/arendst/Tasmota/issues/19589) +- ESP32 shutter frequency [#19717](https://github.com/arendst/Tasmota/issues/19717) +- ESP32 Arduino Core v2 wifi client flush [#19642](https://github.com/arendst/Tasmota/issues/19642) +- ESP32 Partition Wizard grow filesystem support [#19645](https://github.com/arendst/Tasmota/issues/19645) +- ESP32C3 relay click on restart +- Matter support for Virtual Devices controllable via Rules or Berry [#19520](https://github.com/arendst/Tasmota/issues/19520) ### Removed -- Support for ESP32-C3 with chip revision below 3 (old development boards) +- Removed support for Homekit in favour of Matter [#19738](https://github.com/arendst/Tasmota/issues/19738) diff --git a/TEMPLATES.md b/TEMPLATES.md index 4cb82b786..40cabf9ec 100644 --- a/TEMPLATES.md +++ b/TEMPLATES.md @@ -5,7 +5,7 @@ # Templates -Find below the available templates as of August 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) +Find below the available templates as of October 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) ## Adapter Board ``` @@ -258,6 +258,7 @@ Zemismart Backlit {"NAME":"WF-CS01","GPIO":[544,227,289,34,226,161,0, ## DIN Relay ``` +CBI Astute Smart Controller {"NAME":"CBI Astute","GPIO":[2624,320,0,0,0,224,0,0,2720,32,2656,0,0,0],"FLAG":0,"BASE":6} CurrySmarter Power Monitoring 30A {"NAME":"30A Breaker on Led","GPIO":[0,0,0,0,7584,224,0,0,2720,32,2656,2624,320,0],"FLAG":0,"BASE":18} EARU DIN Circuit Breaker 1P 32A/50A {"NAME":"RDCBC-1P","GPIO":[320,0,0,0,0,0,0,0,32,224,0,0,0,0],"FLAG":0,"BASE":18} Hoch Circuit Breaker 1P {"NAME":"HOCH ZJSB9","GPIO":[32,0,0,0,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":18} @@ -297,7 +298,7 @@ Adafruit QT Py ESP32 Pico {"NAME":"QTPy ESP32 Pico","GPIO":[32,3200,0,3232,1, AZ-Envy Environmental Sensor {"NAME":"AZ Envy","GPIO":[32,0,320,0,640,608,0,0,0,0,0,0,0,4704],"FLAG":0,"BASE":18} Coiaca Tasmota {"NAME":"AWR01t","GPIO":[576,1,1,128,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Coiaca Tasmota Development Board AWR12 {"NAME":"AWR12t","GPIO":[320,1,1,1,1,1,0,0,1,1,1,1,1,1],"FLAG":0,"BASE":18} -Dasduino CONNECTPLUS {"NAME":"Dasduino CONNECT","GPIO":[1,1,1376,1,640,608,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18} +Dasduino CONNECT {"NAME":"Dasduino CONNECT","GPIO":[1,1,1376,1,640,608,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18} Dasduino CONNECTPLUS {"NAME":"Dasduino CONNECTPLUS","GPIO":[32,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,640,608,1,0,1,1,1,0,0,0,0,1376,1,1,1,1,0,0,1],"FLAG":0,"BASE":1} Espoir Rev 1.0.0 PoE+ {"NAME":"Espoir","GPIO":[0,0,1,0,1,1,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,5568,5600,1,7968,1,1,1,1],"FLAG":0,"BASE":1} KinCony 128 Channel Controller {"NAME":"KC868-A128","GPIO":[0,1,0,1,609,640,1,1,1,3232,3200,641,608,1,5600,0,0,1,0,5568,0,1,0,0,0,0,0,0,0,0,4705,4707,4706,0,0,4704],"FLAG":0,"BASE":1} @@ -704,6 +705,7 @@ QS-WIFI-RGBCW {"NAME":"QS-WIFI-RGBCW","GPIO":[0,0,32,0,544,417,0, RGB 12-24V {"NAME":"WS03","GPIO":[0,0,0,0,0,0,0,0,418,417,416,0,0,0],"FLAG":0,"BASE":18} RGB+CCT 12-24V {"NAME":"WS05","GPIO":[0,0,0,0,0,420,0,0,418,417,416,419,0,0],"FLAG":0,"BASE":18} RGBW 12-24V {"NAME":"*WS04","GPIO":[0,0,0,0,0,0,0,0,417,418,416,419,0,0],"FLAG":0,"BASE":18} +Robus CCT {"NAME":"RobusCCT","GPIO":[0,0,0,0,32,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18} Shelly RGBW2 {"NAME":"Shelly RGBW2","GPIO":[0,0,288,0,419,1,0,0,416,32,418,417,0,0],"FLAG":0,"BASE":18} Spectrum Smart RGBCCT {"NAME":"Spectrum Smart RGB CCT Controller","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} Tuya RGBCCT {"NAME":"AP-5CH-1","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} @@ -714,7 +716,7 @@ ZJ-WF-ESP-A v1.1 {"NAME":"RGB2","GPIO":[0,0,0,0,0,0,0,0,417,416,418, ## LED Strip ``` Aldi Casalux RGB {"NAME":"DW-RGB-WI01","GPIO":[1088,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} -ARLEC 5m Colour Changing "Not available" +ARLEC 5m Colour Changing {"NAME":"ALD557HA","GPIO":[0,0,0,1376,0,0,0,0,0,1088,0,0,0,0],"FLAG":0,"BASE":18} Arlec Smart 1m CCT LED Strip Light {"NAME":"ALD155HA","GPIO":[0,0,1088,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18} Arlec Smart 2m LED Colour Changing Strip Light {"NAME":"Arlec_Light_Strip","GPIO":[1,1,1088,1,416,419,1,1,417,420,418,0,1,1],"FLAG":0,"BASE":18} Arlec Smart 5m White & Colour Changing {"NAME":"ALD556HA","GPIO":[0,0,1088,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} @@ -913,6 +915,7 @@ Albohes PS-1602 {"NAME":"Albohes PC1606","GPIO":[32,0,0,0,0,225,33, Amzdest Dual {"NAME":"Amzdest c158","GPIO":[0,32,0,225,2720,2656,0,0,224,2624,0,0,0,0],"FLAG":0,"BASE":18} Amzdest IP55 {"NAME":"C168 Outdoor","GPIO":[0,0,0,2624,2720,2656,0,0,224,320,225,226,32,0],"FLAG":0,"BASE":18} Aoycocr X13 {"NAME":"Aoycocr X13","GPIO":[0,0,320,0,0,0,0,0,225,32,0,224,0,0],"FLAG":0,"BASE":18} +Arlec IP44 Weatherproof {"NAME":"PC44HA","GPIO":[0,0,0,35,2720,2656,0,0,2592,320,224,0,0,0],"FLAG":0,"BASE":18} Atomi {"NAME":"AtomiSmartPlug","GPIO":[0,0,0,0,320,576,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Blitzwolf 16A IP44 Dual {"NAME":"Blitzwolf BW-SHP14","GPIO":[0,320,0,32,0,321,0,0,224,0,225,0,0,0],"FLAG":0,"BASE":18} BN-Link {"NAME":"BNC-60/U130T","GPIO":[1,0,1,0,1,320,1,1,224,32,1,0,0,1],"FLAG":0,"BASE":18} @@ -1054,6 +1057,7 @@ Athom 16A UK {"NAME":"Athom PG04-UK16A","GPIO":[0,0,0,32,2720,26 Athom 16A UK V2 {"NAME":"Athom Plug V2","GPIO":[0,0,0,3104,0,32,0,0,224,576,0,0,0,0],"FLAG":0,"BASE":18} Athom 16A US {"NAME":"Athom PG03-US16A","GPIO":[0,0,0,32,2720,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18} Athom 16A US V2 {"NAME":"Athom Plug V2","GPIO":[0,0,0,3104,0,32,0,0,224,576,0,0,0,0],"FLAG":0,"BASE":18} +Athom Plug V3 {"NAME":"Athom Plug V3","GPIO":[0,0,0,32,0,224,576,0,0,0,0,0,0,0,0,0,0,0,0,0,3104,0],"FLAG":0,"BASE":1} Atlantis {"NAME":"Atlantis Smart Plug","GPIO":[32,0,0,0,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18} Atomi AT1217 {"NAME":"AT1217","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Aubess 16A {"NAME":"Aubess 16A Power Monitoring Plug","GPIO":[0,32,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18} @@ -1267,6 +1271,7 @@ HiHome {"NAME":"HIhome WPP-10S","GPIO":[320,0,576,1,0,2720 HiHome {"NAME":"HiHome WPP-16T","GPIO":[32,320,1,1,2720,2656,0,0,33,1,225,2592,224,4704],"FLAG":0,"BASE":18} HIPER IoT P01 {"NAME":"HIPER IoT P01","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} HIPER IoT P05 {"NAME":"HIPER IoT P05","GPIO":[0,320,0,32,0,0,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18} +HIPER IoT P09 {"NAME":"HIPER IoT P09","GPIO":[32,0,0,0,0,320,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18} hiwild W-US002 {"NAME":"W-US002","GPIO":[0,32,0,0,0,0,0,0,0,288,224,0,576,0],"FLAG":0,"BASE":18} HLT-309 {"NAME":"HLT-309","GPIO":[0,0,0,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18} Hoin 10A {"NAME":"NIOH XS-SSC01","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18} @@ -1378,6 +1383,7 @@ Maxcio YX-DE04 {"NAME":"Maxcio YX-DE04","GPIO":[1,32,1,224,320,419 MaxKare XKJJ-0218 {"NAME":"MaxKare XKJJ-0","GPIO":[0,0,0,0,33,2688,0,0,224,32,2656,225,2592,0],"FLAG":0,"BASE":18} Maxus Brio Head 16A {"NAME":"Brio-W-Head16","GPIO":[0,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18} Medion Life+ S85225 {"NAME":"Medion","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":52} +MELINK Smart Socket {"NAME":"MeLink ML1SSO20","GPIO":[0,32,0,32,2720,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18} Merkury Innovations 4 Outlets {"NAME":"MI-WW119-199W","GPIO":[320,3200,0,3232,225,32,0,0,224,226,227,0,0,0],"FLAG":0,"BASE":18} Merkury MI-WW101-199 {"NAME":"merkury WW101","GPIO":[0,0,0,0,0,0,0,0,320,64,0,224,0,0],"FLAG":0,"BASE":18} Merkury MI-WW102-199L {"NAME":"MIC-WW102","GPIO":[32,0,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":36} @@ -1403,6 +1409,7 @@ MXQ LED Nightlight {"NAME":"MXQ SP06","GPIO":[0,0,0,0,288,192,0,0,225, Nanxin NX-SM400 {"NAME":"NX-SM400","GPIO":[0,0,0,32,2720,2656,0,0,2592,288,224,0,0,0],"FLAG":0,"BASE":18} Naxa NSH-1000 {"NAME":"Naxa NSH-1000","GPIO":[0,0,0,0,32,0,0,0,321,320,224,0,0,0],"FLAG":0,"BASE":18} Nedis P110 {"NAME":"Nedis WIFIP110","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49} +Nedis P120 {"NAME":"WIFIP120EWT","GPIO":[32,0,0,0,2688,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49} Nedis P130 {"NAME":"WIFIP130FWT","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} Nedis Schuko Type F 16A {"NAME":"WIFIP120FWT","GPIO":[32,0,0,0,2688,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49} NEO Coolcam 10A {"NAME":"Neo Coolcam 10","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49} @@ -1572,10 +1579,12 @@ TP28Y {"NAME":"TP28Y","GPIO":[0,0,0,32,2720,2656,0,0,2624 Treatlife Dimmable {"NAME":"DP20","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 21,2 | SO20 1 | SO54 1"} Treatlife Smart {"NAME":"Treatlife SK50","GPIO":[1,1,1,1,320,576,1,1,224,1,32,1,1,1],"FLAG":0,"BASE":18} Tuya 16A Nightlight {"NAME":"Nightlight","GPIO":[225,0,320,0,226,227,0,0,34,64,0,224,0,0],"FLAG":0,"BASE":18} +Tuya 20A {"NAME":"Tuya 20A Power Monitoring Plug","GPIO":[1,1,1,32,2720,224,1,1,1,320,289,1,1,1],"FLAG":0,"BASE":18} U10 Series {"NAME":"WIFI-Socket","GPIO":[1,32,1,1,1,1,1,1,1,320,224,1,1,4704],"FLAG":0,"BASE":18} Ucomen Night Light {"NAME":"UCOMEN Plug","GPIO":[0,0,0,0,544,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18} UltraBrite {"NAME":"UltraBrite Smart Plug","GPIO":[1,1,1,1,288,289,1,1,224,32,1,1,1,1],"FLAG":0,"BASE":18} Ultralink UL-P01W {"NAME":"UL-P01W","GPIO":[0,288,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18} +Umax U-Smart Duo {"NAME":"Umax Duo Plug","GPIO":[33,0,0,0,2688,2656,0,0,2624,544,224,225,32,0],"FLAG":0,"BASE":18} Unlocked Automation 15A {"NAME":"UA 100","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,1],"FLAG":0,"BASE":18} UP111 {"NAME":"UP111","GPIO":[0,576,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18} Upstone {"NAME":"UPSTONE","GPIO":[1,1,544,1,320,1,0,0,224,32,1,1,1,1],"FLAG":0,"BASE":18} @@ -2165,7 +2174,7 @@ Shelly Duo RGBW 9W 800lm {"NAME":"Shelly Duo RGBW","GPIO":[0,0,0,0,0,419,0,0 Smart 810lm {"NAME":"OOOLED 60W RGB","GPIO":[0,0,0,0,418,419,0,0,416,0,417,0,0,4704],"FLAG":0,"BASE":18} SmartLED 9W 400lm {"NAME":"SmartLED RGBWW","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} Smartyfi 600lm {"NAME":"SMARTYFI 9W","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18} -Smitch 7W {"NAME":"Smitch RGB 7W SB-1602","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} +Smitch 7W {"NAME":"Smitch RGB 7W SB-1602","GPIO":[0,0,0,0,2912,419,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18} Solimo 12W {"NAME":"Solimo RGBCCT 12","GPIO":[0,0,0,0,416,420,0,0,417,419,418,0,0,0],"FLAG":0,"BASE":18} Solimo 810lm {"NAME":"Solimo RGBWW 9","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18} SPC Sirius 380 {"NAME":"SPC Sirius 380","GPIO":[0,0,0,0,2912,416,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18} diff --git a/boards/esp32c2.json b/boards/esp32c2.json new file mode 100644 index 000000000..563a3357c --- /dev/null +++ b/boards/esp32c2.json @@ -0,0 +1,44 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32c2_out.ld" + }, + "core": "esp32", + "extra_flags": "-DESP32_4M -DESP32C2", + "f_cpu": "120000000L", + "f_flash": "60000000L", + "flash_mode": "dio", + "mcu": "esp32c2", + "variant": "esp32c2", + "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "debug": { + "openocd_target": "esp32c2.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif Generic ESP32-C2 = 4M Flash", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "variants/tasmota/tasmota32c2-safeboot.bin" + ] + ] + }, + "flash_size": "4MB", + "maximum_ram_size": 278528, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html", + "vendor": "Espressif" + } diff --git a/boards/esp32c2_2M.json b/boards/esp32c2_2M.json new file mode 100644 index 000000000..36f16ffe3 --- /dev/null +++ b/boards/esp32c2_2M.json @@ -0,0 +1,44 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32c2_out.ld" + }, + "core": "esp32", + "extra_flags": "-DESP32_2M -DESP32C2", + "f_cpu": "120000000L", + "f_flash": "60000000L", + "flash_mode": "dio", + "mcu": "esp32c2", + "variant": "esp32c2", + "partitions": "partitions/esp32_partition_app1245k_fs64k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "debug": { + "openocd_target": "esp32c2.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif Generic ESP32-C2 = 2M Flash, Tasmota 1245kB Code/OTA, 64k FS", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "variants/tasmota/tasmota32c2-safeboot.bin" + ] + ] + }, + "flash_size": "2MB", + "maximum_ram_size": 278528, + "maximum_size": 2097152, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html", + "vendor": "Espressif" + } diff --git a/boards/esp32c6.json b/boards/esp32c6.json index 919bcfdfe..57dd9b8f4 100644 --- a/boards/esp32c6.json +++ b/boards/esp32c6.json @@ -7,7 +7,7 @@ "extra_flags": "-DESP32_4M -DESP32C6", "f_cpu": "160000000L", "f_flash": "80000000L", - "flash_mode": "dio", + "flash_mode": "qio", "mcu": "esp32c6", "variant": "esp32c6", "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" diff --git a/boards/esp32c6cdc.json b/boards/esp32c6cdc.json new file mode 100644 index 000000000..17932b7a8 --- /dev/null +++ b/boards/esp32c6cdc.json @@ -0,0 +1,45 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32c6_out.ld" + }, + "core": "esp32", + "extra_flags": "-DARDUINO_USB_MODE=1 -DESP32_4M -DESP32C6 -DUSE_USB_CDC_CONSOLE", + "f_cpu": "160000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32c6", + "variant": "esp32c6", + "partitions": "partitions/esp32_partition_app2880k_fs320k.csv" + }, + "connectivity": [ + "wifi", + "bluetooth" + ], + "debug": { + "openocd_target": "esp32c6.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "Espressif Generic ESP32-C6 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS", + "upload": { + "arduino": { + "flash_extra_images": [ + [ + "0x10000", + "variants/tasmota/tasmota32c6cdc-safeboot.bin" + ] + ] + }, + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "require_upload_port": true, + "before_reset": "usb_reset", + "speed": 460800 + }, + "url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html", + "vendor": "Espressif" + } diff --git a/include/esp32x_fixes.h b/include/esp32x_fixes.h index a9f963d42..13860477a 100644 --- a/include/esp32x_fixes.h +++ b/include/esp32x_fixes.h @@ -68,10 +68,28 @@ #define SPI_HOST SPI1_HOST #define HSPI_HOST SPI2_HOST #define VSPI_HOST SPI2_HOST /* No SPI3_host on C3 */ +#if ESP_IDF_VERSION_MAJOR < 5 // fix a bug in esp-idf 4.4 for esp32c3 #ifndef REG_SPI_BASE #define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 ))) // SPI_MOSI_DLEN_REG is not defined anymore in esp32c3, instead use SPI_MS_DLEN_REG #define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x) #endif // REG_SPI_BASE +#endif //ESP_IDF_VERSION_MAJOR < 5 + +#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 +#define SPI_HOST SPI1_HOST +#define HSPI_HOST SPI1_HOST /* No SPI2_host on C2/C6 */ +#define VSPI_HOST SPI1_HOST /* No SPI3_host on C2/C6 */ +#define VSPI SPI +// #if ESP_IDF_VERSION_MAJOR < 5 +// // fix a bug in esp-idf 4.4 for esp32c3 +// #ifndef REG_SPI_BASE +// #define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 ))) +// // SPI_MOSI_DLEN_REG is not defined anymore in esp32c3, instead use SPI_MS_DLEN_REG +#define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x) +// #endif // REG_SPI_BASE +// #endif //ESP_IDF_VERSION_MAJOR < 5 + + #endif // TARGET diff --git a/lib/default/headers/esp-knx-ip.h b/lib/default/headers/esp-knx-ip.h index 6834a6125..5041b6661 100644 --- a/lib/default/headers/esp-knx-ip.h +++ b/lib/default/headers/esp-knx-ip.h @@ -53,7 +53,7 @@ */ #include "Arduino.h" -#include +//#include #include #include #include diff --git a/lib/lib_audio/ESP8266Audio/library.json b/lib/lib_audio/ESP8266Audio/library.json index ddbb6d634..d6a909243 100644 --- a/lib/lib_audio/ESP8266Audio/library.json +++ b/lib/lib_audio/ESP8266Audio/library.json @@ -19,5 +19,9 @@ "frameworks": "Arduino", "examples": [ "examples/*/*.ino" - ] + ], + "build": { + "includeDir": ".", + "flags": [ "-Wno-stringop-overread" ] + } } diff --git a/lib/lib_audio/ESP8266Audio/src/AudioOutputI2S.cpp b/lib/lib_audio/ESP8266Audio/src/AudioOutputI2S.cpp index b18f9ae39..36c14da66 100755 --- a/lib/lib_audio/ESP8266Audio/src/AudioOutputI2S.cpp +++ b/lib/lib_audio/ESP8266Audio/src/AudioOutputI2S.cpp @@ -19,6 +19,7 @@ */ #include +#if ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S #ifdef ESP32 #include "driver/i2s.h" #elif defined(ARDUINO_ARCH_RP2040) || ARDUINO_ESP8266_MAJOR >= 3 @@ -374,3 +375,4 @@ bool AudioOutputI2S::stop() i2sOn = false; return true; } +#endif // TODO Arduino 3.0 Port I2S \ No newline at end of file diff --git a/lib/lib_audio/ESP8266Audio/src/AudioOutputI2SNoDAC.cpp b/lib/lib_audio/ESP8266Audio/src/AudioOutputI2SNoDAC.cpp index 976d73c77..571e7e636 100644 --- a/lib/lib_audio/ESP8266Audio/src/AudioOutputI2SNoDAC.cpp +++ b/lib/lib_audio/ESP8266Audio/src/AudioOutputI2SNoDAC.cpp @@ -19,6 +19,7 @@ */ #include +#if ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S #ifdef ESP32 #include "driver/i2s.h" #elif defined(ARDUINO_ARCH_RP2040) || ARDUINO_ESP8266_MAJOR >= 3 @@ -119,3 +120,4 @@ bool AudioOutputI2SNoDAC::ConsumeSample(int16_t sample[2]) #endif return true; } +#endif // ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S \ No newline at end of file diff --git a/lib/lib_audio/ESP8266Audio/src/AudioOutputSPDIF.cpp b/lib/lib_audio/ESP8266Audio/src/AudioOutputSPDIF.cpp index 6e1cf1978..19074d1c5 100644 --- a/lib/lib_audio/ESP8266Audio/src/AudioOutputSPDIF.cpp +++ b/lib/lib_audio/ESP8266Audio/src/AudioOutputSPDIF.cpp @@ -37,9 +37,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + #if defined(ESP32) || defined(ESP8266) #include +#if ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S #if defined(ESP32) #include "driver/i2s.h" #include "soc/rtc.h" @@ -293,3 +295,4 @@ bool AudioOutputSPDIF::stop() } #endif +#endif // ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S \ No newline at end of file diff --git a/lib/lib_audio/ESP8266Audio/src/AudioOutputULP.cpp b/lib/lib_audio/ESP8266Audio/src/AudioOutputULP.cpp index a6f8773d2..60ac31bf3 100644 --- a/lib/lib_audio/ESP8266Audio/src/AudioOutputULP.cpp +++ b/lib/lib_audio/ESP8266Audio/src/AudioOutputULP.cpp @@ -18,6 +18,9 @@ along with this program. If not, see . */ +#include +#if ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S + #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 #include "AudioOutputULP.h" @@ -260,3 +263,4 @@ bool AudioOutputULP::stop() } #endif +#endif // ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S \ No newline at end of file diff --git a/lib/lib_audio/ESP8266Audio/src/libflac/stream_decoder.c b/lib/lib_audio/ESP8266Audio/src/libflac/stream_decoder.c index 20ae399f5..e8a284188 100644 --- a/lib/lib_audio/ESP8266Audio/src/libflac/stream_decoder.c +++ b/lib/lib_audio/ESP8266Audio/src/libflac/stream_decoder.c @@ -2783,7 +2783,7 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_ if(rice_parameter < pesc) { partitioned_rice_contents->raw_bits[partition] = 0; u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order; - if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)) + if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, (int*) residual + sample, u, rice_parameter)) return false; /* read_callback_ sets the state for us */ sample += u; } @@ -2792,7 +2792,7 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_ return false; /* read_callback_ sets the state for us */ partitioned_rice_contents->raw_bits[partition] = rice_parameter; for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter)) + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, (long int*) &i, rice_parameter)) return false; /* read_callback_ sets the state for us */ residual[sample] = i; } diff --git a/lib/lib_audio/ESP8266Audio/src/libmad/layer3.c b/lib/lib_audio/ESP8266Audio/src/libmad/layer3.c index 66ed7c2e7..db52baa0e 100644 --- a/lib/lib_audio/ESP8266Audio/src/libmad/layer3.c +++ b/lib/lib_audio/ESP8266Audio/src/libmad/layer3.c @@ -1636,7 +1636,7 @@ void III_imdct_l(mad_fixed_t const [18], mad_fixed_t [36], unsigned int); # else # if 1 static -void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[18]) +void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[17]) { mad_fixed_t a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12; mad_fixed_t a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25; diff --git a/lib/lib_audio/ESP8266Audio/tasmota_patches.txt b/lib/lib_audio/ESP8266Audio/tasmota_patches.txt new file mode 100644 index 000000000..7c26b1452 --- /dev/null +++ b/lib/lib_audio/ESP8266Audio/tasmota_patches.txt @@ -0,0 +1,27 @@ +# below are the high-level patches made to the standard ESP8266audio libraries + +# For Arduino 3 (gcc has a higher level of checks + +libmad/layer3.c replace (line 1639) + void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[18]) +to + void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[17]) + + +libflac/stream_decoder.c +line 2786 + if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)) +to + if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, (int*) residual + sample, u, rice_parameter)) + +line 2795 + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter)) +to + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, (long int*) &i, rice_parameter)) + + +l3loop.cpp +remove all 'register' + +mult_noarch_gcc.h +remove all 'register' diff --git a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp index 173526104..764870706 100644 --- a/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp +++ b/lib/lib_basic/IRremoteESP8266/IRremoteESP8266/src/IRrecv.cpp @@ -13,6 +13,11 @@ extern "C" { } #endif // ESP8266 #include +#if defined(ESP32) +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) +#include +#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 +#endif #endif // UNIT_TEST #include #ifdef UNIT_TEST @@ -242,8 +247,13 @@ static void USE_IRAM_ATTR gpio_intr() { // @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L176-L178 timer->dev->config.alarm_en = 1; #else // _ESP32_IRRECV_TIMER_HACK +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) + timerAlarm(timer, MS_TO_USEC(params.timeout), ONCE, 0); + timerAttachInterrupt(timer, &read_timeout); +#else // ESP_ARDUINO_VERSION_MAJOR >= 3 timerWrite(timer, 0); timerAlarmEnable(timer); +#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 #endif // _ESP32_IRRECV_TIMER_HACK #endif // ESP32 } @@ -359,7 +369,11 @@ void IRrecv::enableIRIn(const bool pullup) { #if defined(ESP32) // Initialise the ESP32 timer. // 80MHz / 80 = 1 uSec granularity. +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) + timer = timerBegin(80); +#else // ESP_ARDUINO_VERSION_MAJOR >= 3 timer = timerBegin(_timer_num, 80, true); +#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 #ifdef DEBUG if (timer == NULL) { DPRINT("FATAL: Unable enable system timer: "); @@ -367,12 +381,17 @@ void IRrecv::enableIRIn(const bool pullup) { } #endif // DEBUG assert(timer != NULL); // Check we actually got the timer. +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) + timerAlarm(timer, MS_TO_USEC(params.timeout), ONCE, 0); + timerAttachInterrupt(timer, &read_timeout); +#else // ESP_ARDUINO_VERSION_MAJOR >= 3 // Set the timer so it only fires once, and set it's trigger in uSeconds. timerAlarmWrite(timer, MS_TO_USEC(params.timeout), ONCE); // Note: Interrupt needs to be attached before it can be enabled or disabled. // Note: EDGE (true) is not supported, use LEVEL (false). Ref: #1713 // See: https://github.com/espressif/arduino-esp32/blob/caef4006af491130136b219c1205bdcf8f08bf2b/cores/esp32/esp32-hal-timer.c#L224-L227 timerAttachInterrupt(timer, &read_timeout, false); +#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 #endif // ESP32 // Initialise state machine variables @@ -398,9 +417,13 @@ void IRrecv::disableIRIn(void) { os_timer_disarm(&timer); #endif // ESP8266 #if defined(ESP32) +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) + timerEnd(timer); +#else // ESP_ARDUINO_VERSION_MAJOR >= 3 timerAlarmDisable(timer); timerDetachInterrupt(timer); timerEnd(timer); +#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 #endif // ESP32 detachInterrupt(params.recvpin); #endif // UNIT_TEST @@ -426,7 +449,11 @@ void IRrecv::resume(void) { params.rawlen = 0; params.overflow = false; #if defined(ESP32) +#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) ) + timerEnd(timer); +#else // ESP_ARDUINO_VERSION_MAJOR >= 3 timerAlarmDisable(timer); +#endif // ESP_ARDUINO_VERSION_MAJOR >= 3 gpio_intr_enable((gpio_num_t)params.recvpin); #endif // ESP32 } diff --git a/lib/lib_basic/NeoPixelBus/src/NeoPixelBus.h b/lib/lib_basic/NeoPixelBus/src/NeoPixelBus.h index 1f06ef52c..d810e2a94 100644 --- a/lib/lib_basic/NeoPixelBus/src/NeoPixelBus.h +++ b/lib/lib_basic/NeoPixelBus/src/NeoPixelBus.h @@ -101,9 +101,16 @@ License along with NeoPixel. If not, see #include "internal/NeoEspBitBangMethod.h" #elif defined(ARDUINO_ARCH_ESP32) - +#if ESP_IDF_VERSION_MAJOR < 5 #include "internal/NeoEsp32I2sMethod.h" #include "internal/NeoEsp32RmtMethod.h" +#else +#if !defined(CONFIG_IDF_TARGET_ESP32C2) +#include "internal/NeoEsp32RmtMethod_idf5.h" // every other SOC +#else //CONFIG_IDF_TARGET_ESP32C2 +#include "internal/NeoEsp32SpiMethod_idf5.h" // ESP32C2 +#endif //CONFIG_IDF_TARGET_ESP32C2 +#endif // ESP_IDF_VERSION_MAJOR #include "internal/NeoEspBitBangMethod.h" #include "internal/DotStarEsp32DmaSpiMethod.h" diff --git a/lib/lib_basic/NeoPixelBus/src/internal/DotStarEsp32DmaSpiMethod.h b/lib/lib_basic/NeoPixelBus/src/internal/DotStarEsp32DmaSpiMethod.h index a9d149b71..953a216e7 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/DotStarEsp32DmaSpiMethod.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/DotStarEsp32DmaSpiMethod.h @@ -29,12 +29,12 @@ License along with NeoPixel. If not, see #include "driver/spi_master.h" -#if defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(HSPI_HOST) +#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST) // HSPI_HOST depreciated in C3 #define HSPI_HOST SPI2_HOST #endif -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) class Esp32VspiBus { public: @@ -52,7 +52,7 @@ public: const static int ParallelBits = 1; }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) class Esp32Vspi2BitBus { public: @@ -70,7 +70,7 @@ public: const static int ParallelBits = 2; }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) class Esp32Vspi4BitBus { public: @@ -174,7 +174,7 @@ public: // If pins aren't specified, initialize bus with just the default SCK and MOSI pins for the SPI peripheral (no SS, no >1-bit pins) void Initialize() { -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) if (T_SPIBUS::SpiHostDevice == VSPI_HOST) { Initialize(SCK, -1, MOSI, -1, -1, -1); @@ -277,7 +277,7 @@ private: int8_t _ssPin; }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) // Clock Speed and Default Definitions for DotStarEsp32DmaVspi typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi40MhzMethod; typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi20MhzMethod; @@ -303,7 +303,7 @@ typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHspiHz typedef DotStarEsp32DmaHspi10MhzMethod DotStarEsp32DmaHspiMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) // Clock Speed and Default Definitions for DotStarEsp32DmaVspi2Bit typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit40MhzMethod; typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi2Bit20MhzMethod; @@ -329,7 +329,7 @@ typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaHsp typedef DotStarEsp32DmaHspi2Bit10MhzMethod DotStarEsp32DmaHspi2BitMethod; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) // Clock Speed and Default Definitions for DotStarEsp32DmaVspi4Bit typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit40MhzMethod; typedef DotStarEsp32DmaSpiMethod DotStarEsp32DmaVspi4Bit20MhzMethod; diff --git a/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.c b/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.c index 0f100cb41..5823b1875 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.c +++ b/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.c @@ -20,7 +20,8 @@ #include "sdkconfig.h" // this sets useful config symbols, like CONFIG_IDF_TARGET_ESP32C3 // ESP32C3/S3 I2S is not supported yet due to significant changes to interface -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) +#ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1 +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C2) #include #include @@ -495,5 +496,6 @@ size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free } #endif // !defined(CONFIG_IDF_TARGET_ESP32C3) +#endif //ESP_IDF_VERSION_MAJOR < 5 #endif // defined(ARDUINO_ARCH_ESP32) diff --git a/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.h b/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.h index 1249d2e11..bfc024a8c 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.h @@ -1,7 +1,10 @@ #pragma once +#include "sdkconfig.h" // this sets useful config symbols, like CONFIG_IDF_TARGET_ESP32C3 + +#ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1 // ESP32C3 I2S is not supported yet due to significant changes to interface -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) #ifdef __cplusplus extern "C" { @@ -38,5 +41,5 @@ bool i2sWriteDone(uint8_t bus_num); #ifdef __cplusplus } #endif - #endif +#endif // ESP_IDF_VERSION_MAJOR < 5 diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoBusChannel.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoBusChannel.h index 6f4b3c66f..5fdb131bf 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoBusChannel.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoBusChannel.h @@ -12,7 +12,7 @@ enum NeoBusChannel NeoBusChannel_0, NeoBusChannel_1, -#if !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) NeoBusChannel_2, @@ -35,7 +35,7 @@ enum NeoBusChannel NeoBusChannel_7, #endif // !defined(CONFIG_IDF_TARGET_ESP32S2) -#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) #endif // ARDUINO_ARCH_ESP32 diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32I2sMethod.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32I2sMethod.h index 9dbaa7fe7..2afe6d5aa 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32I2sMethod.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32I2sMethod.h @@ -26,12 +26,16 @@ License along with NeoPixel. If not, see #pragma once +#if ESP_IDF_VERSION_MAJOR <= 4 // ESP32C3 I2S is not supported yet due to significant changes to interface #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) extern "C" { #include +#if ESP_IDF_VERSION_MAJOR >= 5 +#include +#endif #include "Esp32_i2s.h" } @@ -376,5 +380,5 @@ typedef NeoEsp32I2s1Ws2812xInvertedMethod Neo800KbpsInvertedMethod; typedef NeoEsp32I2s1400KbpsInvertedMethod Neo400KbpsInvertedMethod; #endif // !defined(NEOPIXEL_ESP32_RMT_DEFAULT) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) - #endif +#endif // ESP_IDF_VERSION_MAJOR < 5 diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.cpp b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.cpp index f25d20d8f..c8525e09d 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.cpp +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.cpp @@ -32,7 +32,7 @@ License along with NeoPixel. If not, see #include "NeoBusChannel.h" #include "NeoEsp32RmtMethod.h" -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C2) // translate NeoPixelBuffer into RMT buffer diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.h index 2ed7e4a0e..e804cc2a7 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.h @@ -29,7 +29,7 @@ License along with NeoPixel. If not, see #pragma once -#ifdef ARDUINO_ARCH_ESP32 +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C2) /* General Reference documentation for the APIs used in this implementation LOW LEVEL: (what is actually used) @@ -47,6 +47,9 @@ Esp32-hal-rmt.c extern "C" { +#if ESP_IDF_VERSION_MAJOR >= 5 +#include +#endif #include } @@ -451,7 +454,7 @@ public: const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_3; }; -#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) class NeoEsp32RmtChannel4 { diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h new file mode 100644 index 000000000..905710254 --- /dev/null +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h @@ -0,0 +1,892 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +A BIG thanks to Andreas Merkle for the investigation and implementation of +a workaround to the GCC bug that drops method attributes from template methods + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C2) + +/* General Reference documentation for the APIs used in this implementation +LOW LEVEL: (what is actually used) +DOCS: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html +EXAMPLE: https://github.com/espressif/esp-idf/blob/826ff7186ae07dc81e960a8ea09ebfc5304bfb3b/examples/peripherals/rmt_tx/main/rmt_tx_main.c + +HIGHER LEVEL: +NO TRANSLATE SUPPORT so this was not used +NOTE: https://github.com/espressif/arduino-esp32/commit/50d142950d229b8fabca9b749dc4a5f2533bc426 +Esp32-hal-rmt.h +Esp32-hal-rmt.c +*/ + +#include + +extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); + +extern "C" +{ +#include +#include "driver/rmt_tx.h" +#include "driver/rmt_encoder.h" +#include "esp_check.h" +} + +#define RMT_LED_STRIP_RESOLUTION_HZ 40000000 // 40MHz resolution - setting of the "old" driver + +typedef struct { + uint32_t resolution; /*!< Encoder resolution, in Hz */ +} led_strip_encoder_config_t; + +typedef struct { + rmt_encoder_t base; + rmt_encoder_t *bytes_encoder; + rmt_encoder_t *copy_encoder; + int state; + rmt_symbol_word_t reset_code; +} rmt_led_strip_encoder_t; + +static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder; + rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder; + rmt_encode_state_t session_state = RMT_ENCODING_RESET; + rmt_encode_state_t state = RMT_ENCODING_RESET; + size_t encoded_symbols = 0; + switch (led_encoder->state) { + case 0: // send RGB data + encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = 1; // switch to next state when current encoding session finished + } + if (session_state & RMT_ENCODING_MEM_FULL) { + // static_cast(static_cast(a) | static_cast(b)); + state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_MEM_FULL)); + goto out; // yield if there's no free space for encoding artifacts + } + // fall-through + case 1: // send reset code + encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code, + sizeof(led_encoder->reset_code), &session_state); + if (session_state & RMT_ENCODING_COMPLETE) { + led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session + state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_COMPLETE)); + } + if (session_state & RMT_ENCODING_MEM_FULL) { + state = static_cast(static_cast(state) | static_cast(RMT_ENCODING_MEM_FULL)); + goto out; // yield if there's no free space for encoding artifacts + } + } +out: + *ret_state = state; + return encoded_symbols; +} + +static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_del_encoder(led_encoder->bytes_encoder); + rmt_del_encoder(led_encoder->copy_encoder); + delete led_encoder; + return ESP_OK; +} + +static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) +{ + rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base); + rmt_encoder_reset(led_encoder->bytes_encoder); + rmt_encoder_reset(led_encoder->copy_encoder); + led_encoder->state = RMT_ENCODING_RESET; + return ESP_OK; +} + +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder, uint32_t bit0, uint32_t bit1) +{ + const char* TAG = "TEST_RMT"; //TODO: Remove later + esp_err_t ret = ESP_OK; + rmt_led_strip_encoder_t *led_encoder = NULL; + uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us + rmt_bytes_encoder_config_t bytes_encoder_config; + rmt_copy_encoder_config_t copy_encoder_config = {}; + rmt_symbol_word_t reset_code_config; + + + ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + led_encoder = new rmt_led_strip_encoder_t(); + ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder"); + led_encoder->base.encode = rmt_encode_led_strip; + led_encoder->base.del = rmt_del_led_strip_encoder; + led_encoder->base.reset = rmt_led_strip_encoder_reset; + + bytes_encoder_config.bit0.val = bit0; + bytes_encoder_config.bit1.val = bit1; + + bytes_encoder_config.flags.msb_first = 1; // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - TODO: more checks + + ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed"); + ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed"); + + reset_code_config.level0 = 0; + reset_code_config.duration0 = reset_ticks; + reset_code_config.level1 = 0; + reset_code_config.duration1 = reset_ticks; + led_encoder->reset_code = reset_code_config; + *ret_encoder = &led_encoder->base; + return ret; +err: + // AddLog(2,"RMT:could not init led decoder"); + if (led_encoder) { + if (led_encoder->bytes_encoder) { + rmt_del_encoder(led_encoder->bytes_encoder); + } + if (led_encoder->copy_encoder) { + rmt_del_encoder(led_encoder->copy_encoder); + } + delete led_encoder; + } + return ret; +} + +#define NEOPIXELBUS_RMT_INT_FLAGS (ESP_INTR_FLAG_LOWMED) + +class NeoEsp32RmtSpeed +{ +public: +// next section is probably not needed anymore for IDF 5.1 + // ClkDiv of 2 provides for good resolution and plenty of reset resolution; but + // a ClkDiv of 1 will provide enough space for the longest reset and does show + // little better pulse accuracy + const static uint8_t RmtClockDivider = 2; + + inline constexpr static uint32_t FromNs(uint32_t ns) + { + return ns / NsPerRmtTick; + } + +protected: + const static uint32_t RmtCpu = 80000000L; // 80 mhz RMT clock + const static uint32_t NsPerSecond = 1000000000L; + const static uint32_t RmtTicksPerSecond = (RmtCpu / RmtClockDivider); + const static uint32_t NsPerRmtTick = (NsPerSecond / RmtTicksPerSecond); // about 25 +// end of deprecated section + +}; + +class NeoEsp32RmtSpeedBase : public NeoEsp32RmtSpeed +{ +public: + // this is used rather than the rmt_symbol_word_t as you can't correctly initialize + // it as a static constexpr within the template + inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow) + { + return (FromNs(nsLow) << 16) | (1 << 15) | (FromNs(nsHigh)); + } +}; + +class NeoEsp32RmtInvertedSpeedBase : public NeoEsp32RmtSpeed +{ +public: + // this is used rather than the rmt_symbol_word_t as you can't correctly initialize + // it as a static constexpr within the template + inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow) + { + return (FromNs(nsLow) << 16) | (1 << 31) | (FromNs(nsHigh)); + } +}; + +class NeoEsp32RmtSpeedWs2811 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950); // TODO: DRAM_ATTR debatable everywhere + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us +}; + +class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us +}; + +class NeoEsp32RmtSpeedSk6812 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us +}; + +// normal is inverted signal +class NeoEsp32RmtSpeedTm1814 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +// normal is inverted signal +class NeoEsp32RmtSpeedTm1829 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 900); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 400); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +// normal is inverted signal +class NeoEsp32RmtSpeedTm1914 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +class NeoEsp32RmtSpeed800Kbps : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtSpeed400Kbps : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtSpeedApa106 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(350, 1350); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1350, 350); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtSpeedTx1812 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 600); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(600, 300); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us +}; + +class NeoEsp32RmtInvertedSpeedWs2811 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us +}; + +class NeoEsp32RmtInvertedSpeedWs2812x : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us +}; + +class NeoEsp32RmtInvertedSpeedSk6812 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us +}; + +// normal is inverted signal +class NeoEsp32RmtInvertedSpeedTm1814 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +// normal is inverted signal +class NeoEsp32RmtInvertedSpeedTm1829 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 900); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 400); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +// normal is inverted signal +class NeoEsp32RmtInvertedSpeedTm1914 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us +}; + +class NeoEsp32RmtInvertedSpeed800Kbps : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtInvertedSpeed400Kbps : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtInvertedSpeedApa106 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(350, 1350); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1350, 350); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtInvertedSpeedTx1812 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 600); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(600, 300); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us +}; + +class NeoEsp32RmtChannel0 +{ +public: + NeoEsp32RmtChannel0() {}; + rmt_channel_handle_t RmtChannelNumber = NULL; +}; + +class NeoEsp32RmtChannel1 +{ +public: + NeoEsp32RmtChannel1() {}; + + rmt_channel_handle_t RmtChannelNumber = NULL; +}; + +#if !defined(CONFIG_IDF_TARGET_ESP32C6) // C6 only 2 RMT channels ?? +class NeoEsp32RmtChannel2 +{ +public: + NeoEsp32RmtChannel2() {}; + + rmt_channel_handle_t RmtChannelNumber = NULL; +}; + +class NeoEsp32RmtChannel3 +{ +public: + NeoEsp32RmtChannel3() {}; + +protected: + rmt_channel_handle_t RmtChannelNumber = NULL; +}; +#endif // !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) + +class NeoEsp32RmtChannel4 +{ +public: + NeoEsp32RmtChannel4() {}; + + rmt_channel_handle_t RmtChannelNumber = NULL; +}; + +class NeoEsp32RmtChannel5 +{ +public: + NeoEsp32RmtChannel5() {}; + + rmt_channel_handle_t RmtChannelNumber = NULL; +}; + +class NeoEsp32RmtChannel6 +{ +public: + NeoEsp32RmtChannel6() {}; + + rmt_channel_handle_t RmtChannelNumber = NULL; +}; + +class NeoEsp32RmtChannel7 +{ +public: + NeoEsp32RmtChannel7() {}; + + rmt_channel_handle_t RmtChannelNumber = NULL; +}; + +#endif + +// dynamic channel support +class NeoEsp32RmtChannelN +{ +public: + NeoEsp32RmtChannelN(NeoBusChannel channel) : + RmtChannelNumber(RmtChannelNumber) + { + RmtChannelNumber = NULL; + }; + NeoEsp32RmtChannelN() = delete; // no default constructor + rmt_channel_handle_t RmtChannelNumber = NULL; +}; + +template class NeoEsp32RmtMethodBase +{ +public: + typedef NeoNoSettings SettingsObject; + + NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _pin(pin) + { + construct(); + } + + NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : + _sizeData(pixelCount* elementSize + settingsSize), + _pin(pin), + _channel(channel) + { + construct(); + } + + ~NeoEsp32RmtMethodBase() + { + // wait until the last send finishes before destructing everything + // arbitrary time out of 10 seconds + + ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_tx_wait_all_done(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS)); + ESP_ERROR_CHECK( rmt_del_channel(_channel.RmtChannelNumber)); + + gpio_matrix_out(_pin, 0x100, false, false); + pinMode(_pin, INPUT); + + free(_dataEditing); + free(_dataSending); + } + + + bool IsReadyToUpdate() const + { + return (ESP_OK == rmt_tx_wait_all_done(_channel.RmtChannelNumber, 0)); + } + + void Initialize() + { + esp_err_t ret = ESP_OK; + rmt_tx_channel_config_t config = {}; + config.clk_src = RMT_CLK_SRC_DEFAULT; + config.gpio_num = static_cast(_pin); + config.mem_block_symbols = 64; // memory block size, 64 * 4 = 256 Bytes + config.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ; // 1 MHz tick resolution, i.e., 1 tick = 1 µs + config.trans_queue_depth = 4; // set the number of transactions that can pend in the background + config.flags.invert_out = false; // do not invert output signal + config.flags.with_dma = false; // do not need DMA backend + + ret += rmt_new_tx_channel(&config,&_channel.RmtChannelNumber); + led_strip_encoder_config_t encoder_config = {}; + encoder_config.resolution = RMT_LED_STRIP_RESOLUTION_HZ; + + _tx_config.loop_count = 0; //no loop + + ret += rmt_new_led_strip_encoder(&encoder_config, &_led_encoder, T_SPEED::RmtBit0, T_SPEED::RmtBit1); + + // ESP_LOGI(TAG, "Enable RMT TX channel"); + ret += rmt_enable(_channel.RmtChannelNumber); + AddLog(2,"RMT:initialized with error code: %u on pin: %u",ret, _pin); + } + + void Update(bool maintainBufferConsistency) + { + // AddLog(2,".."); + // wait for not actively sending data + // this will time out at 10 seconds, an arbitrarily long period of time + // and do nothing if this happens + + if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_tx_wait_all_done(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS))) + { + // AddLog(2,"__ %u", _sizeData); + // now start the RMT transmit with the editing buffer before we swap + esp_err_t ret = rmt_transmit(_channel.RmtChannelNumber, _led_encoder, _dataEditing, _sizeData, &_tx_config); // 3 for _sizeData + // AddLog(2,"rmt_transmit: %u", ret); + if (maintainBufferConsistency) + { + // copy editing to sending, + // this maintains the contract that "colors present before will + // be the same after", otherwise GetPixelColor will be inconsistent + memcpy(_dataSending, _dataEditing, _sizeData); + } + + // swap so the user can modify without affecting the async operation + std::swap(_dataSending, _dataEditing); + } + } + + uint8_t* getData() const + { + return _dataEditing; + }; + + size_t getDataSize() const + { + return _sizeData; + } + + void applySettings(const SettingsObject& settings) + { + } + +private: + const size_t _sizeData; // Size of '_data*' buffers + const uint8_t _pin; // output pin number + + rmt_transmit_config_t _tx_config = {}; + rmt_encoder_handle_t _led_encoder = nullptr; + + T_CHANNEL _channel; // holds instance for multi channel support + + + // Holds data stream which include LED color values and other settings as needed + uint8_t* _dataEditing; // exposed for get and set + uint8_t* _dataSending; // used for async send using RMT + + + void construct() + { + // AddLog(2,"RMT:construct"); + _dataEditing = static_cast(malloc(_sizeData)); + // data cleared later in Begin() + + _dataSending = static_cast(malloc(_sizeData)); + // no need to initialize it, it gets overwritten on every send + } +}; + +// normal +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNSk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNApa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtN800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtN400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3400KbpsMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tm1829Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tm1914Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tx1812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7400KbpsMethod; + +#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C3) + +// inverted +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNSk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNApa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtN800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtN400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsInvertedMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3400KbpsInvertedMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tm1829InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tm1914InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tx1812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7400KbpsInvertedMethod; + +#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) + + +#if defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) + +// Normally I2s method is the default, defining NEOPIXEL_ESP32_RMT_DEFAULT +// will switch to use RMT as the default method +// The ESP32S2 & ESP32C3 will always defualt to RMT + +#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) + +// RMT channel 1 method is the default method for Esp32S2 & Esp32C3 +typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2813Method; +typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2812xMethod; +typedef NeoEsp32Rmt1800KbpsMethod NeoWs2812Method; +typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2811Method; +typedef NeoEsp32Rmt1Sk6812Method NeoSk6812Method; +typedef NeoEsp32Rmt1Tm1814Method NeoTm1814Method; +typedef NeoEsp32Rmt1Tm1829Method NeoTm1829Method; +typedef NeoEsp32Rmt1Tm1914Method NeoTm1914Method; +typedef NeoEsp32Rmt1Sk6812Method NeoLc8812Method; +typedef NeoEsp32Rmt1Apa106Method NeoApa106Method; +typedef NeoEsp32Rmt1Tx1812Method NeoTx1812Method; + +typedef NeoEsp32Rmt1Ws2812xMethod Neo800KbpsMethod; +typedef NeoEsp32Rmt1400KbpsMethod Neo400KbpsMethod; + +typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2811InvertedMethod; +typedef NeoEsp32Rmt1800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32Rmt1Tm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoEsp32Rmt1Tm1829InvertedMethod NeoTm1829InvertedMethod; +typedef NeoEsp32Rmt1Tm1914InvertedMethod NeoTm1914InvertedMethod; +typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32Rmt1Apa106InvertedMethod NeoApa106InvertedMethod; +typedef NeoEsp32Rmt1Tx1812InvertedMethod NeoTx1812InvertedMethod; + +typedef NeoEsp32Rmt1Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32Rmt1400KbpsInvertedMethod Neo400KbpsInvertedMethod; + +#else // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + +// RMT channel 6 method is the default method for Esp32 +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2813Method; +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2812xMethod; +typedef NeoEsp32Rmt6800KbpsMethod NeoWs2812Method; +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2811Method; +typedef NeoEsp32Rmt6Sk6812Method NeoSk6812Method; +typedef NeoEsp32Rmt6Tm1814Method NeoTm1814Method; +typedef NeoEsp32Rmt6Tm1829Method NeoTm1829Method; +typedef NeoEsp32Rmt6Tm1914Method NeoTm1914Method; +typedef NeoEsp32Rmt6Sk6812Method NeoLc8812Method; +typedef NeoEsp32Rmt6Apa106Method NeoApa106Method; +typedef NeoEsp32Rmt6Tx1812Method NeoTx1812Method; + +typedef NeoEsp32Rmt6Ws2812xMethod Neo800KbpsMethod; +typedef NeoEsp32Rmt6400KbpsMethod Neo400KbpsMethod; + +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2811InvertedMethod; +typedef NeoEsp32Rmt6800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32Rmt6Tm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoEsp32Rmt6Tm1829InvertedMethod NeoTm1829InvertedMethod; +typedef NeoEsp32Rmt6Tm1914InvertedMethod NeoTm1914InvertedMethod; +typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32Rmt6Apa106InvertedMethod NeoApa106InvertedMethod; +typedef NeoEsp32Rmt6Tx1812InvertedMethod NeoTx1812InvertedMethod; + +typedef NeoEsp32Rmt6Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod; + +#endif // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) + +#endif // defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) + +#endif diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h new file mode 100644 index 000000000..826d6ef99 --- /dev/null +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h @@ -0,0 +1,504 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +Adaption of Espressif's component library code by Christian Baars + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is not yet part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(ARDUINO_ARCH_ESP32) + +#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST) +// HSPI_HOST depreciated in C3 +#define HSPI_HOST SPI2_HOST +#endif + +#include + +extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); // TODO: Remove all Addlogs + +extern "C" +{ +#include +#include "esp_rom_gpio.h" +#include "driver/spi_master.h" +#include "esp_check.h" +} + +#define LED_STRIP_SPI_DEFAULT_RESOLUTION (25 * 100 * 1000) // 2.5MHz resolution +#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4 + +#define SPI_BYTES_PER_COLOR_BYTE 3 +#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8) + +static const char *TAG = "led_strip_spi"; // TODO: Remove all TAG log stuff + +typedef enum { + LED_MODEL_WS2812, /*!< LED strip model: WS2812 */ + LED_MODEL_SK6812, /*!< LED strip model: SK6812 */ + LED_MODEL_INVALID /*!< Invalid LED strip model */ +} led_model_t; + +typedef enum { + LED_PIXEL_FORMAT_GRB, /*!< Pixel format: GRB */ + LED_PIXEL_FORMAT_GRBW, /*!< Pixel format: GRBW */ + LED_PIXEL_FORMAT_INVALID /*!< Invalid pixel format */ +} led_pixel_format_t; + +typedef struct { + spi_host_device_t spi_host; + spi_device_handle_t spi_device; + uint32_t strip_len; + uint8_t bytes_per_pixel; + uint8_t pixel_buf[]; +} led_strip_spi_obj; + +/** + * @brief LED Strip Configuration + */ +typedef struct { + int strip_gpio_num; /*!< GPIO number that used by LED strip */ + uint32_t max_leds; /*!< Maximum LEDs in a single strip */ + led_pixel_format_t led_pixel_format; /*!< LED pixel format */ + led_model_t led_model; /*!< LED model */ + + struct { + uint32_t invert_out: 1; /*!< Invert output signal */ + } flags; +} led_strip_config_t; + +typedef struct { + spi_clock_source_t clk_src; /*!< SPI clock source */ + spi_host_device_t spi_bus; /*!< SPI bus ID. Which buses are available depends on the specific chip */ + struct { + uint32_t with_dma: 1; /*!< Use DMA to transmit data */ + } flags; +} led_strip_spi_config_t; + + +class NeoEsp32SpiSpeed +{ +public: + + +protected: + +// end of deprecated section + +}; + +class NeoEsp32SpiSpeedBase : public NeoEsp32SpiSpeed +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedBase : public NeoEsp32SpiSpeed +{ +public: + +}; + +class NeoEsp32SpiSpeedWs2811 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedWs2812x : public NeoEsp32SpiSpeedBase +{ +public: + static const uint8_t bytes_per_pixel = 3; + +}; + +class NeoEsp32SpiSpeedSk6812 : public NeoEsp32SpiSpeedBase +{ +public: + static const uint8_t bytes_per_pixel = 4; + +}; + +class NeoEsp32SpiSpeed400Kbps : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedApa106 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedTx1812 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedWs2811 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedWs2812x : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedSk6812 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeed800Kbps : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeed400Kbps : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedApa106 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedTx1812 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiChannel +{ +public: + +}; + + +template class NeoEsp32SpiMethodBase +{ +public: + typedef NeoNoSettings SettingsObject; + + NeoEsp32SpiMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + // _pixelCount(pixelCount), + _pin(pin) + { + _pixelCount = pixelCount; + construct(); + } + + NeoEsp32SpiMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : + _sizeData(pixelCount* elementSize + settingsSize), + // _pixelCount(pixelCount), + _pin(pin) + // _channel(channel) // TODO: Refactor this somehow + { + _pixelCount = pixelCount; + construct(); + } + + ~NeoEsp32SpiMethodBase() + { + // wait until the last send finishes before destructing everything + // arbitrary time out of 10 seconds + + gpio_matrix_out(_pin, 0x100, false, false); + pinMode(_pin, INPUT); + + spi_bus_remove_device(_spi_strip->spi_device); + spi_bus_free(_spi_strip->spi_host); + free(_spi_strip); + + free(_dataEditing); + free(_dataSending); + } + + + bool IsReadyToUpdate() const + { + return true; // TODO + } + + void Initialize() + { + esp_err_t ret = ESP_OK; + uint8_t bytes_per_pixel = T_SPEED::bytes_per_pixel; + uint32_t mem_caps = MALLOC_CAP_DEFAULT; + spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT; + spi_bus_config_t spi_bus_cfg; + spi_device_interface_config_t spi_dev_cfg; + bool with_dma = true; /// TODO: pass value or compute based on pixelcount + int clock_resolution_khz = 0; + + // ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + // ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format"); + + // if ( LED_PIXEL_FORMAT_GRB == LED_PIXEL_FORMAT_GRBW) { // TODO + // bytes_per_pixel = 4; + // } else if (LED_PIXEL_FORMAT_GRB == LED_PIXEL_FORMAT_GRB) { + // bytes_per_pixel = 3; + // } else { + // assert(false); + // } + + if (with_dma) { // TODO + // DMA buffer must be placed in internal SRAM + mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA; + } + _spi_strip = (led_strip_spi_obj *)heap_caps_calloc(1, sizeof(led_strip_spi_obj) + _pixelCount * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, mem_caps); + + ESP_GOTO_ON_FALSE(_spi_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for spi strip"); + + _spi_strip->spi_host = SPI2_HOST; + + // for backward compatibility, if the user does not set the clk_src, use the default value + // if (clk_src) { + // clk_src = spi_config->clk_src; + // } + + spi_bus_cfg = { + .mosi_io_num = _pin, + //Only use MOSI to generate the signal, set -1 when other pins are not used. + .miso_io_num = -1, + .sclk_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = _pixelCount * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, + }; + ESP_GOTO_ON_ERROR(spi_bus_initialize(_spi_strip->spi_host, &spi_bus_cfg, with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED), err, TAG, "create SPI bus failed"); + + // if (led_config->flags.invert_out == true) { + // esp_rom_gpio_connect_out_signal(_pin, spi_periph_signal[_spi_strip->spi_host].spid_out, true, false); + // } + + spi_dev_cfg = { + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = 0, + //set -1 when CS is not used + .clock_source = clk_src, + .clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION, + .spics_io_num = -1, + .queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE, + }; + + ESP_GOTO_ON_ERROR(spi_bus_add_device(_spi_strip->spi_host, &spi_dev_cfg, &_spi_strip->spi_device), err, TAG, "Failed to add spi device"); + + spi_device_get_actual_freq(_spi_strip->spi_device, &clock_resolution_khz); + // TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution + // But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION + ESP_GOTO_ON_FALSE(clock_resolution_khz == LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000, ESP_ERR_NOT_SUPPORTED, err, + TAG, "unsupported clock resolution:%dKHz", clock_resolution_khz); + + _spi_strip->bytes_per_pixel = bytes_per_pixel; + _spi_strip->strip_len = _pixelCount; + + AddLog(2,"SPI:initialized with error code: %u on pin: %u",ret, _pin); + return; + err: + if (_spi_strip) { + if (_spi_strip->spi_device) { + spi_bus_remove_device(_spi_strip->spi_device); + } + if (_spi_strip->spi_host) { + spi_bus_free(_spi_strip->spi_host); + } + free(_spi_strip); + } + AddLog(2,"SPI-Error:initialized with error code: %u on pin: %u",ret, _pin); + return; + } + + void Update(bool maintainBufferConsistency) + { + // AddLog(2,".."); + // wait for not actively sending data + // this will time out at 10 seconds, an arbitrarily long period of time + // and do nothing if this happens + + // if READY + { + // AddLog(2,"__ %u", _sizeData); + // now start the SPI transmit with the editing buffer before we swap + led_strip_transmit_RGB_buffer(_dataEditing, _sizeData, T_SPEED::bytes_per_pixel); + + if (maintainBufferConsistency) + { + // copy editing to sending, + // this maintains the contract that "colors present before will + // be the same after", otherwise GetPixelColor will be inconsistent + memcpy(_dataSending, _dataEditing, _sizeData); + } + + // swap so the user can modify without affecting the async operation + std::swap(_dataSending, _dataEditing); + } + } + + uint8_t* getData() const + { + return _dataEditing; + }; + + size_t getDataSize() const + { + return _sizeData; + } + + void applySettings(const SettingsObject& settings) + { + } + +private: + const size_t _sizeData; // Size of '_data*' buffers + int16_t _pixelCount; + const uint8_t _pin; // output pin number + T_CHANNEL _channel; // not really used here + + led_strip_spi_obj *_spi_strip; + + + // Holds data stream which include LED color values and other settings as needed + uint8_t* _dataEditing; // exposed for get and set + uint8_t* _dataSending; // used for async send using RMT - TODO: Check if this useful for SPI + + + void construct() + { + _dataEditing = static_cast(malloc(_sizeData)); + // data cleared later in Begin() + + _dataSending = static_cast(malloc(_sizeData)); + // no need to initialize it, it gets overwritten on every send + } + + // please make sure to zero-initialize the buf before calling this function + + void __led_strip_spi_bit(uint8_t data, uint8_t *buf) + { + // Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110 + // So a color byte occupies 3 bytes of SPI. + *(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2); + *(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5); + *(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00; + *(buf + 1) |= BIT(0); + *(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3); + *(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6); + *(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1); + *(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4); + *(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7); + } + + esp_err_t led_strip_spi_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue) + { + if(index >= _spi_strip->strip_len) return ESP_FAIL; + // LED_PIXEL_FORMAT_GRB takes 72bits(9bytes) + uint32_t start = index * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE; + memset(_spi_strip->pixel_buf + start, 0, _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + __led_strip_spi_bit(green, &_spi_strip->pixel_buf[start]); + __led_strip_spi_bit(red, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]); + __led_strip_spi_bit(blue, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]); + if (_spi_strip->bytes_per_pixel > 3) { + __led_strip_spi_bit(0, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]); + } + return ESP_OK; + } + + esp_err_t led_strip_spi_set_pixel_rgbw(uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) + { + // LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes) + uint32_t start = index * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE; + // SK6812 component order is GRBW + memset(_spi_strip->pixel_buf + start, 0, _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + __led_strip_spi_bit(green, &_spi_strip->pixel_buf[start]); + __led_strip_spi_bit(red, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]); + __led_strip_spi_bit(blue, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]); + __led_strip_spi_bit(white, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]); + + return ESP_OK; + } + + esp_err_t led_strip_spi_clear() + { + //Write zero to turn off all leds + memset(_spi_strip->pixel_buf, 0, _spi_strip->strip_len * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + uint8_t *buf = _spi_strip->pixel_buf; + for (int index = 0; index < _spi_strip->strip_len * _spi_strip->bytes_per_pixel; index++) { + __led_strip_spi_bit(0, buf); + buf += SPI_BYTES_PER_COLOR_BYTE; + } + return led_strip_spi_refresh(); + } + + esp_err_t led_strip_spi_refresh() + { + spi_transaction_t tx_conf; + memset(&tx_conf, 0, sizeof(tx_conf)); + + tx_conf.length = _spi_strip->strip_len * _spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE; + tx_conf.tx_buffer = _spi_strip->pixel_buf; + tx_conf.rx_buffer = NULL; + spi_device_transmit(_spi_strip->spi_device, &tx_conf); // TODO -check + return ESP_OK; + } + + void led_strip_transmit_RGB_buffer(uint8_t * buffer, size_t size, uint8_t bytes_per_pixel) + { + for (int i = 0; i < size; i+=bytes_per_pixel) { + led_strip_spi_set_pixel(i/bytes_per_pixel, buffer[i+1], buffer[i], buffer[i+2]); //GRB -> RGB + } + /* Refresh the strip to send data */ + led_strip_spi_refresh(); + } +}; + +// normal +typedef NeoEsp32SpiMethodBase NeoEsp32SpiN800KbpsMethod; +typedef NeoEsp32SpiMethodBase NeoEsp32SpiNSk6812Method; + + +// SPI channel method is the default method for Esp32C2 +#ifdef CONFIG_IDF_TARGET_ESP32C2 +typedef NeoEsp32SpiSpeedWs2812x NeoWs2813Method; +typedef NeoEsp32SpiSpeedWs2812x NeoWs2812xMethod; +typedef NeoEsp32SpiSpeedSk6812 NeoSk6812Method; + +#endif //CONFIG_IDF_TARGET_ESP32C2 + +#endif diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEspBitBangMethod.cpp b/lib/lib_basic/NeoPixelBus/src/internal/NeoEspBitBangMethod.cpp index 32c069f3d..01499fe13 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEspBitBangMethod.cpp +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEspBitBangMethod.cpp @@ -28,8 +28,11 @@ License along with NeoPixel. If not, see #include -// ESP32C3 I2S is not supported yet -#if !defined(CONFIG_IDF_TARGET_ESP32C3) +// ESP32C3 I2S is not supported yet +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if !defined(ARDUINO_ARCH_ESP8266) +#include "soc/gpio_periph.h" +#endif static inline uint32_t getCycleCount(void) { @@ -154,5 +157,5 @@ void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv(uint8_t* pixels, uint8_t* end, } } -#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) #endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEspBitBangMethod.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEspBitBangMethod.h index bfbd13545..44f865488 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEspBitBangMethod.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEspBitBangMethod.h @@ -29,7 +29,7 @@ License along with NeoPixel. If not, see #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) // ESP32C3 I2S is not supported yet -#if !defined(CONFIG_IDF_TARGET_ESP32C3) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) #if defined(ARDUINO_ARCH_ESP8266) #include @@ -377,5 +377,5 @@ typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMet // ESP bitbang doesn't have defaults and should avoided except for testing -#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) #endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) diff --git a/lib/lib_basic/OneWire-Stickbreaker/OneWire.h b/lib/lib_basic/OneWire-Stickbreaker/OneWire.h index cb1e16d73..77910ecb9 100644 --- a/lib/lib_basic/OneWire-Stickbreaker/OneWire.h +++ b/lib/lib_basic/OneWire-Stickbreaker/OneWire.h @@ -159,27 +159,35 @@ static inline __attribute__((always_inline)) IO_REG_TYPE directRead(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 // max. usable Pins are 23 for C6 (below flash pins) +// return digitalRead(pin); // Works most of the time +// return gpio_ll_get_level(&GPIO, pin); // The hal is not public api, don't use in application code + +//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +#if SOC_GPIO_PIN_COUNT <= 32 return (GPIO.in.val >> pin) & 0x1; -#else // plain ESP32 +#else // ESP32 with over 32 gpios if ( pin < 32 ) return (GPIO.in >> pin) & 0x1; - else if ( pin < 46 ) + else return (GPIO.in1.val >> (pin - 32)) & 0x1; #endif - return 0; + } static inline __attribute__((always_inline)) void directWriteLow(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 +// digitalWrite(pin, 0); // Works most of the time +// gpio_ll_set_level(&GPIO, pin, 0); // The hal is not public api, don't use in application code + +//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +#if SOC_GPIO_PIN_COUNT <= 32 GPIO.out_w1tc.val = ((uint32_t)1 << pin); -#else // plain ESP32 +#else // ESP32 with over 32 gpios if ( pin < 32 ) GPIO.out_w1tc = ((uint32_t)1 << pin); - else if ( pin < 46 ) + else GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32)); #endif } @@ -187,66 +195,63 @@ void directWriteLow(IO_REG_TYPE pin) static inline __attribute__((always_inline)) void directWriteHigh(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 +// digitalWrite(pin, 1); // Works most of the time +// gpio_ll_set_level(&GPIO, pin, 1); // The hal is not public api, don't use in application code + +//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +#if SOC_GPIO_PIN_COUNT <= 32 GPIO.out_w1ts.val = ((uint32_t)1 << pin); -#else // plain ESP32 +#else // ESP32 with over 32 gpios if ( pin < 32 ) GPIO.out_w1ts = ((uint32_t)1 << pin); - else if ( pin < 46 ) + else GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32)); #endif + } static inline __attribute__((always_inline)) void directModeInput(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 - GPIO.enable_w1tc.val = ((uint32_t)1 << (pin)); -#else +// pinMode(pin, INPUT); // Too slow - doesn't work +// gpio_ll_output_disable(&GPIO, pin); // The hal is not public api, don't use in application code + if ( digitalPinIsValid(pin) ) { -#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4 - uint32_t rtc_reg(rtc_gpio_desc[pin].reg); - - if ( rtc_reg ) // RTC pins PULL settings - { - ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux); - ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); - } -#endif // Input +//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +#if SOC_GPIO_PIN_COUNT <= 32 + GPIO.enable_w1tc.val = ((uint32_t)1 << (pin)); +#else // ESP32 with over 32 gpios if ( pin < 32 ) GPIO.enable_w1tc = ((uint32_t)1 << pin); else GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32)); - } #endif + } + } static inline __attribute__((always_inline)) void directModeOutput(IO_REG_TYPE pin) { -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 - GPIO.enable_w1ts.val = ((uint32_t)1 << (pin)); -#else - if ( digitalPinIsValid(pin) && pin <= 33 ) // pins above 33 can be only inputs - { -#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4 - uint32_t rtc_reg(rtc_gpio_desc[pin].reg); +// pinMode(pin, OUTPUT); // Too slow - doesn't work +// gpio_ll_output_enable(&GPIO, pin); // The hal is not public api, don't use in application code - if ( rtc_reg ) // RTC pins PULL settings - { - ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux); - ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); - } -#endif + if ( digitalPinCanOutput(pin) ) + { // Output +//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +#if SOC_GPIO_PIN_COUNT <= 32 + GPIO.enable_w1ts.val = ((uint32_t)1 << (pin)); +#else // ESP32 with over 32 gpios if ( pin < 32 ) GPIO.enable_w1ts = ((uint32_t)1 << pin); - else // already validated to pins <= 33 + else GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32)); - } #endif + } + } #define DIRECT_READ(base, pin) directRead(pin) @@ -254,7 +259,6 @@ void directModeOutput(IO_REG_TYPE pin) #define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(pin) #define DIRECT_MODE_INPUT(base, pin) directModeInput(pin) #define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(pin) -//#warning "ESP32 OneWire testing" #elif defined(__SAMD21G18A__) #define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin)) diff --git a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp index 2e2fef4f8..dcffe0428 100644 --- a/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp +++ b/lib/lib_basic/TasmotaModbus-3.6.0/src/TasmotaModbus.cpp @@ -79,6 +79,11 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 uint8_t *frame; uint8_t framepointer = 0; +#ifdef TASMOTAMODBUSDEBUG + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: @%02X f:%02X r:%04X c:%u &:%08X"), device_address, function_code, start_address, count, (uint32)write_data); + if (write_data) AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: Write data 0x%04X"), write_data[0]); +#endif + uint16_t byte_count = count * 2; // In register mode count is nr of registers (2 bytes) if ((function_code == 1) || (function_code == 2) || (function_code == 15)) byte_count = ((count-1) / 8) + 1; // In bitmode count is nr of bits @@ -104,14 +109,20 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 } else if ((function_code == 5) || (function_code == 6)) { - if (write_data == NULL) + if (write_data == nullptr) { free(frame); +#ifdef TASMOTAMODBUSDEBUG + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: no data (13.1)")); +#endif return 13; // Register data not specified } if (count != 1) { free(frame); +#ifdef TASMOTAMODBUSDEBUG + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: wrong count (12.1)")); +#endif return 12; // Wrong register count } frame[framepointer++] = (uint8_t)(write_data[0] >> 8); // MSB @@ -124,14 +135,20 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 frame[framepointer++] = byte_count; - if (write_data == NULL) + if (write_data == nullptr) { free(frame); +#ifdef TASMOTAMODBUSDEBUG + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: no data (13.2)")); +#endif return 13; // Register data not specified } if (count == 0) { free(frame); +#ifdef TASMOTAMODBUSDEBUG + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: wrong count (12.2)")); +#endif return 12; // Wrong register count } for (uint16_t bytepointer = 0; bytepointer < byte_count; bytepointer++) @@ -142,6 +159,9 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1 else { free(frame); +#ifdef TASMOTAMODBUSDEBUG + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: wrong fct (1)")); +#endif return 1; // Wrong function code } diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp index 66ab35bac..6b2262f32 100755 --- a/lib/lib_display/UDisplay/uDisplay.cpp +++ b/lib/lib_display/UDisplay/uDisplay.cpp @@ -24,12 +24,17 @@ #include "esp8266toEsp32.h" #endif +#include "tasmota_options.h" extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size); //#define UDSP_DEBUG +#ifndef UDSP_LBSIZE +#define UDSP_LBSIZE 256 +#endif + #define renderer_swap(a, b) { int16_t t = a; a = b; b = t; } const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\ @@ -133,7 +138,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } lut_partial = 0; lut_full = 0; - char linebuff[128]; + char linebuff[UDSP_LBSIZE]; while (*lp) { uint16_t llen = strlen_ln(lp); @@ -153,10 +158,50 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { lp1++; section = *lp1++; if (section == 'I') { + if (*lp1 == 'C') { allcmd_mode = 1; lp1++; } + + if (*lp1 == 'S') { + // pecial case RGB with software SPI init clk,mosi,cs,reset + lp1++; + if (interface == _UDSP_RGB) { + // collect line and send directly + lp1++; + spi_nr = 4; + spi_dc = -1; + spi_miso = -1; + spi_clk = next_val(&lp1); + spi_mosi = next_val(&lp1); + spi_cs = next_val(&lp1); + reset = next_val(&lp1); + + pinMode(spi_cs, OUTPUT); + digitalWrite(spi_cs, HIGH); + + pinMode(spi_clk, OUTPUT); + digitalWrite(spi_clk, LOW); + + pinMode(spi_mosi, OUTPUT); + digitalWrite(spi_mosi, LOW); + + if (reset >= 0) { + pinMode(reset, OUTPUT); + digitalWrite(reset, HIGH); + delay(50); + reset_pin(50, 200); + } +#ifdef UDSP_DEBUG + Serial.printf("SSPI_MOSI : %d\n", spi_mosi); + Serial.printf("SSPI_SCLK : %d\n", spi_clk); + Serial.printf("SSPI_CS : %d\n", spi_cs); + Serial.printf("DSP RESET : %d\n", reset); +#endif + } + } + } else if (section == 'L') { if (*lp1 >= '1' && *lp1 <= '5') { lut_num = (*lp1 & 0x07); @@ -178,8 +223,9 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { lut_cmd[0] = next_hex(&lp1); } if (*lp1 == ',') lp1++; + } - if (*lp1 != ':' && *lp1 != '\n' && *lp1 != ' ') { // Add space char + if (*lp1 && *lp1 != ':' && *lp1 != '\n' && *lp1 != ' ') { // Add space char switch (section) { case 'H': // header line @@ -286,12 +332,10 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { break; case 'I': // init data - if (interface == _UDSP_I2C) { - dsp_cmds[dsp_ncmds++] = next_hex(&lp1); - if (!str2c(&lp1, ibuff, sizeof(ibuff))) { - dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16); - } - } else { + if (interface == _UDSP_RGB && spi_nr == 4) { + // special case RGB with SPI init + // collect line and send directly + dsp_ncmds = 0; while (1) { if (dsp_ncmds >= sizeof(dsp_cmds)) break; if (!str2c(&lp1, ibuff, sizeof(ibuff))) { @@ -300,6 +344,26 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { break; } } + interface = _UDSP_SPI; + send_spi_icmds(dsp_ncmds); + interface = _UDSP_RGB; + + } else { + if (interface == _UDSP_I2C) { + dsp_cmds[dsp_ncmds++] = next_hex(&lp1); + if (!str2c(&lp1, ibuff, sizeof(ibuff))) { + dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16); + } + } else { + while (1) { + if (dsp_ncmds >= sizeof(dsp_cmds)) break; + if (!str2c(&lp1, ibuff, sizeof(ibuff))) { + dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16); + } else { + break; + } + } + } } break; case 'f': @@ -481,6 +545,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) { } } } + nextline: if (*lp == '\n' || *lp == ' ') { // Add space char lp++; } else { @@ -648,6 +713,50 @@ void uDisplay::delay_arg(uint32_t args) { extern int32_t ESP_ResetInfoReason(); +// special init for GC displays +void uDisplay::send_spi_icmds(uint16_t cmd_size) { +uint16_t index = 0; +uint16_t cmd_offset = 0; + + +#ifdef UDSP_DEBUG + Serial.printf("start send icmd table\n"); +#endif + while (1) { + uint8_t iob; + SPI_CS_LOW + iob = dsp_cmds[cmd_offset++]; + index++; + ulcd_command(iob); + uint8_t args = dsp_cmds[cmd_offset++]; + index++; +#ifdef UDSP_DEBUG + Serial.printf("cmd, args %02x, %d ", iob, args & 0x7f); +#endif + for (uint32_t cnt = 0; cnt < (args & 0x7f); cnt++) { + iob = dsp_cmds[cmd_offset++]; + index++; +#ifdef UDSP_DEBUG + Serial.printf("%02x ", iob); +#endif + ulcd_data8(iob); + } + SPI_CS_HIGH +#ifdef UDSP_DEBUG + Serial.printf("\n"); +#endif + if (args & 0x80) { // delay after the command + delay_arg(args); + } + if (index >= cmd_size) break; + } +#ifdef UDSP_DEBUG + Serial.printf("end send icmd table\n"); +#endif + return; +} + + void uDisplay::send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size) { uint16_t index = 0; #ifdef UDSP_DEBUG @@ -945,7 +1054,11 @@ Renderer *uDisplay::Init(void) { _panel_config->disp_gpio_num = GPIO_NUM_NC; _panel_config->flags.disp_active_low = 0; +#if ESP_IDF_VERSION_MAJOR >= 5 + _panel_config->flags.refresh_on_demand = 0; +#else _panel_config->flags.relax_on_idle = 0; +#endif // ESP_IDF_VERSION_MAJOR >= 5 _panel_config->flags.fb_in_psram = 1; // allocate frame buffer in PSRAM ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(_panel_config, &_panel_handle)); @@ -955,9 +1068,16 @@ Renderer *uDisplay::Init(void) { uint16_t color = random(0xffff); ESP_ERROR_CHECK(_panel_handle->draw_bitmap(_panel_handle, 0, 0, 1, 1, &color)); +#if ESP_IDF_VERSION_MAJOR < 5 _rgb_panel = __containerof(_panel_handle, esp_rgb_panel_t, base); - rgb_fb = (uint16_t *)_rgb_panel->fb; +#else + void * buf = NULL; + esp_lcd_rgb_panel_get_frame_buffer(_panel_handle, 1, &buf); + rgb_fb = (uint16_t *)buf; +#endif + + #endif // USE_ESP32_S3 } @@ -1032,12 +1152,14 @@ Renderer *uDisplay::Init(void) { esp_lcd_new_i80_bus(&bus_config, &_i80_bus); +#if ESP_IDF_VERSION_MAJOR < 5 _dma_chan = _i80_bus->dma_chan; +#endif uint32_t div_a, div_b, div_n, clkcnt; calcClockDiv(&div_a, &div_b, &div_n, &clkcnt, 240*1000*1000, spi_speed*1000000); lcd_cam_lcd_clock_reg_t lcd_clock; - lcd_clock.lcd_clkcnt_n = std::max(1u, clkcnt - 1); + lcd_clock.lcd_clkcnt_n = std::max((uint32_t)1u, clkcnt - 1); // ESP_IDF_VERSION_MAJOR >= 5 lcd_clock.lcd_clk_equ_sysclk = (clkcnt == 1); lcd_clock.lcd_ck_idle_edge = true; lcd_clock.lcd_ck_out_edge = false; @@ -2406,6 +2528,7 @@ void uDisplay::hw_write9(uint8_t val, uint8_t dc) { *dp = regvalue; REG_SET_BIT(SPI_CMD_REG(3), SPI_USR); while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR)); + } #else diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h index 2f11044f1..238802dca 100755 --- a/lib/lib_display/UDisplay/uDisplay.h +++ b/lib/lib_display/UDisplay/uDisplay.h @@ -6,15 +6,15 @@ #include #include - #ifdef ESP32 #ifdef CONFIG_IDF_TARGET_ESP32S3 #define USE_ESP32_S3 #endif -#endif - -#ifdef ESP32 #include "driver/spi_master.h" +#if ESP_IDF_VERSION_MAJOR >= 5 +#include "soc/gpio_periph.h" +#include +#endif // ESP_IDF_VERSION_MAJOR >= 5 #endif #ifdef USE_ESP32_S3 @@ -37,6 +37,9 @@ static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin #include "esp_lcd_panel_ops.h" #include #include +#if ESP_IDF_VERSION_MAJOR >= 5 +#include "esp_rom_lldesc.h" +#endif // ESP_IDF_VERSION_MAJOR >= 5 #endif // USE_ESP32_S3 #define _UDSP_I2C 1 @@ -89,13 +92,16 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR }; #undef GPIO_CLR #undef GPIO_SET_SLOW #undef GPIO_CLR_SLOW -#if CONFIG_IDF_TARGET_ESP32C3 + +#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 #define GPIO_CLR(A) GPIO.out_w1tc.val = (1 << A) #define GPIO_SET(A) GPIO.out_w1ts.val = (1 << A) #else // plain ESP32 #define GPIO_CLR(A) GPIO.out_w1tc = (1 << A) #define GPIO_SET(A) GPIO.out_w1ts = (1 << A) #endif + + #define GPIO_CLR_SLOW(A) digitalWrite(A, LOW) #define GPIO_SET_SLOW(A) digitalWrite(A, HIGH) @@ -110,7 +116,7 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR }; #define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc); -#ifdef USE_ESP32_S3 +#if defined(USE_ESP32_S3) && ESP_IDF_VERSION_MAJOR < 5 struct esp_lcd_i80_bus_t { int bus_id; // Bus ID, index from 0 portMUX_TYPE spinlock; // spinlock used to protect i80 bus members(hal, device_list, cur_trans) @@ -143,7 +149,9 @@ struct esp_rgb_panel_t size_t resolution_hz; // Peripheral clock resolution esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width) gdma_channel_handle_t dma_chan; // DMA channel handle +#if ESP_IDF_VERSION_MAJOR < 5 esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; // Callback, invoked after frame trans done +#endif // ESP_IDF_VERSION_MAJOR < 5 void *user_ctx; // Reserved user's data of callback functions int x_gap; // Extra gap in x coordinate, it's used when calculate the flush window int y_gap; // Extra gap in y coordinate, it's used when calculate the flush window @@ -155,8 +163,7 @@ struct esp_rgb_panel_t } flags; dma_descriptor_t dma_nodes[]; // DMA descriptor pool of size `num_dma_nodes` }; - -#endif +#endif //USE_ESP32_S3 && ESP_IDF_VERSION_MAJOR < 5 class uDisplay : public Renderer { @@ -326,6 +333,8 @@ class uDisplay : public Renderer { void delay_arg(uint32_t arg); void Send_EP_Data(void); void send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size); + void send_spi_icmds(uint16_t cmd_size); + #ifdef USE_ESP32_S3 int8_t par_cs; @@ -352,7 +361,9 @@ class uDisplay : public Renderer { uint16_t pclk_active_neg; esp_lcd_panel_handle_t _panel_handle = NULL; +#if ESP_IDF_VERSION_MAJOR < 5 esp_rgb_panel_t *_rgb_panel; +#endif //ESP_IDF_VERSION_MAJOR < 5 uint16_t *rgb_fb; diff --git a/lib/lib_div/rfid-1.4.7/src/MFRC522Extended.cpp b/lib/lib_div/rfid-1.4.7/src/MFRC522Extended.cpp index da603ab77..fcf030f9b 100644 --- a/lib/lib_div/rfid-1.4.7/src/MFRC522Extended.cpp +++ b/lib/lib_div/rfid-1.4.7/src/MFRC522Extended.cpp @@ -821,7 +821,7 @@ MFRC522::StatusCode MFRC522Extended::TCL_Transceive(TagInfo *tag, byte *sendData // Swap block number on success tag->blockNumber = !tag->blockNumber; - if (backData && (backLen > 0)) { + if (backData && (backLen != 0)) { if (*backLen < in.inf.size) return STATUS_NO_ROOM; @@ -844,7 +844,7 @@ MFRC522::StatusCode MFRC522Extended::TCL_Transceive(TagInfo *tag, byte *sendData if (result != STATUS_OK) return result; - if (backData && (backLen > 0)) { + if (backData && (backLen != 0)) { if ((*backLen + ackDataSize) > totalBackLen) return STATUS_NO_ROOM; diff --git a/lib/lib_i2c/Adafruit_TSL2591_Library/Adafruit_TSL2591.cpp b/lib/lib_i2c/Adafruit_TSL2591_Library/Adafruit_TSL2591.cpp index 1cd9a9de3..57a0a67a9 100644 --- a/lib/lib_i2c/Adafruit_TSL2591_Library/Adafruit_TSL2591.cpp +++ b/lib/lib_i2c/Adafruit_TSL2591_Library/Adafruit_TSL2591.cpp @@ -214,7 +214,7 @@ void Adafruit_TSL2591::setGain(tsl2591Gain_t gain) enable(); _gain = gain; - write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain); + write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, static_cast(_integration) | static_cast(_gain)); disable(); } @@ -245,7 +245,7 @@ void Adafruit_TSL2591::setTiming(tsl2591IntegrationTime_t integration) enable(); _integration = integration; - write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain); + write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, static_cast(_integration) | static_cast(_gain)); disable(); } diff --git a/lib/lib_i2c/Joba_Tsl2561-2.0.10/src/Tsl2561.cpp b/lib/lib_i2c/Joba_Tsl2561-2.0.10/src/Tsl2561.cpp index f0e324eb8..a44a9cd32 100644 --- a/lib/lib_i2c/Joba_Tsl2561-2.0.10/src/Tsl2561.cpp +++ b/lib/lib_i2c/Joba_Tsl2561-2.0.10/src/Tsl2561.cpp @@ -47,7 +47,7 @@ bool Tsl2561::begin() { bool Tsl2561::readByte( register_t reg, uint8_t &val ) { _wire.beginTransmission(_addr); - _wire.write(reg | CONTROL_CMD); + _wire.write(reg | static_cast(CONTROL_CMD)); if( (_status = static_cast(_wire.endTransmission(false))) == ERR_OK ) { if( _wire.requestFrom(_addr, 1) == 1 ) { val = static_cast(_wire.read()); @@ -61,7 +61,7 @@ bool Tsl2561::readByte( register_t reg, uint8_t &val ) { bool Tsl2561::readWord( register_t reg, uint16_t &val ) { _wire.beginTransmission(_addr); - _wire.write(reg | CONTROL_CMD); + _wire.write(reg | static_cast(CONTROL_CMD)); if( (_status = static_cast(_wire.endTransmission(false))) == ERR_OK ) { if( _wire.requestFrom(_addr, 2) == 2 ) { val = static_cast(_wire.read()) & 0xff; @@ -76,7 +76,7 @@ bool Tsl2561::readWord( register_t reg, uint16_t &val ) { bool Tsl2561::writeByte( register_t reg, uint8_t val ) { _wire.beginTransmission(_addr); - _wire.write(reg | CONTROL_CMD); + _wire.write(reg | static_cast(CONTROL_CMD)); _wire.write(val); return (_status = static_cast(_wire.endTransmission())) == ERR_OK; } @@ -118,7 +118,7 @@ bool Tsl2561::off() { } bool Tsl2561::setSensitivity( bool gain, exposure_t exposure ) { - return writeByte(REG_TIMING, (gain ? GAIN_ON : GAIN_OFF) | exposure); + return writeByte(REG_TIMING, (gain ? GAIN_ON : GAIN_OFF) | static_cast(exposure)); } bool Tsl2561::getSensitivity( bool &gain, exposure_t &exposure ) diff --git a/lib/lib_i2c/Joba_Tsl2561-2.0.10/src/Tsl2561.h b/lib/lib_i2c/Joba_Tsl2561-2.0.10/src/Tsl2561.h index 147db2a77..84f86ee27 100644 --- a/lib/lib_i2c/Joba_Tsl2561-2.0.10/src/Tsl2561.h +++ b/lib/lib_i2c/Joba_Tsl2561-2.0.10/src/Tsl2561.h @@ -42,7 +42,7 @@ public: ADDR_VDD = 0b1001001 } address_t; - typedef enum { + typedef enum : uint8_t { REG_CONTROL, // Control of basic functions REG_TIMING, // Integration time/gain control REG_THRESHLOWLOW, // Low byte of low interrupt threshold @@ -61,7 +61,7 @@ public: REG_DATA1HIGH // High byte of ADC channel 1 } register_t; - enum { + enum : uint8_t{ CONTROL_CMD = 0b10000000, CONTROL_CLEAR = 0b01000000, CONTROL_WORD = 0b00100000, // SPI only? diff --git a/lib/libesp32/lib_mail/LICENSE b/lib/lib_i2c/ScioSense_ENS16x/LICENSE.md similarity index 97% rename from lib/libesp32/lib_mail/LICENSE rename to lib/lib_i2c/ScioSense_ENS16x/LICENSE.md index 4ba9966fd..dbc30683e 100644 --- a/lib/libesp32/lib_mail/LICENSE +++ b/lib/lib_i2c/ScioSense_ENS16x/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 mobizt +Copyright (c) 2020 Sciosense Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lib/lib_i2c/ScioSense_ENS16x/README.md b/lib/lib_i2c/ScioSense_ENS16x/README.md new file mode 100644 index 000000000..2bbcaed40 --- /dev/null +++ b/lib/lib_i2c/ScioSense_ENS16x/README.md @@ -0,0 +1,38 @@ +# ScioSense ENS16x +Arduino library for the ENS160 and ENS161 digital four channel MOX gas sensor with I2C interface from ScioSense + +## Introduction +This project is an Arduino *library*. It implements a driver with examples for the ENS160 and ENS161. +The ENS16x chip is a digital gas sensor for TVOC and eCO2 with an I2C interface. +The driver in this Arduino library is based on the code supplied by *Sciosense*, the manufacturer of the chip. + +Note that the ENS16x requires a supply voltage of 1.71V .. 1.98V. +The ENS16x also requires a IO voltage of 1.71V .. 3.6V. + +## Links +The ENS16x is made by [Sciosense](http://www.sciosense.com). + - The datasheet of the ENS160 is available through the website. The datasheet of ENS161 is not yet released but can be provided on request + +## Prerequisites +It is assumed that + - The Arduino IDE has been installed. + If not, refer to "Install the Arduino Desktop IDE" on the + [Arduino site](https://www.arduino.cc/en/Guide/HomePage). + - The library directory is at its default location. + For me, that is `C:\Users\sciosense\Documents\Arduino\libraries`. + +## Installation +- Visit the project page for the Arduino ENS16x library. +- Click the green button Clone or download on the right side. +- From the pop-up choose Download ZIP. +- In Arduino IDE, select Sketch > Include Library > Manage Libraries ... and browse to the just downloaded ZIP file. +- When the IDE is ready this README.md should be located at e.g. `C:\Users\sciosense\Documents\Arduino\libraries\ScioSense_ENS16x\README.md`. + +## Build an example +To build an example sketch + - (Re)start Arduino. + - Open File > Example > Examples from Custom Libraries > ENS16x > ENS16xbasic_normal + - Make sure Tools > Board lists the correct board. + - Select Sketch > Verify/Compile. + +### ScioSense is a Joint Venture of ams AG diff --git a/lib/lib_i2c/ScioSense_ENS16x/keywords.txt b/lib/lib_i2c/ScioSense_ENS16x/keywords.txt new file mode 100644 index 000000000..35ce5e6fb --- /dev/null +++ b/lib/lib_i2c/ScioSense_ENS16x/keywords.txt @@ -0,0 +1,65 @@ +####################################### +# Syntax Coloring Map +####################################### +# https://spencer.bliven.us/index.php/2012/01/18/arduino-ide-keywords/ +# KEYWORD1 Classes, datatypes, and C++ keywords +# KEYWORD2 Methods and functions +# KEYWORD3 setup and loop functions, as well as the Serial keywords +# LITERAL1 Constants +# LITERAL2 Built-in variables (unused by default) + + +####################################### +# Classes, datatypes (KEYWORD1) +####################################### +ENS160 KEYWORD1 +ens160 KEYWORD1 +ENS161 KEYWORD1 +ens161 KEYWORD1 +ScioSense_ENS16x KEYWORD1 +ScioSense_ens16x KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +setI2C KEYWORD2 +available KEYWORD2 +revENS16x KEYWORD2 +setMode KEYWORD2 + +initCustomMode KEYWORD2 +addCustomStep KEYWORD2 + +measure KEYWORD2 +measureRaw KEYWORD2 +set_envdata KEYWORD2 +set_envdata210 KEYWORD2 +getMajorRev KEYWORD2 +getMinorRev KEYWORD2 +getBuild KEYWORD2 + +getAQI KEYWORD2 +getTVOC KEYWORD2 +geteCO2 KEYWORD2 +getAQIS KEYWORD2 +getHP0 KEYWORD2 +getHP0BL KEYWORD2 +getHP1 KEYWORD2 +getHP1BL KEYWORD2 +getHP2 KEYWORD2 +getHP2BL KEYWORD2 +getHP3 KEYWORD2 +getHP3BL KEYWORD2 +getMISR KEYWORD2 + +###################################### +# Constants (LITERAL1) +####################################### + +ENS16x_I2CADDR_0 LITERAL1 +ENS16x_I2CADDR_1 LITERAL1 +ENS16x_OPMODE_IDLE LITERAL1 +ENS16x_OPMODE_STD LITERAL1 +ENS161_OPMODE_LP LITERAL1 +ENS16x_OPMODE_CUSTOM LITERAL1 \ No newline at end of file diff --git a/lib/lib_i2c/ScioSense_ENS16x/library.properties b/lib/lib_i2c/ScioSense_ENS16x/library.properties new file mode 100644 index 000000000..f85dc659e --- /dev/null +++ b/lib/lib_i2c/ScioSense_ENS16x/library.properties @@ -0,0 +1,9 @@ +name=ScioSense ENS16x +version=8.0.0 +author=Christoph Friese +maintainer=ScioSense +sentence=Arduino library for the ENS160 and ENS161 digital four channel MOX gas sensor with I2C interface from ScioSense +paragraph=This library controls the ENS160 and ENS161. The main feature of this library is performing a single shot measurement, retrieving the measurement data. +category=Device Control +url=https://github.com/sciosense/ens16x +architectures=* diff --git a/lib/lib_i2c/ScioSense_ENS16x/src/ScioSense_ENS16x.cpp b/lib/lib_i2c/ScioSense_ENS16x/src/ScioSense_ENS16x.cpp new file mode 100644 index 000000000..6f21190e2 --- /dev/null +++ b/lib/lib_i2c/ScioSense_ENS16x/src/ScioSense_ENS16x.cpp @@ -0,0 +1,490 @@ +/* + ScioSense_ENS16x.h - Library for the ENS160 & ENS161 sensor with I2C interface from ScioSense + 2023 Jul 03 v8 Christoph Friese Update to cover ENS160 and ENS161 + 2023 Mar 23 v7 Christoph Friese Bugfix measurement routine, prepare next release + 2021 Nov 25 v6 Martin Herold Custom mode timing fixed + 2021 July 29 v5 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2021 Feb 04 v4 Giuseppe de Pinto Custom mode fixed + 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option + 2019 May 05 v1 Christoph Friese Created + + based on application note "ENS160 Software Integration.pdf" rev 0.01 +*/ + +#include "ScioSense_ENS16x.h" +#include "math.h" + +ScioSense_ENS16x::ScioSense_ENS16x(uint8_t slaveaddr) { + this->_slaveaddr = slaveaddr; + + this->_ADDR = 0; + this->_nINT = 0; + this->_nCS = 0; +} + +#ifndef ENS16x_DISABLE_ENHANCED_FEATURES +ScioSense_ENS16x::ScioSense_ENS16x(uint8_t ADDR, uint8_t nCS, uint8_t nINT) { + this->_slaveaddr = ENS16x_I2CADDR_0; + + this->_ADDR = ADDR; + this->_nINT = nINT; + this->_nCS = nCS; +} + +ScioSense_ENS16x::ScioSense_ENS16x(uint8_t slaveaddr, uint8_t ADDR, uint8_t nCS, uint8_t nINT) { + this->_slaveaddr = slaveaddr; + + this->_ADDR = ADDR; + this->_nINT = nINT; + this->_nCS = nCS; +} + +// Function to redefine I2C pins +void ScioSense_ENS16x::setI2C(uint8_t sda, uint8_t scl) { + this->_sdaPin = sda; + this->_sclPin = scl; +} +#endif + +// Init I2C communication, resets ENS16x and checks its PART_ID. Returns false on I2C problems or wrong PART_ID. +bool ScioSense_ENS16x::begin(bool debug) +{ +#ifndef ENS16x_DISABLE_DEBUG + debugENS16x = debug; + + //Set pin levels + if (this->_ADDR > 0) { + pinMode(this->_ADDR, OUTPUT); + digitalWrite(this->_ADDR, LOW); + } + if (this->_nINT > 0) pinMode(this->_nINT, INPUT_PULLUP); + if (this->_nCS > 0) { + pinMode(this->_nCS, OUTPUT); + digitalWrite(this->_nCS, HIGH); + } +#endif + + //init I2C + _i2c_init(); +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.println("begin() - I2C init done"); + } +#endif + delay(ENS16x_BOOTING); // Wait to boot after reset + + this->_available = false; + this->_available = this->reset(); + + this->_available = this->checkPartID(); + + if (this->_available) { + this->_available = this->setMode(ENS16x_OPMODE_IDLE); + this->_available = this->clearCommand(); + this->_available = this->getFirmware(); + } +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.println("ENS16x in idle mode"); + } +#endif + return this->_available; +} + +// Sends a reset to the ENS16x. Returns false on I2C problems. +bool ScioSense_ENS16x::reset(void) +{ + uint8_t result = this->write8(_slaveaddr, ENS16x_REG_OPMODE, ENS16x_OPMODE_RESET); + +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("reset() result: "); + Serial.println(result == 0 ? "ok" : "nok"); + } +#endif + delay(ENS16x_BOOTING); // Wait to boot after reset + + return result == 0; +} + +// Reads the part ID and confirms valid sensor +bool ScioSense_ENS16x::checkPartID(void) { + uint8_t i2cbuf[2]; + uint16_t part_id; + bool result = false; + + this->read(_slaveaddr, ENS16x_REG_PART_ID, i2cbuf, 2); + part_id = i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8); + +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("checkPartID() result: "); + if (part_id == ENS160_PARTID) Serial.println("ENS160 ok"); + else if (part_id == ENS161_PARTID) Serial.println("ENS161 ok"); + else Serial.println("nok"); + } +#endif + delay(ENS16x_BOOTING); // Wait to boot after reset + + if (part_id == ENS160_PARTID) { this->_revENS16x = 0; result = true; } + else if (part_id == ENS161_PARTID) { this->_revENS16x = 1; result = true; } + + return result; +} + +// Initialize idle mode and confirms +bool ScioSense_ENS16x::clearCommand(void) { + uint8_t status; + uint8_t result; + + result = this->write8(_slaveaddr, ENS16x_REG_COMMAND, ENS16x_COMMAND_NOP); + result = this->write8(_slaveaddr, ENS16x_REG_COMMAND, ENS16x_COMMAND_CLRGPR); +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("clearCommand() result: "); + Serial.println(result == 0 ? "ok" : "nok"); + } +#endif + delay(ENS16x_BOOTING); // Wait to boot after reset + + status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS); +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("clearCommand() status: 0x"); + Serial.println(status, HEX); + } +#endif + delay(ENS16x_BOOTING); // Wait to boot after reset + + return result == 0; +} + +// Read firmware revisions +bool ScioSense_ENS16x::getFirmware() { + uint8_t i2cbuf[3]; + uint8_t result; + + this->clearCommand(); + + delay(ENS16x_BOOTING); // Wait to boot after reset + + result = this->write8(_slaveaddr, ENS16x_REG_COMMAND, ENS16x_COMMAND_GET_APPVER); + result = this->read(_slaveaddr, ENS16x_REG_GPR_READ_4, i2cbuf, 3); + + this->_fw_ver_major = i2cbuf[0]; + this->_fw_ver_minor = i2cbuf[1]; + this->_fw_ver_build = i2cbuf[2]; + + if (this->_fw_ver_major > 6) this->_revENS16x = 1; + else this->_revENS16x = 0; + +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.println(this->_fw_ver_major); + Serial.println(this->_fw_ver_minor); + Serial.println(this->_fw_ver_build); + Serial.print("getFirmware() result: "); + Serial.println(result == 0 ? "ok" : "nok"); + } +#endif + delay(ENS16x_BOOTING); // Wait to boot after reset + + return result == 0; +} + +// Set operation mode of sensor +bool ScioSense_ENS16x::setMode(uint8_t mode) { + uint8_t result; + + //LP only valid for rev>0 + if ((mode == ENS161_OPMODE_LP) and (_revENS16x == 0)) result = 1; + else result = this->write8(_slaveaddr, ENS16x_REG_OPMODE, mode); + +#ifndef ENS16x_DISABLE_DEBUG + //if (debugENS16x) { + Serial.print("setMode() activate result: "); + Serial.println(result == 0 ? "ok" : "nok"); + //} +#endif + delay(ENS16x_BOOTING); // Wait to boot after reset + + return result == 0; +} + +#ifndef ENS16x_DISABLE_ENHANCED_FEATURES +// Initialize definition of custom mode with steps +bool ScioSense_ENS16x::initCustomMode(uint16_t stepNum) { + uint8_t result; + + if (stepNum > 0) { + this->_stepCount = stepNum; + + result = this->setMode(ENS16x_OPMODE_IDLE); + result = this->clearCommand(); + + result = this->write8(_slaveaddr, ENS16x_REG_COMMAND, ENS16x_COMMAND_SETSEQ); + } else { + result = 1; + } + delay(ENS16x_BOOTING); // Wait to boot after reset + + return result == 0; +} +#endif + +#ifndef ENS16x_DISABLE_ENHANCED_FEATURES +// Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate +bool ScioSense_ENS16x::addCustomStep(uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3) { + uint8_t seq_ack; + uint8_t temp; + +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("setCustomMode() write step "); + Serial.println(this->_stepCount); + } +#endif + delay(ENS16x_BOOTING); // Wait to boot after reset + + temp = (uint8_t)(((time / 24)-1) << 6); + if (measureHP0) temp = temp | 0x20; + if (measureHP1) temp = temp | 0x10; + if (measureHP2) temp = temp | 0x8; + if (measureHP3) temp = temp | 0x4; + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_0, temp); + + temp = (uint8_t)(((time / 24)-1) >> 2); + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_1, temp); + + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_2, (uint8_t)(tempHP0/2)); + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_3, (uint8_t)(tempHP1/2)); + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_4, (uint8_t)(tempHP2/2)); + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_5, (uint8_t)(tempHP3/2)); + + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_6, (uint8_t)(this->_stepCount - 1)); + + if (this->_stepCount == 1) { + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_7, 128); + } else { + this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_7, 0); + } + delay(ENS16x_BOOTING); + + seq_ack = this->read8(_slaveaddr, ENS16x_REG_GPR_READ_7); + delay(ENS16x_BOOTING); // Wait to boot after reset + + if ((ENS16x_SEQ_ACK_COMPLETE | this->_stepCount) != seq_ack) { + this->_stepCount = this->_stepCount - 1; + return 0; + } else { + return 1; + } + +} +#endif + +// Perform prediction measurement and stores result in internal variables +bool ScioSense_ENS16x::measure(bool waitForNew) { + uint8_t i2cbuf[8]; + uint8_t status; + bool newData = false; + + // Set default status for early bail out +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) Serial.println("Start measurement"); +#endif + + if (waitForNew) { + do { + delay(10); + status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS); + +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("Status: "); + Serial.println(status); + } +#endif + } while (!IS_NEWDAT(status)); + } else { + status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS); + } + + // Read predictions + if (IS_NEWDAT(status)) { + newData = true; + this->read(_slaveaddr, ENS16x_REG_DATA_AQI, i2cbuf, 7); + _data_aqi = i2cbuf[0]; + _data_tvoc = i2cbuf[1] | ((uint16_t)i2cbuf[2] << 8); + _data_eco2 = i2cbuf[3] | ((uint16_t)i2cbuf[4] << 8); + if (_revENS16x > 0) _data_aqis = ((uint16_t)i2cbuf[5]) | ((uint16_t)i2cbuf[6] << 8); + else _data_aqis = 0; + } + + return newData; +} + +#ifndef ENS16x_DISABLE_ENHANCED_FEATURES +// Perfrom raw measurement and stores result in internal variables +bool ScioSense_ENS16x::measureRaw(bool waitForNew) { + uint8_t i2cbuf[8]; + uint8_t status; + bool newData = false; + + // Set default status for early bail out +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) Serial.println("Start measurement"); +#endif + + if (waitForNew) { + do { + delay(10); + status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS); + +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("Status: "); + Serial.println(status); + } +#endif + } while (!IS_NEWGPR(status)); + } else { + status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS); + } + + if (IS_NEWGPR(status)) { + newData = true; + + // Read raw resistance values + this->read(_slaveaddr, ENS16x_REG_GPR_READ_0, i2cbuf, 8); + _hp0_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); + _hp1_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); + _hp2_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); + _hp3_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); + + // Read baselines + this->read(_slaveaddr, ENS16x_REG_DATA_BL, i2cbuf, 8); + _hp0_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8))); + _hp1_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8))); + _hp2_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8))); + _hp3_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8))); + + this->read(_slaveaddr, ENS16x_REG_DATA_MISR, i2cbuf, 1); + _misr = i2cbuf[0]; + } + + return newData; +} + +// Writes t (degC) and h (%rh) to ENV_DATA. Returns false on I2C problems. +bool ScioSense_ENS16x::set_envdata(float t, float h) { + + uint16_t t_data = (uint16_t)((t + 273.15f) * 64.0f); + + uint16_t rh_data = (uint16_t)(h * 512.0f); + + return this->set_envdata210(t_data, rh_data); +} + +// Writes t and h (in ENS210 format) to ENV_DATA. Returns false on I2C problems. +bool ScioSense_ENS16x::set_envdata210(uint16_t t, uint16_t h) { + //uint16_t temp; + uint8_t trh_in[4]; + + //temp = (uint16_t)((t + 273.15f) * 64.0f); + trh_in[0] = t & 0xff; + trh_in[1] = (t >> 8) & 0xff; + + //temp = (uint16_t)(h * 512.0f); + trh_in[2] = h & 0xff; + trh_in[3] = (h >> 8) & 0xff; + + uint8_t result = this->write(_slaveaddr, ENS16x_REG_TEMP_IN, trh_in, 4); + + return result; +} +#endif + +/**************************************************************************/ + +void ScioSense_ENS16x::_i2c_init() { +#ifndef ENS16x_DISABLE_ENHANCED_FEATURES + if (this->_sdaPin != this->_sclPin) + Wire.begin(this->_sdaPin, this->_sclPin); + else +#endif + Wire.begin(); +} + +/**************************************************************************/ + +uint8_t ScioSense_ENS16x::read8(uint8_t addr, byte reg) { + uint8_t ret; + this->read(addr, reg, &ret, 1); + + return ret; +} + +uint8_t ScioSense_ENS16x::read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num) { + uint8_t pos = 0; + uint8_t result = 0; + +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("I2C read address: 0x"); + Serial.print(addr, HEX); + Serial.print(" - register: 0x"); + Serial.println(reg, HEX); + } +#endif + + //on arduino we need to read in 32 byte chunks + while(pos < num){ + + uint8_t read_now = min((uint8_t)32, (uint8_t)(num - pos)); + Wire.beginTransmission((uint8_t)addr); + + Wire.write((uint8_t)reg + pos); + result = Wire.endTransmission(); + Wire.requestFrom((uint8_t)addr, read_now); + + for(int i=0; iwrite(addr, reg, &value, 1); + return result; +} + +uint8_t ScioSense_ENS16x::write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num) { +#ifndef ENS16x_DISABLE_DEBUG + if (debugENS16x) { + Serial.print("I2C write address: 0x"); + Serial.print(addr, HEX); + Serial.print(" - register: 0x"); + Serial.print(reg, HEX); + Serial.print(" - value:"); + for (int i = 0; i= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include + +// Chip constants +#define ENS160_PARTID 0x0160 +#define ENS161_PARTID 0x0161 +#define ENS16x_BOOTING 10 + +// 7-bit I2C slave address of the ENS16x +#define ENS16x_I2CADDR_0 0x52 //ADDR low +#define ENS16x_I2CADDR_1 0x53 //ADDR high + +// ENS16x registers for version V0 +#define ENS16x_REG_PART_ID 0x00 // 2 byte register +#define ENS16x_REG_OPMODE 0x10 +#define ENS16x_REG_CONFIG 0x11 +#define ENS16x_REG_COMMAND 0x12 +#define ENS16x_REG_TEMP_IN 0x13 +#define ENS16x_REG_RH_IN 0x15 +#define ENS16x_REG_DATA_STATUS 0x20 +#define ENS16x_REG_DATA_AQI 0x21 +#define ENS16x_REG_DATA_TVOC 0x22 +#define ENS16x_REG_DATA_ECO2 0x24 +#define ENS16x_REG_DATA_BL 0x28 +#define ENS16x_REG_DATA_T 0x30 +#define ENS16x_REG_DATA_RH 0x32 +#define ENS16x_REG_DATA_MISR 0x38 +#define ENS16x_REG_GPR_WRITE_0 0x40 +#define ENS16x_REG_GPR_WRITE_1 ENS16x_REG_GPR_WRITE_0 + 1 +#define ENS16x_REG_GPR_WRITE_2 ENS16x_REG_GPR_WRITE_0 + 2 +#define ENS16x_REG_GPR_WRITE_3 ENS16x_REG_GPR_WRITE_0 + 3 +#define ENS16x_REG_GPR_WRITE_4 ENS16x_REG_GPR_WRITE_0 + 4 +#define ENS16x_REG_GPR_WRITE_5 ENS16x_REG_GPR_WRITE_0 + 5 +#define ENS16x_REG_GPR_WRITE_6 ENS16x_REG_GPR_WRITE_0 + 6 +#define ENS16x_REG_GPR_WRITE_7 ENS16x_REG_GPR_WRITE_0 + 7 +#define ENS16x_REG_GPR_READ_0 0x48 +#define ENS16x_REG_GPR_READ_4 ENS16x_REG_GPR_READ_0 + 4 +#define ENS16x_REG_GPR_READ_6 ENS16x_REG_GPR_READ_0 + 6 +#define ENS16x_REG_GPR_READ_7 ENS16x_REG_GPR_READ_0 + 7 + +//ENS16x data register fields +#define ENS16x_COMMAND_NOP 0x00 +#define ENS16x_COMMAND_CLRGPR 0xCC +#define ENS16x_COMMAND_GET_APPVER 0x0E +#define ENS16x_COMMAND_SETTH 0x02 +#define ENS16x_COMMAND_SETSEQ 0xC2 + +#define ENS16x_OPMODE_RESET 0xF0 +#define ENS16x_OPMODE_DEP_SLEEP 0x00 +#define ENS16x_OPMODE_IDLE 0x01 +#define ENS16x_OPMODE_STD 0x02 +#define ENS161_OPMODE_LP 0x03 +#define ENS16x_OPMODE_CUSTOM 0xC0 + +#define ENS16x_BL_CMD_START 0x02 +#define ENS16x_BL_CMD_ERASE_APP 0x04 +#define ENS16x_BL_CMD_ERASE_BLINE 0x06 +#define ENS16x_BL_CMD_WRITE 0x08 +#define ENS16x_BL_CMD_VERIFY 0x0A +#define ENS16x_BL_CMD_GET_BLVER 0x0C +#define ENS16x_BL_CMD_GET_APPVER 0x0E +#define ENS16x_BL_CMD_EXITBL 0x12 + +#define ENS16x_SEQ_ACK_NOTCOMPLETE 0x80 +#define ENS16x_SEQ_ACK_COMPLETE 0xC0 + +#define IS_ENS16x_SEQ_ACK_NOT_COMPLETE(x) (ENS16x_SEQ_ACK_NOTCOMPLETE == (ENS16x_SEQ_ACK_NOTCOMPLETE & (x))) +#define IS_ENS16x_SEQ_ACK_COMPLETE(x) (ENS16x_SEQ_ACK_COMPLETE == (ENS16x_SEQ_ACK_COMPLETE & (x))) + +#define ENS16x_DATA_STATUS_NEWDAT 0x02 +#define ENS16x_DATA_STATUS_NEWGPR 0x01 + +#define IS_NEWDAT(x) (ENS16x_DATA_STATUS_NEWDAT == (ENS16x_DATA_STATUS_NEWDAT & (x))) +#define IS_NEWGPR(x) (ENS16x_DATA_STATUS_NEWGPR == (ENS16x_DATA_STATUS_NEWGPR & (x))) +#define IS_NEW_DATA_AVAILABLE(x) (0 != ((ENS16x_DATA_STATUS_NEWDAT | ENS16x_DATA_STATUS_NEWGPR ) & (x))) + +#define CONVERT_RS_RAW2OHMS_I(x) (1 << ((x) >> 11)) +#define CONVERT_RS_RAW2OHMS_F(x) (pow (2, (float)(x) / 2048)) + +class ScioSense_ENS16x { + + public: + ScioSense_ENS16x(uint8_t slaveaddr = ENS16x_I2CADDR_0); // Constructor using slave address (5A or 5B) +#ifndef ENS16x_DISABLE_ENHANCED_FEATURES + ScioSense_ENS16x(uint8_t ADDR, uint8_t nCS, uint8_t nINT); // Constructor with pin definition + ScioSense_ENS16x(uint8_t slaveaddr, uint8_t ADDR, uint8_t nCS, uint8_t nINT); // Constructor with slave address and pin definition +#endif + + void setI2C(uint8_t sda, uint8_t scl); // Function to redefine I2C pins + + bool begin(bool debug=false); // Init I2C communication, resets ENS16x and checks its PART_ID. Returns false on I2C problems or wrong PART_ID. + bool available() { return this->_available; } // Report availability of sensor + uint8_t revENS16x() { return this->_revENS16x; } // Report version of sensor (0: ENS16x, 1: ENS161) + bool setMode(uint8_t mode); // Set operation mode of sensor + +#ifndef ENS16x_DISABLE_ENHANCED_FEATURES + bool initCustomMode(uint16_t stepNum); // Initialize definition of custom mode with steps + bool addCustomStep(uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3); + // Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate +#endif + + bool measure(bool waitForNew = true); // Perform measurement and stores result in internal variables +#ifndef ENS16x_DISABLE_ENHANCED_FEATURES + bool measureRaw(bool waitForNew = true); // Perform raw measurement and stores result in internal variables + bool set_envdata(float t, float h); // Writes t (degC) and h (%rh) to ENV_DATA. Returns "0" if I2C transmission is successful + bool set_envdata210(uint16_t t, uint16_t h); // Writes t and h (in ENS210 format) to ENV_DATA. Returns "0" if I2C transmission is successful +#endif + uint8_t getMajorRev() { return this->_fw_ver_major; } // Get major revision number of used firmware + uint8_t getMinorRev() { return this->_fw_ver_minor; } // Get minor revision number of used firmware + uint8_t getBuild() { return this->_fw_ver_build; } // Get build revision number of used firmware + + uint8_t getAQI() { return this->_data_aqi; } // Get AQI value of last measurement + uint16_t getTVOC() { return this->_data_tvoc; } // Get TVOC value of last measurement + uint16_t geteCO2() { return this->_data_eco2; } // Get eCO2 value of last measurement + uint16_t getAQIS() { return this->_data_aqis; } // Get AQI500 value of last measurement + uint32_t getHP0() { return this->_hp0_rs; } // Get resistance of HP0 of last measurement + uint32_t getHP1() { return this->_hp1_rs; } // Get resistance of HP1 of last measurement + uint32_t getHP2() { return this->_hp2_rs; } // Get resistance of HP2 of last measurement + uint32_t getHP3() { return this->_hp3_rs; } // Get resistance of HP3 of last measurement + uint32_t getHP0BL() { return this->_hp0_bl; } // Get baseline resistance of HP0 of last measurement + uint32_t getHP1BL() { return this->_hp1_bl; } // Get baseline resistance of HP1 of last measurement + uint32_t getHP2BL() { return this->_hp2_bl; } // Get baseline resistance of HP2 of last measurement + uint32_t getHP3BL() { return this->_hp3_bl; } // Get baseline resistance of HP3 of last measurement + uint8_t getMISR() { return this->_misr; } // Return status code of sensor + + private: + uint8_t _ADDR; + uint8_t _nINT; + uint8_t _nCS; + uint8_t _sdaPin = 0; + uint8_t _sclPin = 0; + +#ifndef ENS16x_DISABLE_DEBUG + bool debugENS16x = false; +#endif + + bool reset(); // Sends a reset to the ENS16x. Returns false on I2C problems. + bool checkPartID(); // Reads the part ID and confirms valid sensor + bool clearCommand(); // Initialize idle mode and confirms + bool getFirmware(); // Read firmware revisions + + bool _available = false; // ENS16x available + uint8_t _revENS16x = 0; // ENS160 or ENS161 connected? (FW >7) + + uint8_t _fw_ver_major; + uint8_t _fw_ver_minor; + uint8_t _fw_ver_build; + + uint16_t _stepCount; // Counter for custom sequence + + uint8_t _data_aqi; + uint16_t _data_tvoc; + uint16_t _data_eco2; + uint16_t _data_aqis; + uint32_t _hp0_rs; + uint32_t _hp0_bl; + uint32_t _hp1_rs; + uint32_t _hp1_bl; + uint32_t _hp2_rs; + uint32_t _hp2_bl; + uint32_t _hp3_rs; + uint32_t _hp3_bl; + uint16_t _temp; + int _slaveaddr; + uint8_t _misr; + + //Isotherm, HP0 252°C / HP1 350°C / HP2 250°C / HP3 324°C / measure every 1008ms + uint8_t _seq_steps[1][8] = { + { 0x7C, 0x0A, 0x7E, 0xAF, 0xAF, 0xA2, 0x00, 0x80 }, + }; + + +/****************************************************************************/ +/* General functions */ +/****************************************************************************/ + void _i2c_init(); + + uint8_t read8(uint8_t addr, byte reg); + uint8_t read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num); + + uint8_t write8(uint8_t addr, byte reg, byte value); + uint8_t write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num); + +}; + + +#endif \ No newline at end of file diff --git a/lib/lib_i2c/ScioSense_ENS210/README.md b/lib/lib_i2c/ScioSense_ENS210/README.md new file mode 100644 index 000000000..3e5ea811e --- /dev/null +++ b/lib/lib_i2c/ScioSense_ENS210/README.md @@ -0,0 +1,28 @@ +# ENS210 +Arduino library for the ENS210 temperature & humidity sensor with I2C interface from ScioSense + +## Introduction +This project is an Arduino *library*. It implements a driver with examples for the ENS210. +The ENS210 chip is a digital temperature & humidity sensor with an I2C interface. +The driver in this Arduino library is based on the code supplied by *Sciosense*, the manufacturer of the chip. + +Note that the ENS210 requires a supply voltage of 1.71V .. 1.98V. + +## Links +The ENS210 is made by [Sciosense](http://www.sciosense.com). + - The datasheet of the ENS210 is not yet released + +## Prerequisites +It is assumed that + - The Arduino IDE has been installed. + If not, refer to "Install the Arduino Desktop IDE" on the + [Arduino site](https://www.arduino.cc/en/Guide/HomePage). + - The library directory is at its default location. + For me, Christoph, that is `C:\Users\christoph\Documents\Arduino\libraries`. + +## Build an example +To build an example sketch + - (Re)start Arduino. + - Open File > Example > Examples from Custom Libraries > ENS210 > ENS210basic. + - Make sure Tools > Board lists the correct board. + - Select Sketch > Verify/Compile. \ No newline at end of file diff --git a/lib/lib_i2c/ScioSense_ENS210/keywords.txt b/lib/lib_i2c/ScioSense_ENS210/keywords.txt new file mode 100644 index 000000000..db012a2a2 --- /dev/null +++ b/lib/lib_i2c/ScioSense_ENS210/keywords.txt @@ -0,0 +1,53 @@ +####################################### +# Syntax Coloring Map +####################################### +# https://spencer.bliven.us/index.php/2012/01/18/arduino-ide-keywords/ +# KEYWORD1 Classes, datatypes, and C++ keywords +# KEYWORD2 Methods and functions +# KEYWORD3 setup and loop functions, as well as the Serial keywords +# LITERAL1 Constants +# LITERAL2 Built-in variables (unused by default) + + +####################################### +# Classes, datatypes (KEYWORD1) +####################################### +ENS210 KEYWORD1 +ens210 KEYWORD1 +sciosense_ens210 KEYWORD1 +Sciosense_ens210 KEYWORD1 +ScioSense_ens210 KEYWORD1 +sciosense_ENS210 KEYWORD1 +Sciosense_ENS210 KEYWORD1 +ScioSense_ENS210 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +setSingleMode KEYWORD2 +available KEYWORD2 +getPartID KEYWORD2 +getHighUID KEYWORD2 +measure KEYWORD2 +getTempKelvin KEYWORD2 +getTempCelsius KEYWORD2 +getTempFahrenheit KEYWORD2 +getHumidityPercent KEYWORD2 +getAbsoluteHumidityPercent KEYWORD2 +getStatusT KEYWORD2 +getDataT KEYWORD2 +getStatusH KEYWORD2 +getDataH KEYWORD2 +status_str KEYWORD2 +correction_set KEYWORD2 +correction_get KEYWORD2 + +###################################### +# Constants (LITERAL1) +####################################### + +ENS210_STATUS_I2CERROR LITERAL1 +ENS210_STATUS_CRCERROR LITERAL1 +ENS210_STATUS_INVALID LITERAL1 +ENS210_STATUS_OK LITERAL1 diff --git a/lib/lib_i2c/ScioSense_ENS210/library.properties b/lib/lib_i2c/ScioSense_ENS210/library.properties new file mode 100644 index 000000000..0a9f30ed6 --- /dev/null +++ b/lib/lib_i2c/ScioSense_ENS210/library.properties @@ -0,0 +1,9 @@ +name=ScioSense ENS210 +version=3.0.0 +author=Christoph Friese +maintainer=Christoph Friese +sentence=Arduino library for the ENS210 digital temperature & humidity sensor with I2C interface from ScioSense +paragraph=This library controls the ENS210. The main feature of this library is performing a single shot measurement, retrieving the measurement data. +category=Device Control +url=https://github.com/sciosense/ens210 +architectures=* diff --git a/lib/lib_i2c/ScioSense_ENS210/src/ScioSense_ENS210.cpp b/lib/lib_i2c/ScioSense_ENS210/src/ScioSense_ENS210.cpp new file mode 100644 index 000000000..48c291cdc --- /dev/null +++ b/lib/lib_i2c/ScioSense_ENS210/src/ScioSense_ENS210.cpp @@ -0,0 +1,648 @@ +/* + ScioSense_ENS210.h - Library for the ENS210 relative humidity and temperature sensor with I2C interface from ScioSense + 2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams + 2018 Aug 28 v2 Christoph Friese Adjusted I2C communication + 2017 Aug 01 v1 Maarten Pennings Created +*/ + +#include "ScioSense_ENS210.h" +#include + +// Compute the CRC-7 of 'val' (should only have 17 bits) +// https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Computation +static uint32_t crc7( uint32_t val ) +{ + // Setup polynomial + uint32_t pol= CRC7POLY; + // Align polynomial with data + pol = pol << (DATA7WIDTH-CRC7WIDTH-1); + // Loop variable (indicates which bit to test, start with highest) + uint32_t bit = DATA7MSB; + // Make room for CRC value + val = val << CRC7WIDTH; + bit = bit << CRC7WIDTH; + pol = pol << CRC7WIDTH; + // Insert initial vector + val |= CRC7IVEC; + // Apply division until all bits done + while( bit & (DATA7MASK<>= 1; + pol >>= 1; + } + return val; +} + +ScioSense_ENS210::ScioSense_ENS210(uint8_t slaveaddr) { + this->_slaveaddress = slaveaddr; +} + +#ifndef ENS210_DISABLE_ENHANCED_FEATURES +void ScioSense_ENS210::setI2C(uint8_t sda, uint8_t scl) { + this->_sdaPin = sda; + this->_sclPin = scl; +} +#endif + +// Init I2C communication, resets ENS210 and checks its PART_ID. Returns false on I2C problems or wrong PART_ID. +// Stores solder correction. +bool ScioSense_ENS210::begin(bool debug) { + bool result; + +#ifndef ENS210_DISABLE_DEBUG + debugENS210 = debug; +#endif + + //init I2C + _i2c_init(); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.println("ens210 debug - I2C init done"); + } +#endif + + // Record solder correction + this->_soldercorrection= 0; + this->_available = false; + this->_singleMode = true; + this->_t_data = -1; + this->_h_data = -1; + this->_partID = 0; + + this->lowpower(false); + + result = this->getversion(); + + if(this->_partID == ENS210_PARTID ) { + this->_available = true; + } + return result; +} + +#ifndef ENS210_DISABLE_ENHANCED_FEATURES +void ScioSense_ENS210::changeAddr(uint8_t oldAddr, uint8_t newAddr) { + uint8_t i2cbuf[2]; + + _i2c_init(); + + //Disable low power mode --> always on + uint8_t result = this->write8(oldAddr, 0x10, 0x00); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Low Power off result: 0x"); + Serial.println(result,HEX); +#endif + delay(100); + + // read status register + result = this->read(oldAddr, 0x11, i2cbuf, 1); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Read status result: 0x"); + Serial.println(result,HEX); + for (uint8_t i=0; i<1; i++) { + Serial.print("\t0x"); + Serial.print(i2cbuf[i],HEX); + } + Serial.println(); +#endif + delay(100); + + // enable low level access. PASSWORD_WRITE_ENABLE + result = this->write8(oldAddr, 0x10, 0x30); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("PASSWORD_WRITE_ENABLE result: 0x"); + Serial.println(result,HEX); +#endif + delay(100); + + // read status register + result = this->read(oldAddr, 0x11, i2cbuf, 1); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Read status result: 0x"); + Serial.println(result,HEX); + for (uint8_t i=0; i<1; i++) { + Serial.print("\t0x"); + Serial.print(i2cbuf[i],HEX); + } + Serial.println(); +#endif + delay(100); + + // low level access password. Password is 00 00 00 00 + uint8_t passwdCmd[4] = {0x00, 0x00, 0x00, 0x00}; + result = this->write(oldAddr, 0x48, passwdCmd, 5); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Write password result: 0x"); + Serial.println(result,HEX); +#endif + delay(100); + + // read low-level mode sensor output data + result = this->read(oldAddr, 0x46, i2cbuf, 2); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Read low level result: 0x"); + Serial.println(result,HEX); + for (uint8_t i=0; i<2; i++) { + Serial.print("\t0x"); + Serial.print(i2cbuf[i],HEX); + } + Serial.println(); +#endif + delay(100); + + // write values to parameter field and data1&2 field + uint8_t newAddrCmd[5] = {0x00,0x00,0x22,0x00,0x41}; + newAddrCmd[4] = newAddr; + result = this->write(oldAddr, 0x41, newAddrCmd, 5); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Write parameters result: 0x"); + Serial.println(result,HEX); +#endif + delay(100); + + // write SEN_CMD to execute low-level command specified, 0xCE means “APB_WRITE” + result = this->write8(oldAddr, 0x40, 0xCE); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Execute result: 0x"); + Serial.println(result,HEX); +#endif + delay(100); + + // Read low-level mode sensor output data to check if programming succeeded. Expected response: 0x00 0xAC + result = this->read(oldAddr, 0x46, i2cbuf, 2); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Read back result: 0x"); + Serial.println(result,HEX); + for (uint8_t i=0; i<2; i++) { + Serial.print("\t0x"); + Serial.print(i2cbuf[i],HEX); + } + Serial.println(); +#endif + delay(100); + + // reset ENS210 + result = this->write8(oldAddr, 0x10, 0xFF); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Reset result: 0x"); + Serial.println(result,HEX); +#endif + delay(100); + + // reset ENS210 + result = this->write8(oldAddr, 0x10, 0xFF); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Reset result: 0x"); + Serial.println(result,HEX); +#endif + delay(100); + + // reset ENS210 + result = this->write8(newAddr, 0x10, 0xFF); +#ifndef ENS210_DISABLE_DEBUG + Serial.print("Reset result: 0x"); + Serial.println(result,HEX); +#endif + delay(100); +} +#endif //#ifndef ENS210_DISABLE_ENHANCED_FEATURES + +// Sends a reset to the ENS210. Returns false on I2C problems. +bool ScioSense_ENS210::reset(void) { + uint8_t result = this->write8(_slaveaddress, ENS210_REG_SYS_CTRL, 0x80); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - reset: 0x"); + Serial.println(result,HEX); + } +#endif + delay(ENS210_BOOTING); // Wait to boot after reset + return result==0; +} + + +// Sets ENS210 to low (true) or high (false) power. Returns false on I2C problems. +bool ScioSense_ENS210::lowpower(bool enable) { + uint8_t power = enable ? 0x01: 0x00; + uint8_t result = this->write8(this->_slaveaddress, ENS210_REG_SYS_CTRL, power); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - lowpower: 0x"); + Serial.println(result,HEX); + } +#endif + delay(ENS210_BOOTING); // Wait boot-time after power switch + return result==0; +} + + +// Reads PART_ID and UID of ENS210. Returns false on I2C problems. +bool ScioSense_ENS210::getversion() { + bool ok; + uint8_t i2cbuf[8]; + uint8_t result; + + // Must disable low power to read PART_ID or UID + ok= lowpower(false); if(!ok) goto errorexit; + + // Read the PART_ID + result = this->read(this->_slaveaddress, ENS210_REG_PART_ID, i2cbuf, 2); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - PART_ID I2C result: 0x"); + Serial.println(result, HEX); + } +#endif + //this->_partID = (uint16_t)(i2cbuf[1]*256U + i2cbuf[0]*1U); + this->_partID = (uint16_t)(((uint16_t)i2cbuf[1] << 8) | ((uint16_t)i2cbuf[0])); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("PART_ID: 0x"); + Serial.println(this->_partID,HEX); + } +#endif + + // Read the REV + result = this->read(this->_slaveaddress, ENS210_REG_REV, i2cbuf, 2); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - REV I2C result: 0x"); + Serial.println(result, HEX); + } +#endif + this->_rev = (uint16_t)(((uint16_t)i2cbuf[1] << 8) | ((uint16_t)i2cbuf[0])); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("REV: 0x"); + Serial.println(this->_rev,HEX); + } +#endif + + // Read the UID + result = this->read(_slaveaddress, ENS210_REG_UID,i2cbuf,8); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - UID 0x"); + Serial.println(result,HEX); + } +#endif + this->_uID = (uint64_t)((uint64_t)i2cbuf[7]<<56 | (uint64_t)i2cbuf[6]<<48 | (uint64_t)i2cbuf[5]<<40 | (uint64_t)i2cbuf[4]<<32 | (uint64_t)i2cbuf[3]<<24 | (uint64_t)i2cbuf[2]<<16 | (uint64_t)i2cbuf[1]<<8 | (uint64_t)i2cbuf[0]); + + //for( int i=0; i<8; i++) ((uint8_t*)this->_uID)[i]=i2cbuf[i]; //((uint8_t*)this->_uID)[i]=i2cbuf[i]; + this->_uIDhi = (uint32_t)(this->_uID >> 32); + this->_uIDlo = (uint32_t)(this->_uID & 0xFFFFFFFF); + +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("UID hi 0x"); + Serial.print(this->_uIDhi,HEX); + Serial.print(" - 0x"); + Serial.println(this->_uIDlo,HEX); + } +#endif + + // Go back to default power mode (low power enabled) + ok= lowpower(true); if(!ok) goto errorexit; + + // Success + return true; + + errorexit: + // Try to go back to default mode (low power enabled) + ok= lowpower(true); + + // Hopefully enabling low power was successful; but there was an error before that anyhow + return false; +} + +// Configures ENS210 measurement mode +// false for continuous mode / true for single shot measurement. Returns false on I2C problems. +bool ScioSense_ENS210::setSingleMode(bool enable) +{ + this->_singleMode = enable; + uint8_t mode = enable ? 0x00: 0x03; + uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_RUN, mode); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - start mode 0x"); + Serial.print(mode,HEX); + Serial.print(" - result 0x"); + Serial.println(result,HEX); + } +#endif + return result==0; +} + +// Performs one single shot temperature and relative humidity measurement. +void ScioSense_ENS210::measure() //int * t_data, int * t_status, int * h_data, int * h_status ) +{ + bool ok; + // Set default status for early bail out +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) Serial.println("Start measurement"); +#endif + this->_t_status = ENS210_STATUS_I2CERROR; + this->_h_status = ENS210_STATUS_I2CERROR; + + // Start a single shot measurement + if (this->_singleMode) + { + uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_RUN, 0x00); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - start single 0x"); + Serial.println(result,HEX); + } +#endif + } + + //Trigger measurement + uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_START, 0x03); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - trigger measurement 0x"); + Serial.println(result,HEX); + } +#endif + + // Wait for measurement to complete + if (this->_singleMode) delay(ENS210_THCONV_SINGLE_MS); + else delay(ENS210_THCONV_CONT_MS); + + // Get the measurement data +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) Serial.println("Start measurement"); +#endif + ok = readValue(); if(!ok) return; +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) Serial.println("Measurement ok"); +#endif +} + +// Reads measurement data from the ENS210. Returns false on I2C problems. +bool ScioSense_ENS210::readValue() //uint32_t *t_val, uint32_t *h_val) +{ + uint8_t i2cbuf[6]; + uint8_t valid; + uint32_t crc; + uint32_t payload; + uint8_t crc_ok; + + // Read T_VAL and H_VAL + uint8_t result = this->read(_slaveaddress, ENS210_REG_T_VAL, i2cbuf, 6); +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("ens210 debug - readValue:"); + Serial.println(result); + Serial.print(i2cbuf[0],HEX); Serial.print("\t"); + Serial.print(i2cbuf[1],HEX); Serial.print("\t"); + Serial.print(i2cbuf[2],HEX); Serial.print("\t"); + Serial.print(i2cbuf[3],HEX); Serial.print("\t"); + Serial.print(i2cbuf[4],HEX); Serial.print("\t"); + Serial.print(i2cbuf[5],HEX); Serial.println("\t"); + } +#endif + // Retrieve and pack bytes into t_val and h_val + uint32_t t_val= (uint32_t)((uint32_t)i2cbuf[2]<<16 | (uint32_t)i2cbuf[1]<<8 | (uint32_t)i2cbuf[0]); + this->_t_data = (t_val>>0) & 0xffff; + valid = (t_val>>16) & 0x1; + crc = (t_val>>17) & 0x7f; + payload = (t_val>>0 ) & 0x1ffff; + crc_ok = crc7(payload)==crc; + if( !crc_ok ) this->_t_status = ENS210_STATUS_CRCERROR; + else if( !valid ) this->_t_status = ENS210_STATUS_INVALID; + else this->_t_status = ENS210_STATUS_OK; +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("_t_data 0x"); + Serial.print(t_val,HEX); + Serial.print(" - 0x"); + Serial.println(this->_t_data,HEX); + Serial.print("Valid: "); + Serial.print(valid); + Serial.print(" Status: "); + Serial.println(this->_t_status); + } +#endif + + uint32_t h_val= (uint32_t)((uint32_t)i2cbuf[5]<<16 | (uint32_t)i2cbuf[4]<<8 | (uint32_t)i2cbuf[3]); + this->_h_data = (h_val>>0) & 0xffff; + + valid = (h_val>>16) & 0x1; + crc = (h_val>>17) & 0x7f; + payload = (h_val>>0 ) & 0x1ffff; + crc_ok= crc7(payload)==crc; + if( !crc_ok ) this->_h_status= ENS210_STATUS_CRCERROR; + else if( !valid ) this->_h_status= ENS210_STATUS_INVALID; + else this->_h_status= ENS210_STATUS_OK; +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("_h_data 0x"); + Serial.print(h_val,HEX); + Serial.print(" - 0x"); + Serial.println(this->_h_data,HEX); + Serial.print("Valid: "); + Serial.print(valid); + Serial.print(" Status: "); + Serial.println(this->_h_status); + } +#endif + + // Success + return true; +} + + +#ifndef ENS210_DISABLE_ENHANCED_FEATURES +// Converts a status (ENS210_STATUS_XXX) to a human readable string. +const char * ScioSense_ENS210::status_str( int status ) +{ + switch( status ) { + case ENS210_STATUS_I2CERROR : return "i2c-error"; + case ENS210_STATUS_CRCERROR : return "crc-error"; + case ENS210_STATUS_INVALID : return "data-invalid"; + case ENS210_STATUS_OK : return "ok"; + default : return "unknown-status"; + } +} +#endif + +#ifndef ENS210_DISABLE_ENHANCED_FEATURES +// Convert raw `t_data` temperature to Kelvin (also applies the solder correction). +// The output value is in Kelvin multiplied by parameter `multiplier`. +float ScioSense_ENS210::getTempKelvin() +{ + // Force 32 bits + float t = this->_t_data & 0xFFFF; + // Compensate for soldering effect + t-= _soldercorrection; + // Return m*K. This equals m*(t/64) = (m*t)/64 + // Note m is the multiplier, K is temperature in Kelvin, t is raw t_data value. + // Uses K=t/64. + return t/64; //IDIV(t,64); +} +#endif + +// Convert raw `t_data` temperature to Celsius (also applies the solder correction). +// The output value is in Celsius multiplied by parameter `multiplier`. +float ScioSense_ENS210::getTempCelsius() +{ + //assert( (1<=multiplier) && (multiplier<=1024) ); + // Force 32 bits + float t= this->_t_data & 0xFFFF; + // Compensate for soldering effect + t-= _soldercorrection; + // Return m*C. This equals m*(K-273.15) = m*K - 27315*m/100 = m*t/64 - 27315*m/100 + // Note m is the multiplier, C is temperature in Celsius, K is temperature in Kelvin, t is raw t_data value. + // Uses C=K-273.15 and K=t/64. + return t/64 - 27315L/100; //IDIV(t,64) - IDIV(27315L,100); +} + +#ifndef ENS210_DISABLE_ENHANCED_FEATURES +// Convert raw `t_data` temperature to Fahrenheit (also applies the solder correction). +float ScioSense_ENS210::getTempFahrenheit() +{ + float t= this->_t_data & 0xFFFF; + // Compensate for soldering effect + t-= _soldercorrection; + // Return m*F. This equals m*(1.8*(K-273.15)+32) = m*(1.8*K-273.15*1.8+32) = 1.8*m*K-459.67*m = 9*m*K/5 - 45967*m/100 = 9*m*t/320 - 45967*m/100 + // Note m is the multiplier, F is temperature in Fahrenheit, K is temperature in Kelvin, t is raw t_data value. + // Uses F=1.8*(K-273.15)+32 and K=t/64. + return 9*t/320 - 45967/100; //IDIV(9*t,320) - IDIV(45967L,100); + // The first multiplication stays below 32 bits (t:16, multiplier:11, 9:4) + // The second multiplication stays below 32 bits (multiplier:10, 45967:16) +} +#endif + +// Convert raw `h_data` relative humidity to %RH. +float ScioSense_ENS210::getHumidityPercent() +{ + float h= this->_h_data & 0xFFFF; + // Return m*H. This equals m*(h/512) = (m*h)/512 + // Note m is the multiplier, H is the relative humidity in %RH, h is raw h_data value. + // Uses H=h/512. + return h/512; //IDIV(h, 512); +} + + +// Convert raw `h_data` absolute humidity to %RH. +#define MOLAR_MASS_OF_WATER 18.01534 +#define UNIVERSAL_GAS_CONSTANT 8.21447215 + +#ifndef ENS210_DISABLE_ENHANCED_FEATURES +float ScioSense_ENS210::getAbsoluteHumidityPercent() +{ + //taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/ + //precision is about 0.1°C in range -30 to 35°C + //August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04) + //Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97) + //reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html // Use Buck (1981) + + return (6.1121 * pow(2.718281828,(17.67* this->getTempCelsius())/(this->getTempCelsius() + 243.5))* this->getHumidityPercent() *MOLAR_MASS_OF_WATER)/((273.15+ this->getTempCelsius() )*UNIVERSAL_GAS_CONSTANT); +} +#endif + +#ifndef ENS210_DISABLE_ENHANCED_FEATURES +// Sets the solder correction (default is 50mK) - only used by the `toXxx` functions. +void ScioSense_ENS210::correction_set(int correction) +{ + assert( -1*64_soldercorrection = correction; +} +#endif + + +/****************************************************************************/ +/* General functions */ +/****************************************************************************/ + +void ScioSense_ENS210::_i2c_init() { +#ifndef ENS210_DISABLE_ENHANCED_FEATURES + if (this->_sdaPin != this->_sclPin) + Wire.begin(this->_sdaPin, this->_sclPin); + else +#endif + Wire.begin(); +} +/**************************************************************************/ + +uint8_t ScioSense_ENS210::read8(uint8_t addr, byte reg) +{ + uint8_t ret; + this->read(addr, reg, &ret, 1); + + return ret; +} + +uint8_t ScioSense_ENS210::read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num) +{ + uint8_t pos = 0; + uint8_t result = 0; + +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("I2C read address: 0x"); + Serial.print(addr, HEX); + Serial.print(" - register: 0x"); + Serial.println(reg, HEX); + } +#endif + + //on arduino we need to read in 32 byte chunks + while(pos < num){ + + uint8_t read_now = 32; //min((uint8_t)32, (uint8_t)(num - pos)); + Wire.beginTransmission((uint8_t)addr); + + Wire.write((uint8_t)reg + pos); + result = Wire.endTransmission(); + Wire.requestFrom((uint8_t)addr, read_now); + + //for(int i=0; iwrite(addr, reg, &value, 1); + return result; +} + +uint8_t ScioSense_ENS210::write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num) +{ +#ifndef ENS210_DISABLE_DEBUG + if (debugENS210) { + Serial.print("I2C write address: 0x"); + Serial.print(addr, HEX); + Serial.print(" - register: 0x"); + Serial.print(reg, HEX); + Serial.print(" - value: 0x"); + for (int i = 0; i= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include + +#define ENS210_I2CADDR 0x43 //ADDR low + +// Chip constants +#define ENS210_PARTID 0x0210 // The expected part id of the ENS210 +#define ENS210_BOOTING 2 // Booting time in ms (also after reset, or going to high power) +#define ENS210_THCONV_SINGLE_MS 130 // Conversion time in ms for single shot T/H measurement +#define ENS210_THCONV_CONT_MS 238 // Conversion time in ms for continuous T/H measurement + +// Addresses of the ENS210 registers +#define ENS210_REG_PART_ID 0x00 +#define ENS210_REG_REV 0x02 +#define ENS210_REG_UID 0x04 +#define ENS210_REG_SYS_CTRL 0x10 +#define ENS210_REG_SYS_STAT 0x11 +#define ENS210_REG_SENS_RUN 0x21 +#define ENS210_REG_SENS_START 0x22 +#define ENS210_REG_SENS_STOP 0x23 +#define ENS210_REG_SENS_STAT 0x24 +#define ENS210_REG_T_VAL 0x30 +#define ENS210_REG_H_VAL 0x33 + +// Division macro (used in conversion functions), implementing integer division with rounding. +// It supports both positive and negative dividends (n), but ONLY positive divisors (d). +//#define IDIV(n,d) ((n)>0 ? ((n)+(d)/2)/(d) : ((n)-(d)/2)/(d)) + +// 7654 3210 +// Polynomial 0b 1000 1001 ~ x^7+x^3+x^0 +// 0x 8 9 +#define CRC7WIDTH 7 // A 7 bits CRC has polynomial of 7th order, which has 8 terms +#define CRC7POLY 0x89 // The 8 coefficients of the polynomial +#define CRC7IVEC 0x7F // Initial vector has all 7 bits high +// Payload data +#define DATA7WIDTH 17 +#define DATA7MASK ((1UL<_available; } + uint16_t getPartID() { return this->_partID; } + uint16_t getRev() { return this->_rev; } + uint32_t getHighUID(bool high) { uint32_t result = high ? this->_uIDhi : this->_uIDlo; return result; } + void measure(); // perfrom measurement and stores result in internal variables +#ifndef ENS210_DISABLE_ENHANCED_FEATURES + float getTempKelvin (); // Converts and returns data (from `measure`) in Kelvin + float getTempFahrenheit (); // Converts and returns data (from `measure`) in Fahrenheit +#endif + float getTempCelsius (); // Converts and returns data (from `measure`) in Celsius + float getHumidityPercent(); // Converts and returns data (from `measure`) in %RH +#ifndef ENS210_DISABLE_ENHANCED_FEATURES + float getAbsoluteHumidityPercent(); // Converts and returns data (from `measure`) in %aH +#endif + char getStatusT() { return this->_t_status; } // Converts a status (ENS210_STATUS_XXX) to a human readable string. + uint32_t getDataT() { return this->_t_data; } + char getStatusH() { return this->_h_status; } // Converts a status (ENS210_STATUS_XXX) to a human readable string. + uint32_t getDataH() { return this->_h_data; } +#ifndef ENS210_DISABLE_ENHANCED_FEATURES + static const char * status_str( int status ); // Converts a status (ENS210_STATUS_XXX) to a human readable string. +#endif + + // Optionally set a solder `correction` (units: 1/64K, default from `begin` is 0). + // See "Effect of Soldering on Temperature Readout" in "Design-Guidelines" from + // https://download.ams.com/ENVIRONMENTAL-SENSORS/ENS210/Documentation +#ifndef ENS210_DISABLE_ENHANCED_FEATURES + void correction_set(int correction=50*64/1000); // Sets the solder correction (default is 50mK) - only used by the `toXxx()` functions. + int correction_get() {return this->_soldercorrection;} // Gets the solder correction. +#endif + + private: +#ifndef ENS210_DISABLE_DEBUG + bool debugENS210 = false; +#endif + bool reset(void); // Sends a reset to the ENS210. Returns false on I2C problems. + bool lowpower(bool enable); // Sets ENS210 to low (true) or high (false) power. Returns false on I2C problems. + bool getversion(); // Reads PART_ID and UID of ENS210. Returns false on I2C problems. + bool readValue(); // Reads measurement data from the ENS210. Returns false on I2C problems. + + bool _available = false; // ENS210 available + uint16_t _partID; // Part ID of ENS210, should be 0x210 + uint16_t _rev; // Revision 0 MRA2.6 / 1 MRA2.12 + uint64_t _uID; // Unique ID of this specific ENS210 + uint32_t _uIDhi; // First 32bit of unique ID of this specific ENS210 + uint32_t _uIDlo; // Second 32bit of unique ID of this specific ENS210 + bool _singleMode = true; // Measurement mode: true single shot / false continuous + uint32_t _t_data; + uint8_t _t_status; + uint32_t _h_data; + uint8_t _h_status; + uint8_t _slaveaddress = 0x43; // Slave address of ENS210 + uint8_t _soldercorrection; // Correction due to soldering (in 1/64K); subtracted from `t_data` by conversion functions. + + uint8_t _sdaPin = 0; + uint8_t _sclPin = 0; + + /****************************************************************************/ + /* General functions */ + /****************************************************************************/ + + uint8_t write8(uint8_t addr, byte reg, byte value); + uint8_t read8(uint8_t addr, byte reg); + + uint8_t read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num); + uint8_t write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num); + void _i2c_init(); +}; + + +#endif diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.cpp index 2d8b7acab..b95502c47 100644 --- a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.cpp +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CCommunication.cpp @@ -52,7 +52,7 @@ uint16_t SensirionI2CCommunication::sendFrame(uint8_t address, size_t writtenBytes = i2cBus.write(frame._buffer, frame._index); uint8_t i2c_error = i2cBus.endTransmission(); if (writtenBytes != frame._index) { - return WriteError | I2cOtherError; + return static_cast(WriteError) | static_cast(I2cOtherError); } // translate Arduino errors, see // https://www.arduino.cc/en/Reference/WireEndTransmission @@ -60,13 +60,13 @@ uint16_t SensirionI2CCommunication::sendFrame(uint8_t address, case 0: return NoError; case 1: - return WriteError | InternalBufferSizeError; + return static_cast(WriteError) | static_cast(InternalBufferSizeError); case 2: - return WriteError | I2cAddressNack; + return static_cast(WriteError) | static_cast(I2cAddressNack); case 3: - return WriteError | I2cDataNack; + return static_cast(WriteError) | static_cast(I2cDataNack); default: - return WriteError | I2cOtherError; + return static_cast(WriteError) | static_cast(I2cOtherError); } } @@ -89,19 +89,19 @@ uint16_t SensirionI2CCommunication::receiveFrame(uint8_t address, #endif if (numBytes % 3) { - return ReadError | WrongNumberBytesError; + return static_cast(ReadError) | static_cast(WrongNumberBytesError); } if ((numBytes / 3) * 2 > frame._bufferSize) { - return ReadError | BufferSizeError; + return static_cast(ReadError) | static_cast(BufferSizeError); } if (numBytes > sizeBuffer) { - return ReadError | InternalBufferSizeError; + return static_cast(ReadError) | static_cast(InternalBufferSizeError); } readAmount = i2cBus.requestFrom(address, static_cast(numBytes), static_cast(true)); if (numBytes != readAmount) { - return ReadError | NotEnoughDataError; + return static_cast(ReadError) | static_cast(NotEnoughDataError); } do { frame._buffer[i++] = i2cBus.read(); @@ -110,7 +110,7 @@ uint16_t SensirionI2CCommunication::receiveFrame(uint8_t address, uint8_t expectedCRC = generateCRC(&frame._buffer[i - 2], 2, poly); if (actualCRC != expectedCRC) { clearRxBuffer(i2cBus); - return ReadError | CRCError; + return static_cast(ReadError) | static_cast(CRCError); } readAmount -= 3; } while (readAmount > 0); diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.cpp index 67999f86c..301fafaf5 100644 --- a/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.cpp +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionI2CTxFrame.cpp @@ -68,7 +68,7 @@ SensirionI2CTxFrame SensirionI2CTxFrame::createWithUInt16Command( uint16_t SensirionI2CTxFrame::addCommand(uint16_t command) { if (_bufferSize < 2) { - return TxFrameError | BufferSizeError; + return static_cast(TxFrameError) | static_cast(BufferSizeError); } _buffer[0] = static_cast((command & 0xFF00) >> 8); _buffer[1] = static_cast((command & 0x00FF) >> 0); @@ -130,12 +130,12 @@ uint16_t SensirionI2CTxFrame::addBytes(const uint8_t data[], uint16_t SensirionI2CTxFrame::_addByte(uint8_t data) { if (_bufferSize <= _index) { - return TxFrameError | BufferSizeError; + return static_cast(TxFrameError) | static_cast(BufferSizeError); } _buffer[_index++] = data; if ((_index - _numCommandBytes) % 3 == 2) { if (_bufferSize <= _index) { - return TxFrameError | BufferSizeError; + return static_cast(TxFrameError) | static_cast(BufferSizeError); } uint8_t crc = generateCRC(&_buffer[_index - 2], 2, _polynomial_type); _buffer[_index++] = crc; diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.cpp index c653c250d..e89a0b86b 100644 --- a/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.cpp +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionRxFrame.cpp @@ -42,7 +42,7 @@ SensirionRxFrame::SensirionRxFrame(uint8_t buffer[], size_t bufferSize) uint16_t SensirionRxFrame::getUInt32(uint32_t& data) { if (_numBytes < 4) { - return RxFrameError | NoDataError; + return static_cast(RxFrameError) | static_cast(NoDataError); } data = static_cast(_buffer[_index++]) << 24; data |= static_cast(_buffer[_index++]) << 16; @@ -61,7 +61,7 @@ uint16_t SensirionRxFrame::getInt32(int32_t& data) { uint16_t SensirionRxFrame::getUInt16(uint16_t& data) { if (_numBytes < 2) { - return RxFrameError | NoDataError; + return static_cast(RxFrameError) | static_cast(NoDataError); } data = static_cast(_buffer[_index++]) << 8; data |= static_cast(_buffer[_index++]); @@ -78,7 +78,7 @@ uint16_t SensirionRxFrame::getInt16(int16_t& data) { uint16_t SensirionRxFrame::getUInt8(uint8_t& data) { if (_numBytes < 1) { - return RxFrameError | NoDataError; + return static_cast(RxFrameError) | static_cast(NoDataError); } data = _buffer[_index++]; _numBytes -= 1; @@ -87,7 +87,7 @@ uint16_t SensirionRxFrame::getUInt8(uint8_t& data) { uint16_t SensirionRxFrame::getInt8(int8_t& data) { if (_numBytes < 1) { - return RxFrameError | NoDataError; + return static_cast(RxFrameError) | static_cast(NoDataError); } data = static_cast(_buffer[_index++]); _numBytes -= 1; @@ -96,7 +96,7 @@ uint16_t SensirionRxFrame::getInt8(int8_t& data) { uint16_t SensirionRxFrame::getBool(bool& data) { if (_numBytes < 1) { - return RxFrameError | NoDataError; + return static_cast(RxFrameError) | static_cast(NoDataError); } data = static_cast(_buffer[_index++]); _numBytes -= 1; @@ -115,7 +115,7 @@ uint16_t SensirionRxFrame::getFloat(float& data) { uint16_t SensirionRxFrame::getBytes(uint8_t data[], size_t maxBytes) { if (_numBytes < 1) { - return RxFrameError | NoDataError; + return static_cast(RxFrameError) | static_cast(NoDataError); } size_t readAmount = maxBytes; if (_numBytes < maxBytes) { diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.cpp index 300546ee8..ce9155e50 100644 --- a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.cpp +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcCommunication.cpp @@ -42,7 +42,7 @@ static uint16_t readByte(uint8_t& data, Stream& serial, unsigned long startTime, unsigned long timeoutMicros) { do { if (micros() - startTime > timeoutMicros) { - return ReadError | TimeoutError; + return static_cast(ReadError) | static_cast(TimeoutError); } } while (!serial.available()); data = serial.read(); @@ -70,7 +70,7 @@ uint16_t SensirionShdlcCommunication::sendFrame(SensirionShdlcTxFrame& frame, Stream& serial) { size_t writtenBytes = serial.write(&frame._buffer[0], frame._index); if (writtenBytes != frame._index) { - return WriteError | SerialWriteError; + return static_cast(WriteError) | static_cast(SerialWriteError); } return NoError; } @@ -83,7 +83,7 @@ uint16_t SensirionShdlcCommunication::receiveFrame( uint8_t current = 0; if (frame._numBytes) { - return ReadError | NonemptyFrameError; + return static_cast(ReadError) | static_cast(NonemptyFrameError); } // Wait for start byte and ignore all other bytes in case a partial frame @@ -121,7 +121,7 @@ uint16_t SensirionShdlcCommunication::receiveFrame( frame._address + frame._command + frame._state + dataLength; if (dataLength > frame._bufferSize) { - return RxFrameError | BufferSizeError; + return static_cast(RxFrameError) | static_cast(BufferSizeError); } size_t i = 0; @@ -142,7 +142,7 @@ uint16_t SensirionShdlcCommunication::receiveFrame( return error; } if (expectedChecksum != actualChecksum) { - return ReadError | ChecksumError; + return static_cast(ReadError) | static_cast(ChecksumError); } uint8_t stop; @@ -151,10 +151,10 @@ uint16_t SensirionShdlcCommunication::receiveFrame( return error; } if (stop != 0x7e) { - return ReadError | StopByteError; + return static_cast(ReadError) | static_cast(StopByteError); } if (frame._state & 0x7F) { - return ExecutionError | frame._state; + return static_cast(ExecutionError) | frame._state; } frame._dataLength = dataLength; frame._numBytes = dataLength; @@ -175,10 +175,10 @@ uint16_t SensirionShdlcCommunication::sendAndReceiveFrame( return error; } if (rxFrame.getCommand() != txFrame.getCommand()) { - return RxFrameError | RxCommandError; + return static_cast(RxFrameError) | static_cast(RxCommandError); } if (rxFrame.getAddress() != txFrame.getAddress()) { - return RxFrameError | RxAddressError; + return static_cast(RxFrameError) | static_cast(RxAddressError); } return NoError; } diff --git a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.cpp b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.cpp index fc8c4c994..9efc5d824 100644 --- a/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.cpp +++ b/lib/lib_i2c/Sensirion_Core/src/SensirionShdlcTxFrame.cpp @@ -53,7 +53,7 @@ uint16_t SensirionShdlcTxFrame::finish(void) { return error; } if (_index + 1 > _bufferSize) { - return TxFrameError | BufferSizeError; + return static_cast(TxFrameError) | BufferSizeError; } _buffer[_index++] = 0x7e; _isFinished = true; @@ -84,7 +84,7 @@ uint16_t SensirionShdlcTxFrame::addInt16(int16_t data) { uint16_t SensirionShdlcTxFrame::addUInt8(uint8_t data) { if (_index + 2 > _bufferSize) { - return TxFrameError | BufferSizeError; + return static_cast(TxFrameError) | BufferSizeError; } switch (data) { case 0x11: diff --git a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp4x.cpp b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp4x.cpp index 7395d4a51..a45bf7d3f 100644 --- a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp4x.cpp +++ b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp4x.cpp @@ -178,6 +178,28 @@ uint16_t SensirionI2CSgp4x::readSelfTestValue(uint16_t& testResult) { return error; } +uint16_t SensirionI2CSgp4x::getFeaturesValue(uint16_t& featureResult) { + uint16_t error; + uint8_t buffer[3]; + SensirionI2CTxFrame txFrame = + SensirionI2CTxFrame::createWithUInt16Command(0x202F, buffer, 3); + + error = SensirionI2CCommunication::sendFrame(SGP4X_I2C_ADDRESS, txFrame, + *_i2cBus); + + if (error) { + return error; + } + + delay(1); // 1ms delay for feature request + SensirionI2CRxFrame rxFrame(buffer, 3); + error = SensirionI2CCommunication::receiveFrame(SGP4X_I2C_ADDRESS, 3, + rxFrame, *_i2cBus); + + error |= rxFrame.getUInt16(featureResult); + return error; +} + uint16_t SensirionI2CSgp4x::turnHeaterOff() { uint16_t error; uint8_t buffer[2]; diff --git a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp4x.h b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp4x.h index b03bed3f4..460ef7aa1 100644 --- a/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp4x.h +++ b/lib/lib_i2c/arduino-i2c-sgp41/src/SensirionI2CSgp4x.h @@ -120,6 +120,8 @@ class SensirionI2CSgp4x { uint16_t sendSelfTestCmd(void); uint16_t readSelfTestValue(uint16_t& testResult); + uint16_t getFeaturesValue(uint16_t& featureResult); + /** * turnHeaterOff() - This command turns the hotplate off and stops the * measurement. Subsequently, the sensor enters the idle mode. diff --git a/lib/libesp32_div/ESP32-HomeKit/LICENSE b/lib/libesp32/ESP-Mail-Client/LICENSE similarity index 95% rename from lib/libesp32_div/ESP32-HomeKit/LICENSE rename to lib/libesp32/ESP-Mail-Client/LICENSE index 46f369f28..c22fc2301 100644 --- a/lib/libesp32_div/ESP32-HomeKit/LICENSE +++ b/lib/libesp32/ESP-Mail-Client/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2020 Mixiaoxiao (Wang Bin) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2023 mobizt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/libesp32/ESP-Mail-Client/README.md b/lib/libesp32/ESP-Mail-Client/README.md new file mode 100644 index 000000000..79d584f99 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/README.md @@ -0,0 +1,1127 @@ +![ESP Mail](https://raw.githubusercontent.com/mobizt/ESP-Mail-Client/master/media/images/esp-mail-client.svg) + + +![Compile](https://github.com/mobizt/ESP-Mail-Client/actions/workflows/compile_library.yml/badge.svg) ![Examples](https://github.com/mobizt/ESP-Mail-Client/actions/workflows/compile_examples.yml/badge.svg) [![Github Stars](https://img.shields.io/github/stars/mobizt/ESP-Mail-Client?logo=github)](https://github.com/mobizt/ESP-Mail-Client/stargazers) ![Github Issues](https://img.shields.io/github/issues/mobizt/ESP-Mail-Client?logo=github) + +![arduino-library-badge](https://www.ardu-badge.com/badge/ESP%20Mail%20Client.svg) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/ESP%20Mail%20Client.svg) + + +The comprehensive Arduino Email Client Library to send and read Email for Arduino devices. + +This library was tested and works well with ESP32s, ESP8266s, SAMD21s and RP2040 Pico based modules. + +The library supported external networking devices hat work with Arduino Clients e.g. WiFiClient, EthernetClient, and GSMClient. + +Minimum 200k flash space device is recommended for library installation and user code. + +The minimum ram requirement is based on the applications (SMTP and IMAP). IMAP application may required up to 20k memory while SMTP application required much less memory. + + +## Contents + + +[1. Features](#features) + +[2. Supported Devices](#supported-devices) + +[3. Prerequisites](#prerequisites) +- [Gmail SMTP and IMAP required App Passwords to sign in](#gmail-smtp-and-imap-required-app-passwords-to-sign-in) + +- [PlatformIO IDE Compile Options](#platformio-ide-compile-options) + +- [Third party SD library must be removed](#third-party-sd-library-must-be-removed) + +- [SdFat conflicts in ESP8266 and must be removed](#sdfat-conflicts-in-esp8266-and-must-be-removed) + +- [ESP32 and ESP8266 SDKs](#esp32-and-esp8266-sdks) + +- [RP2040 Arduino SDK](#rp2040-arduino-sdk) + +[4. Library Instalation](#library-instalation) + +- [Using Library Manager](#using-library-manager) + +- [Manual installation](#manual-installation) + +[5. Memory Options](#memory-options) + +- [Memory Options for ESP8266](#memory-options-for-esp8266) + + - [Arduino IDE](#arduino-ide) + + - [PlatformIO IDE](#platformio-ide) + + - [ESP8266 and SRAM/PSRAM Chip connection](#esp8266-and-srampsram-chip-connection) + +- [Memory Options for ESP32](#memory-options-for-esp32) + + - [Arduino IDE](#arduino-ide-1) + + - [PlatformIO IDE](#platformio-ide-1) + + +[6. Library Build Options](#library-build-options) + + - [Predefined Options](#predefined-options) + + - [Optional Options](#optional-options) + + +[7. Usage](#usage) + +- [Send Email message](#send-email-message) + +- [Read Email message](#read-email-message) + +- [Get Incoming Message Notification and Reading](#get-incoming-message-notification-and-reading) + +- [Sending Custom IMAP commands](#sending-custom-imap-commands) + +- [Using TCP session KeepAlive in ESP8266 and ESP32](#using-tcp-session-keepalive-in-esp8266-and-esp32) + +- [Use external Arduino Clients interfaces](#use-external-arduino-clients-interfaces) + + - [TTGO T-A7670 LTE with TinyGSM](#ttgo-t-a7670-lte-with-tinygsm) + + - [ESP32 and W5500](#esp32-and-w5500) + +[8. License](#license) + + + +## Features + +* Supports sending Email with attachments. +* Supports reading the message and listening the mailbox changes. +* Supports custom SMTP and IMAP commands. +* Supports PLAIN, LOGIN and XOAUTH2 authentication mechanisms. +* Supports standard ports and user defined ports. +* Supports STARTTLS for both SMTP and IMAP. +* Supports TCP session reusage. +* Supports the content encodings e.g. quoted-printable and base64. +* Supports the content decodings e.g. base64, UTF-8, UTF-7, quoted-printable, ISO-8859-1 (latin1) and ISO-8859-11 (Thai). +* Supports embedded contents e.g. inline images, attachments, parallel media attachments and RFC822 message. +* Supports IMAP MIME data stream callback for external reader. +* supports IMAP custom character decoding callback based on the character set. +* Support full debuging. +* Support on-board or native networking (WiFi and Ethernet) and external networking (WiFi, Ethernet and GSM) via external basic WiFiClient, EthernetClient and GSMClient. +* Supports TinyGSM library integration. + + + + +## Supported Devices + +This following devices are supported. + + * ESP8266 MCUs based boards + * ESP32 MCUs based boards + * Arduino MKR WiFi 1010 + * Arduino MKR 1000 WIFI + * Arduino Nano 33 IoT + * Arduino MKR Vidor 4000 + * Raspberry Pi Pico (RP2040) + * Arduino UNO R4 WiFi (Renesas). + * LAN8720 Ethernet PHY + * TLK110 Ethernet PHY + * IP101 Ethernet PHY + * ENC28J60 SPI Ethernet module + * W5100 SPI Ethernet module + * W5500 SPI Ethernet module + * SIMCom Modules with TinyGSMClient + + + +## Prerequisites + + +### Gmail SMTP and IMAP required App Passwords to sign in + +From May 30, 2022, Google no longer supports the use of third-party apps or devices which ask you to sign in to your GoogleAccount using only your username and password. + +This means the Gmail account credentials i.e. account Email and account password can't be used to sign in with Google SMTP and IMAP servers. This prevents the third party apps hack to Gmail user account. + +To use Gmail with this library, you need to use App Passwords instead. + +For setting up the App Passwords, please read [here](https://support.google.com/accounts/answer/185833). + +After you created App Password, you can use Gmail Email address and App Password created to sign in as the following. + +```cpp +config.login.email = ""; +config.login.password = ""; +``` + + +### PlatformIO IDE Compile Options + +For Arduino Nano RP2040 Connect board, using PlatformIO IDE, to prevent the compile error due to wrong headers compilation, please set the lib_ldf_mode in platformio.ini as this. + +```ini +lib_ldf_mode = chain+ +``` + +### Third party SD library must be removed + +In Arduino IDE, all third party SD libraries installed in libraries folder must be reboved. + +The Core SD library was used instead of third party SD libraries. + +### SdFat conflicts in ESP8266 and must be removed + +The [SdFat](https://github.com/greiman/SdFat) is already implemented as wrapper class in ESP8266 core library. + +For Arduino IDE, the SdFat library should be removed from libraries folder when you compile this library for ESP8266 because of conclicts with core library SDFS.h. + + +### ESP32 and ESP8266 SDKs + +For Espressif's ESP32 and ESP8266 based boards, this library requires Arduino's ESP32 or ESP8266 Core SDK to be installed. + +The latest Core SDK is recommended. For ESP8266, the Core SDK version 3.x.x or later is recommended. + +The ESP8266 Core SDK version 2.5.x and earlier are not supported. + +For ESP32, the Core SDK version 2.0.4 or later is recommended. + +The ESP32 Core SDK version 1.0.4 and earlier are not supported. + + +### RP2040 Arduino SDK + +For Arduino IDE, the Arduino-Pico SDK can be installed from Boards Manager by searching pico and choose Raspberry Pi Pico/RP2040 to install. + +For PlatformIO, the Arduino-Pico SDK can be installed via platformio.ini + +```ini +[env:rpipicow] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board = rpipicow +framework = arduino +board_build.core = earlephilhower +monitor_speed = 115200 +board_build.filesystem_size = 1m +``` + +See this Arduino-Pico SDK [documentation](https://arduino-pico.readthedocs.io/en/latest/) for more information. + + +## Library Instalation + + +### Using Library Manager + +At Arduino IDE, go to menu **Sketch** -> **Include Library** -> **Manage Libraries...** + +In Library Manager Window, search **"ESP Mail Client"** in the search form then select **"ESP Mail Client"**. + +Click **"Install"** button. + + + +For PlatformIO IDE. + +Go to **PIO Home** -> **Libraries** -> **Registry** then search **ESP Mail Client**. + + +If you ever installed this library in Global storage in PlatformIO version prior to v2.0.0 and you have updated the PlatformIO to v2.0.0 and later, the global library installation was not available, the sources files of old library version still be able to search by the library dependency finder (LDF), you needed to remove the library from folder **C:\Users\\\\.platformio\lib** to prevent unexpected behavior when compile and run. + + + +### Manual installation + + +Click on **Code** dropdown at the top of repository, select **Download ZIP** and save file on your computer. + +From Arduino IDE, goto menu **Sketch** -> **Include Library** -> **Add .ZIP Library...** and choose **ESP-Mail-Client-master.zip** that previously downloaded. + +Rename **ESP-Mail-Client-master** folder to **ESP_Mail_Client**. + +Go to menu **Files** -> **Examples** -> **ESP Mail Client** and choose one from examples + + + +## Memory Options + + +### Memory Options for ESP8266 + +This section is optional for memory settings in IDE. + +When you update the ESP8266 Arduino Core SDK to v3.0.0, the memory can be configurable from IDE. + +You can choose the Heap memory between internal and external memory chip from IDE e.g. Arduino IDE and PlatformIO on VSCode or Atom IDE. + +#### Arduino IDE + + +For ESP8266 devices that don't have external SRAM/PSRAM chip installed, choose the MMU **option 3**, 16KB cache + 48KB IRAM and 2nd Heap (shared). + +![Arduino IDE config](/media/images/ArduinoIDE.png) + +For ESP8266 devices that have external 23LC1024 SRAM chip installed, choose the MMU **option 5**, 128K External 23LC1024. + +![MMU VM 128K](/media/images/ESP8266_VM.png) + +For ESP8266 devices that have external ESP-PSRAM64 chip installed, choose the MMU **option 6**, 1M External 64 MBit PSRAM. + + +#### PlatformIO IDE + +The MMU options can be selected from build_flags in your project's platformio.ini file + +For ESP8266 devices that don't not have external SRAM/PSRAM chip installed, add build flag as below. + +```ini +[env:d1_mini] +platform = espressif8266 +build_flags = -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED +board = d1_mini +framework = arduino +monitor_speed = 115200 +``` + + +For ESP8266 devices that have external 23LC1024 SRAM chip installed, add build flag as below. + +```ini +[env:d1_mini] +platform = espressif8266 +;128K External 23LC1024 +build_flags = -D PIO_FRAMEWORK_ARDUINO_MMU_EXTERNAL_128K +board = d1_mini +framework = arduino +monitor_speed = 115200 +``` + + +For ESP8266 devices that have external ESP-PSRAM64 chip installed, add build flag as below. + +```ini +[env:d1_mini] +platform = espressif8266 +;1M External 64 MBit PSRAM +build_flags = -D PIO_FRAMEWORK_ARDUINO_MMU_EXTERNAL_1024K +board = d1_mini +framework = arduino +monitor_speed = 115200 +``` + + +#### ESP8266 and SRAM/PSRAM Chip connection + +Most ESP8266 modules don't have the built-in SRAM/PSRAM on board. External memory chip connection can be done via SPI port as below. + +``` +23LC1024/ESP-PSRAM64 ESP8266 + +CS (Pin 1) GPIO15 +SCK (Pin 6) GPIO14 +MOSI (Pin 5) GPIO13 +MISO (Pin 2) GPIO12 +/HOLD (Pin 7 on 23LC1024 only) 3V3 +Vcc (Pin 8) 3V3 +Vcc (Pin 4) GND +``` + +Once the external Heap memory was selected in IDE, to allow the library to use the external memory, you can set it in [**ESP_Mail_FS.h**](src/ESP_Mail_FS.h) by define this macro. + + +```cpp +#define ESP_MAIL_USE_PSRAM +``` + +This macro was defined by default when you installed or update the library. + + + +### Memory Options for ESP32 + +This section is optional for memory settings in IDE. + +In ESP32 module that has PSRAM installed, you can enable it and set the library to use this external memory instead. + +#### Arduino IDE + +To enable PSRAM in ESP32 module. + +![Enable PSRAM in ESP32](/media/images/ESP32-PSRAM.png) + + +#### PlatformIO IDE + + +In PlatformIO on VSCode or Atom IDE, add the following build_flags in your project's platformio.ini file. + +```ini +build_flags = -DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue +``` + +As in ESP8266, once the external Heap memory was enabled in IDE, to allow the library to use the external memory, you can set it in [**ESP_Mail_FS.h**](src/ESP_Mail_FS.h) by define this macro. + +```cpp +#define ESP_MAIL_USE_PSRAM +``` + + + +## Library Build Options + +The library build options are defined as preprocessor macros (`#define name`). + +Some options can be disabled to reduce program space. + +### Predefined Options + +The predefined options that are already set in [**ESP_Mail_FS.h**](src/ESP_Mail_FS.h) are following. + +```cpp +ENABLE_IMAP // For IMAP class compilation +ENABLE_SMTP // For SMTP class compilation +ENABLE_NTP_TIME // For enabling the device or library time setup from NTP server +ENABLE_ERROR_STRING // For enabling the error string from error reason +ESP_MAIL_USE_PSRAM // For enabling PSRAM support +ESP_MAIL_DEFAULT_FLASH_FS // For enabling flash filesystem support +ESP_MAIL_DEFAULT_SD_FS // For enabling SD filesystem support +``` + +### Optional Options + +The following options are not yet defined in [**ESP_Mail_FS.h**](src/ESP_Mail_FS.h) and can be assigned by user. + +```cpp +SILENT_MODE // For silent operation (no debug printing and callback) +ENABLE_ESP8266_ENC28J60_ETH // For ENC28J60 Ethernet module support in ESP8266 +ENABLE_ESP8266_W5500_ETH // For W5500 Ethernet module support in ESP8266 +ENABLE_ESP8266_W5100_ETH // For W5100 Ethernet module support in ESP8266 +ESP_MAIL_DISABLE_ONBOARD_WIFI // For disabling on-board WiFI functionality in case external Client usage +ESP_MAIL_DISABLE_NATIVE_ETHERNET // For disabling native (sdk) Ethernet functionality in case external Client usage +ESP_MAIL_DISABLE_SSL // // For disabling SSL connection (also disabling TLS using STARTTLS) in MAP and SMTP application +ESP_MAIL_DEBUG_PORT // For debug port assignment if SILENT_MODE option was not set +``` + + +You can assign the optional build options using one of the following methods. + +- By creating user config file `Custom_ESP_Mail_FS.h` in library installed folder and define these optional options. + +- By adding compiler build flags with `-D name`. + +In PlatformIO IDE, using `build_flags` in PlatformIO IDE's platformio.ini is more convenient + +```ini +build_flags = -D ESP_MAIL_DEBUG_PORT=Serial + -D DISABLE_IMAP + -D ESP_MAIL_DISABLE_ONBOARD_WIFI +``` + +For disabling predefined options instead of editing the [**ESP_Mail_FS.h**](src/ESP_Mail_FS.h) or using `#undef` in `Custom_ESP_Mail_FS.h`, you can define these build flags with these names or macros in `Custom_ESP_Mail_FS.h`. + +```cpp +DISABLE_IMAP // For excluding the IMAP class compilation +DISABLE_SMTP // For excluding the SMTP class compilation +DISABLE_NTP_TIME // For disabling the NTP time setting +DISABLE_ERROR_STRING // For disabling the error string from error reason +DISABLE_PSRAM // For disabling PSRAM support +DISABLE_FLASH // For disabling flash filesystem support +DISABLE_SD // For disabling SD filesystem support + +DISABLE_ALL_OPTIONS // For disabling all predefined build options above +``` + +Note that, `Custom_ESP_Mail_FS.h` for user config should be placed in the library install folder inside src folder. + +This `Custom_ESP_Mail_FS.h` will not change or overwrite when update the library. + + + +## Usage + + +See [examples folder](/examples) for all usage examples. + +See [src/README.md](/src/README.md) for the functions descriptions. + +The usefull blogs that described how to send and read E-mail in detail can be found here. + +[ESP32 Send Emails using an SMTP Server: HTML, Text, and Attachments (Arduino IDE) by Rui and Sara from randomnerdtutorials.com](https://randomnerdtutorials.com/esp32-send-email-smtp-server-arduino-ide/) + +[Receiving Emails with ESP32 using IMAP Server by Alina Mybeth from theengineeringprojects.com](https://www.theengineeringprojects.com/2022/01/receiving-emails-with-esp32-using-imap-server.html) + + +The following code snippet showed the minimum usage of the library. + + +### Send Email message + +The following code will send email with image attachment. + +```C++ +// Include WiFi library +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +// Include ESP Mail Client library (this library) +#include + + +// Declare the global used SMTPSession object for SMTP transport +SMTPSession smtp; + +// Declare the global used Session_Config for user defined session credentials +Session_Config config; + +// Callback function to get the Email sending status +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + + WiFi.begin("", ""); + Serial.print("Connecting to Wi-Fi"); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + // Set the session config + config.server.host_name = "smtp.office365.com"; // for outlook.com + config.server.port = 587; // for TLS with STARTTLS or 25 (Plain/TLS with STARTTLS) or 465 (SSL) + config.login.email = "your Email address"; // set to empty for no SMTP Authentication + config.login.password = "your Email password"; // set to empty for no SMTP Authentication + + // For client identity, assign invalid string can cause server rejection + config.login.user_domain = "client domain or public ip"; + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = "pool.ntp.org,time.nist.gov"; + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + // Declare the SMTP_Message class variable to handle to message being transport + SMTP_Message message; + + // Set the message headers + message.sender.name = "My Mail"; + message.sender.email = "sender or your Email address"; + message.subject = "Test sending Email"; + message.addRecipient("name1", "email1"); + message.addRecipient("name2", "email2"); + + message.addCc("email3"); + message.addBcc("email4"); + + // Set the message content + message.text.content = "This is simple plain text message"; + + //Base64 data of image + const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u" + "3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEI" + "EYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCB" + "GCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQ" + "ghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII="; + + // Declare the attachment data + SMTP_Attachment att; + + // Set the attatchment info + att.descr.filename = "green.png"; + att.descr.mime = "image/png"; + att.blob.data = (uint8_t *)greenImg; + att.blob.size = strlen(greenImg); + // Set the transfer encoding to base64 + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + // We set the content encoding to match the above greenImage data + att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; + + // Add attachment to the message + message.addAttachment(att); + + // Set debug option + smtp.debug(1); + + // Set the callback function to get the sending results + smtp.callback(smtpCallback); + + // Connect to the server + smtp.connect(&config); + + // Start sending Email and close the session + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); + +} + +void smtpCallback(SMTP_Status status) +{ + + Serial.println(status.info()); + + if (status.success()) + { + // See example for how to get the sending result + } +} + + +``` + + +### Read Email message + +The following code will read the latest email message in the "INBOX" mailbox. + +```C++ +// Include WiFi library +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +// Include ESP Mail Client library (this library) +#include + +// Declare the global used IMAPSession object for IMAP transport +IMAPSession imap; + +// Declare the global used Session_Config for user defined session credentials +Session_Config config; + +// Callback function to get the Email reading status +void imapCallback(IMAP_Status status) + +void setup() +{ + + Serial.begin(115200); + + WiFi.begin("", ""); + Serial.print("Connecting to Wi-Fi"); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + // Set the session config + config.server.host_name = "outlook.office365.com"; //for outlook.com + config.server.port = 993; // for SSL or 143 for Plain or TLS with STARTTLS + config.login.email = "your Email address"; + config.login.password = "your Email password"; + + // Declare the IMAP_Data object used for user defined IMAP operating options + // and contains the IMAP operating result + IMAP_Data imap_data; + + + // Set to enable the message content which will be stored in the IMAP_Data data + imap_data.enable.html = true; + imap_data.enable.text = true; + + + // Set the debug option + imap.debug(1); + + // Set the callback function to get message information + imap.callback(imapCallback); + + + // Connect to the server + imap.connect(&config, &imap_data); + + // Open or select the mailbox folder to read the message + imap.selectFolder("INBOX"); + + + // Define the message UID (number) which required to fetch or read the message + // In this case we will get the UID from the max message number (lastest message) + // then imap.getUID and imap.selectedFolder().msgCount() should be called after + // calling select or open the folder (mailbox). + imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount()); + + // Empty search criteria to disable the messsage search + imap_data.search.criteria.clear(); + + + // Read the Email and close the session + MailClient.readMail(&imap); + + +} + + +void imapCallback(IMAP_Status status) +{ + + Serial.println(status.info()); + + if (status.success()) + { + // See example for how to get the message info + } +} + +``` + + +### Get Mailbox Changes Notification + +See [Mailbox_Changes_Notification.ino](/examples/IMAP/Mailbox_Changes_Notification/Mailbox_Changes_Notification.ino) for the example. + + +### Sending Custom IMAP commands + +Can't find what you want from exising IMAP functions, sending custom command was supported. + +Please read the RFC 3501 and RFC 9051 documents for the details of IMAP protocol commands. + +See [Custom_Command examples](/examples/IMAP/Custom_Command) for how to use. + + +### Using TCP session KeepAlive in ESP8266 and ESP32 + +The server connection will be probed at some intervals to maintain connection. + +The TCP session KeepAlive can be enabled from executing `.keepAlive` or `.keepAlive` with providing TCP options as arguments, i.e., + +`tcpKeepIdleSeconds`, `tcpKeepIntervalSeconds` and `tcpKeepCount`. + +Ex. + +```cpp +smtp.keepAlive(5 /* tcp KeepAlive idle 5 seconds */, 5 /* tcp KeeAalive interval 5 seconds */, 1 /* tcp KeepAlive count 1 */); + +imap.keepAlive(5 /* tcp KeepAlive idle 5 seconds */, 5 /* tcp KeeAalive interval 5 seconds */, 1 /* tcp KeepAlive count 1 */); + +// If one of three arguments is zero, the KeepAlive will be disabled. +``` + +To check the KeepAlive status, use `.isKeepAlive` or `.isKeepAlive`. + + +For the TCP (KeepAlive) options, see [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/lwip.html#tcp-options). + +You can check the server connecting status, by executing `.connected()` or `.connected()` which will return true when connection to the server is still alive. + + +The TCP KeepAlive was currently available in ESP32 unless in ESP8266, [this ESP8266 PR #8940](https://github.com/esp8266/Arduino/pull/8940) should be merged in the [ESP8266 Arduino Core SDK](https://github.com/esp8266/Arduino/releases), i.e., it will be supported in the ESP8266 core version newer than v3.1.2. + + +In ESP8266 core v3.1.2 and older, the error can be occurred when executing `.keepAlive` or `.isKeepAlive` because of object slicing. + + +The Arduino Pico is currently not support TCP KeepAlive until it's implemented in WiFiClientSecure library as in ESP8266. + + +For External Client, this TCP KeepAlive option is not appliable and should be managed by external Client library. + + + + +### Use External Arduino Clients for External Networking Devices + +This library supports external netwoking devices e.g. WiFi modules, Ethernet modules and GSM modules that connected to the Arduino device via communication ports e.g. SPI and Serial, through the Arduino Clients (driver) for those networking devices e.g. WiFiClient, EthernetClient and GSMClient. + +Since v3.4.0, the Arduino Clients can be used with this library without additional external SSL Client required. + +No additional setup needed, only pass the Arduino Client to the function `setClient` or pass the TinyGSMClient and TinyGSM modem to the function `setGSMClient`. + +Two callback functions required (except for using `setGSMClient`) for network connection (with disconnection) and sending connecting status back to the Mail Client. + +If device has on-board WiFi and supports native (SDK) Ethernet, these two native networks will be auto detectd and used. + +If you don't want to let `ESP Mail Client` library to use the native networking and use external networking devices using Arduino Clients instead, the following build flags or macros should be defined in `Custom_ESP_Mail_FS.h`. + +```cpp +ESP_MAIL_DISABLE_ONBOARD_WIFI + +ESP_MAIL_DISABLE_NATIVE_ETHERNET +``` + +See [External Client Examples](/examples/SMTP/External_Client) for more external Client usage. + + +#### TTGO T-A7670 LTE with TinyGSM + +The following example showed how to use TTGO T-A7670 with `GSMClient` to connect to SMTP server. + +To allow TinyGSM library integration, the following build flag or macro should be defined in `Custom_ESP_Mail_FS.h`. + +```cpp +TINY_GSM_MODEM_SIM7600 +``` + +See the TinyGSM documentation and example for other SIMCom modules definition. + + +```cpp + +// For TTGO T-A7670 +#define TINY_GSM_MODEM_SIM7600 // SIMA7670 Compatible with SIM7600 AT instructions + +// Set serial for debug console (to the Serial Monitor, default speed 115200) +#define SerialMon Serial + +// Set serial for AT commands (to the module) +// Use Hardware Serial on Mega, Leonardo, Micro +#define SerialAT Serial1 + +// See all AT commands, if wanted +// #define DUMP_AT_COMMANDS + +// Define the serial console for debug prints, if needed +#define TINY_GSM_DEBUG SerialMon + +#define TINY_GSM_USE_GPRS true +#define TINY_GSM_USE_WIFI false + +// set GSM PIN, if any +#define GSM_PIN "" + +// Your GPRS credentials, if any +const char apn[] = "YourAPN"; +const char gprsUser[] = ""; +const char gprsPass[] = ""; + + +#define uS_TO_S_FACTOR 1000000ULL // Conversion factor for micro seconds to seconds +#define TIME_TO_SLEEP 600 // Time ESP32 will go to sleep (in seconds) + +#define UART_BAUD 115200 +#define PIN_DTR 25 +#define PIN_TX 26 +#define PIN_RX 27 +#define PWR_PIN 4 +#define BAT_ADC 35 +#define BAT_EN 12 +#define PIN_RI 33 +#define PIN_DTR 25 +#define RESET 5 + +#define SD_MISO 2 +#define SD_MOSI 15 +#define SD_SCLK 14 +#define SD_CS 13 + + +#include +#include + + +TinyGsm modem(SerialAT); + +TinyGsmClient gsm_client(modem); // basic non-secure client + +SMTPSession smtp; + +// Callback function to get the Email sending status +void smtpCallback(SMTP_Status status); + +void setup() +{ + + SerialMon.begin(115200); + + // Set debug option + smtp.debug(1); + + // Set the callback function to get the sending results + smtp.callback(smtpCallback); + + delay(10); + pinMode(BAT_EN, OUTPUT); + digitalWrite(BAT_EN, HIGH); + + // A7670 Reset + pinMode(RESET, OUTPUT); + digitalWrite(RESET, LOW); + delay(100); + digitalWrite(RESET, HIGH); + delay(3000); + digitalWrite(RESET, LOW); + + pinMode(PWR_PIN, OUTPUT); + digitalWrite(PWR_PIN, LOW); + delay(100); + digitalWrite(PWR_PIN, HIGH); + delay(1000); + digitalWrite(PWR_PIN, LOW); + + DBG("Wait..."); + + delay(3000); + + SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX); + + // Restart takes quite some time + // To skip it, call init() instead of restart() + DBG("Initializing modem..."); + if (!modem.init()) + { + DBG("Failed to restart modem, delaying 10s and retrying"); + return; + } + + /* + 2 Automatic + 13 GSM Only + 14 WCDMA Only + 38 LTE Only + */ + modem.setNetworkMode(38); + if (modem.waitResponse(10000L) != 1) + { + DBG(" setNetworkMode faill"); + } + + String name = modem.getModemName(); + DBG("Modem Name:", name); + + String modemInfo = modem.getModemInfo(); + DBG("Modem Info:", modemInfo); + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + config.login.user_domain = F("127.0.0.1"); + + // Declare the SMTP_Message class variable to handle to message being transport + SMTP_Message message; + + // Set the message headers + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email using GSM module"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + // Set the message content + message.text.content = "This is simple plain text message"; + + // Set debug option + smtp.debug(1); + + // Set the callback function to get the sending results + smtp.callback(smtpCallback); + + smtp.setGSMClient(&gsm_client, &modem, GSM_PIN, apn, gprsUser, gprsPass); + + // Connect to the server with the defined session and options + smtp.connect(&config); + + // Start sending Email and close the session + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +void smtpCallback(SMTP_Status status) +{ + + Serial.println(status.info()); + + if (status.success()) + { + // See example for how to get the sending result + } +} + +``` + +#### ESP32 and W5500 + +The below example will use ESP32 and W5500 and Ethernet client library to connect to SMTP server + + +```cpp + +#include + +#include + +#define WIZNET_RESET_PIN 26 // Connect W5500 Reset pin to GPIO 26 of ESP32 +#define WIZNET_CS_PIN 5 // Connect W5500 CS pin to GPIO 5 of ESP32 +#define WIZNET_MISO_PIN 19 // Connect W5500 MISO pin to GPIO 19 of ESP32 +#define WIZNET_MOSI_PIN 23 // Connect W5500 MOSI pin to GPIO 23 of ESP32 +#define WIZNET_SCLK_PIN 18 // Connect W5500 SCLK pin to GPIO 18 of ESP32 + + +EthernetClient eth_client; + +uint8_t Eth_MAC[] = {0x02, 0xF0, 0x0D, 0xBE, 0xEF, 0x01}; + +SMTPSession smtp; + +Session_Config config; + +// Callback function to get the Email sending status +void smtpCallback(SMTP_Status status); + +void ResetEthernet() +{ + Serial.println("Resetting WIZnet W5500 Ethernet Board... "); + pinMode(WIZNET_RESET_PIN, OUTPUT); + digitalWrite(WIZNET_RESET_PIN, HIGH); + delay(200); + digitalWrite(WIZNET_RESET_PIN, LOW); + delay(50); + digitalWrite(WIZNET_RESET_PIN, HIGH); + delay(200); +} + +void networkConnection() +{ + + Ethernet.init(WIZNET_CS_PIN); + + ResetEthernet(); + + Serial.println("Starting Ethernet connection..."); + Ethernet.begin(Eth_MAC); + + unsigned long to = millis(); + + while (Ethernet.linkStatus() == LinkOFF || millis() - to < 2000) + { + delay(100); + } + + if (Ethernet.linkStatus() == LinkON) + { + Serial.print("Connected with IP "); + Serial.println(Ethernet.localIP()); + } + else + { + Serial.println("Can't connect"); + } +} + +void networkStatusRequestCallback() +{ + smtp.setNetworkStatus(Ethernet.linkStatus() == LinkON); +} + +void setup() +{ + Serial.begin(115200); + + networkConnection(); + + config.server.host_name = "smtp.gmail.com"; //for gmail.com + config.server.port = 587; // requires connection upgrade via STARTTLS + config.login.email = "your Email address"; //set to empty for no SMTP Authentication + config.login.password = "your Email password"; //set to empty for no SMTP Authentication + config.login.user_domain = "client domain or ip e.g. mydomain.com"; + + // Declare the SMTP_Message class variable to handle to message being transport + SMTP_Message message; + + // Set the message headers + message.sender.name = "My Mail"; + message.sender.email = "sender or your Email address"; + message.subject = "Test sending Email"; + message.addRecipient("name1", "email1"); + message.addRecipient("name2", "email2"); + + message.addCc("email3"); + message.addBcc("email4"); + + // Set the message content + message.text.content = "This is simple plain text message"; + + // Set the callback function for connection upgrade + smtp.networkStatusRequestCallback(networkStatusRequestCallback); + + smtp.networkConnectionRequestCallback(networkConnection); + + smtp.setClient(ð_client); + + // Set debug option + smtp.debug(1); + + // Set the callback function to get the sending results + smtp.callback(smtpCallback); + + // Connect to the server with the defined session and options + smtp.connect(&config); + + // Start sending Email and close the session + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); + +} + +void smtpCallback(SMTP_Status status) +{ + + Serial.println(status.info()); + + if (status.success()) + { + // See example for how to get the sending result + } +} + +``` + + +## License + +The MIT License (MIT) + +Copyright (c) 2023 K. Suwatchai (Mobizt) + + +Permission is hereby granted, free of charge, to any person returning a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/lib/libesp32/lib_mail/_config.yml b/lib/libesp32/ESP-Mail-Client/_config.yml similarity index 100% rename from lib/libesp32/lib_mail/_config.yml rename to lib/libesp32/ESP-Mail-Client/_config.yml diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/ACL/ACL.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/ACL/ACL.ino new file mode 100644 index 000000000..145e9815c --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/ACL/ACL.ino @@ -0,0 +1,258 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +// This example shows how to get, set the access control list. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + IMAP_Rights_List acl_list; + + Serial.println("\nGet ACLs..."); + + if (!imap.getACL("INBOX", &acl_list)) + { + Serial.println("Get ACLs failed"); + } + else + { + Serial.println("ACL..."); + + for (size_t i = 0; i < acl_list.size(); i++) + { + MailClient.printf("Identifier: %s, Rights: ", acl_list[i].identifier.c_str()); + String r; + for (int j = esp_mail_imap_rights_administer; j < esp_mail_imap_rights_maxType; j++) + { + if (acl_list[i].rights[j]) + r += (char)('a' + j); + } + + Serial.println(r); + } + } + + IMAP_Rights_Info acl; + acl.identifier = "Steve"; + acl.rights[esp_mail_imap_rights_administer] = true; + acl.rights[esp_mail_imap_rights_create] = true; + acl.rights[esp_mail_imap_rights_create_c] = true; + acl.rights[esp_mail_imap_rights_delete_message] = true; + acl.rights[esp_mail_imap_rights_delete_d] = true; + acl.rights[esp_mail_imap_rights_delete_mailbox] = true; + acl.rights[esp_mail_imap_rights_expunge] = true; + acl.rights[esp_mail_imap_rights_lookup] = true; + acl.rights[esp_mail_imap_rights_insert] = true; + acl.rights[esp_mail_imap_rights_post] = true; + acl.rights[esp_mail_imap_rights_read] = true; + acl.rights[esp_mail_imap_rights_write] = true; + acl.rights[esp_mail_imap_rights_seen] = true; + + Serial.println("\nSet ACLs..."); + + if (!imap.setACL("INBOX", &acl)) + { + Serial.println("Set ACLs failed"); + } + else + { + Serial.println("Set ACLs success"); + } + + Serial.println("\nGet my rights..."); + + if (!imap.myRights("INBOX", &acl)) + { + Serial.println("Set my rights failed"); + } + else + { + Serial.print("Rights: "); + + String r; + for (int i = esp_mail_imap_rights_administer; i < esp_mail_imap_rights_maxType; i++) + { + if (acl.rights[i]) + r += (char)('a' + i); + } + + Serial.println(r); + } + + Serial.println("\nDelete ACLs..."); + + if (!imap.deleteACL("INBOX", "Steve")) + { + Serial.println("Set ACLs failed"); + } + else + { + Serial.println("Delete ACLs success"); + } + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Append_Message/Append_Message.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Append_Message/Append_Message.ino new file mode 100644 index 000000000..d7bbea2c2 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Append_Message/Append_Message.ino @@ -0,0 +1,239 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to append message to mailbox. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** Assign SD card type and FS used in src/ESP_Mail_FS.h and + * change the config for that card interfaces in src/extras/SDHelper.h + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#include + +// required IMAP and SMTP +#if defined(ENABLE_IMAP) && defined(ENABLE_SMTP) + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); +} + +#endif + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +// required IMAP and SMTP +#if defined(ENABLE_IMAP) && defined(ENABLE_SMTP) + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + ESP_Mail_Message message[2]; // The same usage as SMTP_Message + + message[0].sender.name = "Fred Foobar"; + message[0].sender.email = "foobar@Blurdybloop.example.COM"; + message[0].subject = "afternoon meeting"; + message[0].addRecipient("Joe Mooch", "mooch@owatagu.example.net"); + message[0].text.content = "Hello Joe, do you think we can meet at 3:30 tomorrow?"; + message[0].text.charSet = "us-ascii"; + message[0].text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + ESP_Mail_Attachment att[2]; // The same usage as SMTP_Attachment + + att[0].descr.filename = "shaun.png"; + att[0].descr.mime = "image/png"; + att[0].blob.data = shaun_png; + att[0].blob.size = sizeof(shaun_png); + att[0].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + message[0].addAttachment(att[0]); + + message[1].sender.name = "Joe Mooch"; + message[1].sender.email = "mooch@OWaTaGu.example.net"; + message[1].subject = "Re: afternoon meeting"; + message[1].addRecipient("Fred Foobar", "foobar@blurdybloop.example.com"); + message[1].text.content = "3:30 is fine with me."; + message[1].text.charSet = "us-ascii"; + message[1].text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + att[1].descr.filename = "mu_law.wav"; + att[1].descr.mime = "audio/basic"; + att[1].blob.data = mu_law_wave; + att[1].blob.size = sizeof(mu_law_wave); + att[1].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + message[1].addAttachment(att[1]); + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + if (!imap.selectFolder(F("INBOX"))) + return; + + // If MULTIAPPEND extension is supported, the multiple messages will send by a single APPEND command. + // If not, one message can append for a APPEND command. + // Outlook.com does not accept flag and date/time arguments in APPEND command + if (!MailClient.appendMessage(&imap, &message[0], false /* if not last message to append */, "\\Flagged" /* flags or empty string for Outlook.com */, "Thu, 16 Jun 2022 12:30:25 -0800 (PST)" /* date/time or empty string for Outlook.com */)) + MailClient.printf("Message appending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + + if (!MailClient.appendMessage(&imap, &message[1], true /* last message to append */)) + MailClient.printf("Message appending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); + +#endif +} + +void loop() +{ +} diff --git a/lib/libesp32/lib_mail/examples/Send_Parallel_Attachment/data.h b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Append_Message/data.h similarity index 98% rename from lib/libesp32/lib_mail/examples/Send_Parallel_Attachment/data.h rename to lib/libesp32/ESP-Mail-Client/examples/IMAP/Append_Message/data.h index 0b73e9752..c7a88aeab 100644 --- a/lib/libesp32/lib_mail/examples/Send_Parallel_Attachment/data.h +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Append_Message/data.h @@ -1,1957 +1,1957 @@ -#include - -static const uint8_t mu_law_wave[] PROGMEM = { -0x52, 0x49, 0x46, 0x46, 0x84, 0x5D, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, -0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x40, 0x1F, 0x00, 0x00, 0x40, 0x1F, 0x00, 0x00, -0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x61, 0x63, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x5D, -0x00, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5D, 0x00, 0x00, 0xFB, 0xFD, 0xFF, 0xFE, 0xFF, 0x7F, -0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7C, 0x7D, -0x7C, 0x7C, 0x7D, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7E, 0xFF, 0x7F, -0x7D, 0x7C, 0x7B, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7C, 0x7C, 0x7B, -0x7B, 0x7B, 0x7A, 0x7A, 0x7B, 0x7A, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x7C, 0x7E, -0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x79, 0x79, 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x7E, 0xFF, 0xFE, 0xFE, -0xFF, 0x7E, 0x7C, 0x7D, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x79, 0x78, 0x79, -0x7A, 0x79, 0x78, 0x78, 0x78, 0x77, 0x78, 0x78, 0x79, 0x79, 0x78, 0x77, 0x77, 0x78, 0x78, 0x79, -0x7A, 0x79, 0x79, 0x78, 0x78, 0x7A, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, -0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFC, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF8, -0xF7, 0xF7, 0xF8, 0xF9, 0xF9, 0xFB, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFE, -0xFF, 0xFF, 0xFE, 0x7E, 0x7D, 0x7D, 0x7C, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7C, -0x7B, 0x7A, 0x79, 0x79, 0x79, 0x77, 0x77, 0x78, 0x79, 0x7B, 0x7C, 0x7B, 0x7B, 0x7C, 0x7B, 0x7B, -0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x79, 0x79, -0x78, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7B, 0x7B, 0x7A, 0x7C, 0x7E, 0x7D, 0x7E, 0x7E, 0x7C, 0x7C, -0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x79, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x78, 0x78, 0x7A, 0x7A, 0x79, -0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFC, 0xFB, 0xFB, 0xFC, -0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFE, 0xFF, 0x7E, 0x7E, 0xFF, 0xFF, 0x7E, 0x7E, 0x7D, 0x7B, -0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, -0x7C, 0x7B, 0x79, 0x7A, 0x7A, 0x7A, 0x7A, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7C, 0x79, 0x79, 0x7A, -0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7C, 0x7C, 0x7C, 0x7E, 0x7D, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0xFE, -0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, -0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7D, 0x7E, 0x7D, 0x7B, 0x7B, 0x7B, 0x79, 0x78, 0x77, -0x78, 0x78, 0x77, 0x77, 0x77, 0x78, 0x78, 0x76, 0x76, 0x75, 0x73, 0x73, 0x73, 0x72, 0x73, 0x73, -0x74, 0x74, 0x74, 0x75, 0x77, 0x78, 0x78, 0x77, 0x76, 0x77, 0x76, 0x76, 0x78, 0x79, 0x79, 0x79, -0x78, 0x79, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7E, -0x7E, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFD, 0xFE, 0xFF, 0xFD, 0xFE, 0x7F, 0xFF, -0x7F, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7E, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7D, 0x7F, -0xFF, 0xFF, 0xFE, 0xFE, 0x7F, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7C, 0x7D, -0x7D, 0x7D, 0x7D, 0x7E, 0x7F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFF, 0xFE, 0xFC, 0xFD, 0xFC, 0xFC, 0xFD, -0xFC, 0xFB, 0xFB, 0xFC, 0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFD, 0xFE, -0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7D, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7D, 0x7B, 0x7B, 0x79, -0x78, 0x78, 0x78, 0x76, 0x74, 0x74, 0x73, 0x72, 0x75, 0x77, 0x77, 0x76, 0x75, 0x75, 0x76, 0x77, -0x77, 0x76, 0x74, 0x74, 0x74, 0x74, 0x76, 0x76, 0x76, 0x77, 0x75, 0x76, 0x78, 0x79, 0x77, 0x77, -0x79, 0x7B, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7D, 0x7F, 0x7E, 0xFF, 0xFF, 0x7F, 0xFE, 0xFC, 0xFE, -0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFD, 0xFC, 0xFE, 0xFF, 0x7E, 0x7F, 0x7F, 0x7D, 0x7E, 0xFF, 0x7F, -0x7F, 0xFF, 0x7F, 0x7E, 0x7D, 0x7E, 0xFF, 0x7E, 0x7F, 0x7F, 0x7C, 0x7D, 0x7F, 0x7D, 0x7E, 0x7E, -0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7B, 0x7D, 0x7B, 0x7A, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7C, -0x7D, 0x7E, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0xFF, 0xFD, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFB, 0xFB, -0xFA, 0xFB, 0xFB, 0xFB, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x7E, 0x7E, 0x7D, 0x7B, 0x7B, 0x7B, -0x78, 0x79, 0x78, 0x75, 0x76, 0x76, 0x76, 0x76, 0x74, 0x74, 0x73, 0x73, 0x74, 0x73, 0x72, 0x73, -0x75, 0x75, 0x74, 0x76, 0x74, 0x72, 0x73, 0x74, 0x75, 0x75, 0x76, 0x77, 0x77, 0x78, 0x77, 0x77, -0x77, 0x78, 0x78, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x7A, 0x79, 0x7B, 0x7C, 0x7B, 0x7B, -0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7C, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, -0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, -0xFE, 0x7E, 0x7E, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7E, 0xFF, 0x7E, 0x7E, 0x7E, 0x7D, -0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFC, 0xFE, 0x7F, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, -0x7F, 0x7E, 0x7D, 0x7D, 0x7D, 0x7B, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, 0x7D, 0x7C, 0x7C, -0x7D, 0x7C, 0x7C, 0x7E, 0x7E, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, -0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFB, -0xFB, 0xFB, 0xFA, 0xFB, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, -0x7E, 0x7E, 0x7E, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7F, -0x7D, 0x7B, 0x7C, 0x7C, 0x7D, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7E, -0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x78, 0x77, 0x77, 0x76, 0x74, 0x73, -0x72, 0x73, 0x74, 0x75, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, -0x7C, 0x7D, 0x7E, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7D, 0x7C, 0x7B, -0x7A, 0x7B, 0x7B, 0x7A, 0x7A, 0x79, 0x79, 0x7A, 0x79, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x79, 0x79, -0x79, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7C, 0x7B, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7F, -0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7D, 0x7D, -0x7D, 0x7D, 0x7E, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7F, 0x7F, 0x7E, 0x7F, 0x7E, 0x7E, 0x7F, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7F, 0x7F, 0x7E, -0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, -0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, -0x7D, 0x7E, 0xFF, 0x7E, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7A, -0x7A, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7D, 0x7C, 0x7C, 0x7A, 0x79, 0x79, 0x78, 0x78, -0x78, 0x77, 0x77, 0x76, 0x75, 0x74, 0x74, 0x74, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x76, 0x75, -0x74, 0x75, 0x77, 0x78, 0x78, 0x7A, 0x7B, 0x7D, 0xFF, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, -0xFC, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, -0xF8, 0xFA, 0xF8, 0xF6, 0xF7, 0xF7, 0xF8, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFB, -0xFB, 0xFB, 0xFD, 0xFE, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, -0x7F, 0x7E, 0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0xFD, 0xFE, 0xFF, -0xFE, 0xFE, 0xFD, 0xFE, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7E, 0x7F, -0x7D, 0x7D, 0x7E, 0x7E, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x79, 0x77, 0x78, 0x79, 0x78, 0x77, 0x76, -0x76, 0x75, 0x73, 0x74, 0x73, 0x71, 0x70, 0x70, 0x71, 0x72, 0x71, 0x71, 0x70, 0x6F, 0x6F, 0x6F, -0x70, 0x71, 0x71, 0x72, 0x73, 0x74, 0x74, 0x74, 0x76, 0x77, 0x76, 0x78, 0x79, 0x79, 0x79, 0x78, -0x7A, 0x7B, 0x7B, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, -0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7D, -0x7D, 0x7D, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7C, 0x7A, 0x78, 0x79, 0x78, 0x77, -0x76, 0x78, 0x79, 0x78, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7A, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, -0x7E, 0xFF, 0xFD, 0xFC, 0xFC, 0xFA, 0xF9, 0xFA, 0xFB, 0xFA, 0xF9, 0xF8, 0xF8, 0xF9, 0xFA, 0xF9, -0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF7, 0xF9, 0xF9, 0xF8, 0xF8, 0xFA, 0xFB, 0xFA, 0xFB, 0xFD, 0xFD, -0xFC, 0xFD, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFF, 0x7F, 0x7F, 0x7E, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, -0x7A, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x75, 0x76, 0x77, 0x76, 0x75, 0x76, 0x76, 0x75, 0x76, 0x77, -0x78, 0x79, 0x7B, 0x7B, 0x7B, 0x7A, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7A, 0x7B, 0x7B, 0x7A, -0x7B, 0x7D, 0x7E, 0x7B, 0x7C, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFC, 0xFD, 0xFE, 0xFF, -0xFE, 0xFF, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7D, 0x7F, 0x7F, 0x7C, 0x7B, -0x7A, 0x78, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7C, 0x7C, 0x7A, 0x7B, 0x7C, 0x7C, 0x7B, 0x7C, 0x7C, -0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x79, 0x7A, 0x79, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, -0x7D, 0xFE, 0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFA, 0xF8, 0xF8, 0xF9, 0xF8, 0xF5, 0xF4, 0xF7, 0xF8, -0xF8, 0xF8, 0xF9, 0xFB, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7B, -0x7A, 0x7B, 0x7B, 0x7A, 0x78, 0x78, 0x77, 0x76, 0x76, 0x75, 0x76, 0x76, 0x76, 0x77, 0x75, 0x75, -0x76, 0x75, 0x76, 0x76, 0x78, 0x78, 0x77, 0x78, 0x76, 0x74, 0x75, 0x77, 0x79, 0x7A, 0x7A, 0x7B, -0x7C, 0x7D, 0x7D, 0x7D, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, -0xFE, 0x7F, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0xFF, 0xFD, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, -0xFC, 0xFD, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7C, -0x7B, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x7A, 0x7C, 0x7A, 0x7B, 0x7C, 0x7C, 0x7E, 0x7E, 0xFF, -0xFF, 0x7F, 0x7F, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, -0x7C, 0x7D, 0xFF, 0x7E, 0x7C, 0x7D, 0xFF, 0xFF, 0xFF, 0xFD, 0xFD, 0xFF, 0x7E, 0x7F, 0x7E, 0x7E, -0x7F, 0x7E, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x79, -0x77, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7C, 0x7D, 0x7D, 0x7E, 0xFD, 0xFD, 0xFE, 0xFC, 0xFC, 0xFB, -0xFB, 0xFC, 0xFB, 0xFB, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, -0xFF, 0xFF, 0xFD, 0xFC, 0xFD, 0xFD, 0xFC, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7D, 0x7C, 0x7D, 0x7E, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, -0x7B, 0x7C, 0x7D, 0x7B, 0x7B, 0x7C, 0x7A, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x75, 0x73, 0x72, -0x72, 0x72, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x74, -0x75, 0x76, 0x76, 0x76, 0x77, 0x78, 0x77, 0x78, 0x79, 0x77, 0x78, 0x78, 0x79, 0x7A, 0x7A, 0x7A, -0x7A, 0x79, 0x77, 0x76, 0x76, 0x78, 0x78, 0x77, 0x77, 0x77, 0x75, 0x74, 0x74, 0x75, 0x75, 0x76, -0x79, 0x79, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7D, 0xFF, 0xFD, 0xFD, 0xFE, 0xFF, 0xFE, 0xFC, -0xF9, 0xF9, 0xFB, 0xFA, 0xF9, 0xF8, 0xF8, 0xF8, 0xF6, 0xF4, 0xF6, 0xF8, 0xF7, 0xF7, 0xF9, 0xF9, -0xF9, 0xF8, 0xF8, 0xFB, 0xFA, 0xF9, 0xFA, 0xFB, 0xFC, 0xFE, 0xFC, 0xFD, 0xFF, 0x7E, 0x7F, 0x7E, -0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, 0x7A, 0x7A, 0x79, 0x79, 0x78, 0x77, 0x78, -0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, 0x7F, 0xFE, 0xFE, 0xFD, 0xFD, -0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFC, 0xFB, 0xFC, -0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, -0x7C, 0x7B, 0x7B, 0x7C, 0x79, 0x79, 0x79, 0x78, 0x76, 0x75, 0x76, 0x78, 0x77, 0x76, 0x76, 0x77, -0x76, 0x74, 0x74, 0x75, 0x75, 0x75, 0x74, 0x74, 0x76, 0x77, 0x78, 0x7A, 0x7C, 0x7B, 0x7A, 0x7D, -0x7E, 0x7E, 0x7C, 0x7D, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFE, 0xFF, -0xFF, 0x7F, 0x7E, 0x7F, 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFC, 0xFB, 0xFC, 0xFE, 0xFD, 0xFC, 0xFE, -0xFF, 0xFE, 0xFD, 0xFF, 0x7E, 0x7F, 0xFE, 0xFC, 0xFD, 0xFE, 0xFD, 0xFD, 0xFE, 0x7F, 0x7E, 0xFF, -0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, -0x7E, 0x7D, 0x7E, 0xFF, 0xFF, 0xFE, 0xFD, 0xFF, 0x7D, 0x7A, 0x79, 0x79, 0x7A, 0x7C, 0x7B, 0x7B, -0x7D, 0x7E, 0x7E, 0x7D, 0xFF, 0xFF, 0x7F, 0x7F, 0x7E, 0x7B, 0x7A, 0x7A, 0x7A, 0x78, 0x77, 0x77, -0x77, 0x78, 0x78, 0x76, 0x76, 0x76, 0x76, 0x74, 0x74, 0x73, 0x74, 0x74, 0x75, 0x74, 0x72, 0x74, -0x76, 0x74, 0x74, 0x76, 0x76, 0x74, 0x73, 0x73, 0x72, 0x73, 0x74, 0x76, 0x77, 0x75, 0x73, 0x75, -0x77, 0x78, 0x75, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7B, -0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7D, 0x7C, 0x7D, 0x7B, 0x7C, 0x7F, -0xFF, 0xFF, 0x7E, 0x7D, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x79, 0x77, 0x77, -0x78, 0x76, 0x76, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x7B, 0x7C, 0x7B, 0x7C, 0x7D, 0xFF, -0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, -0xFA, 0xF9, 0xF9, 0xF7, 0xF7, 0xF7, 0xF4, 0xF4, 0xF4, 0xF2, 0xEF, 0xEE, 0xEF, 0xF2, 0xF2, 0xF1, -0xF2, 0xF5, 0xF5, 0xF3, 0xF1, 0xF2, 0xF5, 0xF7, 0xF8, 0xFA, 0xFB, 0xFC, 0xFC, 0xFB, 0xFC, 0xFC, -0xFD, 0xFF, 0x7F, 0x7E, 0x7C, 0x7A, 0x7A, 0x78, 0x77, 0x76, 0x75, 0x75, 0x74, 0x71, 0x70, 0x71, -0x71, 0x71, 0x70, 0x6F, 0x71, 0x71, 0x71, 0x73, 0x75, 0x77, 0x77, 0x76, 0x79, 0x7A, 0x79, 0x79, -0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7F, 0xFF, 0xFE, 0xFF, 0x7E, 0x7D, 0x7E, 0x7E, 0x7D, 0x7D, -0x7E, 0x7C, 0x7C, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x77, 0x75, 0x75, 0x76, 0x78, 0x79, 0x78, -0x7A, 0x7C, 0x7C, 0x7A, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7B, 0x7D, 0x7D, 0x7C, -0x7C, 0x7E, 0xFF, 0x7F, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0xFF, 0x7F, 0x7E, -0x7D, 0x7D, 0xFF, 0xFF, 0x7F, 0xFF, 0xFC, 0xFC, 0xFD, 0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xFB, 0xFB, -0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0x7F, 0x7F, 0x7E, 0x7D, 0x7E, 0x7D, 0x7B, 0x7C, 0x7B, -0x7B, 0x7C, 0x7C, 0x7A, 0x78, 0x78, 0x7B, 0x7A, 0x77, 0x75, 0x76, 0x75, 0x76, 0x76, 0x76, 0x76, -0x78, 0x79, 0x78, 0x75, 0x75, 0x76, 0x77, 0x7A, 0x7D, 0xFF, 0xFC, 0xFB, 0xFA, 0xFA, 0xFB, 0xFA, -0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0x7E, 0x78, 0x76, 0x72, 0x70, 0x71, 0x75, 0x77, 0x77, 0x79, 0x7A, -0x7A, 0x7A, 0x7B, 0xFF, 0xFB, 0xFA, 0xF9, 0xFB, 0xFD, 0xFE, 0x7E, 0x7F, 0xFF, 0xFC, 0xF6, 0xF3, -0xF7, 0xFC, 0xFF, 0x7A, 0x73, 0x6E, 0x6C, 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6F, 0x74, 0x73, 0x72, -0x75, 0x7A, 0x7D, 0x7D, 0xFF, 0xFF, 0x7C, 0x7C, 0x7D, 0x7B, 0x7A, 0x79, 0x7B, 0xFF, 0xFF, 0x7D, -0x7C, 0xFF, 0xFE, 0x7D, 0xFC, 0xF3, 0xF6, 0xFC, 0xFE, 0xFE, 0xFF, 0x78, 0x75, 0x79, 0x7A, 0x7E, -0xF8, 0xF6, 0xF6, 0xF2, 0xEF, 0xEE, 0xF0, 0xF7, 0xFD, 0xFE, 0xFD, 0x7B, 0x77, 0x7C, 0xFF, 0xFB, -0xFD, 0x7D, 0xFF, 0x7C, 0x78, 0x7A, 0x7A, 0xFF, 0xF9, 0xF5, 0xF1, 0xF4, 0xFA, 0xFC, 0xFC, 0xFA, -0xF8, 0xFA, 0xFB, 0xFA, 0xFB, 0xFC, 0xFD, 0xFF, 0x7D, 0x7B, 0x7D, 0x7E, 0x7A, 0x76, 0x76, 0x75, -0x72, 0x75, 0x7B, 0x7D, 0x7A, 0x7A, 0x7D, 0xFF, 0x7C, 0x7C, 0xFF, 0x7D, 0x7A, 0x7B, 0x7C, 0x7E, -0xFC, 0xFC, 0x7F, 0xFE, 0xFD, 0xFE, 0xFC, 0xF8, 0xF9, 0xFA, 0xFB, 0xFE, 0x7E, 0x79, 0x72, 0x72, -0x74, 0x76, 0x78, 0x76, 0x78, 0x7A, 0x75, 0x76, 0x77, 0x75, 0x73, 0x73, 0x73, 0x73, 0x74, 0x73, -0x73, 0x77, 0x78, 0x79, 0x79, 0x7A, 0x79, 0x73, 0x73, 0x7B, 0x7C, 0x7C, 0xFC, 0xFC, 0xFE, 0x7F, -0x76, 0x73, 0x76, 0x73, 0x73, 0x78, 0x7C, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0x7D, 0x7B, 0x7B, -0x7C, 0x7A, 0x78, 0x7B, 0x7B, 0x7D, 0x7F, 0x7A, 0x77, 0x73, 0x6F, 0x70, 0x72, 0x73, 0x72, 0x72, -0x73, 0x74, 0x74, 0x76, 0x7D, 0xFE, 0x7D, 0x7C, 0x7C, 0x78, 0x76, 0x77, 0x79, 0x7B, 0xFF, 0xFD, -0xFE, 0x7E, 0x7B, 0x7A, 0x78, 0x78, 0x7B, 0x7C, 0x7C, 0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x79, 0x7B, -0xFF, 0xFA, 0xF9, 0xFD, 0x7E, 0x7D, 0x7C, 0x7B, 0x7E, 0xFE, 0xFC, 0xFF, 0x7E, 0xFE, 0xFD, 0xFE, -0xFD, 0xFC, 0xFB, 0xFC, 0xFC, 0xFD, 0xF9, 0xF3, 0xF2, 0xF3, 0xF4, 0xF6, 0xF6, 0xF8, 0xFA, 0xFC, -0xFB, 0xF7, 0xF9, 0xFC, 0xFC, 0xFD, 0xFD, 0x7E, 0x7C, 0x7F, 0xFF, 0x7D, 0x7A, 0x7A, 0x7B, 0x78, -0x78, 0x78, 0x75, 0x75, 0x76, 0x79, 0x7A, 0x79, 0x7C, 0x7F, 0xFD, 0xFF, 0x7E, 0xFF, 0x7D, 0x79, -0x77, 0x78, 0x79, 0x78, 0x79, 0x7C, 0x7D, 0x7F, 0x7E, 0x7E, 0xFE, 0xFC, 0xF8, 0xF7, 0xFA, 0xFB, -0xFC, 0xFD, 0xFF, 0x7D, 0x7E, 0x7F, 0xFF, 0x7D, 0x7B, 0x7D, 0xFE, 0xF9, 0xF5, 0xF6, 0xF6, 0xF4, -0xF6, 0xFA, 0xFE, 0x7D, 0x79, 0x78, 0x77, 0x77, 0x7A, 0x7E, 0xFE, 0xFF, 0xFF, 0xFA, 0xFA, 0xFE, -0x7C, 0x75, 0x71, 0x72, 0x74, 0x75, 0x74, 0x75, 0x75, 0x77, 0x79, 0x79, 0x77, 0x74, 0x74, 0x74, -0x72, 0x71, 0x70, 0x71, 0x70, 0x6F, 0x72, 0x73, 0x72, 0x73, 0x71, 0x70, 0x73, 0x78, 0x7A, 0x78, -0x77, 0x77, 0x76, 0x74, 0x73, 0x72, 0x70, 0x71, 0x75, 0x78, 0x7B, 0x7F, 0xFF, 0xFE, 0xFB, 0xFD, -0x7E, 0xFF, 0xFD, 0x7F, 0x7C, 0x7B, 0x7F, 0xFD, 0xFF, 0xFE, 0xFC, 0xFE, 0xFD, 0xFC, 0xFA, 0xF7, -0xF7, 0xFB, 0xFD, 0xFE, 0x7E, 0x7C, 0x7B, 0x7A, 0x7B, 0x79, 0x75, 0x75, 0x76, 0x78, 0x7D, 0xFF, -0x7E, 0x7D, 0x7E, 0x7C, 0x77, 0x75, 0x76, 0x76, 0x78, 0x7E, 0xFD, 0xFB, 0xFC, 0xFD, 0xFE, 0x7C, -0x78, 0x78, 0x7A, 0x7B, 0x7E, 0x7E, 0x7D, 0x7D, 0x7C, 0x7A, 0x78, 0x79, 0x7B, 0x7A, 0x7D, 0xFC, -0xFD, 0x7E, 0xFF, 0xFB, 0xF7, 0xF6, 0xF7, 0xF7, 0xF6, 0xFA, 0xFF, 0xFE, 0xFD, 0xFF, 0x7D, 0xFF, -0xFC, 0xFB, 0xF9, 0xFD, 0xFE, 0xFD, 0x7E, 0x79, 0x76, 0x71, 0x6F, 0x6E, 0x6E, 0x6F, 0x72, 0x76, -0x7A, 0x7E, 0xFF, 0xFF, 0x7C, 0x7B, 0x7C, 0x7B, 0x7A, 0x79, 0x7A, 0x7E, 0xFF, 0xFF, 0x7E, 0x7D, -0x7D, 0x7E, 0x7C, 0x78, 0x79, 0x7A, 0x7B, 0xFF, 0xFF, 0x7F, 0x7E, 0x7B, 0x79, 0x79, 0x76, 0x72, -0x73, 0x7B, 0xFF, 0xFE, 0xFB, 0xFA, 0xFA, 0xFC, 0x7D, 0x78, 0x77, 0x78, 0x79, 0x79, 0x78, 0x79, -0x77, 0x73, 0x74, 0x76, 0x77, 0x79, 0x7A, 0x7B, 0x7F, 0xFD, 0xFE, 0xFF, 0x7F, 0x7E, 0x7E, 0x7C, -0x78, 0x78, 0x7B, 0x7B, 0x7A, 0x7C, 0x7F, 0xFE, 0xFD, 0xFE, 0x7E, 0xFF, 0xFD, 0xFC, 0xF9, 0xF5, -0xF2, 0xF0, 0xF2, 0xF3, 0xF0, 0xF1, 0xF2, 0xF1, 0xF4, 0xF7, 0xF8, 0xFC, 0xFC, 0xF6, 0xF3, 0xF4, -0xF5, 0xF5, 0xF6, 0xFB, 0xFF, 0xFF, 0xFF, 0x7D, 0x7D, 0x7E, 0x7D, 0x79, 0x75, 0x74, 0x75, 0x72, -0x72, 0x75, 0x75, 0x74, 0x77, 0x7A, 0x7A, 0x7A, 0x7A, 0x77, 0x74, 0x73, 0x72, 0x74, 0x75, 0x76, -0x77, 0x74, 0x74, 0x77, 0x79, 0x79, 0x79, 0x78, 0x77, 0x74, 0x70, 0x6F, 0x70, 0x6F, 0x6E, 0x6E, -0x6E, 0x6F, 0x6F, 0x72, 0x75, 0x72, 0x74, 0x79, 0x7B, 0x7B, 0x7B, 0x7D, 0xFF, 0x7E, 0x7F, 0xFE, -0xFE, 0x7F, 0x7D, 0x7D, 0xFF, 0xFD, 0xFE, 0x7E, 0x7D, 0x7D, 0x7E, 0x7C, 0x79, 0x77, 0x75, 0x76, -0x77, 0x78, 0x78, 0x74, 0x75, 0x7A, 0x7F, 0xFB, 0xF9, 0xF9, 0xF8, 0xFD, 0x7E, 0x7B, 0x76, 0x78, -0x7B, 0x7C, 0x7E, 0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x7C, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0x7D, 0x7B, -0x7B, 0x79, 0x79, 0x7A, 0x7D, 0xFF, 0x7F, 0x7F, 0xFF, 0xFD, 0xFB, 0xFD, 0xFE, 0xFE, 0xFF, 0x7D, -0x7C, 0x7F, 0xFB, 0xF7, 0xF6, 0xFC, 0x7F, 0xFF, 0xFE, 0xFB, 0xFD, 0xFE, 0xFC, 0xFD, 0xFE, 0x7C, -0x76, 0x74, 0x74, 0x79, 0x79, 0x76, 0x77, 0x79, 0x7C, 0x7D, 0x7B, 0x7B, 0x7B, 0x7E, 0xFD, 0xFB, -0xF9, 0xF9, 0xFE, 0x7C, 0x79, 0x79, 0x77, 0x76, 0x79, 0x7B, 0x7D, 0x7C, 0x7C, 0x7D, 0x7C, 0x78, -0x75, 0x74, 0x72, 0x72, 0x73, 0x71, 0x70, 0x73, 0x78, 0x7C, 0x7D, 0x7E, 0xFF, 0x7F, 0x7F, 0x7D, -0x7A, 0x78, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x7B, 0xFF, 0xFF, 0xFD, 0xFC, 0xFC, 0xFA, 0xF9, -0xF8, 0xF9, 0xFE, 0x7E, 0xFF, 0xFE, 0xFE, 0x7D, 0x7A, 0x78, 0x75, 0x75, 0x77, 0x7A, 0x7A, 0x79, -0x7B, 0x7D, 0xFF, 0xFD, 0xFC, 0xFC, 0xFB, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9, 0xFB, 0xFA, 0xF9, 0xF7, -0xF8, 0xFA, 0xF8, 0xF9, 0xFC, 0xFD, 0xFD, 0xFC, 0xF9, 0xF7, 0xF8, 0xFC, 0x7E, 0x7B, 0x7A, 0x7A, -0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x77, 0x72, 0x72, 0x74, 0x76, 0x7B, 0x7C, 0x7B, 0x7D, 0x7E, 0x7D, -0x7D, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x78, 0x78, 0x79, 0x79, 0x79, 0x78, 0x79, 0x7B, 0x7C, 0x7C, -0x7A, 0x7A, 0x77, 0x75, 0x75, 0x74, 0x73, 0x70, 0x6E, 0x6E, 0x6E, 0x6F, 0x72, 0x75, 0x77, 0x7A, -0x7D, 0x7D, 0x7D, 0x7E, 0xFF, 0x7D, 0x7A, 0x7A, 0x7A, 0x7B, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, -0x7D, 0x7B, 0x78, 0x75, 0x73, 0x74, 0x75, 0x75, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7D, 0xFE, 0xFC, -0xF9, 0xF8, 0xF8, 0xF8, 0xF6, 0xF5, 0xF6, 0xF8, 0xFB, 0xFC, 0xFB, 0xFD, 0xFF, 0x7E, 0x7D, 0x7C, -0x7C, 0x7B, 0x7C, 0x7B, 0x79, 0x79, 0x7A, 0x79, 0x76, 0x74, 0x72, 0x72, 0x73, 0x74, 0x75, 0x77, -0x78, 0x78, 0x78, 0x77, 0x76, 0x75, 0x75, 0x78, 0x7A, 0x79, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0x7F, -0xFE, 0xFC, 0xFC, 0xFC, 0xFA, 0xF8, 0xF7, 0xF7, 0xF8, 0xF7, 0xF5, 0xF5, 0xF5, 0xF4, 0xF5, 0xF6, -0xF7, 0xF8, 0xF9, 0xFB, 0xFE, 0x7F, 0x7D, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7D, 0x7A, 0x7A, 0x7A, -0x7A, 0x79, 0x79, 0x79, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x7A, 0x7A, 0x79, 0x77, 0x76, -0x77, 0x77, 0x77, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7B, -0x78, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0x7F, 0x7F, 0xFE, -0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFE, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, -0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x76, 0x77, 0x78, 0x77, 0x79, -0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7D, 0x7B, 0x7B, 0x7D, 0x7C, 0x7D, 0xFF, 0x7E, -0xFF, 0xFD, 0xFB, 0xF9, 0xF8, 0xF9, 0xF9, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF3, 0xF5, 0xF6, 0xF6, -0xF7, 0xF9, 0xFB, 0xFB, 0xFA, 0xFA, 0xFB, 0xFC, 0xFB, 0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFA, 0xF8, -0xF8, 0xF9, 0xFB, 0xFD, 0x7E, 0x7B, 0x78, 0x78, 0x77, 0x77, 0x77, 0x76, 0x76, 0x76, 0x75, 0x75, -0x73, 0x71, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6E, 0x6E, 0x6F, 0x6F, 0x6E, 0x6E, 0x6E, 0x6D, -0x6D, 0x6E, 0x6D, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x79, 0x7C, 0x7D, 0x7E, 0xFF, -0xFF, 0xFF, 0xFD, 0xFC, 0xFA, 0xF9, 0xFB, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0x7E, 0x7B, 0x7A, -0x79, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7C, 0x7C, 0x7B, 0x79, 0x79, 0x78, 0x78, 0x79, 0x7A, 0x7C, -0x7E, 0x7E, 0x7E, 0x7C, 0x7B, 0x7A, 0x7A, 0x7A, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7D, 0xFF, 0xFD, -0xFC, 0xFB, 0xFA, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFB, 0xFB, -0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFD, 0xFC, 0xFC, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, 0xF7, -0xF6, 0xF7, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0x7E, 0x7D, 0x7C, 0x7C, -0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, -0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7B, 0x78, 0x77, 0x76, 0x75, 0x75, 0x75, 0x76, 0x76, 0x75, 0x76, -0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7B, 0x7D, 0x7D, 0x7E, 0x7F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, -0xFD, 0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0x7F, 0x7E, 0x7C, 0x7C, 0x7B, -0x7A, 0x7A, 0x7A, 0x78, 0x78, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7C, 0x7D, 0x7B, -0x7A, 0x7B, 0x7C, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7B, 0x7F, 0xFD, 0x7D, 0x79, 0xFE, -0xFA, 0xFE, 0xFC, 0xF8, 0xFC, 0xFF, 0xFF, 0xFE, 0xFB, 0xFC, 0x7F, 0xFF, 0x7F, 0x7C, 0x7D, 0x7D, -0x7E, 0x7E, 0x7B, 0x7A, 0x7A, 0x7B, 0x7C, 0x7E, 0x7E, 0x7C, 0x7B, 0x7A, 0x7A, 0x7B, 0x7C, 0x7D, -0x7D, 0x7E, 0x7F, 0x7E, 0x7F, 0xFF, 0xFE, 0xFD, 0xFE, 0xFF, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7E, -0x7D, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x7A, 0x7A, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x75, 0x74, 0x73, -0x74, 0x75, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x77, 0x76, 0x77, 0x77, 0x79, 0x7B, 0x7C, 0x7D, -0x7D, 0x7D, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFE, 0xFD, 0xFE, 0xFF, 0xFE, 0xFD, 0xFB, 0xFC, 0xFD, -0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7E, -0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, -0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, -0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, 0x7F, 0x7E, -0x7D, 0x7C, 0x7B, 0x7B, 0x79, 0x77, 0x77, 0x78, 0x76, 0x76, 0x78, 0x7A, 0x78, 0x78, 0x78, 0x77, -0x77, 0x76, 0x75, 0x76, 0x75, 0x75, 0x77, 0x77, 0x76, 0x74, 0x74, 0x75, 0x76, 0x75, 0x76, 0x76, -0x75, 0x76, 0x76, 0x75, 0x74, 0x73, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x78, 0x7A, 0x7A, 0x7B, -0x7C, 0x7B, 0x7D, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFE, 0xFD, 0xFD, 0xFD, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0xFE, -0xFE, 0xFE, 0x7F, 0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFD, 0xFD, 0xFD, -0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0xFE, 0xFC, 0xFA, 0xF9, 0xF8, 0xF8, 0xF8, 0xF9, 0xFA, -0xFD, 0xFE, 0xFC, 0xFD, 0xFE, 0xFE, 0xFF, 0x7F, 0xFF, 0x7E, 0x7D, 0x7B, 0x79, 0x79, 0x7B, 0x7C, -0x7C, 0x7D, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7B, 0x7B, 0x7A, 0x77, 0x78, 0x75, 0x75, 0x76, 0x76, -0x78, 0x75, 0x76, 0x77, 0x73, 0x75, 0x73, 0x77, 0x76, 0x73, 0x78, 0x73, 0x78, 0x77, 0x75, 0x7B, -0x70, 0x7E, 0x68, 0x5B, 0xE4, 0xD9, 0x77, 0x66, 0x5F, 0x6B, 0xEB, 0x78, 0x6B, 0xEC, 0xE9, 0x67, -0x5A, 0x62, 0xF8, 0xE2, 0xF1, 0x6B, 0x6F, 0x72, 0x6E, 0x6D, 0x72, 0xEF, 0xE7, 0xF7, 0x6D, 0x6A, -0x70, 0x7B, 0xFC, 0xF5, 0xED, 0xEF, 0x7D, 0x71, 0x70, 0xFF, 0xEE, 0xEF, 0xF8, 0xFC, 0x7B, 0x73, -0x6F, 0x71, 0x7E, 0xF2, 0xF2, 0x76, 0x67, 0x68, 0x78, 0xF7, 0xF5, 0xFC, 0x7E, 0x7B, 0x73, 0x70, -0x79, 0xF4, 0xEB, 0xEC, 0xF8, 0x7C, 0x7B, 0xFF, 0xF6, 0xEF, 0xEF, 0xF4, 0xF8, 0xFE, 0x7D, 0xFE, -0xF8, 0xF4, 0xF4, 0xF9, 0xFE, 0x7E, 0x7C, 0x7C, 0xFD, 0xF8, 0xF8, 0xFD, 0x7D, 0x7A, 0x79, 0x7C, -0xFF, 0xFD, 0xFB, 0xFC, 0x7D, 0x7B, 0x7D, 0x7F, 0xFD, 0xFD, 0xFF, 0x7E, 0x7C, 0x7A, 0x79, 0x7C, -0x7E, 0x7D, 0x7D, 0x7B, 0x78, 0x79, 0x7B, 0x7A, 0x78, 0x79, 0x77, 0x76, 0x78, 0x71, 0x70, 0x78, -0x7E, 0xF6, 0xFE, 0x67, 0x68, 0xF4, 0xEF, 0x74, 0x69, 0x6A, 0xFF, 0x7E, 0x6E, 0xF2, 0xFB, 0x69, -0x66, 0x69, 0xDD, 0xD9, 0x71, 0x7B, 0x74, 0x5F, 0x69, 0x61, 0x6A, 0xE6, 0xEC, 0x66, 0x55, 0x50, -0x5C, 0xFB, 0xED, 0xF5, 0xFA, 0x6F, 0x6E, 0x7B, 0xE8, 0xCF, 0xC7, 0xC6, 0xCA, 0xCB, 0xDB, 0x3A, -0x2E, 0x49, 0xBD, 0xB7, 0xC6, 0x4D, 0x41, 0x4B, 0x49, 0x4D, 0xD9, 0xBF, 0xC2, 0xFD, 0x3F, 0x3D, -0x51, 0xDF, 0xCD, 0xCC, 0xD5, 0xF4, 0x50, 0x46, 0x4D, 0xF0, 0xCB, 0xCA, 0xDA, 0x61, 0x51, 0x52, -0x5B, 0xE6, 0xD0, 0xCE, 0xDC, 0x5D, 0x53, 0x51, 0x6A, 0xF9, 0x48, 0x67, 0xC2, 0xE0, 0x5F, 0x5B, -0x4C, 0x71, 0xFA, 0x6E, 0xCE, 0xCF, 0x7A, 0x64, 0x79, 0xD8, 0xCE, 0xD1, 0xCD, 0xC3, 0xC5, 0xCD, -0xC7, 0xDC, 0x42, 0x3E, 0x53, 0xD2, 0xC0, 0xDE, 0x44, 0x48, 0x58, 0x53, 0x59, 0xFA, 0xD9, 0xD6, -0x5E, 0x43, 0x47, 0x61, 0xE1, 0xD8, 0xEA, 0x64, 0x46, 0x3C, 0x51, 0x7F, 0x77, 0xD0, 0xF6, 0x4B, -0x4B, 0x4A, 0x6F, 0xCA, 0xC6, 0xC9, 0xC7, 0xC2, 0xC8, 0xBD, 0xB0, 0xAB, 0xBB, 0x1F, 0x19, 0x5F, -0xA3, 0xA5, 0xBA, 0x30, 0x30, 0x47, 0x31, 0x37, 0xBC, 0xAB, 0xB8, 0x3D, 0x2B, 0x30, 0x4E, 0xBD, -0xB4, 0xC4, 0x5D, 0x3F, 0x38, 0x41, 0x6E, 0xC8, 0xC1, 0xDC, 0x4B, 0x3B, 0x3F, 0xE5, 0xBF, 0xBC, -0xC8, 0xE5, 0xDE, 0xC0, 0xAE, 0xAD, 0xAF, 0xC1, 0x20, 0x1A, 0x63, 0xA8, 0xA7, 0xB5, 0x36, 0x2E, -0x3D, 0x32, 0x3F, 0xBD, 0xB1, 0xC1, 0x39, 0x2E, 0x42, 0xE8, 0xCA, 0xC3, 0xDB, 0x5F, 0x47, 0x39, -0x47, 0xD5, 0xCB, 0xD1, 0x70, 0x4B, 0x4D, 0xF0, 0xC1, 0xB3, 0xAE, 0xB4, 0xBE, 0xB8, 0xB8, 0x34, -0x1C, 0x27, 0xB6, 0xA3, 0xAC, 0x4F, 0x2C, 0x32, 0x3B, 0x3E, 0xEB, 0xB9, 0xBB, 0x45, 0x2E, 0x39, -0x60, 0xC3, 0xBB, 0xD8, 0x4D, 0x45, 0x41, 0x57, 0xD6, 0xDE, 0x79, 0x5D, 0x50, 0x5B, 0xDB, 0xBE, -0xB4, 0xB3, 0xBC, 0xC4, 0xB6, 0xAC, 0xC2, 0x26, 0x1A, 0x30, 0xAB, 0xA9, 0xBB, 0x61, 0x33, 0x30, -0x36, 0x39, 0xCF, 0xB9, 0x64, 0x41, 0x42, 0x3E, 0x5E, 0xD3, 0xCF, 0xC4, 0xEC, 0x47, 0x56, 0x5C, -0x50, 0x57, 0x62, 0xDF, 0xD2, 0xD3, 0xC4, 0xB6, 0xB3, 0xBA, 0xB8, 0xAD, 0xAF, 0x3C, 0x1C, 0x1E, -0xCB, 0xA1, 0xA9, 0xFE, 0x2D, 0x2C, 0x39, 0x3D, 0x64, 0xBE, 0xD5, 0x4B, 0x42, 0x3A, 0x40, 0xEC, -0xC4, 0xBE, 0xD1, 0x4A, 0x3E, 0x47, 0x62, 0xE4, 0xD7, 0xD6, 0xDC, 0xDE, 0xCD, 0xB6, 0xAD, 0xAE, -0xAC, 0xAD, 0xE6, 0x22, 0x19, 0x2E, 0xA6, 0x9E, 0xB2, 0x39, 0x28, 0x2D, 0x39, 0x4E, 0xC2, 0xBE, -0x5B, 0x3E, 0x3B, 0x3C, 0x58, 0xC6, 0xBD, 0xC7, 0x60, 0x3F, 0x3F, 0x51, 0xED, 0xCF, 0xC8, 0xD1, -0xE0, 0xD9, 0xBC, 0xAC, 0xAB, 0xAB, 0xA9, 0xC2, 0x25, 0x17, 0x22, 0xAE, 0x9D, 0xA9, 0x47, 0x26, -0x29, 0x34, 0x47, 0xC5, 0xBB, 0x77, 0x3F, 0x3A, 0x38, 0x4E, 0xC6, 0xBC, 0xBE, 0xE6, 0x3D, 0x39, -0x43, 0x67, 0xCE, 0xC7, 0xD6, 0xED, 0xD9, 0xBD, 0xAB, 0xAB, 0xAE, 0xA9, 0xB4, 0x30, 0x1A, 0x1B, -0xD5, 0x9D, 0xA3, 0xDA, 0x2A, 0x26, 0x31, 0x3C, 0x6C, 0xBF, 0xCE, 0x5E, 0x42, 0x32, 0x3C, 0xD6, -0xBC, 0xB8, 0xCC, 0x3F, 0x37, 0x3B, 0x51, 0xCC, 0xC1, 0xCC, 0xE2, 0xDE, 0xBD, 0xAC, 0xAA, 0xA9, -0xA7, 0xC5, 0x26, 0x18, 0x1F, 0xB7, 0x9D, 0xA6, 0xDF, 0x2B, 0x26, 0x2D, 0x37, 0xEB, 0xBA, 0xCB, -0x5E, 0x3C, 0x30, 0x44, 0xC9, 0xBB, 0xB8, 0xCF, 0x3D, 0x34, 0x3B, 0x5F, 0xC1, 0xBE, 0xCE, 0xD6, -0xCE, 0xB8, 0xAB, 0xAA, 0xA4, 0xA8, 0x42, 0x1C, 0x18, 0x31, 0xA4, 0x9F, 0xAF, 0x48, 0x29, 0x28, -0x2C, 0x37, 0xCC, 0xBA, 0xC7, 0x57, 0x30, 0x31, 0x5A, 0xC6, 0xB6, 0xB7, 0x5F, 0x38, 0x34, 0x3D, -0xE2, 0xBD, 0xBD, 0xC7, 0xD2, 0xCA, 0xB2, 0xAB, 0xA7, 0xA2, 0xB3, 0x29, 0x18, 0x1C, 0xD2, 0x9F, -0xA5, 0xBC, 0x3A, 0x2A, 0x29, 0x2A, 0x3E, 0xC3, 0xBB, 0xC1, 0x43, 0x2D, 0x3A, 0xF5, 0xC1, 0xB5, -0xBE, 0x4F, 0x36, 0x32, 0x3F, 0xD2, 0xBB, 0xBA, 0xBE, 0xC5, 0xBF, 0xB1, 0xAB, 0xA4, 0xA7, 0x75, -0x1F, 0x18, 0x27, 0xAE, 0xA2, 0xAD, 0xD6, 0x36, 0x2B, 0x28, 0x2C, 0x4E, 0xC2, 0xB8, 0xC9, 0x35, -0x2F, 0x42, 0x71, 0xBA, 0xB4, 0xD2, 0x44, 0x34, 0x34, 0x4C, 0xCD, 0xBE, 0xBB, 0xB9, 0xBC, 0xB3, -0xAE, 0xAB, 0xA3, 0xB0, 0x2C, 0x1A, 0x1C, 0x5F, 0xA4, 0xA9, 0xBA, 0x6F, 0x34, 0x28, 0x26, 0x32, -0x77, 0xB9, 0xB3, 0x5E, 0x32, 0x38, 0x40, 0xD8, 0xB6, 0xBE, 0xF4, 0x40, 0x34, 0x3A, 0x5B, 0xC7, -0xB7, 0xB4, 0xB7, 0xB4, 0xB2, 0xAE, 0xA5, 0xAB, 0x3B, 0x1D, 0x1B, 0x34, 0xAE, 0xAA, 0xB4, 0xC7, -0x42, 0x2C, 0x25, 0x2B, 0x43, 0xCF, 0xB5, 0xBE, 0x3F, 0x38, 0x3D, 0x4D, 0xC4, 0xBD, 0xCF, 0x5D, -0x3E, 0x38, 0x43, 0xE4, 0xBF, 0xB4, 0xAF, 0xB0, 0xAF, 0xAE, 0xA8, 0xA7, 0xF6, 0x21, 0x1A, 0x27, -0xBA, 0xAC, 0xB5, 0xB9, 0xE2, 0x36, 0x26, 0x25, 0x33, 0x4E, 0xBA, 0xB2, 0x64, 0x41, 0x3F, 0x3D, -0xE6, 0xC6, 0xCD, 0xD4, 0x50, 0x3D, 0x3C, 0x48, 0xD4, 0xB9, 0xAF, 0xAD, 0xAE, 0xAE, 0xAA, 0xA7, -0xC0, 0x2A, 0x1B, 0x1F, 0x65, 0xAF, 0xB5, 0xB5, 0xBF, 0x4C, 0x2C, 0x23, 0x2A, 0x37, 0xE6, 0xAF, -0xBC, 0x5B, 0x4B, 0x3B, 0x49, 0xCF, 0xCE, 0xD0, 0xDE, 0x4F, 0x40, 0x3F, 0x57, 0xC7, 0xB3, 0xAA, -0xA9, 0xAC, 0xAE, 0xA9, 0xAE, 0x3B, 0x1E, 0x1E, 0x37, 0xBA, 0xB7, 0xB7, 0xB5, 0xC9, 0x3A, 0x26, -0x27, 0x2E, 0x37, 0xC1, 0xB1, 0xCA, 0xE8, 0x49, 0x3E, 0x62, 0x78, 0xEF, 0xD7, 0x69, 0x4F, 0x44, -0x48, 0xFB, 0xC5, 0xAF, 0xA9, 0xA8, 0xAA, 0xAB, 0xAA, 0xCF, 0x26, 0x1C, 0x22, 0x4A, 0xBD, 0xBB, -0xAF, 0xB1, 0xD7, 0x31, 0x25, 0x27, 0x28, 0x38, 0xB9, 0xB6, 0xC3, 0xCB, 0x4B, 0x45, 0x4E, 0x47, -0x62, 0xE0, 0xF9, 0x5C, 0x4C, 0x5C, 0xE4, 0xBF, 0xAD, 0xA8, 0xA5, 0xA7, 0xA9, 0xB2, 0x36, 0x20, -0x1E, 0x29, 0x56, 0xCC, 0xB8, 0xAC, 0xB5, 0xFA, 0x2F, 0x28, 0x25, 0x25, 0x45, 0xBE, 0xBF, 0xB8, -0xC5, 0x5F, 0x54, 0x41, 0x43, 0x4F, 0x56, 0x75, 0x70, 0xFE, 0xE2, 0xD3, 0xB9, 0xAD, 0xA8, 0xA6, -0xA6, 0xA8, 0xCA, 0x2D, 0x22, 0x21, 0x2E, 0x47, 0x77, 0xB4, 0xAD, 0xB7, 0xDC, 0x39, 0x2D, 0x24, -0x28, 0x40, 0x5A, 0xC7, 0xB5, 0xBD, 0xC0, 0xDB, 0x4E, 0x4C, 0x40, 0x44, 0x4E, 0x56, 0xDA, 0xCC, -0xC0, 0xB1, 0xAC, 0xA7, 0xA5, 0xA6, 0xAD, 0x4F, 0x2A, 0x23, 0x25, 0x2F, 0x39, 0x6C, 0xB6, 0xB1, -0xB7, 0xD6, 0x43, 0x2F, 0x26, 0x2C, 0x35, 0x3A, 0xDF, 0xC7, 0xBE, 0xBA, 0xCB, 0xD4, 0x6E, 0x48, -0x44, 0x3E, 0x4A, 0x6C, 0xD6, 0xB9, 0xB0, 0xA8, 0xA4, 0xA5, 0xA4, 0xB5, 0x42, 0x2C, 0x23, 0x27, -0x2B, 0x2E, 0x55, 0xC2, 0xB9, 0xB6, 0xC5, 0xF4, 0x3C, 0x32, 0x34, 0x2F, 0x37, 0x4A, 0x5B, 0xCF, -0xC9, 0xC6, 0xC0, 0xCA, 0xCF, 0xF4, 0x52, 0x51, 0x4E, 0xF8, 0xC4, 0xB7, 0xAD, 0xA9, 0xA6, 0xA7, -0xB8, 0x5D, 0x38, 0x2F, 0x2E, 0x2B, 0x2C, 0x35, 0x42, 0x5D, 0x7D, 0xE3, 0xDF, 0x6F, 0x73, 0x5A, -0x4D, 0x55, 0x4F, 0x4F, 0x58, 0x5C, 0x6E, 0xFA, 0xE2, 0xD4, 0xD4, 0xD6, 0xD9, 0xD6, 0xCC, 0xC6, -0xBF, 0xBB, 0xB8, 0xB6, 0xBC, 0xC9, 0xDC, 0x60, 0x59, 0x53, 0x4A, 0x49, 0x46, 0x45, 0x46, 0x43, -0x45, 0x45, 0x49, 0x56, 0x5A, 0x5D, 0x6E, 0x72, 0x7C, 0x74, 0x6D, 0x7A, 0x7A, 0xFC, 0xED, 0xE8, -0xEB, 0xFF, 0xFD, 0xEC, 0xDE, 0xD2, 0xCC, 0xC7, 0xC5, 0xCA, 0xD2, 0xD9, 0xDB, 0xD4, 0xCF, 0xD1, -0xD9, 0xE7, 0xFC, 0x6E, 0x60, 0x57, 0x50, 0x4C, 0x49, 0x47, 0x46, 0x45, 0x47, 0x4A, 0x4D, 0x4F, -0x4F, 0x53, 0x5A, 0x5F, 0x62, 0x60, 0x62, 0x6B, 0x77, 0xEC, 0xD8, 0xCC, 0xC7, 0xC7, 0xCB, 0xCF, -0xD3, 0xD3, 0xCE, 0xCB, 0xCA, 0xCC, 0xCF, 0xD4, 0xD9, 0xDF, 0xEB, 0xFE, 0x6A, 0x58, 0x4D, 0x46, -0x43, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x52, 0x54, 0x55, 0x54, 0x57, 0x5C, 0x61, 0x72, 0xE5, -0xD4, 0xCC, 0xCB, 0xCD, 0xD0, 0xD4, 0xD3, 0xD1, 0xD0, 0xCF, 0xD1, 0xD2, 0xD4, 0xD6, 0xD9, 0xDB, -0xDB, 0xDD, 0xEC, 0x6B, 0x59, 0x53, 0x54, 0x57, 0x59, 0x58, 0x57, 0x5A, 0x5C, 0x5A, 0x55, 0x52, -0x52, 0x51, 0x51, 0x57, 0x61, 0xFC, 0xE3, 0xDF, 0xE0, 0xE4, 0xE3, 0xE0, 0xDF, 0xDE, 0xDD, 0xDE, -0xDD, 0xDF, 0xE0, 0xDF, 0xDC, 0xD9, 0xDC, 0xE7, 0x7E, 0x6B, 0x6D, 0x7C, 0xEE, 0xE6, 0xE7, 0xEA, -0xEC, 0xF5, 0x7A, 0x6A, 0x61, 0x5A, 0x51, 0x4F, 0x50, 0x55, 0x5D, 0x62, 0x63, 0x60, 0x5F, 0x61, -0x65, 0x68, 0x6D, 0x75, 0xFA, 0xF1, 0xF1, 0xEE, 0xE6, 0xDD, 0xDB, 0xDE, 0xEB, 0x79, 0x6B, 0x6F, -0xF7, 0xE2, 0xDC, 0xDB, 0xDA, 0xDA, 0xDC, 0xDD, 0xDE, 0xE0, 0xF1, 0x6B, 0x5F, 0x5F, 0x66, 0x6B, -0x6A, 0x65, 0x5E, 0x5B, 0x5A, 0x59, 0x5A, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x68, 0xFC, 0xE8, 0xE5, -0xEB, 0xFB, 0x71, 0x6D, 0x78, 0xEE, 0xE2, 0xDE, 0xDD, 0xDC, 0xDE, 0xDF, 0xDC, 0xD9, 0xD9, 0xE0, -0xED, 0xF0, 0xEC, 0xE4, 0xE2, 0xE6, 0xEE, 0x7C, 0x6D, 0x65, 0x5E, 0x5E, 0x62, 0x64, 0x61, 0x5C, -0x5B, 0x5F, 0x70, 0xF7, 0xF8, 0x78, 0x6B, 0x65, 0x61, 0x69, 0xFA, 0xE9, 0xE5, 0xE2, 0xE5, 0xEA, -0xED, 0xEB, 0xE5, 0xE5, 0xED, 0xF9, 0xFC, 0xEF, 0xE3, 0xDE, 0xDE, 0xE1, 0xE9, 0xF4, 0x74, 0x6A, -0x6B, 0x6F, 0x6F, 0x67, 0x5E, 0x5C, 0x5F, 0x6A, 0x6F, 0x6C, 0x66, 0x5F, 0x5D, 0x5E, 0x64, 0x6F, -0xFE, 0xEF, 0xEC, 0xF2, 0xFD, 0x7E, 0xFB, 0xF6, 0xFF, 0x6F, 0x6A, 0x6A, 0x74, 0xF4, 0xE9, 0xE4, -0xE7, 0xEE, 0x7D, 0x6A, 0x69, 0x6F, 0xFE, 0xF7, 0x7B, 0x6B, 0x68, 0x6E, 0x79, 0x78, 0x6F, 0x69, -0x62, 0x5F, 0x60, 0x66, 0x72, 0xF6, 0xEB, 0xEC, 0xF3, 0xFC, 0xFA, 0xF2, 0xF2, 0xFE, 0x70, 0x69, -0x69, 0x71, 0xF7, 0xE8, 0xE3, 0xE4, 0xED, 0x76, 0x69, 0x6A, 0x6F, 0x7E, 0xFB, 0x7D, 0x75, 0x73, -0x7C, 0xFB, 0xFC, 0x7D, 0x73, 0x6D, 0x6A, 0x69, 0x6F, 0xFD, 0xEC, 0xE8, 0xED, 0xF6, 0xF7, 0xF1, -0xED, 0xEF, 0xF6, 0x7E, 0x76, 0x78, 0xFB, 0xEC, 0xE2, 0xDE, 0xE0, 0xEB, 0xFE, 0x73, 0x73, 0x7E, -0xFA, 0xFC, 0xFF, 0x7B, 0x7D, 0xFC, 0xFE, 0x7B, 0x74, 0x6F, 0x6D, 0x6C, 0x6E, 0x77, 0xFA, 0xEE, -0xED, 0xF6, 0x7A, 0x73, 0x77, 0x7B, 0x7C, 0x78, 0x6E, 0x6B, 0x6F, 0x7C, 0xEF, 0xE7, 0xE2, 0xE6, -0xF2, 0x7A, 0x71, 0x75, 0x7D, 0xFE, 0xFD, 0xFD, 0xFB, 0xF5, 0xF7, 0xFE, 0x77, 0x6E, 0x6A, 0x67, -0x67, 0x6C, 0x76, 0xF7, 0xEE, 0xEF, 0xFA, 0x7B, 0x78, 0x7B, 0xFF, 0x7F, 0x78, 0x6F, 0x6C, 0x6C, -0x72, 0xFE, 0xEF, 0xEC, 0xEF, 0xFD, 0x76, 0x70, 0x71, 0x75, 0x7A, 0x7E, 0x7E, 0xFF, 0xFC, 0xFD, -0x7C, 0x73, 0x6D, 0x69, 0x65, 0x63, 0x65, 0x6B, 0x79, 0xFB, 0xFD, 0x78, 0x70, 0x70, 0x74, 0x79, -0x7C, 0x7B, 0x79, 0x77, 0x78, 0x7F, 0xF4, 0xED, 0xED, 0xF2, 0xFB, 0x7A, 0x74, 0x74, 0x76, 0x7A, -0x7F, 0xFB, 0xF5, 0xF4, 0xF6, 0xFA, 0x7D, 0x75, 0x6E, 0x6B, 0x6B, 0x6F, 0x7D, 0xF3, 0xEF, 0xF4, -0x7E, 0x78, 0x7A, 0xFF, 0xFA, 0xF7, 0xF5, 0xF4, 0xF4, 0xF1, 0xED, 0xE9, 0xE6, 0xE8, 0xEE, 0xF8, -0x7F, 0x7C, 0x7A, 0x7A, 0x7B, 0x7D, 0xFD, 0xF8, 0xF8, 0xF9, 0xFC, 0x7D, 0x74, 0x6C, 0x69, 0x69, -0x6C, 0x76, 0xFA, 0xF6, 0xFD, 0x78, 0x71, 0x6F, 0x6F, 0x6F, 0x71, 0x74, 0x77, 0x7C, 0xFD, 0xF5, -0xEC, 0xE9, 0xEA, 0xEF, 0xFB, 0x7A, 0x74, 0x73, 0x73, 0x73, 0x73, 0x78, 0x7E, 0xFE, 0xFD, 0xFE, -0x7B, 0x74, 0x6D, 0x68, 0x66, 0x69, 0x6F, 0x7B, 0x7F, 0x7C, 0x77, 0x73, 0x72, 0x6F, 0x6D, 0x6D, -0x6D, 0x6D, 0x6E, 0x72, 0x7A, 0xFA, 0xF1, 0xEE, 0xEF, 0xF6, 0xFD, 0x7D, 0x7B, 0x7A, 0x78, 0x78, -0x79, 0x79, 0x7A, 0x7C, 0x7D, 0x7E, 0x7D, 0x77, 0x70, 0x6E, 0x71, 0x79, 0x7E, 0x7E, 0x7E, 0x7D, -0x7E, 0x7D, 0x7C, 0x7A, 0x78, 0x76, 0x74, 0x73, 0x75, 0x7A, 0xFC, 0xF6, 0xF4, 0xF4, 0xF6, 0xF6, -0xF6, 0xF9, 0xF9, 0xF7, 0xF5, 0xF3, 0xF1, 0xF1, 0xF3, 0xF5, 0xF7, 0xFA, 0x7B, 0x6F, 0x6D, 0x6D, -0x6F, 0x6F, 0x6E, 0x6E, 0x70, 0x70, 0x71, 0x74, 0x78, 0x7C, 0x7D, 0x7E, 0x7D, 0xFF, 0xFB, 0xF7, -0xF4, 0xF4, 0xF6, 0xF8, 0xFB, 0xFD, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x7F, 0xFF, 0xFC, 0xF8, -0xF9, 0xFD, 0x7D, 0x7C, 0x7F, 0xFE, 0x7E, 0x7C, 0x7A, 0x79, 0x77, 0x75, 0x75, 0x76, 0x79, 0x76, -0x71, 0x6F, 0x6F, 0x71, 0x76, 0x78, 0x78, 0x78, 0x7B, 0x7D, 0x7A, 0x77, 0x76, 0x76, 0x78, 0x79, -0x78, 0x79, 0x7C, 0xFD, 0xF4, 0xF1, 0xF2, 0xF5, 0xF9, 0xFB, 0x7F, 0x79, 0x76, 0x76, 0x78, 0x77, -0x77, 0x7B, 0xFF, 0xFA, 0xF6, 0xF6, 0xF7, 0xF6, 0xF6, 0xF7, 0xF9, 0xFA, 0xF9, 0xF6, 0xF6, 0xF9, -0xFB, 0xFE, 0x7F, 0x7E, 0x7C, 0x79, 0x7A, 0xFE, 0xF5, 0xEF, 0xEE, 0xEF, 0xF1, 0xF3, 0xF4, 0xFB, -0x79, 0x73, 0x72, 0x6E, 0x6B, 0x68, 0x68, 0x6C, 0x73, 0x7A, 0x7C, 0x7B, 0x7B, 0x7D, 0x7D, 0xFD, -0xF6, 0xF0, 0xEE, 0xEF, 0xF6, 0xFB, 0xFF, 0x7D, 0x7F, 0x7D, 0x7A, 0x7A, 0x7B, 0x7C, 0x7D, 0x7B, -0x7A, 0xFF, 0xFD, 0xFF, 0x7E, 0x7A, 0x75, 0x74, 0x71, 0x6F, 0x6F, 0x70, 0x77, 0x7A, 0x78, 0x75, -0x72, 0x75, 0x73, 0x6F, 0x6F, 0x70, 0x75, 0x77, 0x76, 0x78, 0x75, 0x78, 0x7B, 0x7B, 0x7F, 0x7B, -0x7E, 0x7F, 0x7E, 0x7E, 0x77, 0x79, 0x73, 0x71, 0x71, 0x6B, 0x6F, 0x60, 0x5B, 0x6F, 0x72, 0x69, -0x71, 0x72, 0x7E, 0xFC, 0xF7, 0xEE, 0xF4, 0xFB, 0x7E, 0x7E, 0xFC, 0xF9, 0xFD, 0x7F, 0xFC, 0x72, -0x78, 0x64, 0x53, 0x71, 0xDF, 0xF0, 0xEB, 0xE9, 0xF0, 0x7C, 0x7B, 0xEA, 0xF6, 0x7E, 0x79, 0x6C, -0x79, 0x5F, 0x5B, 0xEC, 0xE2, 0xEF, 0xED, 0xF1, 0xF7, 0xFE, 0x7C, 0xFE, 0x75, 0x6E, 0x75, 0x79, -0x7A, 0x72, 0x6E, 0x75, 0x7A, 0x7B, 0x77, 0x77, 0xFE, 0xF8, 0xF6, 0xF5, 0xEB, 0xE9, 0xEC, 0xE8, -0xEE, 0xEC, 0xED, 0x77, 0xFD, 0x61, 0x51, 0x66, 0xE7, 0xDC, 0xD8, 0xD3, 0xD3, 0x6C, 0x52, 0x63, -0x6F, 0x73, 0x7F, 0xFB, 0xF4, 0x79, 0x7B, 0xF1, 0xED, 0xEC, 0xFA, 0x76, 0x7A, 0x74, 0x6B, 0x6B, -0x75, 0x7C, 0x7C, 0x79, 0xFE, 0xF6, 0xFE, 0x7A, 0x71, 0x75, 0xFF, 0x70, 0x6D, 0x6E, 0x69, 0x66, -0x5E, 0x62, 0xFA, 0xEA, 0xE5, 0xE0, 0xE1, 0xE5, 0xEE, 0xF1, 0xE5, 0xE4, 0xEA, 0xE8, 0xE7, 0xE7, -0xE3, 0xE7, 0xE8, 0xE8, 0xEF, 0xF7, 0x78, 0x6E, 0x6D, 0x60, 0x5A, 0x57, 0x54, 0x53, 0x51, 0x50, -0x52, 0x54, 0x57, 0x59, 0x5D, 0x67, 0x70, 0x7B, 0xF5, 0xE5, 0xDA, 0xD5, 0xD2, 0xCD, 0xC4, 0xBE, -0xBB, 0xB7, 0xB5, 0xBB, 0xCB, 0xDE, 0xE9, 0x56, 0x3F, 0x3A, 0x39, 0x3B, 0x3B, 0x3A, 0x3F, 0x4E, -0x5D, 0x69, 0xF2, 0xDD, 0xD9, 0xE2, 0xF3, 0xF4, 0x72, 0x5C, 0x53, 0x4E, 0x4D, 0x4E, 0x4E, 0x4F, -0x58, 0x7E, 0xDA, 0xCB, 0xBF, 0xBA, 0xB7, 0xB4, 0xB0, 0xAE, 0xB2, 0xBE, 0xD7, 0x70, 0x4E, 0x3B, -0x32, 0x30, 0x33, 0x35, 0x35, 0x3A, 0x49, 0x5F, 0x7E, 0xEF, 0xE1, 0xD2, 0xD1, 0xE6, 0xEF, 0xF7, -0x5F, 0x4F, 0x48, 0x48, 0x4B, 0x48, 0x4B, 0x55, 0x72, 0xE1, 0xD2, 0xC2, 0xBA, 0xB6, 0xB3, 0xB0, -0xAD, 0xAE, 0xBA, 0xD0, 0x64, 0x4C, 0x3C, 0x30, 0x2E, 0x2F, 0x33, 0x35, 0x3A, 0x47, 0x6C, 0xE6, -0xEB, 0xD0, 0xC6, 0xCC, 0xD6, 0xE3, 0xEF, 0x69, 0x4E, 0x4B, 0x4B, 0x47, 0x46, 0x48, 0x4F, 0x61, -0xFE, 0xD1, 0xBE, 0xB8, 0xB5, 0xB2, 0xAF, 0xAD, 0xAE, 0xBA, 0xCD, 0x5F, 0x47, 0x3B, 0x2F, 0x2D, -0x2E, 0x30, 0x35, 0x3B, 0x47, 0x6C, 0xF4, 0xE2, 0xCB, 0xC7, 0xCD, 0xD7, 0xDD, 0xE3, 0x6E, 0x4E, -0x4A, 0x4B, 0x48, 0x47, 0x4A, 0x5B, 0xE4, 0xD3, 0xC0, 0xB7, 0xB3, 0xB0, 0xAF, 0xAC, 0xAC, 0xB3, -0xC4, 0x7D, 0x4C, 0x3E, 0x30, 0x2C, 0x2E, 0x31, 0x35, 0x3A, 0x45, 0x62, 0xFA, 0xEB, 0xCE, 0xCA, -0xD2, 0xDA, 0xE7, 0xE9, 0x6D, 0x4C, 0x49, 0x49, 0x47, 0x48, 0x4C, 0x68, 0xD7, 0xCA, 0xBC, 0xB5, -0xB2, 0xB0, 0xAE, 0xAC, 0xAE, 0xB9, 0xCE, 0x5D, 0x45, 0x39, 0x2F, 0x2D, 0x2E, 0x31, 0x36, 0x3B, -0x47, 0x5C, 0x6E, 0xE4, 0xD3, 0xD3, 0xD4, 0xDA, 0xDE, 0xEB, 0x5B, 0x4D, 0x4A, 0x47, 0x48, 0x49, -0x54, 0xEB, 0xCE, 0xBE, 0xB8, 0xB7, 0xB3, 0xB3, 0xB5, 0xB3, 0xBB, 0xC9, 0xC8, 0xED, 0x47, 0x42, -0x3A, 0x36, 0x37, 0x34, 0x39, 0x3E, 0x3F, 0x47, 0x4E, 0x65, 0xDE, 0xEC, 0xDC, 0xCE, 0xD9, 0xEB, -0x5F, 0x54, 0x51, 0x47, 0x46, 0x4C, 0x58, 0xFC, 0xD8, 0xC4, 0xBB, 0xBA, 0xB8, 0xB5, 0xB2, 0xAF, -0xB0, 0xB6, 0xBD, 0xCC, 0x66, 0x47, 0x3B, 0x34, 0x32, 0x32, 0x34, 0x38, 0x3B, 0x3F, 0x4B, 0x58, -0x69, 0xE9, 0xD9, 0xD4, 0xDB, 0x77, 0x5C, 0x59, 0x4F, 0x4A, 0x4B, 0x51, 0x69, 0xE0, 0xCE, 0xC2, -0xBD, 0xBC, 0xBA, 0xB8, 0xB7, 0xB4, 0xB2, 0xB7, 0xC3, 0xCE, 0xD4, 0x67, 0x44, 0x3D, 0x3C, 0x3B, -0x38, 0x38, 0x3B, 0x3F, 0x42, 0x46, 0x4E, 0x5F, 0x6A, 0x6B, 0xFD, 0xF7, 0x70, 0x5C, 0x54, 0x58, -0x58, 0x53, 0x5B, 0x73, 0xE5, 0xD2, 0xCA, 0xC6, 0xC2, 0xBF, 0xBE, 0xBE, 0xBD, 0xBB, 0xBC, 0xC3, -0xCA, 0xD0, 0xE2, 0x5F, 0x4E, 0x4A, 0x44, 0x3E, 0x3D, 0x3D, 0x3F, 0x42, 0x44, 0x4B, 0x55, 0x57, -0x5F, 0x69, 0x68, 0x63, 0x58, 0x56, 0x5B, 0x56, 0x57, 0x66, 0x79, 0xE8, 0xD9, 0xCF, 0xCB, 0xCB, -0xC8, 0xC4, 0xC5, 0xC6, 0xC9, 0xC9, 0xC6, 0xCD, 0xD4, 0xD8, 0xE2, 0xF1, 0x66, 0x5C, 0x57, 0x4C, -0x49, 0x49, 0x48, 0x49, 0x49, 0x4B, 0x51, 0x51, 0x4F, 0x53, 0x56, 0x58, 0x58, 0x54, 0x58, 0x5F, -0x5E, 0x5B, 0x63, 0xF2, 0xE5, 0xE5, 0xD7, 0xCF, 0xD2, 0xD6, 0xD1, 0xCF, 0xD6, 0xD6, 0xD2, 0xCF, -0xCE, 0xD0, 0xD8, 0xDB, 0xDB, 0xE5, 0x6D, 0x67, 0x65, 0x5C, 0x58, 0x54, 0x59, 0x5D, 0x57, 0x57, -0x5B, 0x5B, 0x59, 0x56, 0x57, 0x5A, 0x56, 0x52, 0x5A, 0x5C, 0x5D, 0x7D, 0xF1, 0xF3, 0xE7, 0xE3, -0xDF, 0xDB, 0xDA, 0xE7, 0xEC, 0xDE, 0xE5, 0xE9, 0xE6, 0xE4, 0xD6, 0xDF, 0xF8, 0xDE, 0xE9, 0x7C, -0xEE, 0xFB, 0x7A, 0x6B, 0x65, 0xFF, 0x79, 0x69, 0x6B, 0x63, 0x65, 0x62, 0x56, 0x5A, 0x60, 0x55, -0x58, 0x62, 0x5E, 0x64, 0x79, 0x7C, 0x78, 0xED, 0xE1, 0xEC, 0xF0, 0xE4, 0xF0, 0x6E, 0x7C, 0xED, -0xDD, 0xDB, 0xFE, 0x73, 0xED, 0xF0, 0xFF, 0xF9, 0xDE, 0xDC, 0x76, 0x6E, 0xFB, 0x7B, 0xFB, 0x6F, -0x6F, 0xEF, 0x7B, 0x6E, 0xF8, 0xE9, 0x7E, 0x5B, 0x5F, 0xF3, 0xFD, 0x67, 0x74, 0xEA, 0xEF, 0x77, -0x6D, 0x7C, 0xE8, 0xE2, 0xEE, 0xFB, 0xE6, 0xED, 0x66, 0x6C, 0x7B, 0x7C, 0xF4, 0xEF, 0xE2, 0xE6, -0x72, 0x70, 0xF0, 0xEE, 0x6E, 0x6B, 0xFB, 0xF5, 0xF6, 0x71, 0x6A, 0x6C, 0x65, 0x67, 0x5F, 0x5D, -0x6B, 0x62, 0x65, 0xFD, 0xED, 0xE9, 0xF2, 0xED, 0xE3, 0xE7, 0xE4, 0xE8, 0xED, 0xEF, 0x66, 0x5E, -0x79, 0x7E, 0x78, 0xF5, 0xFA, 0x79, 0x7A, 0xF5, 0xE7, 0xE2, 0xE4, 0xF2, 0xFF, 0x73, 0x66, 0x6B, -0x70, 0xFD, 0xEF, 0x6F, 0x67, 0x5F, 0x5C, 0x6B, 0x6E, 0x78, 0x77, 0x6D, 0xF1, 0xF4, 0xF8, 0xE5, -0xE9, 0xEB, 0xEC, 0xEF, 0xEF, 0xF0, 0xE7, 0xED, 0x6B, 0x6F, 0xF0, 0xFF, 0x6A, 0x6F, 0x7E, 0x6F, -0x69, 0xED, 0xDF, 0xFF, 0x7C, 0xEB, 0xF3, 0xF8, 0x7E, 0x7A, 0xFB, 0x6E, 0x5E, 0x60, 0x70, 0x7A, -0xFC, 0xF4, 0xFF, 0xEF, 0xF5, 0x72, 0xF1, 0xEC, 0xEA, 0xE1, 0xE9, 0xED, 0xF2, 0xFC, 0xE7, 0xF0, -0x68, 0x76, 0xEF, 0xF4, 0xF9, 0x77, 0x79, 0xFB, 0xFC, 0xF6, 0xEE, 0xE9, 0xF2, 0x6D, 0x70, 0x6F, -0x6F, 0xFE, 0x6A, 0x69, 0x7F, 0x6F, 0x6F, 0x79, 0x78, 0x77, 0x6E, 0xFE, 0xEE, 0xF0, 0xEF, 0x7E, -0xF4, 0xE9, 0xF8, 0xFD, 0x7C, 0x77, 0x7D, 0x78, 0x7D, 0xFE, 0x79, 0x72, 0x6E, 0x72, 0x7B, 0x73, -0x6B, 0x74, 0x76, 0x6C, 0x72, 0x70, 0x75, 0x6D, 0x5A, 0x5C, 0x6A, 0x77, 0xFE, 0x71, 0x7A, 0xF2, -0xE9, 0xE7, 0xEA, 0xDE, 0xE6, 0xF5, 0xEB, 0xF5, 0xEE, 0xEA, 0xF3, 0xEE, 0xF4, 0xEE, 0xF5, 0x73, -0xF4, 0xF6, 0x73, 0x7C, 0xEC, 0xE9, 0x72, 0x67, 0x6C, 0x70, 0x6E, 0x69, 0x6F, 0x68, 0x5D, 0x64, -0x71, 0x75, 0x6B, 0x6D, 0xF9, 0x79, 0x6F, 0xF4, 0xEA, 0xF5, 0x79, 0x7B, 0x7D, 0xFA, 0xF3, 0xF7, -0xF4, 0xF4, 0xF9, 0x7F, 0x77, 0x7F, 0xF5, 0xFD, 0x71, 0x71, 0x7B, 0x78, 0x7A, 0x73, 0x68, 0x71, -0x7A, 0x6B, 0x6C, 0x6E, 0x69, 0x6E, 0x71, 0x6C, 0x69, 0x6C, 0x7A, 0x7D, 0xF6, 0xEB, 0xF4, 0xF2, -0xF4, 0x78, 0xF8, 0xF1, 0xF6, 0xFE, 0x71, 0x75, 0x7C, 0x7B, 0x7D, 0x7E, 0xFB, 0x7E, 0x77, 0x76, -0xFF, 0xF7, 0x79, 0x70, 0x6E, 0x6C, 0x71, 0x6F, 0x6C, 0x6A, 0x70, 0x6E, 0x5F, 0x65, 0x6C, 0x66, -0x6D, 0x7A, 0xF1, 0x78, 0x6B, 0xED, 0xFB, 0x6C, 0x7C, 0x74, 0xF1, 0xEC, 0x76, 0xF9, 0xF8, 0x75, -0x71, 0x7A, 0xEC, 0xFA, 0x6C, 0x76, 0x7C, 0x7F, 0x6E, 0x6A, 0x76, 0x6C, 0x76, 0xF2, 0x7C, 0x76, -0x66, 0x62, 0x7D, 0xF9, 0x78, 0x69, 0x6A, 0xF8, 0x78, 0x6D, 0xFC, 0xF8, 0xF3, 0xF7, 0x7D, 0xEF, -0xF1, 0x7C, 0xF1, 0xE9, 0xEB, 0xEE, 0xF3, 0xFD, 0x73, 0x7D, 0xFA, 0x74, 0x78, 0x7A, 0x6E, 0x70, -0x76, 0x73, 0x6F, 0x6D, 0x6C, 0x68, 0x6D, 0x7D, 0x6E, 0x64, 0x6D, 0xFC, 0xFA, 0x71, 0x6F, 0xFF, -0x70, 0x70, 0xF0, 0xEE, 0xEF, 0xEB, 0xEC, 0xEC, 0xED, 0xF0, 0xEE, 0xE9, 0xEB, 0xF8, 0xFB, 0xED, -0xE9, 0xF7, 0xFF, 0xED, 0xEE, 0xEF, 0xF3, 0x6E, 0x70, 0xF3, 0xFF, 0x6F, 0x6F, 0x6F, 0x79, 0x7C, -0x79, 0x7E, 0x77, 0x6E, 0x6E, 0x7B, 0x7C, 0x6B, 0x72, 0xF6, 0xFF, 0x7D, 0x7D, 0x72, 0x78, 0xFB, -0xFD, 0xFB, 0xFA, 0x7D, 0x7A, 0x6D, 0x68, 0x74, 0x75, 0xF1, 0xE7, 0x7B, 0x76, 0x6B, 0x66, 0xFD, -0x73, 0x68, 0x6B, 0x73, 0x7C, 0x62, 0x64, 0x70, 0x64, 0x6D, 0x79, 0x70, 0x70, 0x74, 0xF8, 0x7C, -0x7C, 0xF8, 0x6B, 0x70, 0xF9, 0x7D, 0xF1, 0xF0, 0xFF, 0x7F, 0xF8, 0xED, 0xF2, 0xFC, 0xFF, 0x76, -0x7B, 0x7C, 0xFE, 0xFE, 0x6C, 0x7C, 0xED, 0x79, 0x77, 0x71, 0x69, 0x76, 0x7A, 0x76, 0x7A, 0x6F, -0x6E, 0x6E, 0x73, 0xFF, 0x78, 0x76, 0x7F, 0x7A, 0x6F, 0x78, 0xFE, 0x77, 0xFB, 0xEE, 0xEE, 0xF1, -0x7A, 0xFB, 0xEE, 0x75, 0x70, 0xFE, 0x7D, 0x72, 0x6D, 0x6F, 0x7B, 0xFB, 0xF9, 0x7C, 0x7E, 0x7A, -0x70, 0x76, 0x7B, 0xF7, 0xF5, 0x70, 0x74, 0xFF, 0x78, 0xFA, 0xFC, 0x79, 0x78, 0x6D, 0x7A, 0xFA, -0x77, 0xFC, 0xF4, 0xF1, 0xF1, 0xF7, 0xEB, 0xED, 0xFB, 0xF7, 0xEF, 0xF2, 0x78, 0x79, 0xF0, 0xF3, -0xFC, 0xFC, 0x7E, 0x77, 0xFF, 0xFC, 0x78, 0xF6, 0xF9, 0x6F, 0x7A, 0x78, 0x6F, 0xFF, 0xF9, 0x7E, -0x76, 0x72, 0x76, 0x78, 0x79, 0xFD, 0xFA, 0x7A, 0x7E, 0xF1, 0xFB, 0x7A, 0xF2, 0xEF, 0xFF, 0x74, -0x75, 0x7E, 0xFF, 0xF6, 0xE9, 0xF4, 0x71, 0x74, 0x74, 0x7C, 0xF8, 0x79, 0x75, 0x74, 0x73, 0xF9, -0xFE, 0xFF, 0xFA, 0x6A, 0x6C, 0xFE, 0x70, 0x72, 0x7C, 0x7D, 0x70, 0x67, 0x6F, 0x76, 0x7B, 0xF0, -0x7E, 0x6E, 0x6E, 0x76, 0xF1, 0xF2, 0x7A, 0x72, 0x7B, 0xFD, 0x79, 0x77, 0x6E, 0x6A, 0x6D, 0x6E, -0x74, 0x72, 0x77, 0xF5, 0x7C, 0x6D, 0x6C, 0x6D, 0x70, 0x76, 0xFD, 0xFC, 0xFF, 0xFE, 0xFE, 0xFA, -0x7D, 0x77, 0x74, 0x6F, 0xFB, 0xFA, 0x71, 0xFC, 0xF8, 0xFE, 0xEB, 0xE5, 0xEE, 0x7F, 0xF6, 0xED, -0xFA, 0x78, 0xF6, 0xF1, 0xF8, 0xF6, 0x79, 0x70, 0x7C, 0x75, 0x78, 0xF6, 0xFA, 0xFC, 0xFB, 0x7B, -0x7D, 0xF9, 0xF7, 0xF7, 0x7E, 0x6B, 0x68, 0xFA, 0xE6, 0xEE, 0x7B, 0x7B, 0x79, 0x7E, 0xFB, 0xF2, -0xEA, 0xEE, 0xF1, 0xF6, 0x79, 0xFB, 0xF0, 0xFB, 0xFF, 0xF0, 0xEE, 0xF4, 0xEF, 0xFB, 0x6F, 0x6C, -0x72, 0xFF, 0x71, 0x6C, 0x6A, 0x6D, 0xF4, 0xFB, 0x7C, 0xF3, 0xFA, 0xFC, 0x6F, 0x73, 0xFB, 0x72, -0x7D, 0x78, 0x76, 0xEF, 0xF3, 0x7C, 0x71, 0xFA, 0xF2, 0xFB, 0xEF, 0xF0, 0xEA, 0xFD, 0x6B, 0xED, -0xF2, 0x77, 0x6E, 0x6D, 0xFD, 0x64, 0xF3, 0xDF, 0x5C, 0x61, 0xED, 0xF2, 0x7E, 0x66, 0x73, 0x6E, -0x66, 0xFF, 0x6F, 0x72, 0x70, 0x66, 0xF3, 0xF7, 0x6F, 0x72, 0x75, 0xED, 0xEF, 0xF4, 0xED, 0xEF, -0xEF, 0x6E, 0x6F, 0xF7, 0x72, 0x7E, 0x78, 0x6F, 0xF9, 0x77, 0xFC, 0xF4, 0x6C, 0x66, 0x6A, 0x76, -0x65, 0x5C, 0x6D, 0xFF, 0xF8, 0xEA, 0xE2, 0xEF, 0x65, 0x70, 0xEB, 0xE8, 0xE2, 0xDF, 0xDA, 0xD9, -0xE3, 0xF0, 0xFA, 0xE6, 0xDD, 0xDF, 0xDF, 0xE0, 0xE4, 0xFC, 0x63, 0x60, 0x64, 0x63, 0x66, 0x78, -0x65, 0x57, 0x60, 0x67, 0x64, 0x67, 0x5F, 0x6E, 0xF3, 0x7F, 0x75, 0xFE, 0xEA, 0xF4, 0xF8, 0xE0, -0xE0, 0xE4, 0xE3, 0xE7, 0xEA, 0xFB, 0x6F, 0x6E, 0x75, 0x72, 0x68, 0x6E, 0x77, 0x74, 0x6D, 0x73, -0xF9, 0x74, 0xF2, 0xE2, 0xEF, 0xDE, 0xDD, 0x79, 0xFD, 0xF4, 0x6F, 0x6A, 0x6E, 0xFE, 0x7A, 0x68, -0x60, 0x63, 0x6B, 0x66, 0x67, 0x76, 0xFE, 0x78, 0x65, 0x63, 0x7A, 0xFF, 0x72, 0x72, 0x74, 0x7D, -0x7C, 0x6B, 0x72, 0xEF, 0xF6, 0x73, 0x74, 0x7C, 0x74, 0x68, 0x68, 0x73, 0xFA, 0xF6, 0x6F, 0x67, -0x6F, 0x6D, 0x6A, 0x69, 0x68, 0x74, 0x6D, 0x64, 0x6F, 0x75, 0x77, 0xFA, 0x7F, 0xF5, 0xEF, 0x78, -0x77, 0x7D, 0x7A, 0xFE, 0x77, 0x73, 0xF8, 0xF4, 0xFE, 0x6F, 0x71, 0xF7, 0x74, 0x79, 0xEF, 0x7B, -0xF9, 0xFA, 0x68, 0x71, 0x7F, 0x76, 0x73, 0x71, 0x7D, 0x7D, 0x65, 0x5D, 0x69, 0x6E, 0x5F, 0x67, -0x6F, 0x6D, 0xFF, 0x7F, 0x6E, 0x6F, 0x73, 0x77, 0xF2, 0xDE, 0xD4, 0xD0, 0xD0, 0xCF, 0xCE, 0xD0, -0xD2, 0xD6, 0xDA, 0xDB, 0xE7, 0x6D, 0x5B, 0x52, 0x4C, 0x47, 0x44, 0x43, 0x44, 0x47, 0x49, 0x4B, -0x4E, 0x52, 0x56, 0x5A, 0x5D, 0x64, 0x75, 0xE6, 0xCF, 0xC5, 0xBF, 0xBD, 0xBB, 0xB7, 0xB5, 0xB1, -0xAF, 0xB5, 0xC1, 0xDF, 0x51, 0x44, 0x3A, 0x33, 0x33, 0x37, 0x3D, 0x44, 0x48, 0x4D, 0x51, 0x54, -0x53, 0x4D, 0x49, 0x44, 0x43, 0x45, 0x46, 0x4C, 0x54, 0x65, 0xE4, 0xCF, 0xC4, 0xBB, 0xB4, 0xAF, -0xAD, 0xAC, 0xAA, 0xAB, 0xB5, 0xD1, 0x49, 0x3B, 0x35, 0x2F, 0x2D, 0x32, 0x3D, 0x4E, 0x57, 0x51, -0x4F, 0x50, 0x4C, 0x42, 0x3D, 0x3F, 0x46, 0x4A, 0x4F, 0x5E, 0xEC, 0xD9, 0xDA, 0xD2, 0xC8, 0xBE, -0xB7, 0xB0, 0xAD, 0xAB, 0xA9, 0xA8, 0xAD, 0xC4, 0x48, 0x36, 0x31, 0x2E, 0x2D, 0x30, 0x3E, 0x67, -0xE2, 0x63, 0x47, 0x43, 0x42, 0x39, 0x36, 0x3B, 0x46, 0x6B, 0xE1, 0xDB, 0xCC, 0xC8, 0xCC, 0xD7, -0xDD, 0xC6, 0xBA, 0xB2, 0xAC, 0xAA, 0xA7, 0xA7, 0xB0, 0x69, 0x32, 0x2D, 0x2D, 0x2C, 0x2D, 0x39, -0xF1, 0xC2, 0xCA, 0x5E, 0x3D, 0x38, 0x34, 0x2E, 0x2F, 0x3E, 0x69, 0xCC, 0xC3, 0xBD, 0xBD, 0xC2, -0xCD, 0xEC, 0xF4, 0xCD, 0xC0, 0xB7, 0xAC, 0xA7, 0xA4, 0xA4, 0xB7, 0x3A, 0x2A, 0x29, 0x2A, 0x2B, -0x30, 0x56, 0xBA, 0xB6, 0xCD, 0x4A, 0x33, 0x2C, 0x2C, 0x2B, 0x34, 0x65, 0xC3, 0xBB, 0xBB, 0xBC, -0xC1, 0xDA, 0x7F, 0x6A, 0x75, 0xD1, 0xC2, 0xB8, 0xAC, 0xA6, 0xA5, 0xA4, 0xB0, 0x35, 0x23, 0x25, -0x29, 0x2F, 0x38, 0x73, 0xB3, 0xAF, 0xC8, 0x3E, 0x2E, 0x29, 0x26, 0x2C, 0x3D, 0xDF, 0xB8, 0xB5, -0xBB, 0xC5, 0xE7, 0x5A, 0x53, 0x68, 0xD9, 0xC8, 0xBA, 0xB3, 0xAD, 0xA8, 0xA7, 0xA6, 0xAF, 0x34, -0x1F, 0x24, 0x2E, 0x3B, 0x48, 0xDA, 0xB3, 0xB0, 0xD6, 0x33, 0x29, 0x29, 0x29, 0x2F, 0x5B, 0xC3, -0xB9, 0xB8, 0xC1, 0xDB, 0x53, 0x46, 0x4E, 0xEE, 0xCB, 0xC5, 0xBF, 0xBA, 0xB6, 0xAE, 0xAA, 0xA8, -0xAA, 0xDB, 0x26, 0x20, 0x2B, 0x3E, 0x5E, 0xEE, 0xC1, 0xB6, 0xC1, 0x3F, 0x2A, 0x29, 0x2A, 0x2F, -0x4F, 0xCA, 0xC0, 0xBE, 0xC5, 0xDC, 0x51, 0x44, 0x4B, 0x7D, 0xCB, 0xC5, 0xC5, 0xC2, 0xBF, 0xBD, -0xB1, 0xA9, 0xA8, 0xAA, 0xCB, 0x28, 0x20, 0x2C, 0x44, 0x7E, 0xDE, 0xC8, 0xBB, 0xC6, 0x3F, 0x2B, -0x29, 0x2E, 0x35, 0x4C, 0xCB, 0xBF, 0xC3, 0xCA, 0xE6, 0x4E, 0x43, 0x44, 0x6A, 0xC8, 0xC3, 0xC3, -0xC8, 0xC8, 0xBE, 0xB5, 0xAB, 0xA7, 0xA8, 0xBC, 0x2D, 0x1F, 0x29, 0x42, 0xD7, 0xD0, 0xCD, 0xBF, -0xC5, 0x4C, 0x2E, 0x2B, 0x2F, 0x36, 0x4A, 0xD7, 0xBE, 0xBD, 0xD5, 0x74, 0x50, 0x42, 0x45, 0x53, -0xD1, 0xBE, 0xBE, 0xC5, 0xD2, 0xCD, 0xBC, 0xAE, 0xA7, 0xA7, 0xB5, 0x36, 0x21, 0x28, 0x41, 0xD1, -0xC9, 0xD4, 0xCB, 0xCB, 0x51, 0x31, 0x2B, 0x2F, 0x39, 0x47, 0xE9, 0xC5, 0xC0, 0xCD, 0xED, 0x50, -0x3F, 0x3F, 0x52, 0xCD, 0xBB, 0xBC, 0xC6, 0xDE, 0xE7, 0xCB, 0xB5, 0xA8, 0xA4, 0xA9, 0xCC, 0x28, -0x20, 0x2E, 0x6F, 0xC2, 0xCF, 0xF7, 0xDA, 0xEB, 0x3F, 0x2E, 0x2D, 0x34, 0x3E, 0x5D, 0xCD, 0xBF, -0xC7, 0x73, 0x53, 0x43, 0x3C, 0x49, 0xDD, 0xBC, 0xB7, 0xC2, 0xE4, 0x62, 0xEC, 0xBD, 0xAA, 0xA3, -0xA4, 0xB3, 0x32, 0x1F, 0x26, 0x42, 0xC3, 0xC0, 0xF2, 0x68, 0x73, 0x4D, 0x37, 0x2D, 0x2F, 0x39, -0x47, 0xDD, 0xC2, 0xBE, 0xD2, 0x4A, 0x3E, 0x3B, 0x42, 0xEB, 0xBE, 0xB5, 0xB9, 0xD5, 0x54, 0x54, -0xCB, 0xAD, 0xA3, 0xA2, 0xAC, 0x4D, 0x23, 0x21, 0x34, 0xCF, 0xBA, 0xD0, 0x5E, 0x73, 0x5D, 0x43, -0x34, 0x30, 0x38, 0x3C, 0x46, 0xCE, 0xB9, 0xBE, 0x5F, 0x3E, 0x3B, 0x3E, 0x62, 0xC0, 0xB5, 0xB6, -0xC9, 0x54, 0x48, 0xE3, 0xB1, 0xA4, 0xA0, 0xA6, 0xC3, 0x2B, 0x1E, 0x29, 0x5D, 0xB9, 0xBD, 0x72, -0x50, 0x5B, 0x50, 0x3C, 0x30, 0x30, 0x36, 0x3F, 0x7C, 0xC0, 0xBA, 0xD0, 0x45, 0x3A, 0x38, 0x46, -0xCB, 0xB7, 0xB5, 0xC4, 0x5A, 0x48, 0x62, 0xBA, 0xA8, 0xA1, 0xA3, 0xB0, 0x3C, 0x20, 0x20, 0x39, -0xBD, 0xB1, 0xC7, 0x4F, 0x4A, 0x4E, 0x48, 0x35, 0x2E, 0x31, 0x39, 0x56, 0xC0, 0xB8, 0xC2, 0x4D, -0x39, 0x37, 0x3E, 0xE2, 0xBC, 0xB6, 0xBB, 0xDC, 0x4B, 0x4A, 0xD3, 0xAE, 0xA3, 0xA0, 0xA8, 0xD5, -0x29, 0x1F, 0x2B, 0xE3, 0xB3, 0xBA, 0x65, 0x47, 0x4C, 0x4F, 0x3D, 0x2F, 0x2D, 0x30, 0x41, 0xCB, -0xB7, 0xBA, 0x76, 0x3D, 0x38, 0x39, 0x51, 0xC5, 0xB6, 0xB6, 0xCC, 0x50, 0x46, 0x7E, 0xB4, 0xA6, -0xA1, 0xA4, 0xB8, 0x35, 0x20, 0x25, 0x48, 0xB8, 0xB5, 0xDB, 0x47, 0x47, 0x52, 0x4A, 0x34, 0x2D, -0x2E, 0x39, 0xEC, 0xBA, 0xB6, 0xCF, 0x3F, 0x38, 0x37, 0x41, 0xD0, 0xB8, 0xB4, 0xBF, 0x6A, 0x4A, -0x5B, 0xBC, 0xA8, 0xA1, 0xA2, 0xAF, 0x3E, 0x22, 0x24, 0x3E, 0xBA, 0xB3, 0xD4, 0x45, 0x41, 0x4F, -0x52, 0x37, 0x2D, 0x2D, 0x36, 0x65, 0xBB, 0xB6, 0xC9, 0x46, 0x38, 0x35, 0x3D, 0xDC, 0xB7, 0xB0, -0xBA, 0xF0, 0x48, 0x4E, 0xC1, 0xAA, 0xA2, 0xA1, 0xAB, 0x5E, 0x27, 0x21, 0x32, 0xC7, 0xB4, 0xC8, -0x48, 0x3E, 0x4B, 0x58, 0x3D, 0x2E, 0x2C, 0x2F, 0x48, 0xBF, 0xB5, 0xBF, 0x4C, 0x36, 0x34, 0x3A, -0x67, 0xBC, 0xB2, 0xB7, 0xD6, 0x4C, 0x4A, 0xCE, 0xAD, 0xA3, 0xA0, 0xA7, 0xD8, 0x29, 0x20, 0x2F, -0xD2, 0xB5, 0xC4, 0x4C, 0x40, 0x4B, 0x64, 0x44, 0x2F, 0x2C, 0x2D, 0x3F, 0xC4, 0xB4, 0xB9, 0x5F, -0x39, 0x36, 0x39, 0x5D, 0xBE, 0xB3, 0xB4, 0xC8, 0x59, 0x4B, 0xDC, 0xAF, 0xA3, 0x9F, 0xA5, 0xC5, -0x2C, 0x21, 0x2C, 0xFB, 0xB9, 0xC1, 0x53, 0x42, 0x4A, 0x5F, 0x49, 0x31, 0x2C, 0x2C, 0x3A, 0xCF, -0xB6, 0xBA, 0xF7, 0x3E, 0x39, 0x3A, 0x4C, 0xCA, 0xB7, 0xB4, 0xBF, 0x79, 0x4D, 0xE5, 0xB1, 0xA4, -0x9F, 0xA4, 0xC6, 0x2B, 0x20, 0x2C, 0xEC, 0xB7, 0xC1, 0x57, 0x43, 0x49, 0x5C, 0x47, 0x31, 0x2C, -0x2C, 0x39, 0xD3, 0xB7, 0xBA, 0xDC, 0x46, 0x3C, 0x39, 0x47, 0xCE, 0xB9, 0xB5, 0xBD, 0xDE, 0x5E, -0xD3, 0xB0, 0xA4, 0xA0, 0xA6, 0xCF, 0x2A, 0x21, 0x2D, 0xF6, 0xBB, 0xC8, 0x55, 0x44, 0x48, 0x51, -0x3F, 0x2F, 0x2C, 0x2D, 0x3B, 0xD8, 0xBC, 0xBF, 0xE7, 0x4E, 0x45, 0x3C, 0x44, 0xEB, 0xBE, 0xB5, -0xBA, 0xCA, 0xE3, 0xC9, 0xAF, 0xA5, 0xA0, 0xA7, 0xE6, 0x28, 0x22, 0x2E, 0xEA, 0xBD, 0xC8, 0x5D, -0x46, 0x4A, 0x4D, 0x3B, 0x2F, 0x2D, 0x2F, 0x3F, 0xD0, 0xBE, 0xC3, 0xE6, 0x56, 0x4B, 0x43, 0x4C, -0xFA, 0xC8, 0xBB, 0xBB, 0xC3, 0xC8, 0xBD, 0xAE, 0xA7, 0xA3, 0xAA, 0x6C, 0x2A, 0x25, 0x30, 0x5A, -0xCD, 0xD3, 0x5F, 0x4D, 0x50, 0x4C, 0x3B, 0x2F, 0x2D, 0x2F, 0x3D, 0xE6, 0xCC, 0xD3, 0xDA, 0xDB, -0x79, 0x55, 0x56, 0x68, 0xE0, 0xCA, 0xC2, 0xC0, 0xBC, 0xB1, 0xAB, 0xA6, 0xA5, 0xAE, 0x53, 0x2C, -0x29, 0x30, 0x41, 0x59, 0x62, 0x53, 0x57, 0x7F, 0x5D, 0x40, 0x35, 0x2E, 0x2F, 0x3D, 0x58, 0x78, -0xE5, 0xCD, 0xC8, 0xCF, 0xDA, 0xEC, 0x7B, 0xE4, 0xD1, 0xCA, 0xC4, 0xBA, 0xB0, 0xAC, 0xAA, 0xAB, -0xBA, 0x4F, 0x39, 0x39, 0x3D, 0x3F, 0x42, 0x3D, 0x3C, 0x45, 0x51, 0x52, 0x4C, 0x42, 0x3B, 0x3E, -0x4A, 0x4C, 0x4D, 0x57, 0x69, 0xEE, 0xDE, 0xE4, 0xFD, 0xED, 0xDC, 0xD3, 0xCD, 0xCA, 0xC3, 0xBD, -0xB9, 0xB6, 0xB8, 0xC3, 0xCE, 0xC8, 0xC1, 0xC5, 0xCE, 0xF9, 0x4A, 0x3F, 0x3F, 0x41, 0x3F, 0x3D, -0x39, 0x38, 0x3B, 0x3C, 0x3A, 0x3C, 0x43, 0x4C, 0x52, 0x58, 0x5B, 0x59, 0x65, 0xDC, 0xCB, 0xC3, -0xBD, 0xB8, 0xB6, 0xB2, 0xAF, 0xB2, 0xB6, 0xB2, 0xB0, 0xB6, 0xBF, 0xD7, 0x4F, 0x40, 0x3F, 0x3D, -0x3A, 0x35, 0x2F, 0x2D, 0x2F, 0x32, 0x33, 0x34, 0x39, 0x3E, 0x46, 0x51, 0x59, 0x5C, 0x6F, 0xD8, -0xC6, 0xBD, 0xB8, 0xB4, 0xB2, 0xAF, 0xAC, 0xAD, 0xAF, 0xAE, 0xAE, 0xB2, 0xBC, 0xCF, 0x55, 0x42, -0x3E, 0x3B, 0x36, 0x31, 0x2D, 0x2A, 0x2B, 0x2F, 0x32, 0x33, 0x36, 0x3B, 0x40, 0x4A, 0x57, 0x69, -0xEE, 0xD6, 0xC8, 0xBF, 0xB9, 0xB3, 0xB1, 0xAF, 0xAC, 0xAB, 0xAE, 0xAF, 0xAF, 0xB1, 0xB9, 0xC6, -0x75, 0x46, 0x3D, 0x3A, 0x36, 0x30, 0x2D, 0x2B, 0x2A, 0x2D, 0x31, 0x34, 0x36, 0x39, 0x3E, 0x46, -0x56, 0x77, 0xE3, 0xD4, 0xCA, 0xC3, 0xBD, 0xB6, 0xB1, 0xAF, 0xAC, 0xAB, 0xAC, 0xAF, 0xAF, 0xB0, -0xB5, 0xBE, 0xDA, 0x4E, 0x3E, 0x3A, 0x36, 0x31, 0x2D, 0x2C, 0x2B, 0x2C, 0x2F, 0x32, 0x34, 0x38, -0x3D, 0x43, 0x4D, 0x66, 0xE7, 0xD6, 0xCB, 0xC5, 0xC0, 0xBA, 0xB3, 0xAF, 0xAD, 0xAB, 0xAC, 0xAE, -0xAF, 0xAF, 0xB3, 0xBB, 0xCD, 0x5A, 0x40, 0x3A, 0x36, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, 0x2F, 0x31, -0x32, 0x38, 0x3D, 0x41, 0x4B, 0x5C, 0xF8, 0xD8, 0xCA, 0xC3, 0xBF, 0xBA, 0xB4, 0xB0, 0xAD, 0xAB, -0xAB, 0xAE, 0xAF, 0xB0, 0xB3, 0xBA, 0xC9, 0x68, 0x46, 0x3C, 0x37, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, -0x2F, 0x30, 0x31, 0x36, 0x3C, 0x3F, 0x49, 0x58, 0x70, 0xDD, 0xCA, 0xC2, 0xBE, 0xB9, 0xB3, 0xB0, -0xAD, 0xAA, 0xAB, 0xAE, 0xAF, 0xAF, 0xB4, 0xBC, 0xCB, 0x61, 0x46, 0x3D, 0x36, 0x30, 0x2E, 0x2C, -0x2B, 0x2D, 0x2F, 0x2F, 0x31, 0x37, 0x3B, 0x3F, 0x4B, 0x5C, 0xFF, 0xD8, 0xC8, 0xC1, 0xBC, 0xB6, -0xB2, 0xAF, 0xAC, 0xAA, 0xAB, 0xAD, 0xAE, 0xAF, 0xB5, 0xBD, 0xCF, 0x5C, 0x45, 0x3C, 0x35, 0x2F, -0x2D, 0x2C, 0x2C, 0x2D, 0x2F, 0x2F, 0x32, 0x37, 0x3B, 0x3F, 0x4B, 0x5F, 0xEE, 0xD4, 0xC8, 0xC1, -0xBC, 0xB5, 0xB0, 0xAE, 0xAB, 0xAA, 0xAB, 0xAD, 0xAF, 0xB1, 0xB7, 0xC0, 0xD9, 0x53, 0x42, 0x3B, -0x34, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x30, 0x33, 0x37, 0x3C, 0x43, 0x4D, 0x5E, 0xEC, 0xD0, -0xC7, 0xC0, 0xBB, 0xB6, 0xB0, 0xAE, 0xAB, 0xAA, 0xAC, 0xAE, 0xAF, 0xB3, 0xB9, 0xC5, 0xE2, 0x4E, -0x3F, 0x39, 0x32, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x2F, 0x33, 0x39, 0x3D, 0x44, 0x4F, 0x65, -0xE3, 0xCE, 0xC5, 0xBF, 0xBA, 0xB4, 0xAF, 0xAD, 0xAA, 0xAA, 0xAC, 0xAE, 0xB0, 0xB5, 0xBB, 0xC8, -0xF8, 0x4C, 0x3E, 0x38, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, 0x2E, 0x2F, 0x31, 0x35, 0x39, 0x3E, 0x4A, -0x5C, 0xF9, 0xD8, 0xCB, 0xC2, 0xBC, 0xB7, 0xB2, 0xAE, 0xAB, 0xA9, 0xAA, 0xAC, 0xAE, 0xB2, 0xB8, -0xBE, 0xCE, 0x72, 0x48, 0x3B, 0x34, 0x2F, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x31, 0x36, 0x3A, -0x3E, 0x4A, 0x5F, 0xEA, 0xD0, 0xC9, 0xC1, 0xBB, 0xB5, 0xB0, 0xAE, 0xAB, 0xA9, 0xAB, 0xAC, 0xAE, -0xB4, 0xBB, 0xC4, 0xD6, 0x60, 0x45, 0x39, 0x30, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x32, -0x35, 0x3A, 0x43, 0x51, 0x6A, 0xDF, 0xCB, 0xC3, 0xBD, 0xB8, 0xB2, 0xAE, 0xAC, 0xAA, 0xAA, 0xAB, -0xAC, 0xAF, 0xB7, 0xBD, 0xCC, 0xF1, 0x51, 0x3F, 0x36, 0x2F, 0x2D, 0x2B, 0x2A, 0x2C, 0x2D, 0x2E, -0x2F, 0x33, 0x37, 0x3B, 0x45, 0x58, 0x77, 0xD5, 0xC8, 0xC0, 0xBB, 0xB6, 0xB1, 0xAE, 0xAB, 0xA9, -0xAA, 0xAB, 0xAC, 0xB1, 0xB9, 0xC0, 0xD3, 0x6A, 0x4A, 0x3C, 0x33, 0x2E, 0x2D, 0x2B, 0x2B, 0x2C, -0x2D, 0x2E, 0x31, 0x34, 0x38, 0x3F, 0x4C, 0x5D, 0xEA, 0xCE, 0xC6, 0xBE, 0xB8, 0xB4, 0xAF, 0xAD, -0xAB, 0xAA, 0xAA, 0xAB, 0xAD, 0xB2, 0xB9, 0xC3, 0xD8, 0x61, 0x47, 0x3A, 0x32, 0x2E, 0x2C, 0x2B, -0x2C, 0x2C, 0x2D, 0x2F, 0x31, 0x34, 0x38, 0x3F, 0x4D, 0x62, 0xDD, 0xCC, 0xC3, 0xBC, 0xB7, 0xB2, -0xAE, 0xAC, 0xAA, 0xAA, 0xAA, 0xAB, 0xAE, 0xB3, 0xBA, 0xC6, 0xE1, 0x55, 0x41, 0x37, 0x30, 0x2D, -0x2B, 0x2A, 0x2B, 0x2C, 0x2D, 0x2F, 0x31, 0x34, 0x39, 0x40, 0x4D, 0x6A, 0xD8, 0xC9, 0xC1, 0xBC, -0xB7, 0xB2, 0xAE, 0xAC, 0xAA, 0xAA, 0xAB, 0xAC, 0xAF, 0xB7, 0xBB, 0xC6, 0x79, 0x55, 0x44, 0x37, -0x30, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2D, 0x2F, 0x33, 0x35, 0x39, 0x42, 0x51, 0x6C, 0xDA, 0xCA, -0xC4, 0xBE, 0xBA, 0xB6, 0xB0, 0xAD, 0xAC, 0xAC, 0xAC, 0xAD, 0xAF, 0xB4, 0xB9, 0xC0, 0xD0, 0x65, -0x47, 0x3A, 0x32, 0x2F, 0x2C, 0x2B, 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x36, 0x3A, 0x3F, 0x4A, 0x5E, -0xDC, 0xCC, 0xC4, 0xBE, 0xBA, 0xB6, 0xB2, 0xAF, 0xAE, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB8, 0xBE, -0xCA, 0xE6, 0x4F, 0x3F, 0x38, 0x31, 0x2E, 0x2C, 0x2C, 0x2C, 0x2D, 0x2F, 0x31, 0x35, 0x3A, 0x3F, -0x4B, 0x64, 0xDD, 0xCB, 0xC3, 0xBD, 0xBA, 0xB7, 0xB4, 0xB1, 0xAF, 0xAE, 0xAE, 0xB0, 0xB3, 0xB5, -0xB9, 0xBE, 0xC6, 0xD3, 0x74, 0x4E, 0x40, 0x3A, 0x35, 0x32, 0x30, 0x2F, 0x2F, 0x30, 0x33, 0x36, -0x3A, 0x3F, 0x48, 0x52, 0x6C, 0xDF, 0xCE, 0xC7, 0xC1, 0xBE, 0xBB, 0xB9, 0xB8, 0xB7, 0xB6, 0xB6, -0xB7, 0xB9, 0xBB, 0xBE, 0xC4, 0xCA, 0xD9, 0x6C, 0x50, 0x45, 0x3D, 0x3A, 0x37, 0x35, 0x35, 0x35, -0x36, 0x37, 0x39, 0x3C, 0x3F, 0x46, 0x4F, 0x5E, 0xF1, 0xD9, 0xCF, 0xCC, 0xC9, 0xC5, 0xC1, 0xBE, -0xBC, 0xBC, 0xBC, 0xBD, 0xBF, 0xC2, 0xC4, 0xC7, 0xCC, 0xD5, 0xE8, 0x64, 0x52, 0x4A, 0x45, 0x41, -0x3F, 0x3E, 0x3D, 0x3D, 0x3E, 0x41, 0x45, 0x49, 0x4D, 0x53, 0x5C, 0x71, 0xE9, 0xDD, 0xD6, 0xD1, -0xCE, 0xCB, 0xC9, 0xC8, 0xC8, 0xC7, 0xC7, 0xC8, 0xC9, 0xCC, 0xCF, 0xD4, 0xDA, 0xE4, 0xF7, 0x69, -0x5B, 0x53, 0x4F, 0x4E, 0x4D, 0x4D, 0x4D, 0x4E, 0x51, 0x58, 0x5F, 0x68, 0x6F, 0x77, 0xFC, 0xEE, -0xE8, 0xE5, 0xE1, 0xDD, 0xDE, 0xDE, 0xDE, 0xE2, 0xE6, 0xE6, 0xEB, 0xF0, 0xED, 0xEA, 0xEC, 0xEE, -0xF8, 0x6A, 0x5C, 0x57, 0x55, 0x56, 0x58, 0x59, 0x58, 0x58, 0x5B, 0x5E, 0x63, 0x71, 0xF7, 0xEE, -0xE9, 0xE3, 0xE4, 0xE8, 0xE7, 0xEA, 0xEE, 0xEE, 0xF2, 0xFB, 0xFF, 0x7B, 0x74, 0x6E, 0x6B, 0x65, -0x60, 0x65, 0x67, 0x61, 0x60, 0x61, 0x5E, 0x5E, 0x62, 0x69, 0x70, 0x7F, 0xF6, 0xF2, 0xEC, 0xE7, -0xE6, 0xE3, 0xDF, 0xDE, 0xDE, 0xDD, 0xDE, 0xE0, 0xE5, 0xEC, 0xF6, 0x7F, 0x78, 0x75, 0x70, 0x6B, -0x64, 0x5E, 0x5A, 0x58, 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5E, 0x61, 0x67, 0x6C, 0x75, 0xF8, 0xEC, -0xE6, 0xE0, 0xDD, 0xDD, 0xDE, 0xDF, 0xE0, 0xE2, 0xE2, 0xE4, 0xE6, 0xE9, 0xEE, 0xF9, 0x7D, 0x75, -0x6E, 0x6A, 0x65, 0x61, 0x5E, 0x5C, 0x5B, 0x5C, 0x5D, 0x5E, 0x60, 0x63, 0x66, 0x6C, 0x76, 0xFA, -0xEE, 0xE9, 0xE4, 0xE1, 0xDF, 0xDD, 0xDE, 0xDF, 0xE2, 0xE6, 0xEA, 0xEE, 0xF4, 0xFA, 0x7E, 0x7A, -0x75, 0x72, 0x74, 0x74, 0x71, 0x70, 0x6D, 0x6A, 0x6A, 0x6B, 0x6D, 0x70, 0x74, 0x78, 0x7A, 0x7D, -0xFA, 0xF0, 0xEA, 0xE5, 0xE3, 0xE2, 0xE0, 0xDF, 0xE1, 0xE3, 0xE4, 0xE8, 0xEB, 0xEE, 0xF4, 0xFB, -0x7E, 0x75, 0x6D, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x65, 0x64, 0x63, 0x64, 0x66, 0x69, 0x6D, 0x72, -0x77, 0x7B, 0xFE, 0xF7, 0xF0, 0xEB, 0xE8, 0xE7, 0xE6, 0xE6, 0xE6, 0xE7, 0xE7, 0xE8, 0xEA, 0xED, -0xF3, 0xFC, 0x79, 0x72, 0x6F, 0x6C, 0x6B, 0x6B, 0x69, 0x66, 0x64, 0x63, 0x62, 0x63, 0x67, 0x6C, -0x73, 0x7C, 0xFE, 0xFD, 0xFA, 0xF4, 0xEE, 0xEA, 0xE5, 0xE1, 0xE1, 0xE2, 0xE5, 0xE9, 0xED, 0xEF, -0xF1, 0xF2, 0xF4, 0xF8, 0xFF, 0x76, 0x6E, 0x6A, 0x68, 0x67, 0x66, 0x65, 0x64, 0x62, 0x61, 0x61, -0x63, 0x67, 0x6B, 0x72, 0x7E, 0xFA, 0xF5, 0xF1, 0xEE, 0xED, 0xEC, 0xE9, 0xE8, 0xE7, 0xE7, 0xE9, -0xEC, 0xF0, 0xF9, 0x7D, 0x77, 0x73, 0x70, 0x6F, 0x6E, 0x6C, 0x69, 0x67, 0x65, 0x66, 0x66, 0x68, -0x69, 0x69, 0x6A, 0x6C, 0x6E, 0x75, 0x7F, 0xF8, 0xF1, 0xED, 0xEB, 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, -0xEA, 0xE9, 0xEA, 0xEC, 0xEF, 0xF4, 0xFB, 0x7D, 0x77, 0x73, 0x71, 0x6F, 0x6D, 0x6B, 0x69, 0x67, -0x66, 0x67, 0x68, 0x69, 0x6B, 0x6D, 0x6F, 0x74, 0x79, 0x7F, 0xF9, 0xF3, 0xEF, 0xEE, 0xEE, 0xEE, -0xEE, 0xED, 0xED, 0xED, 0xEE, 0xEC, 0xEC, 0xF1, 0xF3, 0xF6, 0xFD, 0xFF, 0x7D, 0x78, 0x78, 0x76, -0x70, 0x6F, 0x6E, 0x6D, 0x6D, 0x6E, 0x6F, 0x71, 0x73, 0x77, 0x7B, 0x7D, 0xFF, 0xFB, 0xF8, 0xF8, -0xFA, 0xFB, 0xFE, 0x7E, 0x7D, 0x7A, 0x79, 0x7A, 0x76, 0x76, 0x76, 0x72, 0x70, 0x6F, 0x6D, 0x6E, -0x6D, 0x6B, 0x6E, 0x65, 0x66, 0x57, 0x41, 0x59, 0xC7, 0x62, 0x57, 0xCD, 0x64, 0x6B, 0xCC, 0x6D, -0xF6, 0xD1, 0x69, 0x6E, 0xDA, 0x7D, 0x61, 0xEE, 0xF1, 0xFD, 0xFF, 0x6E, 0xE7, 0x74, 0x66, 0xE9, -0x6A, 0xFC, 0xF2, 0x64, 0xEE, 0x6F, 0x6B, 0x7B, 0x69, 0xF2, 0x68, 0x74, 0xEC, 0x5F, 0xED, 0xFC, -0x5F, 0xDE, 0x72, 0x65, 0xDC, 0x51, 0x4C, 0xE8, 0x5F, 0xEF, 0xD7, 0x4E, 0xF3, 0xF9, 0x52, 0xC3, -0xE2, 0x56, 0xC9, 0x5B, 0x59, 0xE4, 0x50, 0x53, 0x47, 0x66, 0xF9, 0x47, 0xC9, 0xCB, 0x59, 0xD4, -0x55, 0x58, 0xD3, 0x5C, 0xF9, 0xCE, 0xD7, 0x6D, 0x61, 0xDB, 0xE4, 0xE8, 0x70, 0x79, 0xCD, 0x6B, -0x5D, 0xEC, 0x66, 0xDC, 0x6C, 0x5F, 0xD3, 0xF9, 0xFB, 0x66, 0x55, 0xDE, 0xFB, 0x64, 0xD7, 0xDA, -0xF1, 0xF1, 0xF1, 0xE5, 0xDB, 0xF4, 0x75, 0xDF, 0xE7, 0xFD, 0x79, 0xEC, 0xD9, 0xF0, 0x6E, 0xF5, -0xE4, 0xE5, 0x64, 0x74, 0xDF, 0x7D, 0x68, 0x75, 0xF0, 0xFD, 0x7B, 0xFC, 0x7B, 0xDE, 0xEF, 0x64, -0xDF, 0xE8, 0xFF, 0xE9, 0xFF, 0xE2, 0xE1, 0x76, 0xF6, 0xEF, 0xEC, 0xF9, 0x6D, 0x7C, 0x73, 0x6D, -0x69, 0x67, 0x76, 0x75, 0x73, 0x64, 0x66, 0xFD, 0x60, 0x5F, 0x77, 0x67, 0x70, 0x74, 0x60, 0x78, -0x7A, 0x5C, 0x67, 0x79, 0x6C, 0x77, 0x63, 0x63, 0xEF, 0x6C, 0x66, 0x73, 0x6D, 0xF8, 0x72, 0x74, -0xE6, 0xFB, 0x7B, 0xF3, 0xF6, 0xF1, 0xFE, 0x7B, 0xF5, 0xF1, 0x6D, 0x63, 0x75, 0x6E, 0x60, 0x64, -0x67, 0x67, 0x68, 0x67, 0x67, 0x6C, 0x64, 0x5B, 0x65, 0x6E, 0x69, 0x72, 0x76, 0x74, 0xFE, 0xFD, -0xFF, 0xF6, 0xF3, 0x7C, 0x7A, 0xFC, 0xFE, 0xFB, 0x7E, 0x75, 0xF5, 0xEE, 0xFC, 0xF7, 0xF3, 0xFF, -0xFE, 0x74, 0x6B, 0x6F, 0x6D, 0x6A, 0x6C, 0x6A, 0x7A, 0xF9, 0x71, 0x7C, 0xF5, 0x7C, 0x7B, 0x7F, -0xFE, 0x72, 0x6E, 0xFF, 0x6F, 0x66, 0x6B, 0x6A, 0x6E, 0x76, 0x71, 0x7C, 0x7A, 0x6E, 0x6C, 0x69, -0x6C, 0x6D, 0x63, 0x65, 0x6A, 0x66, 0x63, 0x65, 0x6C, 0x68, 0x64, 0x69, 0x6A, 0x6E, 0x79, 0x7B, -0x78, 0x6D, 0x6E, 0x79, 0x77, 0xFA, 0xED, 0xEF, 0xEF, 0xEC, 0xE8, 0xEF, 0xFB, 0xF6, 0xEF, 0xEE, -0xF7, 0xF9, 0xF3, 0xF7, 0xF1, 0xF3, 0xFD, 0xFD, 0x7A, 0x7B, 0xFE, 0x79, 0x7C, 0x7B, 0x6E, 0x72, -0x7A, 0x72, 0x71, 0x79, 0x79, 0x6F, 0x6F, 0x78, 0x74, 0x72, 0x7B, 0x72, 0x78, 0xF6, 0xF7, 0xF9, -0x78, 0x79, 0xEE, 0xF5, 0x74, 0x76, 0x7A, 0xFE, 0x7E, 0x75, 0x7A, 0x7E, 0x74, 0x70, 0x7D, 0xF8, -0xF8, 0x7D, 0x77, 0xF8, 0xF0, 0x7F, 0x7E, 0xF2, 0xED, 0xF0, 0xF4, 0xEB, 0xE9, 0xFE, 0x74, 0xEF, -0xE1, 0xE0, 0xDC, 0xD9, 0xD7, 0xD3, 0xD7, 0xDD, 0xD9, 0xD9, 0xDF, 0xE6, 0xEB, 0xF2, 0x78, 0x65, -0x61, 0x65, 0x5F, 0x5A, 0x5B, 0x5B, 0x5A, 0x5C, 0x5B, 0x5D, 0x5E, 0x5C, 0x5B, 0x5B, 0x5B, 0x5C, -0x5E, 0x6B, 0xEA, 0xD9, 0xD2, 0xD1, 0xCD, 0xC8, 0xC6, 0xC5, 0xC5, 0xC3, 0xC3, 0xC6, 0xCA, 0xD2, -0xE8, 0x67, 0x51, 0x49, 0x42, 0x3D, 0x3D, 0x3E, 0x3F, 0x41, 0x44, 0x49, 0x4E, 0x50, 0x55, 0x5A, -0x5F, 0x6F, 0xEF, 0xDA, 0xCD, 0xCA, 0xC8, 0xC4, 0xBF, 0xBD, 0xBB, 0xB9, 0xB7, 0xB6, 0xBA, 0xC2, -0xCC, 0xE2, 0x56, 0x43, 0x3B, 0x39, 0x37, 0x36, 0x37, 0x3B, 0x3E, 0x42, 0x47, 0x4B, 0x51, 0x5A, -0x5B, 0x5E, 0x67, 0x7A, 0xED, 0xE8, 0xDB, 0xCF, 0xCB, 0xC5, 0xBD, 0xB9, 0xB6, 0xB2, 0xB0, 0xB4, -0xB9, 0xBF, 0xCD, 0xFC, 0x49, 0x3B, 0x37, 0x33, 0x31, 0x32, 0x33, 0x38, 0x3E, 0x45, 0x4F, 0x5F, -0x74, 0xF0, 0xEF, 0xF1, 0xF4, 0xFF, 0x77, 0x72, 0xFB, 0xE4, 0xD9, 0xCE, 0xC3, 0xBA, 0xB6, 0xB2, -0xB0, 0xB2, 0xB6, 0xBB, 0xC8, 0xE4, 0x51, 0x3E, 0x38, 0x33, 0x2F, 0x2F, 0x31, 0x35, 0x3A, 0x3E, -0x49, 0x5D, 0xFE, 0xE4, 0xDD, 0xD9, 0xD9, 0xE1, 0xEB, 0xEE, 0xEE, 0xE7, 0xDD, 0xD2, 0xC7, 0xBD, -0xB9, 0xB5, 0xB2, 0xB5, 0xB8, 0xBB, 0xC6, 0xDA, 0x5F, 0x45, 0x3D, 0x37, 0x33, 0x31, 0x31, 0x35, -0x39, 0x3D, 0x45, 0x53, 0x6F, 0xE3, 0xD9, 0xD0, 0xCF, 0xD2, 0xD5, 0xD9, 0xD9, 0xD8, 0xD4, 0xCE, -0xC8, 0xC0, 0xBD, 0xB9, 0xB8, 0xBB, 0xBD, 0xC1, 0xCD, 0xDF, 0x5F, 0x4A, 0x41, 0x3B, 0x37, 0x36, -0x35, 0x36, 0x3A, 0x3D, 0x44, 0x4E, 0x5F, 0xEC, 0xDB, 0xD6, 0xD2, 0xD4, 0xD6, 0xDA, 0xDD, 0xDB, -0xD8, 0xD2, 0xCD, 0xC9, 0xC3, 0xBF, 0xBE, 0xBF, 0xC3, 0xC4, 0xCA, 0xD6, 0xED, 0x5E, 0x50, 0x48, -0x3F, 0x3C, 0x3B, 0x3A, 0x3A, 0x3D, 0x40, 0x4A, 0x55, 0x6A, 0xE6, 0xDC, 0xD8, 0xD6, 0xD8, 0xD8, -0xDB, 0xDE, 0xDF, 0xE2, 0xDE, 0xDC, 0xD9, 0xD0, 0xCB, 0xC8, 0xC8, 0xCC, 0xCD, 0xCD, 0xD1, 0xDB, -0xF2, 0x67, 0x5B, 0x51, 0x49, 0x44, 0x42, 0x41, 0x42, 0x44, 0x49, 0x4E, 0x55, 0x5C, 0x6A, 0x7E, -0xF3, 0xED, 0xED, 0xEF, 0xEC, 0xED, 0xF4, 0xF7, 0xF0, 0xEB, 0xE4, 0xDF, 0xDA, 0xD2, 0xCD, 0xCC, -0xCC, 0xCF, 0xCF, 0xCE, 0xD3, 0xDB, 0xE7, 0x7C, 0x69, 0x5E, 0x54, 0x4F, 0x4E, 0x4D, 0x4E, 0x4F, -0x52, 0x58, 0x5B, 0x5E, 0x63, 0x67, 0x6B, 0x6B, 0x6A, 0x6B, 0x6C, 0x6E, 0x6F, 0x73, 0x7D, 0xF3, -0xEA, 0xE1, 0xDC, 0xD8, 0xD3, 0xD1, 0xCF, 0xCE, 0xD1, 0xD2, 0xD2, 0xD6, 0xDB, 0xE2, 0xEF, 0xFD, -0x73, 0x66, 0x5F, 0x5C, 0x5A, 0x59, 0x58, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x5A, 0x5C, 0x5D, -0x61, 0x65, 0x6A, 0x74, 0x7E, 0xF4, 0xEA, 0xE2, 0xDD, 0xDA, 0xD7, 0xD5, 0xD2, 0xD1, 0xD0, 0xD1, -0xD3, 0xD3, 0xD4, 0xD7, 0xDB, 0xE0, 0xE8, 0xEF, 0x7B, 0x69, 0x5F, 0x5B, 0x57, 0x53, 0x50, 0x4F, -0x4F, 0x4F, 0x4F, 0x50, 0x52, 0x56, 0x59, 0x5C, 0x60, 0x68, 0x6E, 0x7A, 0xFB, 0xF1, 0xEB, 0xE7, -0xE2, 0xDE, 0xDC, 0xDA, 0xD7, 0xD5, 0xD3, 0xD3, 0xD3, 0xD5, 0xD5, 0xD8, 0xDC, 0xE4, 0xF2, 0x78, -0x6A, 0x5E, 0x59, 0x55, 0x52, 0x50, 0x4F, 0x4F, 0x50, 0x52, 0x55, 0x58, 0x5A, 0x5D, 0x61, 0x64, -0x69, 0x6E, 0x74, 0xFF, 0xF6, 0xEE, 0xE9, 0xE4, 0xDF, 0xDC, 0xD8, 0xD5, 0xD2, 0xD0, 0xD1, 0xD1, -0xD2, 0xD6, 0xD7, 0xDA, 0xDF, 0xE8, 0xF8, 0x71, 0x69, 0x60, 0x5C, 0x58, 0x56, 0x54, 0x53, 0x53, -0x53, 0x55, 0x56, 0x58, 0x5A, 0x5C, 0x5F, 0x63, 0x69, 0x71, 0xFF, 0xEF, 0xEA, 0xE6, 0xE1, 0xDF, -0xDE, 0xDB, 0xDA, 0xDA, 0xD7, 0xD4, 0xD1, 0xD1, 0xD2, 0xD4, 0xD7, 0xD8, 0xDB, 0xE1, 0xED, 0x78, -0x69, 0x61, 0x5A, 0x53, 0x50, 0x4F, 0x4E, 0x4F, 0x4F, 0x51, 0x55, 0x59, 0x5D, 0x60, 0x65, 0x6C, -0x6F, 0x76, 0x7E, 0xFC, 0xF5, 0xF2, 0xF2, 0xED, 0xE7, 0xE1, 0xDD, 0xD9, 0xD4, 0xCE, 0xCB, 0xCA, -0xC8, 0xCA, 0xCF, 0xD0, 0xD7, 0xE6, 0x7C, 0x5E, 0x53, 0x4F, 0x4C, 0x4A, 0x4A, 0x4A, 0x4C, 0x4E, -0x4F, 0x51, 0x57, 0x5D, 0x62, 0x66, 0x69, 0x6D, 0x6D, 0x67, 0x63, 0x65, 0x6B, 0x70, 0x75, 0xFE, -0xEA, 0xDC, 0xD3, 0xCE, 0xC9, 0xC2, 0xBE, 0xBC, 0xBC, 0xC1, 0xC8, 0xCB, 0xDC, 0x69, 0x50, 0x46, -0x42, 0x3F, 0x3D, 0x3D, 0x3F, 0x43, 0x4B, 0x4F, 0x55, 0x61, 0x6F, 0xFC, 0xF0, 0xFA, 0xFD, 0x7B, -0x63, 0x5A, 0x54, 0x52, 0x54, 0x58, 0x62, 0x7D, 0xDE, 0xCC, 0xC4, 0xBC, 0xB6, 0xB1, 0xAE, 0xB2, -0xBA, 0xC1, 0xDA, 0x5A, 0x45, 0x38, 0x33, 0x32, 0x33, 0x36, 0x3A, 0x3E, 0x4B, 0x66, 0xEA, 0xD6, -0xCE, 0xCF, 0xD3, 0xE0, 0x6E, 0x5C, 0x51, 0x4D, 0x4B, 0x4A, 0x4F, 0x5B, 0x7A, 0xD6, 0xC6, 0xBA, -0xB1, 0xAE, 0xAA, 0xAA, 0xAF, 0xBA, 0xD1, 0x4E, 0x3D, 0x31, 0x2B, 0x2B, 0x2C, 0x30, 0x38, 0x3E, -0x4E, 0xEA, 0xCD, 0xC7, 0xC8, 0xCB, 0xCE, 0xDD, 0x64, 0x4F, 0x48, 0x48, 0x47, 0x46, 0x4D, 0x62, -0xDD, 0xCA, 0xBD, 0xB1, 0xAC, 0xA9, 0xA7, 0xAA, 0xB2, 0xC4, 0x51, 0x3A, 0x2F, 0x29, 0x28, 0x2A, -0x2E, 0x39, 0x45, 0x5A, 0xDB, 0xC8, 0xC2, 0xC5, 0xCD, 0xD5, 0xE8, 0x5B, 0x4C, 0x46, 0x47, 0x4C, -0x4E, 0x59, 0xF3, 0xD3, 0xC6, 0xBE, 0xB5, 0xAD, 0xAA, 0xA6, 0xA8, 0xB2, 0xC5, 0x54, 0x38, 0x2F, -0x28, 0x26, 0x2A, 0x2F, 0x3A, 0x4B, 0x73, 0xCF, 0xC5, 0xC4, 0xC9, 0xD9, 0xF8, 0x5F, 0x4C, 0x47, -0x47, 0x48, 0x4F, 0x5A, 0x74, 0xD9, 0xCE, 0xC7, 0xBF, 0xBA, 0xB0, 0xAC, 0xAA, 0xA9, 0xB0, 0xC5, -0x5C, 0x3B, 0x30, 0x2B, 0x27, 0x29, 0x2E, 0x39, 0x49, 0x6C, 0xD2, 0xC7, 0xC5, 0xCA, 0xDA, 0x7A, -0x5E, 0x4D, 0x48, 0x49, 0x4B, 0x52, 0x5E, 0x70, 0xDC, 0xCE, 0xC9, 0xC4, 0xBE, 0xB5, 0xAE, 0xAC, -0xAA, 0xAD, 0xBB, 0xE1, 0x43, 0x35, 0x2E, 0x29, 0x28, 0x2B, 0x32, 0x3D, 0x4E, 0x7E, 0xD2, 0xC9, -0xC7, 0xCC, 0xDF, 0xFE, 0x61, 0x4F, 0x4C, 0x4B, 0x4C, 0x54, 0x5D, 0x72, 0xDA, 0xCE, 0xC7, 0xC0, -0xB9, 0xB0, 0xAD, 0xAA, 0xAA, 0xB1, 0xC5, 0x5D, 0x3D, 0x33, 0x2C, 0x29, 0x29, 0x2D, 0x35, 0x3F, -0x4F, 0x78, 0xD7, 0xCA, 0xC7, 0xCD, 0xD9, 0xE3, 0x71, 0x5C, 0x54, 0x4D, 0x4E, 0x55, 0x5A, 0x6E, -0xE3, 0xD3, 0xC8, 0xBE, 0xB6, 0xAF, 0xAC, 0xAA, 0xAC, 0xB7, 0xCE, 0x53, 0x3D, 0x34, 0x2D, 0x2A, -0x2A, 0x2E, 0x35, 0x3E, 0x4A, 0x5C, 0xE5, 0xCD, 0xC8, 0xCB, 0xCE, 0xD5, 0xE2, 0xF7, 0x66, 0x57, -0x54, 0x56, 0x5B, 0x6E, 0xE7, 0xD5, 0xC9, 0xBE, 0xB6, 0xB1, 0xAE, 0xAE, 0xB4, 0xBE, 0xD3, 0x5C, -0x46, 0x3C, 0x34, 0x30, 0x2F, 0x32, 0x38, 0x3E, 0x45, 0x4E, 0x69, 0xDC, 0xCF, 0xCD, 0xCF, 0xD3, -0xD9, 0xDF, 0xEF, 0x6F, 0x68, 0x67, 0x6F, 0xF7, 0xE7, 0xDC, 0xD2, 0xC8, 0xC1, 0xBE, 0xBC, 0xBD, -0xC3, 0xCB, 0xD5, 0xEA, 0x6A, 0x58, 0x4D, 0x47, 0x43, 0x43, 0x44, 0x47, 0x4A, 0x4D, 0x52, 0x5D, -0x6D, 0x78, 0x77, 0x78, 0x76, 0x73, 0x75, 0x72, 0x72, 0x78, 0x7E, 0xF6, 0xEB, 0xE3, 0xDC, 0xD6, -0xD2, 0xCF, 0xCE, 0xCE, 0xCD, 0xCF, 0xD2, 0xD4, 0xD7, 0xDA, 0xDD, 0xE3, 0xEF, 0x7A, 0x6C, 0x65, -0x5F, 0x5B, 0x57, 0x53, 0x4F, 0x4E, 0x4D, 0x4C, 0x4A, 0x4A, 0x4A, 0x4B, 0x4D, 0x4F, 0x53, 0x59, -0x5F, 0x6C, 0xFE, 0xEC, 0xE3, 0xDE, 0xDC, 0xDA, 0xD9, 0xD8, 0xD7, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, -0xD8, 0xDA, 0xDC, 0xDE, 0xE3, 0xEC, 0xFB, 0x6F, 0x63, 0x5B, 0x55, 0x4F, 0x4D, 0x4C, 0x4B, 0x4C, -0x4C, 0x4D, 0x4F, 0x53, 0x58, 0x5E, 0x67, 0x73, 0xFB, 0xEE, 0xE8, 0xE3, 0xDF, 0xDC, 0xDA, 0xD9, -0xD8, 0xD8, 0xD8, 0xD9, 0xDB, 0xDD, 0xDF, 0xE1, 0xE5, 0xE9, 0xEE, 0xF6, 0x7C, 0x6E, 0x66, 0x5F, -0x5C, 0x5A, 0x58, 0x56, 0x56, 0x57, 0x58, 0x5A, 0x5D, 0x60, 0x66, 0x6D, 0x74, 0x7C, 0xFB, 0xF4, -0xEE, 0xEA, 0xE7, 0xE5, 0xE4, 0xE4, 0xE4, 0xE7, 0xEA, 0xEC, 0xED, 0xED, 0xEC, 0xED, 0xEC, 0xED, -0xEE, 0xF1, 0xF9, 0x7F, 0x79, 0x75, 0x70, 0x6D, 0x6C, 0x6C, 0x6E, 0x73, 0x79, 0xFE, 0xF9, 0xF3, -0xEE, 0xEB, 0xE9, 0xE8, 0xE6, 0xE5, 0xE6, 0xE8, 0xEA, 0xED, 0xF1, 0xF8, 0xFD, 0x7E, 0x7E, 0xFE, -0xFC, 0xF9, 0xF5, 0xF5, 0xF6, 0xFB, 0x7C, 0x77, 0x71, 0x6E, 0x6C, 0x6A, 0x69, 0x69, 0x6B, 0x6E, -0x70, 0x75, 0x7A, 0xFE, 0xF6, 0xF1, 0xEE, 0xEC, 0xEB, 0xEB, 0xEC, 0xEE, 0xF1, 0xF5, 0xFB, 0x7D, -0x7B, 0x7A, 0x7C, 0xFE, 0xFA, 0xF4, 0xF1, 0xF0, 0xF0, 0xF3, 0xF7, 0xFB, 0xFD, 0xFF, 0xFF, 0x7F, -0x7F, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0xFD, 0xFC, 0xFA, 0xF5, 0xF4, 0xF1, 0xEF, 0xEF, 0xEF, 0xF0, -0xF4, 0xF8, 0xFD, 0x7D, 0x78, 0x77, 0x78, 0x7A, 0x7C, 0x7C, 0x7E, 0x7C, 0x7A, 0x79, 0x76, 0x77, -0x78, 0x77, 0x7B, 0x7E, 0xFF, 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0x7E, 0xFE, 0xFB, -0xFA, 0xF9, 0xFA, 0xFB, 0xFE, 0x7F, 0x7C, 0x79, 0x78, 0x77, 0x77, 0x7A, 0x7C, 0x7D, 0x7E, 0x7B, -0x77, 0x74, 0x71, 0x6F, 0x6E, 0x6E, 0x6F, 0x6F, 0x70, 0x71, 0x73, 0x74, 0x76, 0x76, 0x75, 0x76, -0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x77, 0x74, 0x72, 0x70, 0x6F, 0x6E, 0x6E, 0x6E, 0x70, 0x74, -0x78, 0x7B, 0x7D, 0x7D, 0x7C, 0x7C, 0x7A, 0x76, 0x72, 0x71, 0x70, 0x70, 0x70, 0x71, 0x72, 0x72, -0x74, 0x76, 0x78, 0x7B, 0x7F, 0xFE, 0xFC, 0xF9, 0xF6, 0xF5, 0xF7, 0xFC, 0xFF, 0x7C, 0x79, 0x78, -0x77, 0x77, 0x77, 0x7A, 0x7E, 0xFE, 0xFC, 0xFA, 0xF8, 0xF8, 0xFA, 0xFC, 0xFE, 0x7D, 0x7A, 0x76, -0x74, 0x74, 0x73, 0x75, 0x76, 0x76, 0x78, 0x7A, 0x7C, 0x7E, 0xFF, 0xFB, 0xF9, 0xF8, 0xF9, 0xFD, -0x7E, 0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x78, 0x7C, 0x7F, 0xFB, 0xF6, 0xF5, 0xF2, 0xF2, 0xF3, -0xF4, 0xF7, 0xF8, 0xFA, 0xFC, 0xFE, 0xFF, 0xFF, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFA, -0xF7, 0xF6, 0xF8, 0xFC, 0x7F, 0x7C, 0x79, 0x72, 0x6F, 0x6E, 0x6E, 0x6E, 0x6F, 0x73, 0x77, 0x77, -0x7B, 0x7D, 0x7E, 0x7F, 0x7E, 0x7C, 0x7A, 0x77, 0x75, 0x71, 0x6F, 0x6E, 0x6D, 0x6E, 0x6F, 0x70, -0x73, 0x74, 0x77, 0x79, 0x7C, 0x7D, 0x7D, 0x7D, 0x7B, 0x7A, 0x79, 0x76, 0x73, 0x70, 0x6F, 0x71, -0x73, 0x78, 0x7B, 0x7F, 0xFB, 0xF8, 0xF5, 0xF3, 0xF5, 0xF6, 0xF6, 0xF8, 0xF9, 0xFC, 0xFE, 0xFF, -0x7F, 0xFF, 0xFD, 0xFC, 0xFC, 0xFB, 0xF7, 0xF6, 0xF6, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF7, 0xF9, -0xFA, 0xFC, 0xFF, 0xFF, 0x7F, 0x7F, 0xFE, 0xFD, 0xFE, 0xFD, 0xFB, 0xFB, 0xFC, 0xFE, 0x7E, 0x7C, -0x7A, 0x79, 0x77, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7C, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, -0x7D, 0x7E, 0x7C, 0x7E, 0x7F, 0x7E, 0x7E, 0xFF, 0xFD, 0xFC, 0xFB, 0xF8, 0xF8, 0xFA, 0xFA, 0xFC, -0xFE, 0x7D, 0x78, 0x75, 0x72, 0x70, 0x70, 0x73, 0x75, 0x76, 0x78, 0x79, 0x79, 0x7A, 0x79, 0x78, -0x77, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7D, 0x7F, 0xFC, 0xF8, 0xF6, -0xF4, 0xF2, 0xF3, 0xF7, 0xF9, 0xFB, 0x7E, 0x78, 0x75, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, -0x75, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x76, 0x79, 0x7B, -0x7C, 0x7E, 0xFE, 0xFC, 0xF9, 0xF6, 0xF5, 0xF6, 0xF7, 0xF9, 0xFC, 0xFE, 0x7C, 0x79, 0x77, 0x76, -0x75, 0x74, 0x74, 0x75, 0x74, 0x76, 0x77, 0x78, 0x79, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x78, 0x78, -0x77, 0x76, 0x77, 0x77, 0x77, 0x78, 0x7A, 0x7C, 0xFF, 0xFD, 0xFA, 0xF8, 0xF6, 0xF7, 0xF8, 0xF7, -0xF8, 0xF8, 0xF8, 0xF9, 0xFA, 0xF9, 0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0xFD, 0xFD, 0xFC, 0xFD, 0xFE, -0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7B, 0x7A, 0x79, 0x79, 0x79, 0x78, 0x79, 0x7B, 0x7C, 0x7C, 0x7C, -0x7C, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x71, 0x70, 0x6F, 0x6F, 0x6E, -0x6D, 0x6C, 0x6C, 0x6D, 0x6E, 0x6E, 0x6E, 0x6F, 0x6E, 0x6F, 0x70, 0x70, 0x72, 0x75, 0x78, 0x7B, -0x7B, 0x7C, 0x7D, 0xFF, 0xFD, 0xFC, 0xFA, 0xFA, 0xF9, 0xF7, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF9, -0xFA, 0xFA, 0xFA, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFB, -0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFF, 0x7F, 0xFC, 0xFA, 0xFB, 0xFA, 0xFA, 0xF9, -0xFA, 0xFC, 0xFC, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFE, 0xFD, 0xFC, 0xFD, 0xFA, 0xFA, 0xF9, 0xF8, -0xFA, 0xF8, 0xFA, 0xFA, 0xFB, 0xFE, 0xFB, 0xFF, 0xFD, 0xFD, 0xFF, 0xFB, 0xFF, 0xFA, 0xFC, 0x7F, -0xFC, 0x70, 0x6A, 0x64, 0x61, 0x67, 0x6C, 0x73, 0x61, 0x60, 0x5A, 0x47, 0x53, 0xDF, 0x7D, 0x6F, -0x71, 0x69, 0x7F, 0x72, 0x70, 0x68, 0x5A, 0x5B, 0x59, 0x55, 0x5A, 0x5D, 0x4E, 0x46, 0x51, 0x77, -0xF6, 0xEC, 0xE8, 0xE6, 0xE5, 0xE4, 0xE1, 0xE5, 0xFD, 0x60, 0x65, 0xE6, 0xDB, 0xDD, 0xE1, 0xE4, -0xE2, 0xDC, 0xD4, 0xCF, 0xCF, 0xCF, 0xD1, 0xD2, 0xCF, 0xCD, 0xCC, 0xCD, 0xD0, 0xD4, 0xD7, 0xD5, -0xCE, 0xCD, 0xD3, 0xD9, 0xDB, 0xDA, 0xD9, 0xDC, 0xE2, 0xE5, 0xF1, 0xEE, 0xD7, 0xD2, 0xD9, 0xDC, -0xDD, 0xD9, 0xDC, 0xE7, 0xDF, 0xD9, 0xDD, 0x74, 0x62, 0xFC, 0xE9, 0xF2, 0x6C, 0x5D, 0x5D, 0x61, -0x6B, 0x6C, 0x5C, 0x5D, 0x70, 0x64, 0x5B, 0x6D, 0x78, 0x61, 0x57, 0x58, 0x65, 0x62, 0x53, 0x51, -0x69, 0xF5, 0x59, 0x53, 0x69, 0x68, 0x54, 0x4F, 0x67, 0xFA, 0x5B, 0x58, 0x5D, 0x60, 0x5D, 0x4E, -0x53, 0x61, 0x5A, 0x5F, 0x63, 0x61, 0x5E, 0x4C, 0x4C, 0x5A, 0x6B, 0xF7, 0x58, 0x47, 0x51, 0x6D, -0x68, 0x5A, 0x55, 0x53, 0x4A, 0x4E, 0xEE, 0xE1, 0x56, 0x46, 0x4D, 0x74, 0x70, 0x59, 0x53, 0x4C, -0x4E, 0x62, 0xF2, 0xF3, 0x5A, 0x4A, 0x4F, 0x6D, 0x6B, 0x57, 0x63, 0xED, 0x79, 0x69, 0x62, 0x5D, -0x6C, 0x67, 0x5E, 0xF5, 0xEA, 0x69, 0x63, 0x76, 0xFA, 0x6A, 0x59, 0x5D, 0xFB, 0xF6, 0x72, 0xFB, -0x71, 0x5D, 0x65, 0x7D, 0xFC, 0x79, 0xFB, 0xE9, 0xE2, 0xDD, 0xE3, 0xF9, 0xFA, 0xF3, 0xEA, 0xEC, -0x7D, 0xF1, 0xE5, 0xF2, 0x78, 0x6D, 0x6D, 0xED, 0xE4, 0xE5, 0xE4, 0xF6, 0x7A, 0xF8, 0xE5, 0xDC, -0xEA, 0xDF, 0xCF, 0xD3, 0xE7, 0x6C, 0x78, 0xCF, 0xC9, 0xD5, 0x7E, 0x64, 0x7E, 0xD7, 0xCF, 0xD7, -0xE0, 0xE8, 0xDC, 0xCB, 0xC5, 0xCC, 0xE6, 0x73, 0xE9, 0xD2, 0xC9, 0xCA, 0xD3, 0xED, 0x68, 0xF3, -0xD9, 0xDA, 0xDC, 0xDA, 0xD7, 0xDB, 0xE1, 0xE1, 0xEA, 0x69, 0x59, 0x60, 0xEE, 0xE0, 0xDC, 0xDF, -0xE5, 0xDD, 0xE1, 0xED, 0xED, 0xF4, 0xF6, 0xF2, 0xEE, 0xED, 0xFC, 0x6F, 0x64, 0x5C, 0x5C, 0x61, -0x76, 0xEA, 0xE1, 0xEB, 0x73, 0x66, 0x60, 0x69, 0xFB, 0x7E, 0x70, 0x76, 0xFF, 0x78, 0x73, 0xEB, -0xE2, 0x6F, 0x5C, 0x69, 0xE9, 0xDB, 0xDE, 0x73, 0x5E, 0x6D, 0xED, 0xEB, 0xF4, 0xFF, 0x77, 0xFD, -0xE7, 0xE2, 0xFB, 0x66, 0x69, 0xFE, 0xFA, 0x6B, 0x63, 0x69, 0x74, 0x74, 0x66, 0x63, 0x6F, 0xFB, -0xFD, 0x73, 0x71, 0x7B, 0xF4, 0xE8, 0xE2, 0xE8, 0xF2, 0xEB, 0xDE, 0xDC, 0xDE, 0xE2, 0xE7, 0xE5, -0xDF, 0xDF, 0xE8, 0xFC, 0x6D, 0x6A, 0x66, 0x5C, 0x53, 0x51, 0x56, 0x5B, 0x59, 0x56, 0x56, 0x5A, -0x5E, 0x5A, 0x53, 0x53, 0x59, 0x5D, 0x5F, 0x64, 0x74, 0xE9, 0xD6, 0xCB, 0xCB, 0xD3, 0xDC, 0xD4, -0xC8, 0xC1, 0xBF, 0xBE, 0xBE, 0xC5, 0xCE, 0xDC, 0xEA, 0x68, 0x4B, 0x3E, 0x3B, 0x3B, 0x3D, 0x3E, -0x41, 0x45, 0x47, 0x48, 0x4A, 0x4C, 0x4A, 0x47, 0x49, 0x4F, 0x5E, 0x6D, 0xF5, 0xDB, 0xCC, 0xC5, -0xC1, 0xBF, 0xBE, 0xBC, 0xBA, 0xB7, 0xB2, 0xAF, 0xAE, 0xB7, 0xDA, 0x43, 0x38, 0x35, 0x32, 0x31, -0x33, 0x3A, 0x46, 0x54, 0x5D, 0x56, 0x4A, 0x44, 0x43, 0x46, 0x44, 0x3F, 0x40, 0x4B, 0x61, 0x7B, -0xFD, 0xE7, 0xD4, 0xCA, 0xC5, 0xBF, 0xBB, 0xB6, 0xB1, 0xAF, 0xAD, 0xAC, 0xAC, 0xB4, 0xD8, 0x3C, -0x2D, 0x2B, 0x2D, 0x2F, 0x37, 0x41, 0x54, 0x76, 0xFF, 0x68, 0x54, 0x46, 0x40, 0x44, 0x49, 0x4A, -0x49, 0x4C, 0x5C, 0xFB, 0xE9, 0xE5, 0xDB, 0xCE, 0xC8, 0xC3, 0xBE, 0xBA, 0xB6, 0xB1, 0xAE, 0xAB, -0xA9, 0xAB, 0xBD, 0x3F, 0x2A, 0x26, 0x2A, 0x31, 0x3A, 0x43, 0x58, 0xE9, 0xDB, 0xE8, 0x5E, 0x46, -0x3C, 0x3D, 0x48, 0x55, 0x56, 0x55, 0x61, 0xF3, 0xE8, 0xE6, 0xDC, 0xCF, 0xC9, 0xC0, 0xB9, 0xB4, -0xB3, 0xB3, 0xAF, 0xAA, 0xA8, 0xAF, 0x75, 0x2C, 0x22, 0x24, 0x2D, 0x3F, 0x56, 0x72, 0xE0, 0xCF, -0xD4, 0x59, 0x3F, 0x38, 0x38, 0x3E, 0x4C, 0x68, 0xE8, 0xE3, 0xEA, 0x7E, 0x67, 0x64, 0x79, 0xDC, -0xCB, 0xBF, 0xB7, 0xB1, 0xAF, 0xAE, 0xAC, 0xAA, 0xB1, 0x56, 0x29, 0x1F, 0x20, 0x2B, 0x45, 0xD1, -0xC4, 0xC7, 0xCB, 0xD8, 0x4B, 0x33, 0x2E, 0x34, 0x42, 0x6D, 0xCD, 0xC5, 0xC8, 0xD1, 0xE0, 0x69, -0x52, 0x52, 0x6D, 0xD4, 0xC6, 0xBB, 0xB1, 0xAC, 0xAB, 0xAA, 0xA8, 0xAE, 0x68, 0x28, 0x1D, 0x1E, -0x2B, 0x53, 0xBC, 0xB6, 0xBD, 0xCA, 0xE1, 0x4E, 0x33, 0x2A, 0x2C, 0x3B, 0x7D, 0xBF, 0xBB, 0xC1, -0xD5, 0xED, 0x6A, 0x4F, 0x4C, 0x58, 0x7E, 0xD6, 0xC7, 0xBB, 0xB2, 0xAD, 0xA9, 0xA6, 0xA9, 0xC3, -0x2D, 0x1D, 0x1B, 0x23, 0x41, 0xBC, 0xAF, 0xB5, 0xC2, 0xDE, 0x4F, 0x3B, 0x2D, 0x27, 0x2D, 0x49, -0xC3, 0xB5, 0xB9, 0xCB, 0x64, 0x54, 0x56, 0x51, 0x58, 0x75, 0xE3, 0xD1, 0xCA, 0xC1, 0xB6, 0xAB, -0xA6, 0xA3, 0xA6, 0xC0, 0x2B, 0x1C, 0x1A, 0x24, 0x4D, 0xB0, 0xAA, 0xB0, 0xC3, 0xF0, 0x46, 0x38, -0x2D, 0x28, 0x2B, 0x4C, 0xBC, 0xB2, 0xB6, 0xD1, 0x4B, 0x46, 0x4F, 0x58, 0x61, 0xEE, 0xE1, 0xDB, -0xCF, 0xCB, 0xBD, 0xAE, 0xA7, 0xA3, 0xA2, 0xB6, 0x2C, 0x1B, 0x19, 0x21, 0x52, 0xAB, 0xA5, 0xAE, -0xC9, 0x4F, 0x3B, 0x37, 0x32, 0x2A, 0x2A, 0x3D, 0xC9, 0xB2, 0xB1, 0xCA, 0x44, 0x3D, 0x49, 0x5F, -0xDD, 0xD8, 0x77, 0x6E, 0xED, 0xDB, 0xC7, 0xB7, 0xAB, 0xA5, 0xA3, 0xA6, 0xC8, 0x26, 0x1A, 0x1A, -0x27, 0xC5, 0xA4, 0xA3, 0xAF, 0xE9, 0x3B, 0x33, 0x34, 0x31, 0x2D, 0x31, 0x57, 0xBF, 0xB3, 0xBA, -0x78, 0x41, 0x3E, 0x4E, 0xDC, 0xCE, 0xD4, 0x78, 0x5B, 0x67, 0xDC, 0xC4, 0xB7, 0xAC, 0xA6, 0xA5, -0xA5, 0xBA, 0x2C, 0x1B, 0x19, 0x23, 0xD8, 0xA3, 0x9F, 0xAB, 0xDA, 0x34, 0x2D, 0x30, 0x33, 0x33, -0x37, 0x54, 0xC1, 0xB7, 0xBD, 0x6E, 0x41, 0x3D, 0x4A, 0xD8, 0xCA, 0xD0, 0xEB, 0x56, 0x54, 0x74, -0xCE, 0xBD, 0xAF, 0xA8, 0xA6, 0xA5, 0xAE, 0x3B, 0x1E, 0x19, 0x1E, 0x43, 0xA8, 0x9E, 0xA6, 0xC8, -0x33, 0x29, 0x2C, 0x32, 0x39, 0x3D, 0x4E, 0xCD, 0xBE, 0xC2, 0xFF, 0x40, 0x3D, 0x48, 0xE0, 0xC4, -0xCB, 0xEA, 0x4F, 0x48, 0x59, 0xD7, 0xBE, 0xB5, 0xAD, 0xA9, 0xA9, 0xA7, 0xB3, 0x34, 0x1D, 0x19, -0x20, 0xEE, 0xA2, 0x9D, 0xA8, 0x60, 0x2A, 0x26, 0x2D, 0x3B, 0x4A, 0x4E, 0x64, 0xCE, 0xC6, 0xCF, -0x57, 0x42, 0x47, 0x67, 0xCB, 0xC3, 0xD4, 0x5C, 0x48, 0x47, 0x63, 0xCA, 0xBA, 0xB2, 0xAE, 0xAC, -0xAC, 0xAB, 0xB3, 0x3D, 0x1F, 0x1B, 0x20, 0x51, 0xA5, 0x9E, 0xA8, 0x6C, 0x2A, 0x24, 0x2B, 0x3E, -0x5E, 0x6C, 0x66, 0xFA, 0xE0, 0xE4, 0x60, 0x4B, 0x4E, 0x71, 0xD2, 0xC8, 0xD8, 0x5A, 0x4A, 0x49, -0x6E, 0xC6, 0xB9, 0xB3, 0xB1, 0xAF, 0xAE, 0xAC, 0xAF, 0x48, 0x21, 0x1B, 0x1F, 0x4C, 0xA5, 0x9D, -0xA7, 0x64, 0x28, 0x23, 0x2C, 0x4A, 0xD6, 0xD9, 0x61, 0x59, 0x6C, 0xEF, 0xF8, 0x5B, 0x5B, 0xEE, -0xD5, 0xCD, 0xDB, 0x5C, 0x4D, 0x4C, 0x6E, 0xC8, 0xBB, 0xB8, 0xB8, 0xB6, 0xB3, 0xAD, 0xA8, 0xBC, -0x2D, 0x1D, 0x1B, 0x2B, 0xB7, 0x9F, 0xA1, 0xB9, 0x33, 0x23, 0x28, 0x3A, 0xEB, 0xCF, 0x77, 0x50, -0x56, 0x6E, 0xE2, 0x73, 0x55, 0x5D, 0xE6, 0xCF, 0xD9, 0x5B, 0x4B, 0x47, 0x59, 0xD2, 0xC3, 0xBD, -0xBD, 0xBC, 0xB6, 0xAE, 0xA9, 0xAB, 0x68, 0x24, 0x1B, 0x1E, 0x3C, 0xAA, 0x9E, 0xA6, 0xDE, 0x2A, -0x23, 0x2C, 0x47, 0xD1, 0xCE, 0x72, 0x55, 0x58, 0x6A, 0x78, 0x5D, 0x5B, 0xF9, 0xDA, 0xD3, 0xDE, -0x5A, 0x49, 0x4A, 0x5F, 0xD1, 0xC0, 0xBD, 0xBC, 0xB9, 0xB3, 0xAD, 0xA9, 0xB1, 0x3C, 0x1F, 0x1C, -0x24, 0xE1, 0xA4, 0x9F, 0xAD, 0x44, 0x26, 0x25, 0x32, 0x6E, 0xC3, 0xCD, 0x64, 0x4F, 0x4F, 0x62, -0x70, 0x5C, 0x68, 0xE1, 0xD4, 0xD3, 0xF6, 0x4E, 0x45, 0x4B, 0x78, 0xCA, 0xBE, 0xBC, 0xBC, 0xB8, -0xB3, 0xAC, 0xA9, 0xBC, 0x2F, 0x1E, 0x1C, 0x2A, 0xBC, 0xA0, 0xA1, 0xB7, 0x35, 0x24, 0x28, 0x3B, -0xD8, 0xC4, 0xDC, 0x53, 0x4B, 0x4F, 0x67, 0x6D, 0x65, 0xEA, 0xDB, 0xD5, 0xDA, 0x5E, 0x4B, 0x48, -0x53, 0xDB, 0xC4, 0xBD, 0xBD, 0xBB, 0xB5, 0xAE, 0xA8, 0xAB, 0x75, 0x25, 0x1B, 0x1E, 0x3D, 0xAA, -0x9E, 0xA6, 0xDC, 0x2B, 0x25, 0x2E, 0x4E, 0xCC, 0xCC, 0x66, 0x4B, 0x4C, 0x5A, 0x74, 0x6C, 0x6D, -0xDF, 0xD6, 0xD6, 0xED, 0x4D, 0x43, 0x46, 0x59, 0xD0, 0xBF, 0xBC, 0xBB, 0xB8, 0xB3, 0xAD, 0xA9, -0xB3, 0x38, 0x1E, 0x1B, 0x24, 0xCF, 0xA2, 0x9F, 0xAF, 0x3E, 0x26, 0x27, 0x36, 0x6A, 0xCD, 0xE6, -0x4F, 0x4D, 0x55, 0x6E, 0xEF, 0x63, 0x7B, 0xDA, 0xDB, 0xDF, 0x5F, 0x49, 0x47, 0x4F, 0xE8, 0xC5, -0xBD, 0xBC, 0xBB, 0xB6, 0xAF, 0xAA, 0xAA, 0xCD, 0x29, 0x1C, 0x1D, 0x34, 0xAE, 0x9F, 0xA4, 0xC7, -0x2E, 0x25, 0x2C, 0x41, 0xDB, 0xD2, 0x75, 0x5B, 0x59, 0x60, 0x6E, 0x5B, 0x5C, 0xDF, 0xD0, 0xD8, -0x74, 0x4B, 0x43, 0x4B, 0x6E, 0xCC, 0xBF, 0xBD, 0xBE, 0xBC, 0xB5, 0xAD, 0xA8, 0xAD, 0x4B, 0x22, -0x1C, 0x22, 0x65, 0xA6, 0x9F, 0xAC, 0x4C, 0x2A, 0x28, 0x33, 0x50, 0xDE, 0xF2, 0x65, 0x7C, 0xF8, -0x79, 0x5A, 0x4B, 0x5E, 0xD7, 0xCF, 0xD6, 0x5F, 0x45, 0x43, 0x4C, 0xFB, 0xC9, 0xBF, 0xBD, 0xBC, -0xB8, 0xB2, 0xAD, 0xAA, 0xB7, 0x38, 0x20, 0x1D, 0x29, 0xC6, 0xA5, 0xA4, 0xB8, 0x3C, 0x2A, 0x2C, -0x39, 0x53, 0x7F, 0x6F, 0x79, 0xE8, 0xF9, 0x61, 0x4D, 0x4B, 0xFF, 0xD0, 0xD3, 0xEC, 0x4F, 0x45, -0x49, 0x58, 0xDF, 0xC7, 0xBF, 0xBD, 0xBB, 0xB5, 0xAF, 0xA9, 0xAA, 0xCA, 0x2C, 0x1D, 0x1E, 0x36, -0xB1, 0xA2, 0xA8, 0xCE, 0x33, 0x2B, 0x30, 0x3E, 0x4F, 0x5A, 0x6D, 0xD8, 0xD2, 0xF5, 0x4F, 0x46, -0x54, 0xD4, 0xCA, 0xD7, 0x65, 0x48, 0x43, 0x4C, 0x61, 0xD7, 0xC4, 0xBF, 0xBD, 0xB7, 0xB1, 0xAD, -0xAA, 0xB0, 0x48, 0x23, 0x1D, 0x24, 0x5D, 0xAA, 0xA4, 0xB0, 0x56, 0x30, 0x2E, 0x34, 0x3E, 0x47, -0x52, 0xE3, 0xC9, 0xCE, 0x65, 0x45, 0x43, 0x6A, 0xCE, 0xCD, 0xDE, 0x58, 0x49, 0x49, 0x4F, 0x6D, -0xD1, 0xC0, 0xBB, 0xB6, 0xAF, 0xAE, 0xAA, 0xAB, 0xCF, 0x2B, 0x1D, 0x1E, 0x36, 0xB2, 0xA4, 0xA9, -0xC7, 0x3B, 0x2F, 0x31, 0x37, 0x3D, 0x46, 0x6E, 0xC7, 0xC5, 0xE5, 0x4C, 0x41, 0x50, 0xD5, 0xCB, -0xDF, 0x58, 0x4C, 0x49, 0x4E, 0x62, 0xE4, 0xC8, 0xBD, 0xB9, 0xB4, 0xAF, 0xAD, 0xA9, 0xB2, 0x41, -0x22, 0x1D, 0x26, 0xEB, 0xAA, 0xA6, 0xB3, 0x5D, 0x38, 0x32, 0x32, 0x34, 0x39, 0x4D, 0xCC, 0xBD, -0xC7, 0x60, 0x44, 0x47, 0x6D, 0xDC, 0xE2, 0xEF, 0x63, 0x58, 0x50, 0x4D, 0x5A, 0xDB, 0xC3, 0xBA, -0xB3, 0xAF, 0xAD, 0xAC, 0xAE, 0xD3, 0x2D, 0x1F, 0x20, 0x38, 0xB9, 0xA9, 0xAD, 0xC4, 0x4C, 0x39, -0x33, 0x30, 0x32, 0x3C, 0xFA, 0xBE, 0xBE, 0xD5, 0x51, 0x46, 0x4F, 0x6F, 0x7B, 0x65, 0x68, 0x76, -0x60, 0x54, 0x52, 0x61, 0xCF, 0xBF, 0xB7, 0xAE, 0xAC, 0xAB, 0xAB, 0xBC, 0x39, 0x22, 0x1E, 0x2B, -0xE7, 0xAF, 0xAC, 0xB6, 0xD1, 0x4E, 0x3A, 0x2F, 0x2D, 0x31, 0x45, 0xCC, 0xBC, 0xC2, 0xDA, 0x58, -0x4D, 0x55, 0x52, 0x52, 0x68, 0xED, 0xF4, 0x66, 0x55, 0x59, 0xEF, 0xCE, 0xBF, 0xB5, 0xAD, 0xAB, -0xAB, 0xAE, 0xCC, 0x31, 0x22, 0x22, 0x2F, 0xE8, 0xB6, 0xB1, 0xB8, 0xC4, 0x73, 0x3D, 0x2F, 0x2B, -0x2F, 0x3F, 0xDD, 0xC0, 0xBF, 0xC7, 0xD8, 0x73, 0x55, 0x46, 0x44, 0x53, 0x7B, 0xEE, 0xED, 0xF2, -0xED, 0xDC, 0xCF, 0xC1, 0xB3, 0xAC, 0xA9, 0xA9, 0xB2, 0x58, 0x2C, 0x24, 0x28, 0x36, 0x5C, 0xC7, -0xBA, 0xB6, 0xB7, 0xCA, 0x49, 0x34, 0x2D, 0x2E, 0x37, 0x49, 0xE0, 0xC4, 0xBD, 0xBE, 0xC7, 0xEA, -0x4C, 0x42, 0x44, 0x49, 0x50, 0x69, 0xDD, 0xD0, 0xCB, 0xC6, 0xBD, 0xB3, 0xAD, 0xAB, 0xAB, 0xBA, -0x49, 0x2F, 0x2B, 0x2D, 0x32, 0x3A, 0x4B, 0xD6, 0xBC, 0xB6, 0xBD, 0xD7, 0x51, 0x3D, 0x36, 0x34, -0x37, 0x3E, 0x52, 0xDE, 0xC8, 0xC3, 0xC7, 0xCE, 0xDE, 0x72, 0x56, 0x4F, 0x53, 0x5D, 0xFF, 0xDA, -0xC9, 0xBD, 0xB7, 0xB4, 0xB2, 0xB6, 0xC6, 0x62, 0x47, 0x3F, 0x3D, 0x3B, 0x3B, 0x40, 0x4E, 0x6F, -0xEC, 0x7B, 0x67, 0x5E, 0x5B, 0x59, 0x55, 0x5A, 0x65, 0x5E, 0x5A, 0x5F, 0x61, 0x5E, 0x63, 0x65, -0x61, 0x6D, 0xF5, 0xFA, 0x7A, 0x77, 0x77, 0xFF, 0xEB, 0xDC, 0xD5, 0xCE, 0xCA, 0xC8, 0xC8, 0xCD, -0xD9, 0xEC, 0x76, 0x70, 0xFD, 0xED, 0xEA, 0xEE, 0x7D, 0x66, 0x59, 0x53, 0x50, 0x4F, 0x50, 0x54, -0x56, 0x58, 0x59, 0x5A, 0x5A, 0x5C, 0x5F, 0x6B, 0xF6, 0xE5, 0xE1, 0xE7, 0xEF, 0xF5, 0xF2, 0xEA, -0xDF, 0xD8, 0xCE, 0xC8, 0xC4, 0xC5, 0xCB, 0xD4, 0xDF, 0xE9, 0xE7, 0xE1, 0xDD, 0xDB, 0xDE, 0xEE, -0x68, 0x57, 0x4F, 0x4D, 0x4D, 0x4E, 0x4F, 0x4F, 0x52, 0x54, 0x53, 0x51, 0x53, 0x57, 0x5E, 0x6F, -0xFA, 0xEF, 0xEF, 0xF3, 0xF1, 0xF1, 0xEE, 0xE6, 0xDE, 0xD6, 0xCF, 0xCD, 0xCE, 0xD3, 0xDA, 0xDC, -0xDF, 0xDF, 0xD9, 0xD5, 0xD4, 0xD7, 0xE0, 0xFE, 0x6B, 0x5F, 0x5A, 0x58, 0x56, 0x54, 0x54, 0x53, -0x53, 0x50, 0x4E, 0x4F, 0x52, 0x56, 0x5C, 0x64, 0x67, 0x66, 0x69, 0x6C, 0x6D, 0x74, 0xFA, 0xEC, -0xDF, 0xD7, 0xD6, 0xDD, 0xE6, 0xF3, 0x7B, 0xF7, 0xE8, 0xDC, 0xD3, 0xD0, 0xD2, 0xD9, 0xE1, 0xE7, -0xEB, 0xF6, 0x7B, 0x74, 0x6F, 0x6B, 0x66, 0x5E, 0x59, 0x55, 0x53, 0x52, 0x56, 0x59, 0x5C, 0x61, -0x5F, 0x64, 0x65, 0x62, 0x6F, 0x7B, 0xFC, 0xE4, 0xDC, 0xD9, 0xE2, 0x7E, 0xFF, 0xFE, 0xFF, 0xEE, -0xDF, 0xD8, 0xD6, 0xD7, 0xDB, 0xDD, 0xDD, 0xE8, 0xE7, 0xE3, 0xEA, 0xE7, 0xF9, 0x72, 0x7C, 0x5F, -0x56, 0x58, 0x58, 0x56, 0x57, 0x57, 0x53, 0x54, 0x4A, 0x42, 0x4F, 0x67, 0x6A, 0xE0, 0xD4, 0xD8, -0xD7, 0xDD, 0xFD, 0xFE, 0xE4, 0x7B, 0xFF, 0xD9, 0xDF, 0xDE, 0xD7, 0xDA, 0xCF, 0xCF, 0xD3, 0xCD, -0xD3, 0xDF, 0xDD, 0xDE, 0xF3, 0x6D, 0x5F, 0x55, 0x54, 0x55, 0x51, 0x51, 0x50, 0x4F, 0x51, 0x53, -0x57, 0x59, 0x60, 0x73, 0xFB, 0xE7, 0xE1, 0xEA, 0xF4, 0x7D, 0x6D, 0x6F, 0x7F, 0x78, 0xF5, 0xE7, -0xEA, 0xE0, 0xDE, 0xD9, 0xCD, 0xCB, 0xC5, 0xC2, 0xC5, 0xCB, 0xDB, 0xDD, 0xEC, 0x53, 0x4C, 0x45, -0x42, 0x49, 0x48, 0x49, 0x4D, 0x51, 0x5A, 0x55, 0x55, 0x5D, 0x64, 0xF4, 0xED, 0xF5, 0xEB, 0xF2, -0x7A, 0x6D, 0x60, 0x5E, 0x6E, 0xF3, 0xF7, 0xE9, 0xDF, 0xDD, 0xD4, 0xCD, 0xC8, 0xC1, 0xBC, 0xB8, -0xB5, 0xB8, 0xC7, 0xF5, 0x52, 0x3E, 0x38, 0x37, 0x36, 0x3D, 0x4B, 0x59, 0xFD, 0xDF, 0xE3, 0xFE, -0x5C, 0x54, 0x52, 0x4E, 0x50, 0x55, 0x5D, 0xFF, 0xF2, 0xF1, 0xE9, 0xFB, 0xFD, 0x74, 0x5E, 0x62, -0x7A, 0xE3, 0xD2, 0xCA, 0xC0, 0xB9, 0xB1, 0xAD, 0xAE, 0xBC, 0x68, 0x3E, 0x31, 0x2D, 0x2E, 0x30, -0x3B, 0x5B, 0xD4, 0xC7, 0xC9, 0xD6, 0x65, 0x4A, 0x46, 0x3E, 0x3D, 0x47, 0x51, 0x7F, 0xD5, 0xD0, -0xCE, 0xD2, 0xE2, 0x6E, 0x57, 0x55, 0x61, 0xEA, 0xCD, 0xBE, 0xB7, 0xB2, 0xAD, 0xAB, 0xB0, 0xCE, -0x40, 0x2F, 0x2B, 0x2D, 0x2F, 0x38, 0x59, 0xCA, 0xBD, 0xBE, 0xCF, 0x70, 0x45, 0x39, 0x3A, 0x3B, -0x3F, 0x5D, 0xD9, 0xCB, 0xC4, 0xC5, 0xCF, 0xEA, 0x62, 0x52, 0x50, 0x5C, 0x7E, 0xD1, 0xBE, 0xB5, -0xAF, 0xAE, 0xAB, 0xAC, 0xC2, 0x44, 0x2F, 0x2A, 0x2D, 0x32, 0x38, 0x55, 0xC6, 0xBA, 0xBC, 0xCF, -0x5B, 0x40, 0x36, 0x34, 0x38, 0x40, 0x66, 0xCD, 0xC4, 0xC2, 0xC6, 0xD1, 0xFE, 0x52, 0x4C, 0x4F, -0x5C, 0xEF, 0xCF, 0xC1, 0xB7, 0xAF, 0xAD, 0xAB, 0xAD, 0xC9, 0x3C, 0x2D, 0x29, 0x2D, 0x35, 0x3D, -0xF1, 0xBD, 0xB8, 0xBF, 0xE1, 0x4C, 0x3C, 0x32, 0x31, 0x39, 0x47, 0xF7, 0xCB, 0xC4, 0xC2, 0xC7, -0xD9, 0x6F, 0x54, 0x4D, 0x4F, 0x5D, 0xEF, 0xCF, 0xC1, 0xB8, 0xAF, 0xAD, 0xAB, 0xAC, 0xC9, 0x3A, -0x2C, 0x29, 0x2D, 0x37, 0x44, 0xD8, 0xB9, 0xB7, 0xC4, 0x6C, 0x44, 0x38, 0x31, 0x30, 0x39, 0x4E, -0xDF, 0xCA, 0xC5, 0xC6, 0xCD, 0xEF, 0x5E, 0x5A, 0x53, 0x55, 0x64, 0xE8, 0xCD, 0xC4, 0xBB, 0xB0, -0xAC, 0xAA, 0xAC, 0xD0, 0x36, 0x2C, 0x2B, 0x2E, 0x39, 0x4A, 0xCB, 0xB6, 0xB7, 0xC8, 0x5D, 0x43, -0x39, 0x31, 0x32, 0x3D, 0x58, 0xD9, 0xCD, 0xCA, 0xC9, 0xD6, 0x73, 0x62, 0x63, 0x62, 0x68, 0x72, -0xE9, 0xCE, 0xC6, 0xBB, 0xAF, 0xAD, 0xAB, 0xAE, 0xD7, 0x38, 0x2D, 0x2C, 0x2F, 0x3B, 0x4F, 0xCA, -0xB6, 0xB8, 0xCB, 0x5D, 0x41, 0x39, 0x32, 0x33, 0x3E, 0x59, 0xDC, 0xCF, 0xCD, 0xCB, 0xD8, 0x63, -0x53, 0x5A, 0x5E, 0x61, 0x6F, 0xEA, 0xCF, 0xC6, 0xBC, 0xB0, 0xAD, 0xAB, 0xAE, 0xEE, 0x32, 0x2C, -0x2C, 0x30, 0x3B, 0x50, 0xC9, 0xB6, 0xB9, 0xCF, 0x5D, 0x47, 0x3A, 0x32, 0x33, 0x3F, 0x63, 0xDB, -0xD5, 0xCC, 0xC8, 0xD7, 0x66, 0x56, 0x58, 0x5C, 0x5A, 0x5B, 0x7E, 0xCE, 0xC4, 0xBB, 0xB0, 0xAD, -0xAB, 0xAF, 0x7B, 0x2F, 0x2C, 0x2E, 0x31, 0x39, 0x52, 0xC6, 0xB6, 0xBA, 0xD1, 0x5C, 0x4E, 0x3E, -0x32, 0x33, 0x3F, 0x64, 0xEA, 0xFD, 0xCE, 0xC2, 0xD0, 0x6C, 0x57, 0x5D, 0x64, 0x56, 0x53, 0x6C, -0xCE, 0xC4, 0xBD, 0xB1, 0xAD, 0xAA, 0xAE, 0x6F, 0x31, 0x2F, 0x31, 0x31, 0x37, 0x4F, 0xC5, 0xB6, -0xBA, 0xD2, 0xFC, 0x60, 0x45, 0x36, 0x35, 0x41, 0x56, 0xF8, 0xF2, 0xE4, 0xC6, 0xC8, 0x7C, 0x5A, -0x6A, 0x6A, 0x57, 0x52, 0x5B, 0xDA, 0xC6, 0xC0, 0xB6, 0xAE, 0xAA, 0xAC, 0xDD, 0x33, 0x30, 0x35, -0x31, 0x30, 0x42, 0xCE, 0xBA, 0xBA, 0xCC, 0xD9, 0xD9, 0x53, 0x3A, 0x35, 0x3E, 0x4D, 0x52, 0x60, -0xD6, 0xC5, 0xD2, 0x71, 0xE7, 0x7C, 0x55, 0x53, 0x51, 0x5B, 0xEE, 0xDC, 0xD3, 0xBE, 0xB2, 0xB0, -0xAD, 0xAE, 0x67, 0x31, 0x38, 0x39, 0x2F, 0x32, 0x49, 0xD5, 0xBE, 0xBF, 0xCF, 0xCD, 0xCA, 0x5C, -0x3D, 0x3C, 0x41, 0x41, 0x47, 0x5D, 0xE1, 0xC9, 0xC7, 0xD4, 0xDD, 0xFC, 0x51, 0x4C, 0x4C, 0x4C, -0x5F, 0xE2, 0xDC, 0xCA, 0xBF, 0xBD, 0xB9, 0xB5, 0xAF, 0xBA, 0x43, 0x35, 0x44, 0x3E, 0x2F, 0x36, -0x53, 0xD4, 0xC8, 0xCC, 0xD1, 0xC3, 0xC5, 0x5E, 0x41, 0x45, 0x49, 0x42, 0x44, 0x55, 0xE9, 0xD0, -0xD1, 0xDA, 0xD6, 0xD7, 0xFD, 0x5A, 0x58, 0x5B, 0x5A, 0x5B, 0x5F, 0x6C, 0x7A, 0xE1, 0xD3, 0xD2, -0xCC, 0xC8, 0xC4, 0xBF, 0xBD, 0xBA, 0xC2, 0x49, 0x3C, 0x4C, 0x41, 0x35, 0x3B, 0x52, 0xF3, 0xD6, -0xD1, 0xCE, 0xC3, 0xC6, 0x7A, 0x53, 0x57, 0x4E, 0x44, 0x46, 0x4F, 0x64, 0xE8, 0xDF, 0xDD, 0xD4, -0xD6, 0xEC, 0x56, 0x49, 0x54, 0x5E, 0x4F, 0x57, 0xFA, 0xE1, 0xDC, 0xE0, 0xE3, 0xD6, 0xD0, 0xDC, -0xD9, 0xC9, 0xC2, 0xBD, 0xC5, 0x58, 0x50, 0xE6, 0x4B, 0x37, 0x3F, 0x4F, 0x4D, 0x52, 0x6D, 0xDD, -0xC8, 0xC8, 0xDC, 0xDC, 0xD1, 0x72, 0x4A, 0x4A, 0x4E, 0x4B, 0x4E, 0x57, 0x6A, 0xDF, 0xD7, 0xDB, -0xD5, 0xCF, 0xDA, 0xF4, 0x74, 0x67, 0x5E, 0x5E, 0x5E, 0x66, 0xF9, 0xED, 0xEC, 0xE8, 0xE4, 0xE8, -0xF4, 0xF7, 0x60, 0x52, 0x6D, 0xF3, 0x5B, 0x66, 0xE7, 0xE1, 0xE0, 0xDF, 0xDF, 0xD8, 0xD1, 0xEA, -0x6B, 0xD9, 0xD1, 0xE5, 0xE6, 0xCC, 0xC4, 0xE7, 0x52, 0xEA, 0xE4, 0x4C, 0x48, 0x59, 0x5D, 0x59, -0x5D, 0x60, 0xF7, 0xDF, 0x79, 0x6A, 0xDF, 0xDC, 0xFE, 0xF8, 0xE2, 0xF0, 0x6F, 0x6B, 0x61, 0x5F, -0x62, 0x5D, 0x5E, 0x6C, 0x76, 0x70, 0xF7, 0xE5, 0xE6, 0xE7, 0xE5, 0xEA, 0xF4, 0x7D, 0x6C, 0x66, -0x68, 0x66, 0x66, 0x73, 0xF8, 0xF3, 0xF4, 0xF6, 0xFB, 0x7E, 0x7A, 0x7E, 0xF6, 0xEF, 0xED, 0xE9, -0xE9, 0xEF, 0xFB, 0x78, 0x6E, 0x69, 0x64, 0x63, 0x68, 0x6E, 0x74, 0x7B, 0xFA, 0xF6, 0xF3, 0xFF, -0x6B, 0x69, 0x69, 0x60, 0x5F, 0x65, 0x6C, 0x73, 0x7C, 0xF3, 0xEB, 0xE9, 0xEA, 0xE8, 0xE6, 0xE6, -0xE7, 0xE4, 0xDE, 0xDD, 0xE2, 0xE2, 0xE1, 0xE9, 0xF8, 0x77, 0x6B, 0x62, 0x5D, 0x5B, 0x5A, 0x59, -0x5A, 0x5B, 0x5D, 0x5E, 0x5E, 0x5E, 0x5F, 0x62, 0x67, 0x6D, 0x78, 0xFA, 0xF2, 0xEE, 0xEF, 0xF3, -0xF7, 0xF8, 0xFA, 0xFE, 0xFA, 0xF3, 0xF1, 0xEF, 0xEA, 0xE7, 0xE5, 0xE6, 0xE9, 0xEF, 0xFB, 0x79, -0x70, 0x6C, 0x6A, 0x6C, 0x6F, 0x77, 0x7C, 0xFD, 0xFB, 0x7F, 0x73, 0x6C, 0x69, 0x69, 0x6C, 0x73, -0xFA, 0xED, 0xE9, 0xE5, 0xE1, 0xE4, 0xE8, 0xE8, 0xE7, 0xE7, 0xE5, 0xE2, 0xE0, 0xDD, 0xDC, 0xE1, -0xE3, 0xE2, 0xEC, 0x7C, 0x6C, 0x63, 0x5D, 0x5B, 0x59, 0x58, 0x5A, 0x5B, 0x5B, 0x5C, 0x5F, 0x60, -0x5F, 0x60, 0x65, 0x6A, 0x75, 0xF8, 0xEC, 0xE7, 0xE6, 0xE7, 0xEA, 0xF0, 0xF8, 0xF9, 0xF4, 0xED, -0xE9, 0xE5, 0xE3, 0xE3, 0xE6, 0xEB, 0xF6, 0x76, 0x6C, 0x67, 0x62, 0x5F, 0x61, 0x64, 0x69, 0x6F, -0x73, 0x73, 0x75, 0x75, 0x70, 0x6E, 0x6F, 0x6E, 0x6E, 0x75, 0xFE, 0xF3, 0xEC, 0xE9, 0xE9, 0xE9, -0xED, 0xFA, 0x7A, 0x74, 0x71, 0x72, 0x73, 0x74, 0x7A, 0xFF, 0xFF, 0x7B, 0x72, 0x6E, 0x6D, 0x6C, -0x6C, 0x6E, 0x73, 0x7C, 0xFC, 0xF7, 0xF0, 0xEB, 0xE6, 0xE0, 0xDD, 0xDB, 0xDB, 0xDB, 0xDC, 0xDF, -0xE2, 0xE3, 0xE8, 0xF2, 0x7D, 0x6C, 0x61, 0x5D, 0x5A, 0x58, 0x59, 0x5C, 0x5E, 0x61, 0x66, 0x69, -0x6A, 0x6B, 0x6C, 0x6B, 0x6C, 0x75, 0xFE, 0xF7, 0xEE, 0xEA, 0xE8, 0xE6, 0xE9, 0xEC, 0xEB, 0xEB, -0xEE, 0xF0, 0xF2, 0xF6, 0xF9, 0xFD, 0x7F, 0xFF, 0x7C, 0x74, 0x6D, 0x69, 0x66, 0x64, 0x64, 0x68, -0x6B, 0x6D, 0x75, 0x7D, 0xFC, 0xF8, 0xFA, 0xFC, 0xFA, 0xF7, 0xF5, 0xF0, 0xEB, 0xE6, 0xE4, 0xE5, -0xE9, 0xED, 0xF2, 0xFC, 0x7A, 0x74, 0x6E, 0x6C, 0x6A, 0x69, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6E, -0x6D, 0x6E, 0x70, 0x71, 0x74, 0x79, 0x7B, 0x7E, 0xFB, 0xF6, 0xF8, 0xF9, 0xF6, 0xF5, 0xF8, 0xFA, -0xF7, 0xF0, 0xEE, 0xF0, 0xF7, 0xFC, 0x7D, 0x73, 0x6C, 0x6B, 0x6B, 0x6A, 0x6B, 0x6B, 0x6B, 0x6B, -0x6C, 0x6D, 0x6D, 0x6E, 0x71, 0x71, 0x71, 0x72, 0x77, 0x7D, 0xFC, 0xF7, 0xF3, 0xED, 0xEB, 0xEB, -0xEE, 0xF4, 0xF9, 0xFE, 0x79, 0x77, 0x7B, 0x7F, 0x7F, 0xFF, 0xFF, 0x7B, 0x77, 0x76, 0x77, 0x79, -0x79, 0x7A, 0x7C, 0xFF, 0xFC, 0xFC, 0xFA, 0xF8, 0xF9, 0xF9, 0xFA, 0xFD, 0xFE, 0xFD, 0xFA, 0xF8, -0xF5, 0xF2, 0xF1, 0xF2, 0xF4, 0xF8, 0xFE, 0x7C, 0x79, 0x77, 0x77, 0x7A, 0x7E, 0x7F, 0x7C, 0x79, -0x78, 0x75, 0x73, 0x72, 0x71, 0x73, 0x75, 0x76, 0x78, 0x7D, 0xFD, 0xFB, 0xFC, 0xFF, 0x7D, 0x79, -0x76, 0x76, 0x77, 0x7C, 0xFB, 0xF5, 0xF3, 0xF3, 0xF3, 0xF7, 0x7D, 0x74, 0x6F, 0x6D, 0x6B, 0x6C, -0x6E, 0x73, 0x77, 0x77, 0x77, 0x7A, 0x7A, 0x76, 0x73, 0x72, 0x6F, 0x6D, 0x6B, 0x6C, 0x6F, 0x76, -0x7A, 0x7D, 0xFE, 0xFC, 0x7E, 0x7A, 0x75, 0x71, 0x6E, 0x6D, 0x6E, 0x71, 0x77, 0x7D, 0xFE, 0xFC, -0xFC, 0xFE, 0xFF, 0x7D, 0x7B, 0x7C, 0x7E, 0xFF, 0xFF, 0xFC, 0xF9, 0xF7, 0xF6, 0xF8, 0xFA, 0xFC, -0xFF, 0x7E, 0x7F, 0xFF, 0xFD, 0xFB, 0xF7, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFD, 0x7D, 0x7A, 0x7A, -0x7D, 0x7E, 0x7F, 0xFF, 0xFE, 0xFE, 0x7E, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0xFF, 0xFD, 0xFD, 0xFD, -0xFB, 0xF8, 0xF7, 0xF9, 0xFD, 0x7C, 0x79, 0x78, 0x78, 0x77, 0x77, 0x76, 0x75, 0x75, 0x75, 0x75, -0x75, 0x74, 0x76, 0x78, 0x79, 0x7B, 0x7D, 0x7F, 0xFD, 0xFB, 0xFF, 0x7A, 0x79, 0x7D, 0xFE, 0xFD, -0xFD, 0xFC, 0xFD, 0xFA, 0xF5, 0xF2, 0xF3, 0xF6, 0xF8, 0xF9, 0xFC, 0xFF, 0xFD, 0xF8, 0xF5, 0xF5, -0xF6, 0xFA, 0xFC, 0xFD, 0x7F, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x77, 0x7B, 0x7E, 0x7E, 0x7E, 0x7F, -0x7E, 0x7C, 0x79, 0x76, 0x76, 0x78, 0x79, 0x78, 0x7B, 0x7E, 0xFF, 0x7F, 0x7C, 0x7A, 0x78, 0x75, -0x73, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7B, 0x7B, 0x79, 0x79, 0x78, 0x77, 0x78, 0x74, 0x71, 0x72, -0x73, 0x76, 0x77, 0x77, 0x79, 0x79, 0x77, 0x76, 0x75, 0x76, 0x78, 0x7B, 0x7F, 0xFC, 0xFB, 0xFB, -0xFA, 0xFB, 0xFE, 0x7C, 0x79, 0x79, 0x78, 0x78, 0x7B, 0xFF, 0xFD, 0xFD, 0xFC, 0xFC, 0xFE, 0x7E, -0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x78, 0x79, 0x7A, 0x7C, 0x7C, 0x7C, 0x7B, 0x77, 0x78, 0x7A, -0x7A, 0x7A, 0x7C, 0x7E, 0xFF, 0x7F, 0x7F, 0xFF, 0xFF, 0x7F, 0x7E, 0x7F, 0x7E, 0x7C, 0x7A, 0x7A, -0x79, 0x79, 0x7B, 0x7E, 0x7E, 0x7F, 0xFD, 0xFC, 0xFD, 0xFD, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, -0xFF, 0x7E, 0x7D, 0x7F, 0xFF, 0xFF, 0xFE, 0xFC, 0xFB, 0xFC, 0xFC, 0xFE, 0x7E, 0x7F, 0x7E, 0x7B, -0x7C, 0x7D, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x77, 0x7A, -0x7C, 0x7D, 0x7E, 0x7E, 0x7C, 0x79, 0x76, 0x77, 0x79, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0x7D, -0x7D, 0x7C, 0x7A, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x7C, 0x7E, 0x7D, 0x7E, 0x7E, 0x7C, 0x7B, 0x7C, -0x7C, 0x7C, 0x7D, 0xFF, 0xFC, 0xFB, 0xFB, 0xFC, 0xFF, 0x7C, 0x79, 0x77, 0x74, 0x75, 0x77, 0x7A, -0x7D, 0x7E, 0xFF, 0xFD, 0xFD, 0xFE, 0x7E, 0x7D, 0x7D, 0x7B, 0x7A, 0x7B, 0x7D, 0x7E, 0xFE, 0xFD, -0xFF, 0x7F, 0x7D, 0x7B, 0x7A, 0x78, 0x76, 0x76, 0x79, 0x7C, 0x7E, 0xFF, 0xFF, 0x7F, 0x7E, 0x7C, -0x7A, 0x79, 0x78, 0x78, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0x7F, 0x7E, 0x7D, 0x7B, 0x7A, -0x7B, 0x7C, 0x7D, 0xFE, 0xFC, 0xFA, 0xF9, 0xFA, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFA, 0xF8, 0xF7, -0xF6, 0xF7, 0xF9, 0xFB, 0xFE, 0x7E, 0x7C, 0x7A, 0x79, 0x79, 0x7B, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, -0x7E, 0x7C, 0x7B, 0x79, 0x7A, 0x7C, 0x7C, 0x7E, 0x7E, 0x7F, 0xFF, 0x7F, 0x7E, 0x7C, 0x7B, 0x79, -0x77, 0x76, 0x76, 0x78, 0x7B, 0x7B, 0x7B, 0x7A, 0x7A, 0x7A, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7B, -0x7D, 0x79, 0x79, 0x7E, 0x79, 0x78, 0x79, 0x78, 0x7A, 0x78, 0x7D, 0x7D, 0x7C, 0xFF, 0x7D, 0x7F, -0x7E, 0x7B, 0x7A, 0x76, 0x79, 0x76, 0x78, 0x7B, 0x79, 0xFF, 0x7D, 0xFB, 0xFD, 0x7D, 0xF9, 0x7B, -0xFF, 0x79, 0x75, 0xFF, 0x6E, 0x7F, 0x71, 0x73, 0x79, 0x51, 0x60, 0xE2, 0x6F, 0x7D, 0xF7, 0xF5, -0x77, 0x72, 0xE4, 0x50, 0x4C, 0xDE, 0xFB, 0x66, 0xE5, 0xF6, 0x6F, 0x6C, 0xE7, 0xDC, 0x6E, 0xFD, -0xE6, 0x7E, 0xE9, 0x77, 0x62, 0xE3, 0xE9, 0x6C, 0x71, 0xEA, 0xDE, 0x75, 0x7E, 0xE8, 0x75, 0xF8, -0x7A, 0xFC, 0xF2, 0x65, 0xF8, 0xEE, 0xF9, 0xF4, 0x73, 0xE4, 0xF9, 0x6E, 0xE5, 0x75, 0x67, 0x5A, -0x50, 0x57, 0x5A, 0x7D, 0x6C, 0x64, 0xDA, 0xED, 0x64, 0xEA, 0xE9, 0xF5, 0x7E, 0x6F, 0xFC, 0xF2, -0x66, 0x63, 0xF7, 0x7D, 0x78, 0xF6, 0xF8, 0xE1, 0xE2, 0xF9, 0xEB, 0xE4, 0xED, 0xFE, 0xFA, 0xF6, -0xF1, 0xF2, 0x6F, 0xFE, 0xE8, 0xFF, 0x7F, 0xEA, 0xE8, 0xED, 0xEE, 0xEA, 0xEB, 0xED, 0xF8, 0xEF, -0xE8, 0x7F, 0xF5, 0xE6, 0xF7, 0xF2, 0xF3, 0xF2, 0xDF, 0xEB, 0xF5, 0xE3, 0xEC, 0xF2, 0xEF, 0xFC, -0xED, 0xEF, 0xFD, 0xED, 0xF0, 0x7C, 0x77, 0xFE, 0xF1, 0x77, 0x79, 0xEF, 0xF6, 0xF8, 0xFB, 0x72, -0x75, 0x79, 0x78, 0x70, 0x6E, 0x7C, 0x7D, 0x74, 0x79, 0x77, 0x6E, 0x71, 0x7D, 0x6F, 0x6B, 0x7D, -0xFE, 0x76, 0x7A, 0x7D, 0x7F, 0x75, 0x6C, 0x7B, 0xF7, 0x7A, 0x7B, 0x7E, 0x74, 0x79, 0x75, 0x70, -0x7C, 0x79, 0xFD, 0xF6, 0x6E, 0x6E, 0x7B, 0x6B, 0x67, 0x6D, 0x6E, 0x6A, 0x67, 0x6A, 0x6D, 0x6F, -0x6B, 0x67, 0x6D, 0x6C, 0x65, 0x63, 0x5E, 0x65, 0x6A, 0x5F, 0x68, 0x6C, 0x60, 0x6C, 0x7D, 0x6D, -0x6E, 0x7D, 0x7C, 0xFF, 0xEE, 0xEB, 0xEC, 0xE3, 0xDE, 0xE1, 0xE4, 0xE0, 0xE8, 0xF8, 0xEE, 0xFA, -0x6D, 0x69, 0x5C, 0x58, 0x59, 0x53, 0x50, 0x4E, 0x4D, 0x4E, 0x4F, 0x4F, 0x53, 0x51, 0x51, 0x54, -0x55, 0x56, 0x5A, 0x5E, 0x69, 0xF7, 0xE2, 0xD8, 0xCF, 0xCE, 0xCD, 0xCC, 0xCE, 0xCE, 0xCA, 0xC7, -0xC2, 0xBF, 0xBE, 0xBD, 0xC2, 0xD5, 0xF1, 0x62, 0x4B, 0x3F, 0x3D, 0x3D, 0x3E, 0x40, 0x42, 0x4A, -0x51, 0x51, 0x51, 0x55, 0x56, 0x4F, 0x4D, 0x4E, 0x50, 0x52, 0x55, 0x5C, 0x69, 0xFA, 0xE4, 0xD9, -0xCD, 0xC9, 0xC5, 0xC1, 0xBF, 0xBB, 0xBB, 0xBD, 0xB9, 0xB7, 0xB5, 0xB7, 0xC8, 0xDD, 0x61, 0x43, -0x3C, 0x38, 0x38, 0x3D, 0x40, 0x46, 0x4E, 0x5A, 0x60, 0x5D, 0x5B, 0x5B, 0x5A, 0x58, 0x56, 0x58, -0x5C, 0x5E, 0x5E, 0x64, 0x6B, 0x6D, 0xF9, 0xED, 0xE5, 0xDC, 0xD9, 0xD2, 0xCC, 0xC5, 0xBF, 0xBF, -0xBA, 0xB7, 0xB6, 0xB1, 0xB7, 0xCB, 0xFA, 0x49, 0x3A, 0x35, 0x31, 0x33, 0x3A, 0x42, 0x4C, 0x5C, -0xFD, 0xE1, 0xEE, 0x68, 0x66, 0x5C, 0x51, 0x4F, 0x4D, 0x55, 0x5F, 0x5D, 0x64, 0x71, 0xFA, 0xED, -0xEF, 0xEB, 0xDE, 0xD3, 0xCC, 0xC3, 0xBE, 0xBD, 0xB9, 0xB8, 0xB5, 0xAF, 0xB7, 0xCC, 0x60, 0x3F, -0x39, 0x34, 0x2F, 0x31, 0x3A, 0x47, 0x56, 0x6F, 0xE3, 0xDA, 0xD5, 0xEC, 0x56, 0x50, 0x4E, 0x4B, -0x4B, 0x4C, 0x57, 0x7B, 0xE7, 0xE0, 0xDC, 0xD5, 0xD6, 0xDE, 0xEC, 0xEF, 0xDE, 0xD7, 0xCC, 0xC1, -0xBD, 0xB8, 0xB5, 0xB4, 0xB0, 0xB6, 0xCB, 0x58, 0x3E, 0x38, 0x34, 0x2F, 0x2F, 0x38, 0x45, 0x59, -0x7D, 0xDD, 0xD1, 0xCE, 0xDD, 0x63, 0x53, 0x4E, 0x4C, 0x4A, 0x4B, 0x53, 0x69, 0xE7, 0xDB, 0xD5, -0xD0, 0xCE, 0xD3, 0xDC, 0xE4, 0xEA, 0xE8, 0xE2, 0xD5, 0xC8, 0xC0, 0xBB, 0xB8, 0xB5, 0xB2, 0xB9, -0xD1, 0x54, 0x40, 0x3A, 0x34, 0x2F, 0x2F, 0x36, 0x3F, 0x4C, 0x5B, 0x7E, 0xDE, 0xD4, 0xDB, 0xFF, -0x62, 0x58, 0x55, 0x53, 0x4F, 0x52, 0x5D, 0x6F, 0xF0, 0xE4, 0xDE, 0xDA, 0xD8, 0xDC, 0xE1, 0xE5, -0xDF, 0xDC, 0xD6, 0xCC, 0xC6, 0xC1, 0xBE, 0xBB, 0xB8, 0xBC, 0xCE, 0x67, 0x4B, 0x44, 0x3E, 0x38, -0x35, 0x37, 0x3D, 0x45, 0x4B, 0x53, 0x61, 0xFA, 0xE4, 0xEC, 0x7F, 0x79, 0x78, 0x79, 0x70, 0x68, -0x68, 0x70, 0x7B, 0x7D, 0x7D, 0xF9, 0xEE, 0xEA, 0xE8, 0xE6, 0xE1, 0xDB, 0xD6, 0xCF, 0xCB, 0xC8, -0xC5, 0xC1, 0xBE, 0xBF, 0xC7, 0xD5, 0xF9, 0x5F, 0x55, 0x4A, 0x42, 0x3E, 0x3E, 0x41, 0x45, 0x48, -0x4C, 0x56, 0x5F, 0x6F, 0xF8, 0xEF, 0xE7, 0xE4, 0xE6, 0xE2, 0xEA, 0xF5, 0xFD, 0x75, 0x75, 0x79, -0x75, 0x76, 0x7E, 0xFA, 0xF1, 0xE9, 0xE0, 0xDA, 0xD3, 0xCF, 0xCC, 0xCA, 0xC7, 0xC4, 0xC5, 0xCC, -0xD3, 0xDF, 0xFF, 0x69, 0x58, 0x4C, 0x47, 0x43, 0x42, 0x42, 0x43, 0x46, 0x4C, 0x55, 0x59, 0x62, -0x77, 0xFD, 0xEE, 0xEC, 0xF3, 0xEC, 0xF2, 0x76, 0x76, 0x6F, 0x6E, 0x79, 0x79, 0x7F, 0xF3, 0xED, -0xE4, 0xDD, 0xDB, 0xD7, 0xD3, 0xD0, 0xCE, 0xCC, 0xCB, 0xCA, 0xCC, 0xD1, 0xD6, 0xDD, 0xEA, 0x7E, -0x62, 0x56, 0x4F, 0x4C, 0x49, 0x48, 0x49, 0x4C, 0x50, 0x56, 0x58, 0x5C, 0x67, 0x6F, 0x6C, 0x6E, -0x6D, 0x6A, 0x6F, 0x6D, 0x6B, 0x6E, 0x6D, 0x76, 0xFA, 0xF9, 0xF1, 0xEB, 0xE7, 0xE1, 0xDE, 0xDD, -0xDB, 0xD8, 0xD7, 0xD4, 0xD2, 0xD0, 0xCF, 0xD4, 0xD8, 0xDA, 0xDF, 0xEA, 0xF8, 0x6D, 0x60, 0x5C, -0x58, 0x56, 0x56, 0x56, 0x57, 0x59, 0x5B, 0x5B, 0x5A, 0x5C, 0x5F, 0x5F, 0x5F, 0x63, 0x66, 0x6B, -0x72, 0x77, 0x7E, 0xF7, 0xF0, 0xEC, 0xE9, 0xE9, 0xE8, 0xE8, 0xE8, 0xE8, 0xEA, 0xE7, 0xE6, 0xE5, -0xE3, 0xE1, 0xDD, 0xDA, 0xD9, 0xD8, 0xDD, 0xDF, 0xDD, 0xE0, 0xE7, 0xEE, 0xFE, 0x74, 0x6C, 0x62, -0x5C, 0x59, 0x56, 0x54, 0x52, 0x51, 0x51, 0x52, 0x55, 0x58, 0x59, 0x5D, 0x62, 0x68, 0x70, 0x75, -0x7D, 0xF9, 0xF8, 0xF4, 0xF5, 0xF9, 0xF5, 0xF3, 0xF3, 0xF2, 0xF2, 0xEF, 0xED, 0xEB, 0xEA, 0xE6, -0xE3, 0xE0, 0xDC, 0xDA, 0xD7, 0xD8, 0xDB, 0xDB, 0xDA, 0xDC, 0xDF, 0xE8, 0xF6, 0x7F, 0x6E, 0x60, -0x5B, 0x58, 0x56, 0x54, 0x53, 0x52, 0x53, 0x59, 0x5C, 0x5E, 0x63, 0x68, 0x6F, 0x7B, 0x7C, 0xFF, -0xFC, 0xFC, 0xFB, 0xFC, 0xFD, 0xF8, 0xF7, 0xF6, 0xF4, 0xF5, 0xF3, 0xF0, 0xEF, 0xED, 0xEB, 0xE8, -0xE4, 0xE0, 0xDD, 0xDA, 0xD9, 0xDA, 0xDC, 0xDC, 0xDC, 0xE0, 0xE9, 0xF8, 0x76, 0x6B, 0x61, 0x5C, -0x5A, 0x5A, 0x5A, 0x5B, 0x5C, 0x5E, 0x62, 0x67, 0x6B, 0x6D, 0x6F, 0x72, 0x75, 0x76, 0x76, 0x75, -0x74, 0x79, 0x7E, 0x7B, 0x78, 0x7D, 0xFB, 0xFB, 0xFD, 0xFA, 0xF6, 0xF5, 0xF2, 0xEF, 0xEC, 0xE9, -0xE4, 0xDF, 0xDE, 0xDE, 0xE0, 0xE7, 0xEA, 0xEC, 0xF2, 0xFE, 0x76, 0x6F, 0x6F, 0x6D, 0x6A, 0x6A, -0x6B, 0x6C, 0x6C, 0x69, 0x67, 0x67, 0x66, 0x65, 0x64, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6B, 0x6E, -0x71, 0x76, 0x7A, 0x7D, 0xFE, 0xFC, 0xFA, 0xF8, 0xF4, 0xF0, 0xEE, 0xEC, 0xEA, 0xE9, 0xE8, 0xE9, -0xEB, 0xEB, 0xEC, 0xED, 0xEE, 0xED, 0xEB, 0xE9, 0xEA, 0xE9, 0xE9, 0xEA, 0xEC, 0xF0, 0xF6, 0xFD, -0x78, 0x71, 0x6D, 0x69, 0x67, 0x66, 0x65, 0x65, 0x66, 0x67, 0x66, 0x66, 0x67, 0x67, 0x66, 0x66, -0x69, 0x6B, 0x6D, 0x73, 0x7A, 0xFE, 0xF7, 0xF3, 0xEF, 0xEE, 0xEE, 0xEC, 0xEB, 0xEA, 0xE8, 0xE7, -0xE5, 0xE3, 0xE1, 0xE1, 0xE1, 0xE3, 0xE6, 0xE8, 0xEB, 0xEF, 0xF8, 0x7E, 0x75, 0x6F, 0x6B, 0x69, -0x67, 0x66, 0x65, 0x65, 0x66, 0x67, 0x67, 0x68, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, -0x70, 0x6F, 0x6F, 0x6F, 0x72, 0x75, 0x79, 0xFF, 0xFB, 0xF6, 0xF2, 0xEF, 0xEE, 0xED, 0xEE, 0xF0, -0xF3, 0xF6, 0xF8, 0xFC, 0xFF, 0x7D, 0x79, 0x76, 0x72, 0x6E, 0x6D, 0x6B, 0x6B, 0x6C, 0x6C, 0x6D, -0x6E, 0x71, 0x76, 0x7B, 0xFF, 0xFE, 0xFD, 0xFC, 0xFD, 0x7F, 0x7B, 0x78, 0x75, 0x74, 0x75, 0x77, -0x7A, 0x7E, 0xFC, 0xF9, 0xF6, 0xF5, 0xF4, 0xF4, 0xF5, 0xF7, 0xF8, 0xF8, 0xF7, 0xF6, 0xF5, 0xF5, -0xF6, 0xF8, 0xFA, 0xFC, 0x7F, 0x7B, 0x79, 0x78, 0x77, 0x77, 0x79, 0x7D, 0xFD, 0xF9, 0xF4, 0xF2, -0xF1, 0xF1, 0xF3, 0xF5, 0xFA, 0xFE, 0x7F, 0xFF, 0xFD, 0xFC, 0xFB, 0xF7, 0xF5, 0xF4, 0xF4, 0xF6, -0xF8, 0xFB, 0xFD, 0xFF, 0x7E, 0x7E, 0x7E, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7E, 0x7B, 0x79, 0x77, -0x76, 0x75, 0x74, 0x74, 0x75, 0x78, 0x7C, 0x7F, 0xFE, 0xFD, 0xFE, 0xFF, 0x7E, 0x7C, 0x7B, 0x79, -0x79, 0x7A, 0x7D, 0xFE, 0xFC, 0xFA, 0xF8, 0xF8, 0xF9, 0xFB, 0xFD, 0x7F, 0x7B, 0x78, 0x76, 0x75, -0x74, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x7A, 0x7C, -0x7E, 0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7C, 0x7A, 0x78, 0x77, 0x77, 0x76, 0x79, 0x7B, 0x7E, 0xFF, -0xFE, 0xFD, 0xFD, 0xFF, 0x7E, 0x7C, 0x7C, 0x7B, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x74, 0x74, -0x74, 0x74, 0x75, 0x76, 0x79, 0x7C, 0x7E, 0xFF, 0xFC, 0xF8, 0xF7, 0xF6, 0xF7, 0xF7, 0xF7, 0xF9, -0xFC, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7F, 0xFF, 0xFC, 0xFB, 0xFA, 0xF8, 0xF8, 0xF8, 0xF6, 0xF5, -0xF5, 0xF4, 0xF4, 0xF5, 0xF7, 0xF8, 0xFA, 0xFD, 0x7F, 0x7E, 0x7D, 0x7C, 0x7C, 0x7D, 0x7E, 0xFE, -0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF9, 0xF9, 0xFA, 0xFB, 0xFD, 0xFF, 0x7E, 0x7D, 0x79, 0x77, 0x75, -0x72, 0x71, 0x70, 0x70, 0x70, 0x71, 0x71, 0x70, 0x71, 0x72, 0x71, 0x72, 0x71, 0x72, 0x73, 0x72, -0x72, 0x71, 0x71, 0x71, 0x72, 0x74, 0x74, 0x76, 0x77, 0x77, 0x77, 0x78, 0x77, 0x78, 0x78, 0x78, -0x7A, 0x7C, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFD, 0xFF, 0x7E, 0x7D, 0x7B, 0x7C, 0x7B, -0x7B, 0x7B, 0x7B, 0x7B, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7B, 0x7C, 0x7E, 0xFF, 0xFD, -0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0xFF, 0x7F, 0x7D, 0x7C, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7D, -0x7F, 0x7F, 0xFF, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, -0xFF, 0xFF, 0xFF, 0xFD, 0xFA, 0xF9, 0xF7, 0xF5, 0xF4, 0xF3, 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, -0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xFA, 0xFC, 0xFE, 0xFE, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, -0x7F, 0x7D, 0x7C, 0x7D, 0x7B, 0x7A, 0x7D, 0x7B, 0x7B, 0x7C, 0x7B, 0x7B, 0x7B, 0x79, 0x78, 0x77, -0x77, 0x76, 0x75, 0x76, 0x75, 0x74, 0x74, 0x75, 0x74, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73, 0x74, -0x72, 0x70, 0x70, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x71, 0x72, 0x73, 0x73, 0x76, -0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7B, 0x7D, 0x7E, 0x7D, 0x7F, 0x7D, 0x7C, 0x7B, 0x7B, 0x7C, -0x7B, 0x7B, 0x7A, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0xFF, 0x7D, 0x7E, 0x7C, 0x7C, 0x7B, 0x78, -0x7C, 0x7A, 0x7C, 0x7D, 0x7B, 0x7E, 0x7C, 0x7F, 0x7D, 0x7A, 0x7E, 0x78, 0x7B, 0x6F, 0x68, 0x5C, -0x4C, 0x58, 0xDD, 0xE1, 0xEB, 0xE1, 0xE9, 0xEF, 0xF8, 0xE9, 0xE1, 0xED, 0xF9, 0xFC, 0xF2, 0xED, -0x7D, 0x76, 0xFB, 0xF9, 0x7C, 0x70, 0x6F, 0x78, 0x79, 0x6D, 0x6D, 0x76, 0x7D, 0xFE, 0x7A, 0x79, -0xFC, 0xFD, 0xFD, 0xFA, 0xFB, 0xFA, 0xFC, 0xFF, 0xFC, 0xFC, 0xFE, 0xFD, 0xFE, 0xFB, 0xFB, 0xFE, -0xFE, 0x7E, 0x7D, 0x7C, 0x7C, 0x7B, 0x78, 0x7D, 0x7D, 0xFF, 0xFA, 0xFF, 0xF9, 0xF9, 0xFA, 0xF7, -0x7F, 0xF9, 0x7A, 0x7A, 0x6F, 0x51, 0x52, 0x6E, 0x71, 0xF1, 0xD8, 0xD3, 0xDB, 0xEF, 0xE2, 0xDB, -0xED, 0xF6, 0xF3, 0xEF, 0xF4, 0x6A, 0x74, 0x73, 0x57, 0x5E, 0x77, 0x6E, 0xFD, 0xF4, 0xFC, 0x7D, -0x73, 0xE9, 0xDE, 0xE2, 0xDE, 0xE3, 0xE5, 0xE8, 0xFA, 0xF7, 0xFA, 0x6F, 0x6C, 0x6A, 0x6B, 0x6A, -0x66, 0x6B, 0x75, 0x70, 0x74, 0xFA, 0xFB, 0xFD, 0xF8, 0xF3, 0xF2, 0xFB, 0xF5, 0xED, 0xEF, 0xEB, -0xE5, 0xDF, 0xDA, 0xD7, 0xD5, 0xD3, 0xD3, 0xD4, 0xD8, 0xE0, 0xEE, 0x76, 0x5D, 0x53, 0x4D, 0x49, -0x46, 0x43, 0x42, 0x43, 0x43, 0x45, 0x48, 0x4B, 0x4F, 0x57, 0x60, 0x6D, 0xF7, 0xE3, 0xDB, 0xD4, -0xCF, 0xCB, 0xC8, 0xC4, 0xBE, 0xBC, 0xB9, 0xB4, 0xB6, 0xBC, 0xC1, 0xC3, 0xD5, 0x4F, 0x4B, 0x43, -0x36, 0x33, 0x34, 0x32, 0x31, 0x36, 0x3B, 0x3F, 0x48, 0x60, 0xDF, 0xD2, 0xC9, 0xC1, 0xC3, 0xC6, -0xC7, 0xCF, 0xE3, 0x67, 0x56, 0x47, 0x3E, 0x3F, 0x3C, 0x3B, 0x43, 0x48, 0x4F, 0xFA, 0xD5, 0xC5, -0xBD, 0xB7, 0xB1, 0xAE, 0xAC, 0xAE, 0xB1, 0xB5, 0xC0, 0xD7, 0x5D, 0x40, 0x38, 0x31, 0x2E, 0x2D, -0x2C, 0x2E, 0x32, 0x37, 0x3F, 0x4F, 0xF8, 0xD0, 0xC4, 0xBC, 0xBB, 0xBB, 0xBB, 0xBE, 0xC7, 0xD0, -0xF1, 0x56, 0x48, 0x40, 0x3D, 0x3B, 0x3D, 0x42, 0x49, 0x63, 0xDA, 0xCB, 0xBC, 0xB6, 0xB0, 0xAE, -0xAF, 0xAF, 0xB4, 0xBC, 0xC6, 0xFE, 0x4C, 0x3E, 0x34, 0x30, 0x2E, 0x2D, 0x2E, 0x30, 0x35, 0x3C, -0x46, 0x62, 0xDE, 0xCA, 0xBE, 0xBD, 0xBB, 0xBA, 0xBD, 0xC3, 0xCB, 0xDC, 0x6B, 0x59, 0x51, 0x52, -0x60, 0xFF, 0xD5, 0xC4, 0xBE, 0xBC, 0xBA, 0xB9, 0xBB, 0xC3, 0xC8, 0xD6, 0x5A, 0x4C, 0x42, 0x39, -0x36, 0x35, 0x32, 0x34, 0x36, 0x39, 0x41, 0x47, 0x58, 0xE0, 0xDA, 0xC9, 0xC1, 0xC4, 0xC0, 0xC0, -0xC6, 0xCA, 0xD1, 0xDC, 0xF3, 0x6E, 0xFC, 0xE8, 0xDB, 0xCB, 0xC2, 0xBE, 0xBD, 0xBE, 0xBD, 0xC0, -0xCD, 0xCE, 0xEC, 0x4E, 0x4C, 0x40, 0x38, 0x39, 0x37, 0x35, 0x38, 0x38, 0x3B, 0x43, 0x49, 0x54, -0xEA, 0xDB, 0xCE, 0xC5, 0xC5, 0xC3, 0xC1, 0xC7, 0xCA, 0xCF, 0xDB, 0xE9, 0xFD, 0xF7, 0xE9, 0xDD, -0xCE, 0xC6, 0xC1, 0xBF, 0xC0, 0xBF, 0xC3, 0xCF, 0xD0, 0xE6, 0x51, 0x4E, 0x43, 0x3A, 0x3B, 0x38, -0x35, 0x38, 0x38, 0x3A, 0x3F, 0x44, 0x4E, 0x5F, 0xEF, 0xD7, 0xCD, 0xC8, 0xC6, 0xC4, 0xC6, 0xC9, -0xCC, 0xD4, 0xDD, 0xE6, 0xE1, 0xDA, 0xD7, 0xCA, 0xC3, 0xC4, 0xC4, 0xC1, 0xC3, 0xCC, 0xCF, 0xD8, -0x60, 0x54, 0x4E, 0x3F, 0x3D, 0x3D, 0x39, 0x3A, 0x3C, 0x3B, 0x3D, 0x47, 0x48, 0x51, 0x79, 0xFA, -0xDD, 0xCD, 0xCF, 0xCC, 0xC8, 0xCD, 0xCE, 0xCE, 0xD7, 0xDC, 0xDC, 0xD7, 0xD4, 0xCC, 0xC3, 0xC1, -0xBF, 0xBF, 0xC2, 0xC1, 0xCE, 0xDB, 0xDD, 0x54, 0x4C, 0x49, 0x3C, 0x3B, 0x3B, 0x38, 0x3A, 0x3B, -0x3C, 0x3E, 0x48, 0x4C, 0x55, 0xF3, 0xEC, 0xDB, 0xCD, 0xD1, 0xCD, 0xCB, 0xD2, 0xD1, 0xD6, 0xDD, -0xE1, 0xE2, 0xD7, 0xD3, 0xCA, 0xC0, 0xBE, 0xBE, 0xBF, 0xBE, 0xC1, 0xCF, 0xD0, 0xED, 0x4E, 0x4D, -0x41, 0x3A, 0x3A, 0x37, 0x35, 0x38, 0x3A, 0x3A, 0x3F, 0x49, 0x4A, 0x62, 0xE7, 0xEA, 0xCE, 0xCB, -0xCF, 0xC8, 0xCB, 0xD1, 0xCF, 0xD7, 0xE2, 0xE5, 0xE5, 0xDF, 0xD5, 0xCC, 0xC5, 0xBE, 0xBE, 0xC0, -0xBC, 0xC0, 0xCD, 0xC8, 0xDC, 0x58, 0x5B, 0x47, 0x3C, 0x3D, 0x39, 0x36, 0x39, 0x3A, 0x39, 0x3E, -0x47, 0x49, 0x59, 0xEA, 0xEC, 0xD0, 0xC9, 0xCD, 0xC7, 0xC8, 0xCE, 0xCD, 0xD2, 0xDC, 0xDF, 0xDF, -0xDD, 0xD6, 0xCB, 0xC6, 0xBF, 0xBF, 0xC4, 0xBD, 0xC4, 0xD1, 0xC9, 0xEF, 0x55, 0x5D, 0x43, 0x3D, -0x3E, 0x38, 0x37, 0x3A, 0x3A, 0x3A, 0x3E, 0x45, 0x48, 0x56, 0x74, 0xF8, 0xD8, 0xCF, 0xD0, 0xCB, -0xCB, 0xCE, 0xCE, 0xD2, 0xD9, 0xDC, 0xDC, 0xD7, 0xD3, 0xCA, 0xC4, 0xC0, 0xBF, 0xC2, 0xBE, 0xC3, -0xCF, 0xCB, 0xE5, 0x58, 0x5C, 0x45, 0x3D, 0x3E, 0x39, 0x37, 0x39, 0x3A, 0x3A, 0x3D, 0x45, 0x46, -0x52, 0x79, 0x73, 0xD7, 0xCD, 0xD1, 0xC8, 0xC8, 0xCD, 0xCA, 0xCF, 0xD5, 0xD7, 0xDC, 0xDA, 0xD4, -0xCD, 0xC7, 0xC1, 0xC0, 0xC5, 0xBF, 0xC2, 0xD1, 0xCA, 0xDA, 0x5A, 0x68, 0x4C, 0x3E, 0x42, 0x3B, -0x38, 0x3B, 0x3A, 0x3A, 0x3D, 0x42, 0x44, 0x4B, 0x62, 0x66, 0xF1, 0xD0, 0xD6, 0xCD, 0xC8, 0xCE, -0xCA, 0xCB, 0xD1, 0xCF, 0xD2, 0xD2, 0xCE, 0xC9, 0xC5, 0xC1, 0xBF, 0xC5, 0xC1, 0xC0, 0xD3, 0xCE, -0xD6, 0x57, 0x5F, 0x4E, 0x3E, 0x41, 0x3D, 0x39, 0x3B, 0x3B, 0x3A, 0x3D, 0x42, 0x44, 0x4C, 0x5A, -0x5E, 0xEC, 0xDD, 0xDC, 0xCE, 0xD0, 0xD1, 0xCD, 0xD4, 0xD4, 0xD4, 0xDA, 0xD3, 0xCE, 0xCB, 0xC4, -0xBF, 0xBE, 0xC2, 0xBE, 0xBF, 0xCD, 0xCB, 0xD5, 0x5B, 0x5F, 0x4D, 0x3E, 0x3F, 0x3B, 0x37, 0x39, -0x3A, 0x39, 0x3C, 0x3F, 0x42, 0x4B, 0x59, 0x61, 0xEA, 0xDA, 0xD6, 0xCD, 0xCD, 0xCE, 0xCD, 0xCF, -0xD3, 0xD6, 0xDA, 0xD7, 0xD2, 0xCE, 0xC7, 0xC2, 0xBF, 0xC0, 0xC1, 0xBE, 0xC8, 0xCE, 0xCB, 0x79, -0x5A, 0x5C, 0x41, 0x3F, 0x3E, 0x38, 0x39, 0x3A, 0x39, 0x3A, 0x3E, 0x42, 0x45, 0x51, 0x62, 0x65, -0xDD, 0xD5, 0xD7, 0xCA, 0xCC, 0xCE, 0xCA, 0xCE, 0xD0, 0xCF, 0xCF, 0xCD, 0xC9, 0xC4, 0xBF, 0xBD, -0xBE, 0xBF, 0xBD, 0xC5, 0xCE, 0xCB, 0xF8, 0x58, 0x5B, 0x43, 0x3E, 0x3E, 0x39, 0x38, 0x3A, 0x39, -0x3A, 0x3E, 0x44, 0x45, 0x51, 0x6E, 0x69, 0xDC, 0xCF, 0xD7, 0xCA, 0xCB, 0xD0, 0xCC, 0xD1, 0xD5, -0xD5, 0xD5, 0xCF, 0xCB, 0xC5, 0xBF, 0xBC, 0xBD, 0xBF, 0xBB, 0xC3, 0xCC, 0xC8, 0xEF, 0x5B, 0x5D, -0x41, 0x3D, 0x3D, 0x37, 0x37, 0x38, 0x37, 0x38, 0x3B, 0x41, 0x43, 0x4E, 0x6B, 0x67, 0xDC, 0xCE, -0xD4, 0xC9, 0xC8, 0xCE, 0xCA, 0xCE, 0xD5, 0xD4, 0xD5, 0xD3, 0xCE, 0xC7, 0xC3, 0xBE, 0xBE, 0xC3, -0xBD, 0xC2, 0xD0, 0xC9, 0xDE, 0x57, 0x61, 0x47, 0x3D, 0x3F, 0x39, 0x36, 0x38, 0x38, 0x38, 0x3A, -0x41, 0x40, 0x48, 0x6A, 0x5C, 0xF7, 0xCD, 0xDB, 0xCD, 0xC6, 0xD1, 0xCC, 0xCC, 0xD6, 0xD5, 0xD3, -0xCF, 0xCE, 0xC6, 0xC0, 0xBF, 0xBE, 0xBF, 0xBE, 0xC0, 0xCC, 0xCB, 0xDB, 0x5D, 0x5B, 0x49, 0x3E, -0x3E, 0x39, 0x37, 0x38, 0x38, 0x38, 0x3B, 0x40, 0x42, 0x4A, 0x63, 0x66, 0xE5, 0xCE, 0xD0, 0xCA, -0xC7, 0xCA, 0xCA, 0xCC, 0xCE, 0xD1, 0xCF, 0xCC, 0xCC, 0xC4, 0xBF, 0xBF, 0xBE, 0xC0, 0xBE, 0xC2, -0xCE, 0xCC, 0xE2, 0x58, 0x59, 0x47, 0x3D, 0x3D, 0x39, 0x37, 0x39, 0x39, 0x39, 0x3C, 0x40, 0x44, -0x4D, 0x5D, 0x6F, 0xE0, 0xD4, 0xCF, 0xCC, 0xCB, 0xCB, 0xCD, 0xCF, 0xCF, 0xD4, 0xD1, 0xCC, 0xCA, -0xC4, 0xBF, 0xBD, 0xBF, 0xBF, 0xBE, 0xC7, 0xCF, 0xCE, 0x79, 0x52, 0x51, 0x41, 0x3C, 0x3B, 0x38, -0x36, 0x38, 0x39, 0x38, 0x3D, 0x44, 0x44, 0x55, 0x70, 0x76, 0xD5, 0xCF, 0xCF, 0xC9, 0xCB, 0xCB, -0xCD, 0xD1, 0xD1, 0xD9, 0xD2, 0xCD, 0xCD, 0xC4, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xC9, 0xCF, 0xD0, -0x6A, 0x53, 0x4F, 0x3F, 0x3C, 0x3B, 0x38, 0x37, 0x38, 0x39, 0x3A, 0x3E, 0x44, 0x4A, 0x56, 0x75, -0xE7, 0xD7, 0xCD, 0xCB, 0xCA, 0xC9, 0xCA, 0xCD, 0xCE, 0xCF, 0xD3, 0xCE, 0xCA, 0xC7, 0xC0, 0xBE, -0xBE, 0xBF, 0xBF, 0xC1, 0xCD, 0xD2, 0xDB, 0x5C, 0x4F, 0x4A, 0x3E, 0x3C, 0x3B, 0x39, 0x38, 0x3A, -0x3A, 0x3C, 0x43, 0x46, 0x4E, 0x71, 0x7A, 0xDD, 0xCE, 0xD0, 0xCB, 0xCA, 0xCD, 0xCC, 0xD1, 0xD2, -0xD5, 0xD7, 0xCC, 0xCC, 0xC7, 0xBE, 0xBF, 0xBF, 0xBE, 0xC0, 0xC6, 0xCD, 0xD5, 0xEE, 0x54, 0x4D, -0x45, 0x3C, 0x3B, 0x39, 0x37, 0x38, 0x39, 0x3A, 0x3E, 0x44, 0x4A, 0x59, 0x71, 0xE8, 0xD4, 0xCE, -0xCC, 0xC9, 0xCB, 0xCB, 0xCE, 0xD2, 0xD4, 0xD7, 0xD2, 0xCD, 0xCB, 0xC4, 0xBF, 0xBF, 0xC0, 0xC0, -0xC0, 0xC9, 0xD1, 0xD8, 0x73, 0x52, 0x4B, 0x42, 0x3C, 0x3A, 0x39, 0x38, 0x38, 0x39, 0x3C, 0x3F, -0x41, 0x4E, 0x5D, 0x63, 0xDF, 0xD3, 0xD1, 0xCD, 0xCB, 0xCC, 0xD1, 0xD1, 0xD3, 0xDE, 0xDA, 0xD1, -0xCF, 0xCC, 0xC4, 0xBF, 0xC2, 0xC2, 0xBF, 0xC6, 0xCD, 0xD2, 0xE3, 0x63, 0x4F, 0x4A, 0x42, 0x3C, -0x3B, 0x3A, 0x39, 0x3A, 0x3B, 0x3F, 0x42, 0x47, 0x5A, 0x62, 0x7C, 0xD5, 0xD2, 0xCF, 0xCC, 0xCD, -0xCE, 0xD5, 0xD6, 0xD9, 0xE0, 0xD9, 0xD2, 0xCE, 0xCB, 0xC4, 0xBF, 0xC2, 0xC2, 0xBF, 0xC6, 0xCD, -0xD4, 0xE2, 0x67, 0x4F, 0x4B, 0x43, 0x3D, 0x3C, 0x3B, 0x3B, 0x3B, 0x3C, 0x42, 0x43, 0x49, 0x60, -0x6B, 0xF5, 0xD4, 0xD2, 0xD0, 0xD2, 0xD2, 0xD4, 0xDF, 0xDD, 0xDF, 0xEA, 0xDC, 0xD5, 0xD0, 0xCB, -0xC4, 0xC0, 0xC2, 0xBF, 0xC0, 0xC7, 0xC9, 0xD0, 0xDD, 0x7A, 0x57, 0x52, 0x48, 0x3F, 0x3F, 0x3D, -0x3C, 0x3C, 0x3D, 0x42, 0x44, 0x49, 0x5B, 0x64, 0x7C, 0xDE, 0xDB, 0xDB, 0xDC, 0xDA, 0xDF, 0xEE, -0xE9, 0xE6, 0xE8, 0xE3, 0xDB, 0xD0, 0xCD, 0xCC, 0xC5, 0xC3, 0xC5, 0xC2, 0xC3, 0xC8, 0xCD, 0xD1, -0xDE, 0x6F, 0x5B, 0x50, 0x4A, 0x44, 0x40, 0x3F, 0x3E, 0x3E, 0x42, 0x43, 0x47, 0x4F, 0x58, 0x5F, -0x69, 0xF6, 0xED, 0xF7, 0xEB, 0xE8, 0xEA, 0xEC, 0xE8, 0xE0, 0xE0, 0xDD, 0xD7, 0xD0, 0xCE, 0xCC, -0xC8, 0xC7, 0xC6, 0xC4, 0xC8, 0xC9, 0xCB, 0xD2, 0xDA, 0xEF, 0x71, 0x5B, 0x4F, 0x4E, 0x49, 0x45, -0x46, 0x45, 0x47, 0x47, 0x4A, 0x4E, 0x4E, 0x54, 0x5A, 0x5D, 0x62, 0x65, 0x70, 0x6C, 0x69, 0xFA, -0x7A, 0x7A, 0xE6, 0xE2, 0xDF, 0xDA, 0xD5, 0xCF, 0xD1, 0xD1, 0xCB, 0xCE, 0xD4, 0xCE, 0xD1, 0xD9, -0xDB, 0xE0, 0xE1, 0xEE, 0x6A, 0x74, 0x6C, 0x5A, 0x5B, 0x5A, 0x56, 0x56, 0x53, 0x56, 0x57, 0x53, -0x57, 0x5B, 0x59, 0x59, 0x5D, 0x65, 0x60, 0x61, 0x6F, 0x73, 0xF7, 0xEF, 0xEA, 0xDD, 0xDF, 0xDC, -0xD5, 0xD8, 0xDC, 0xDC, 0xDA, 0xDF, 0xE5, 0xE1, 0xEB, 0xED, 0xED, 0xFC, 0xFF, 0x70, 0x6C, 0x6C, -0x66, 0x5F, 0x5F, 0x62, 0x5F, 0x60, 0x60, 0x5A, 0x5F, 0x64, 0x5C, 0x64, 0x6E, 0x5F, 0x5E, 0x69, -0x6B, 0x7B, 0xF0, 0xFA, 0xE9, 0xE4, 0xE8, 0xDF, 0xE6, 0xEB, 0xE1, 0xE2, 0xE6, 0xE3, 0xE8, 0xED, -0xE5, 0xFC, 0x71, 0xE9, 0xFE, 0x7A, 0xEC, 0x73, 0x7E, 0x77, 0x64, 0xFD, 0x74, 0x66, 0x7B, 0x6C, -0x6B, 0x72, 0x6A, 0x79, 0x73, 0x71, 0xF4, 0x79, 0xFC, 0xEF, 0xF9, 0xEB, 0xF1, 0xF0, 0xE2, 0xE3, -0xE0, 0xE2, 0xE3, 0xEB, 0xFC, 0xEA, 0xF8, 0x6F, 0x70, 0x69, 0x77, 0x6C, 0x6D, 0xEF, 0x6B, 0x67, -0x6D, 0x65, 0x76, 0x75, 0x6F, 0x7E, 0x69, 0x67, 0x6F, 0x68, 0x6F, 0x73, 0x68, 0x69, 0x68, 0x69, -0x75, 0xFA, 0xEE, 0xF2, 0xEA, 0xDE, 0xE2, 0xE7, 0xE5, 0xEB, 0xF3, 0xED, 0xE8, 0xF7, 0x7F, 0xFA, -0x74, 0x6A, 0x68, 0x65, 0x66, 0x68, 0x64, 0x65, 0x68, 0x64, 0x6D, 0x77, 0x72, 0x70, 0x69, 0x77, -0x78, 0x64, 0x6B, 0x68, 0x60, 0x66, 0x67, 0x67, 0x61, 0x6D, 0xEB, 0xE8, 0xEC, 0xEB, 0xEA, 0xF7, -0xF5, 0xE2, 0xE5, 0xF6, 0xF8, 0xF0, 0x7E, 0x77, 0xFA, 0x76, 0x77, 0x7D, 0x6E, 0x74, 0x74, 0x72, -0x72, 0x6D, 0x75, 0x74, 0x74, 0x75, 0x76, 0xEF, 0xEE, 0xEF, 0xEA, 0xFA, 0x7F, 0xF2, 0xF6, 0xF7, -0xEF, 0xEA, 0xE4, 0xE5, 0xE7, 0xE3, 0xE9, 0xEC, 0xE8, 0xEB, 0xF0, 0xF8, 0xFC, 0x7F, 0x73, 0x73, -0x70, 0x72, 0x75, 0x69, 0x67, 0x6A, 0x6C, 0x6D, 0x6C, 0x70, 0x6D, 0x6D, 0x78, 0x72, 0x6F, 0x6E, -0x6C, 0x6F, 0x77, 0xF7, 0xEF, 0xF1, 0xF6, 0xF4, 0xF1, 0xFC, 0xF8, 0xEE, 0xF0, 0xEE, 0xEF, 0xEF, -0xEC, 0xEE, 0xF3, 0xF4, 0x76, 0x69, 0x77, 0xFA, 0x70, 0x75, 0x7E, 0x6E, 0x6D, 0x6E, 0x6E, 0x6E, -0x6D, 0x70, 0x74, 0x79, 0xFE, 0x7D, 0x78, 0x7C, 0x7A, 0x75, 0x78, 0x75, 0x70, 0x7C, 0xFC, 0xFB, -0xF4, 0xF3, 0xED, 0xEC, 0xF6, 0xF1, 0xEF, 0xF6, 0xF0, 0xFB, 0x7A, 0x7C, 0x74, 0x79, 0x74, 0x6C, -0x6C, 0x63, 0x67, 0x6C, 0x62, 0x66, 0x67, 0x68, 0x6C, 0x6A, 0x7D, 0x78, 0x6B, 0x7B, 0x71, 0x75, -0xFB, 0x75, 0x76, 0x7E, 0xEE, 0xED, 0xFA, 0xE8, 0xEE, 0x7F, 0xE4, 0xE9, 0xED, 0xE1, 0xEC, 0xEE, -0xE6, 0xF6, 0xFE, 0xF7, 0xFF, 0x7B, 0x72, 0x7C, 0x7F, 0x6B, 0x6C, 0x66, 0x67, 0x71, 0x66, 0x72, -0xFF, 0x69, 0x7B, 0xF7, 0xFF, 0xF3, 0xF6, 0xF3, 0xF2, 0xEE, 0xED, 0xFF, 0xF6, 0xED, 0xFB, 0xF2, -0xE9, 0xF0, 0xEC, 0xE6, 0xF4, 0xF2, 0xF5, 0x7C, 0xED, 0x7E, 0x6B, 0x7B, 0x77, 0xFE, 0x7A, 0x69, -0x68, 0x60, 0x65, 0x66, 0x61, 0x71, 0x74, 0x74, 0xFC, 0x7E, 0xFA, 0xFF, 0x7E, 0xF9, 0xFB, 0xEE, -0xED, 0xEF, 0xEF, 0xF4, 0xEC, 0xEC, 0xF2, 0xF0, 0xEF, 0xED, 0xF4, 0xF6, 0xEF, 0xFD, 0xF8, 0xF1, -0x77, 0x74, 0x7A, 0x70, 0x6F, 0x79, 0x76, 0x6A, 0x68, 0x6C, 0x6C, 0x69, 0x65, 0x66, 0x6E, 0x73, -0x6C, 0x6D, 0x7A, 0x79, 0x7A, 0xFE, 0x73, 0x72, 0x7A, 0x7E, 0xF3, 0xEF, 0xEE, 0xF1, 0xF6, 0xEC, -0xEF, 0xFA, 0xEE, 0xF5, 0xFE, 0xF2, 0xF0, 0xF7, 0xFA, 0xF9, 0xFB, 0xFB, 0x7A, 0x6B, 0x6B, 0x72, -0x6C, 0x6A, 0x76, 0x74, 0x6E, 0x72, 0x6C, 0x6B, 0x6F, 0x6B, 0x6E, 0x71, 0x6D, 0x75, 0x76, 0x70, -0x78, 0x7C, 0xFA, 0xF2, 0xF7, 0xF1, 0xED, 0xF3, 0xF4, 0xF6, 0xFA, 0xF0, 0xEF, 0xFD, 0x7B, 0xFF, -0x78, 0x6C, 0x70, 0x72, 0x6E, 0x73, 0x6D, 0x6D, 0x6D, 0x65, 0x65, 0x69, 0x6F, 0x70, 0x6B, 0x6E, -0x71, 0x6E, 0x6E, 0x6F, 0x7A, 0x7D, 0x7E, 0xEF, 0xF4, 0x7D, 0xFB, 0xF3, 0xEC, 0xEB, 0xF0, 0xEF, -0xEE, 0xEE, 0xF3, 0xF0, 0xED, 0xFF, 0xFF, 0xF3, 0x7E, 0xFB, 0xFF, 0x73, 0x7E, 0x7A, 0x76, 0x6F, -0x6C, 0x7A, 0x74, 0x6F, 0xFF, 0x7B, 0x79, 0xF7, 0xF5, 0xFB, 0xF6, 0xF3, 0x7E, 0x7D, 0xFA, 0xFD, -0xF6, 0xF5, 0x7D, 0x7B, 0x7A, 0xFF, 0xFB, 0x7D, 0x75, 0x76, 0xF3, 0xF3, 0x78, 0xFE, 0x76, 0x6B, -0x7B, 0xFB, 0x75, 0x69, 0x6C, 0xF6, 0xF6, 0x7B, 0x6F, 0x69, 0x6E, 0x72, 0x70, 0x74, 0x78, 0xFF, -0x7F, 0xFD, 0xF5, 0xF8, 0xF5, 0xF9, 0x75, 0x74, 0x7D, 0xF7, 0xFB, 0x70, 0x7E, 0xE9, 0xEF, 0xF7, -0xE6, 0xED, 0x74, 0x7A, 0xF7, 0x7D, 0x71, 0x77, 0xFE, 0xF6, 0xFC, 0x6B, 0x6B, 0x72, 0x69, 0x6D, -0x7B, 0x7C, 0xFD, 0x6F, 0x6B, 0xFC, 0x7F, 0x73, 0xF9, 0xF5, 0x70, 0x6E, 0xFD, 0xFF, 0x7C, 0xFB, -0x70, 0x76, 0xEF, 0x7D, 0x75, 0xFB, 0xF6, 0xEF, 0xF6, 0x7C, 0x79, 0x76, 0xFE, 0x7D, 0x73, 0xFD, -0xFE, 0x76, 0x6E, 0x66, 0x6B, 0x75, 0x6D, 0x7D, 0xF2, 0x6D, 0x75, 0xED, 0x7A, 0x6D, 0x7E, 0xF9, -0xFE, 0x6E, 0x78, 0xF4, 0x6E, 0x73, 0xF8, 0x74, 0xFF, 0xFE, 0x77, 0xF6, 0x7C, 0x71, 0x7F, 0x7E, -0x7E, 0x79, 0x78, 0x7C, 0x6E, 0x6F, 0x70, 0x6D, 0xFD, 0xFA, 0x6C, 0x6B, 0x71, 0x70, 0x7B, 0x7A, -0x7C, 0xFD, 0x6D, 0x75, 0xED, 0xF8, 0xFC, 0xF7, 0xFB, 0xEE, 0xEF, 0x79, 0xFF, 0xED, 0xF8, 0x7A, -0xF1, 0xED, 0xF7, 0xFC, 0xF8, 0xF1, 0xF8, 0x79, 0x7D, 0xF6, 0x78, 0x6E, 0xFD, 0xFB, 0x72, 0x6E, -0x6C, 0x74, 0xFE, 0xFF, 0xF7, 0xFE, 0x6D, 0x75, 0x79, 0x6F, 0x7C, 0x7D, 0x76, 0x78, 0x7A, 0x7F, -0x75, 0x7D, 0xF7, 0xF8, 0xEF, 0x7B, 0x7A, 0xF3, 0xFF, 0xEF, 0xF8, 0xFE, 0xF6, 0x6E, 0xF4, 0xED, -0x6F, 0x7C, 0x74, 0x75, 0xF2, 0x7C, 0x75, 0xF9, 0xEE, 0xFF, 0x70, 0x7C, 0x7F, 0xFD, 0xFD, 0xFA, -0x79, 0x6C, 0x7C, 0x7F, 0xFD, 0xF3, 0x78, 0xFE, 0xF7, 0xFC, 0xED, 0xF1, 0xFD, 0xFE, 0x7D, 0xF4, -0xED, 0xF4, 0xFA, 0xFD, 0x70, 0x73, 0xF6, 0xFF, 0x7D, 0xF7, 0x79, 0x72, 0x78, 0x7D, 0x77, 0x6E, -0x71, 0x6C, 0x6A, 0x7D, 0x74, 0x71, 0x7D, 0x6E, 0x79, 0xF8, 0x70, 0x7C, 0xFE, 0x6D, 0x6F, 0x6E, -0x6D, 0x7D, 0xFD, 0xFB, 0xFA, 0x7C, 0xFD, 0xFA, 0xF7, 0xF4, 0xFD, 0x7B, 0x76, 0x7D, 0xF3, 0xF5, -0xFD, 0xF5, 0xED, 0x7A, 0x6D, 0xF5, 0x7C, 0x76, 0xEF, 0x77, 0x6E, 0xFF, 0x74, 0x79, 0xFD, 0x76, -0x7A, 0x7E, 0x7B, 0x7D, 0x78, 0x73, 0x7A, 0xFB, 0xFB, 0x7E, 0xFB, 0xF2, 0xF8, 0xF9, 0xFB, 0xFE, -0xF5, 0xF6, 0xF9, 0x7E, 0x73, 0xF7, 0xFA, 0x74, 0xFC, 0x7B, 0x70, 0xFF, 0xFC, 0x7E, 0x7C, 0xFE, -0xFF, 0x7C, 0xFC, 0x7E, 0x79, 0xFF, 0x7C, 0x79, 0x79, 0x79, 0x7A, 0x79, 0x7A, 0x7C, 0x7A, 0x75, -0x72, 0x7C, 0xFC, 0xFE, 0xFE, 0xFC, 0xF9, 0xFE, 0xFE, 0xFA, 0x7C, 0xFD, 0xFC, 0x77, 0x7B, 0x7A, -0x73, 0x78, 0x7A, 0x78, 0x7B, 0x77, 0x6E, 0x70, 0x7B, 0x7A, 0x72, 0x74, 0x76, 0x75, 0x77, 0x75, -0x70, 0x6F, 0x6F, 0x6F, 0x74, 0x77, 0x72, 0x6F, 0x70, 0x79, 0x79, 0x6F, 0x7E, 0xFA, 0x72, 0x79, -0x79, 0x78, 0xFE, 0x78, 0xFF, 0xFE, 0x76, 0xFF, 0xFF, 0x7D, 0xFF, 0x7E, 0x7B, 0x78, 0x7C, 0x75, -0x75, 0xFF, 0xFF, 0xF8, 0xF6, 0xFD, 0xF5, 0xF4, 0xF6, 0xFC, 0x7C, 0x7C, 0x7B, 0xFC, 0xFD, 0xFD, -0xFD, 0x77, 0x7A, 0x7F, 0x7E, 0xFC, 0xFA, 0xF7, 0xFF, 0xFE, 0xF1, 0xFD, 0xFD, 0xF0, 0xF9, 0xF8, -0xEE, 0xEF, 0xF8, 0x7E, 0x79, 0x77, 0x6C, 0x66, 0x6A, 0x68, 0x67, 0x71, 0x74, 0x77, 0x7E, 0x7B, -0xFD, 0xFD, 0x7F, 0xFF, 0x79, 0xFE, 0xFE, 0x75, 0x78, 0x7A, 0x74, 0x70, 0x76, 0x77, 0x75, 0x7C, -0x7C, 0x79, 0x78, 0x77, 0x78, 0x7C, 0x7E, 0x77, 0x74, 0x79, 0x77, 0x78, 0x78, 0x77, 0x7B, 0x78, -0x77, 0x77, 0x7A, 0xFE, 0x7D, 0xFE, 0xF6, 0xFB, 0xFC, 0xF8, 0xF6, 0xFA, 0xFD, 0xFB, 0xFC, 0x7D, -0x7B, 0xFB, 0xF5, 0xFC, 0xFF, 0xFD, 0xFE, 0xFF, 0x7F, 0xFC, 0xF8, 0xFF, 0x7F, 0xF7, 0xF9, 0xFA, -0xF9, 0xFB, 0xFA, 0xFA, 0xFA, 0xF8, 0xF8, 0xFD, 0x7E, 0xF8, 0xF7, 0xEF, 0xE0, 0xE1, 0xF7, 0x6E, -0x69, 0x65, 0x5C, 0x5B, 0x61, 0x69, 0x6E, 0x76, 0xF8, 0xEF, 0xF2, 0xEB, 0xE3, 0xDE, 0xE2, 0xFA, -0x66, 0x5B, 0x5F, 0x6E, 0x6E, 0xFB, 0xED, 0xED, 0xEC, 0xF8, 0x7E, 0x7B, 0x6E, 0x67, 0x60, 0x65, -0x6E, 0x6F, 0x78, 0xFB, 0x7E, 0x7D, 0xFA, 0xF9, 0xF7, 0xF5, 0xF7, 0xEE, 0xEB, 0xF3, 0xFA, 0x7A, -0x6D, 0x69, 0x6A, 0x69, 0x64, 0x69, 0x6E, 0x6F, 0x78, 0xFB, 0xFB, 0x7C, 0xF8, 0xF1, 0xFB, 0xF4, -0xF9, 0x7D, 0xF8, 0x7D, 0xFD, 0xF3, 0x7C, 0xFD, 0xF4, 0x7A, 0x6F, 0x79, 0xFF, 0x75, 0x78, 0xFA, -0xFB, 0xFE, 0xFB, 0xF9, 0xFE, 0xFF, 0xFF, 0xFC, 0xF5, 0xFD, 0x79, 0xFF, 0xF9, 0xFA, 0xFF, 0xFF, -0x7B, 0x74, 0x75, 0x6F, 0x71, 0x7D, 0x74, 0x75, 0x79, 0x71, 0x77, 0x7E, 0x7E, 0x7C, 0x74, 0x71, -0x77, 0x7A, 0x7F, 0xFB, 0x72, 0x69, 0x74, 0x74, 0x6A, 0x74, 0x7E, 0x79, 0x76, 0x74, 0x7F, 0x7C, -0x76, 0xF8, 0xF8, 0x7E, 0x7D, 0x7E, 0xFE, 0x77, 0x7B, 0xF8, 0x7B, 0xFF, 0xF3, 0xFC, 0xFF, 0xFE, -0xFD, 0xF5, 0xF6, 0xF3, 0xF2, 0xFA, 0xF8, 0xF3, 0xFB, 0x7E, 0xFA, 0xFA, 0x7E, 0xFE, 0xFC, 0x7C, -0x78, 0x7D, 0xFB, 0xF3, 0xFD, 0x74, 0xF7, 0xF5, 0x76, 0xF9, 0xF8, 0xFF, 0xF5, 0x76, 0x7B, 0xFA, -0x77, 0xFD, 0x7C, 0x77, 0x7D, 0x6F, 0x7D, 0xF7, 0xFC, 0xFD, 0x7B, 0xF5, 0xF8, 0x7A, 0xF4, 0xFB, -0x77, 0x7B, 0x76, 0x74, 0x7D, 0x7E, 0x72, 0x71, 0x70, 0x70, 0x77, 0x70, 0x7B, 0xFD, 0x6F, 0x72, -0x7D, 0x7A, 0x71, 0x79, 0xF8, 0x77, 0x6F, 0x74, 0x7A, 0x78, 0x7C, 0xF6, 0x7C, 0xFB, 0x7D, 0x6C, -0xEF, 0xFC, 0x6D, 0xF1, 0xF5, 0x7D, 0x79, 0xFA, 0xF5, 0x75, 0xF4, 0x7C, 0xFC, 0xE6, 0x68, 0x78, -0xE4, 0x6E, 0x77, 0xF2, 0x7E, 0x70, 0x69, 0xF9, 0xF7, 0x6C, 0x74, 0xF3, 0xEE, 0x79, 0x7E, 0xFB, -0x7A, 0xF6, 0x6C, 0x6B, 0xED, 0x77, 0x6A, 0x70, 0x6F, 0xFC, 0x7E, 0x79, 0xF2, 0xEE, 0xF8, 0x7D, -0xEF, 0xEB, 0x7E, 0x72, 0x7D, 0x74, 0x6B, 0xFA, 0xE5, 0xE7, 0xE4, 0xEB, 0xF8, 0xEC, 0xEA, 0xF3, -0xFB, 0xFA, 0xEF, 0xF6, 0x7C, 0xFF, 0x7B, 0x72, 0x78, 0x7C, 0x6F, 0x6E, 0xFF, 0xFF, 0x75, 0x74, -0x74, 0x76, 0x6C, 0x6A, 0x7F, 0x78, 0x6D, 0x74, 0x6E, 0x76, 0x7B, 0x69, 0x6B, 0x79, 0x72, 0x6A, -0x6D, 0x77, 0xFD, 0xFC, 0x6F, 0x7C, 0xEE, 0x76, 0x69, 0x74, 0xFB, 0x74, 0x6A, 0x7D, 0xF0, 0xFF, -0x6B, 0x71, 0xEF, 0x7D, 0x74, 0xF8, 0x75, 0x74, 0x77, 0x6C, 0x6E, 0x71, 0x73, 0x72, 0x70, 0xF4, -0xF0, 0x79, 0x7B, 0xFB, 0xF3, 0xF4, 0x78, 0x79, 0xF7, 0xFC, 0x6E, 0x70, 0xF8, 0xF8, 0x79, 0x6D, -0x70, 0xFB, 0x6E, 0x64, 0x6B, 0x72, 0x6F, 0x65, 0x71, 0xFC, 0x71, 0x76, 0x6E, 0x71, 0xF9, 0xFF, -0xFD, 0x73, 0x7A, 0xFF, 0x66, 0x70, 0xFE, 0x79, 0xFD, 0x7D, 0xF1, 0xF6, 0x76, 0x79, 0x6D, 0x79, -0xFF, 0x72, 0x7F, 0xF8, 0xF0, 0xFF, 0x71, 0xEC, 0xE9, 0x7C, 0x7C, 0xF1, 0xF7, 0xF7, 0xF5, 0xFA, -0xF1, 0x7C, 0x70, 0x7D, 0xFB, 0xF4, 0x7C, 0x7D, 0xF6, 0xFD, 0xEF, 0xF6, 0xEE, 0xE1, 0xEE, 0xF4, -0xF3, 0xEE, 0xF4, 0x78, 0xEC, 0xF7, 0x72, 0x74, 0x6E, 0xF5, 0x6A, 0x7B, 0xDF, 0x69, 0x7F, 0xE7, -0x6F, 0x7C, 0x68, 0xF4, 0xEE, 0x5C, 0x72, 0x6B, 0x6D, 0xEC, 0x60, 0x7E, 0xEB, 0x66, 0x6D, 0x6A, -0x7A, 0xFF, 0x6A, 0x6E, 0x74, 0xED, 0x79, 0x6B, 0xED, 0xFA, 0xFC, 0x70, 0x65, 0xF6, 0x75, 0x67, -0x78, 0x78, 0xF4, 0xFF, 0x5F, 0xF9, 0xE3, 0x6D, 0xF1, 0x7A, 0x70, 0xDB, 0x6A, 0xF9, 0xDC, 0x66, -0xDB, 0xF8, 0x65, 0xD6, 0x6A, 0xF2, 0xE6, 0x5E, 0xE1, 0x76, 0x6F, 0xF5, 0x65, 0xEF, 0x5F, 0x66, -0x6F, 0x5A, 0xFB, 0x5E, 0x65, 0x7E, 0x60, 0xF2, 0x5D, 0x72, 0xE8, 0x5A, 0xEA, 0x6E, 0x62, 0xE4, -0x5E, 0x6F, 0x74, 0x67, 0xEA, 0x64, 0x77, 0xF3, 0x69, 0xF1, 0x6B, 0x6E, 0xEB, 0x74, 0x74, 0x74, -0xF6, 0xF5, 0x66, 0xF5, 0xF7, 0x6C, 0xE9, 0x70, 0x6F, 0xE4, 0x6E, 0xF0, 0xF4, 0x63, 0xE1, 0xFE, -0x6D, 0xE4, 0x6D, 0xF2, 0xEF, 0x6C, 0xE8, 0x7B, 0xFC, 0xED, 0x74, 0xEB, 0xFE, 0xFC, 0xEF, 0x6D, -0xEC, 0xFB, 0x71, 0xEB, 0x77, 0xF3, 0xF8, 0x6F, 0xE9, 0xFE, 0xFC, 0xEE, 0x6F, 0xEB, 0xED, 0x7A, -0xEE, 0xF4, 0xF3, 0xF8, 0xF1, 0xEE, 0x79, 0xF4, 0xF3, 0xFC, 0xF1, 0x7C, 0xF4, 0xF9, 0x76, 0xE8, -0xF8, 0x75, 0xE3, 0x7B, 0x6E, 0xE0, 0x75, 0x72, 0xE3, 0x6C, 0xF8, 0xE7, 0x6D, 0xEA, 0xF4, 0x75, -0xEA, 0x71, 0xFA, 0xED, 0x6A, 0xF2, 0xFB, 0x70, 0xEB, 0x6F, 0x71, 0xEE, 0x6C, 0xF6, 0xF2, 0x68, -0xF3, 0xF8, 0x6D, 0x7A, 0xFC, 0x75, 0x6D, 0xF3, 0x6E, 0x6E, 0xEE, 0x61, 0x7C, 0xFE, 0x60, 0xF2, -0x6D, 0x78, 0x7C, 0x63, 0xEB, 0x64, 0x71, 0xED, 0x5C, 0xEB, 0x6F, 0x69, 0xEA, 0x5D, 0xE7, 0xF8, -0x5E, 0xE6, 0x6F, 0xFA, 0x79, 0x72, 0xE8, 0x5E, 0xE9, 0xFB, 0x5F, 0xDE, 0x61, 0xFA, 0xE3, 0x5A, -0xE3, 0x79, 0x62, 0xDF, 0x64, 0x76, 0xE4, 0x63, 0xFE, 0xE9, 0x64, 0xF8, 0xE6, 0x5F, 0xF2, 0xE8, -0x62, 0xE7, 0xFB, 0x6A, 0xF0, 0x77, 0xF9, 0x77, 0xE9, 0x78, 0x59, 0xE3, 0x71, 0x6C, 0xDF, 0x5F, -0xEF, 0xE9, 0x5F, 0xFA, 0x76, 0xF9, 0x7D, 0x67, 0xEE, 0x7B, 0x6F, 0x7E, 0x6B, 0x6D, 0xF7, 0x6E, -0x6B, 0xF0, 0x63, 0xF0, 0x75, 0x57, 0xD4, 0x59, 0x57, 0xCD, 0x4F, 0xEE, 0xDE, 0x4B, 0xCF, 0x68, -0x5B, 0xD4, 0x50, 0xE0, 0xEF, 0x54, 0xD5, 0x57, 0x6A, 0xD3, 0x54, 0x79, 0xDF, 0x5E, 0xFC, 0xE6, -0x5F, 0x71, 0xE0, 0x64, 0x76, 0xFC, 0x5D, 0xEA, 0xF8, 0x58, 0x79, 0xDB, 0x68, 0x59, 0xDF, 0x76, -0x64, 0xDA, 0x63, 0x5A, 0xD9, 0xE0, 0x51, 0xF3, 0xD3, 0x4D, 0xDE, 0xCF, 0x3F, 0xDA, 0xC2, 0x41, -0x6A, 0xC3, 0x50, 0x55, 0xC6, 0x5A, 0x4B, 0xC2, 0x7A, 0x46, 0xCA, 0xDF, 0x4C, 0xD8, 0xDE, 0x4F, -0xE2, 0xD2, 0x4D, 0x6B, 0xCD, 0x5C, 0x56, 0xD8, 0xEB, 0x54, 0xEF, 0xDE, 0x4F, 0x78, 0xD7, 0x54, -0x5B, 0xDA, 0xFA, 0x56, 0xF6, 0xE9, 0x58, 0xF1, 0xE5, 0x59, 0x6D, 0xE8, 0x7B, 0x64, 0x7E, 0xE2, -0x60, 0x6D, 0xDC, 0x63, 0x67, 0xDC, 0x6F, 0x62, 0xE2, 0x7B, 0x60, 0xEC, 0xF3, 0x67, 0x77, 0xF1, -0x7C, 0x75, 0xF0, 0x79, 0x6F, 0xED, 0x76, 0x6B, 0xF3, 0xFF, 0x74, 0xF4, 0xF8, 0x6B, 0x6C, 0xE6, -0xE7, 0x61, 0x79, 0xDD, 0x6F, 0x77, 0xDE, 0x6D, 0x6E, 0xE4, 0x7E, 0xF9, 0xE8, 0x6D, 0x6F, 0xDE, -0xEF, 0x5C, 0xEF, 0xDB, 0x64, 0x6B, 0xDF, 0xF9, 0x6C, 0xF4, 0xF5, 0x72, 0xF5, 0xF7, 0x66, 0x7D, -0xE9, 0x7D, 0x70, 0x79, 0xF6, 0x7B, 0x6C, 0xF3, 0xF2, 0x6A, 0x76, 0xED, 0x79, 0x6B, 0xF2, 0xF1, -0x6B, 0x78, 0xEF, 0x73, 0x74, 0xED, 0x73, 0x6A, 0xEB, 0xF2, 0x64, 0x6F, 0xE2, 0xF8, 0x5E, 0xF3, -0xE8, 0x64, 0x74, 0xEF, 0x7B, 0x77, 0x74, 0x78, 0x6D, 0xF8, 0xEA, 0x63, 0x68, 0xEC, 0xEF, 0x6E, -0x63, 0xEE, 0xFA, 0x5F, 0xE5, 0xEB, 0x58, 0x73, 0xD1, 0xF3, 0x4D, 0xF2, 0xCD, 0x5D, 0x54, 0xDF, -0xDD, 0x61, 0x5B, 0xD9, 0xDF, 0x50, 0xF0, 0xD3, 0x5F, 0x5D, 0xE4, 0xDF, 0x6E, 0x5B, 0xED, 0xD8, -0x68, 0x56, 0xEA, 0xD3, 0x70, 0x52, 0xF0, 0xD3, 0x74, 0x57, 0xF5, 0xD8, 0x6A, 0x58, 0xE4, 0xE2, -0x5C, 0x7A, 0xD8, 0x77, 0x5A, 0xE8, 0xD9, 0x73, 0x5F, 0x7D, 0xE3, 0xEC, 0x73, 0x72, 0x6E, 0xF6, -0xDF, 0xF7, 0x62, 0x6B, 0xE5, 0xDD, 0x6B, 0x58, 0xF7, 0xDB, 0x73, 0x5E, 0x75, 0x7E, 0xF6, 0xFE, -0x66, 0x71, 0x7B, 0x7E, 0xEE, 0x6C, 0x6B, 0xEB, 0x76, 0x6C, 0xEA, 0x7A, 0x67, 0xE5, 0xE8, 0x5F, -0x75, 0xDE, 0xEE, 0x6F, 0x7A, 0xED, 0xE8, 0xF8, 0xFB, 0xF4, 0x78, 0xF1, 0xE4, 0x6E, 0x62, 0xEB, -0xEC, 0x65, 0x6D, 0x7E, 0x6B, 0x69, 0x6E, 0x72, 0x78, 0x68, 0x5E, 0x74, 0xE9, 0x6F, 0x5E, 0x72, -0xEB, 0x7A, 0x6F, 0xF1, 0x78, 0x75, 0xE5, 0xE6, 0xE2, 0xDD, 0xE0, 0xD6, 0xD1, 0xD5, 0xD1, 0xD3, -0xDE, 0xE0, 0xDD, 0xE9, 0x68, 0x57, 0x52, 0x50, 0x4B, 0x48, 0x48, 0x48, 0x48, 0x4B, 0x51, 0x56, -0x56, 0x5D, 0x68, 0x6A, 0x69, 0x7C, 0xE8, 0xED, 0xED, 0xDC, 0xD5, 0xCD, 0xCB, 0xCD, 0xC5, 0xBE, -0xBE, 0xBC, 0xBC, 0xBF, 0xC5, 0xD2, 0x72, 0x52, 0x48, 0x40, 0x3C, 0x39, 0x39, 0x3B, 0x3D, 0x40, -0x4A, 0x5A, 0x6C, 0x7E, 0xDF, 0xCF, 0xCE, 0xDB, 0x6F, 0x63, 0x6E, 0x60, 0x4D, 0x47, 0x4D, 0x5E, -0x7C, 0xFA, 0xE4, 0xCD, 0xC1, 0xBD, 0xBC, 0xBA, 0xB7, 0xB4, 0xB5, 0xBE, 0xD7, 0xEB, 0xF2, 0x4E, -0x3B, 0x36, 0x37, 0x39, 0x38, 0x39, 0x3D, 0x48, 0x58, 0xFE, 0xDA, 0xD6, 0xD8, 0xCF, 0xC8, 0xCD, -0xF3, 0x5A, 0x59, 0x58, 0x4E, 0x47, 0x48, 0x4F, 0x5F, 0xF2, 0xD9, 0xCE, 0xC6, 0xBF, 0xBB, 0xBA, -0xB9, 0xB7, 0xB5, 0xB7, 0xC0, 0xD9, 0x68, 0x57, 0x49, 0x3B, 0x35, 0x35, 0x38, 0x3A, 0x3B, 0x3F, -0x4B, 0x60, 0xE7, 0xD8, 0xD5, 0xD4, 0xCE, 0xCA, 0xCF, 0xF9, 0x59, 0x51, 0x4E, 0x4C, 0x48, 0x46, -0x49, 0x56, 0xFB, 0xD9, 0xD1, 0xC9, 0xBE, 0xB8, 0xB6, 0xB5, 0xB3, 0xB2, 0xB6, 0xC3, 0xE5, 0x60, -0x4E, 0x3F, 0x37, 0x32, 0x34, 0x37, 0x39, 0x3C, 0x41, 0x4E, 0x6F, 0xDA, 0xD2, 0xD4, 0xD1, 0xCA, -0xC9, 0xD7, 0x6F, 0x59, 0x4D, 0x47, 0x47, 0x48, 0x45, 0x46, 0x52, 0xEE, 0xD7, 0xD0, 0xC7, 0xBC, -0xB5, 0xB3, 0xB3, 0xB1, 0xB0, 0xB7, 0xCA, 0x68, 0x4F, 0x45, 0x3B, 0x32, 0x2E, 0x30, 0x35, 0x39, -0x3D, 0x44, 0x52, 0xEC, 0xD0, 0xCF, 0xD3, 0xD0, 0xCD, 0xCF, 0xE3, 0x63, 0x5B, 0x59, 0x52, 0x4D, -0x4C, 0x4F, 0x5A, 0x6D, 0xE5, 0xD2, 0xC8, 0xBE, 0xB9, 0xB5, 0xB3, 0xB1, 0xAF, 0xB1, 0xBD, 0xE3, -0x53, 0x4B, 0x40, 0x35, 0x2E, 0x2F, 0x34, 0x39, 0x3B, 0x3F, 0x4C, 0x75, 0xDA, 0xD6, 0xD2, 0xCE, -0xCE, 0xD0, 0xD9, 0xEF, 0x62, 0x56, 0x55, 0x55, 0x4F, 0x4E, 0x52, 0x61, 0xEF, 0xDB, 0xCC, 0xBF, -0xB9, 0xB5, 0xB3, 0xB0, 0xAE, 0xB4, 0xC8, 0x63, 0x4D, 0x45, 0x39, 0x2E, 0x2C, 0x2F, 0x35, 0x38, -0x3B, 0x43, 0x5A, 0xDD, 0xCE, 0xCD, 0xCC, 0xCB, 0xCD, 0xD2, 0xDE, 0x76, 0x5A, 0x52, 0x53, 0x51, -0x4E, 0x4F, 0x5C, 0x7C, 0xE2, 0xD2, 0xC5, 0xBB, 0xB5, 0xB2, 0xB0, 0xAE, 0xAE, 0xB6, 0xCF, 0x55, -0x48, 0x3F, 0x34, 0x2C, 0x2C, 0x2F, 0x36, 0x39, 0x3D, 0x4A, 0x7D, 0xCE, 0xCA, 0xCB, 0xCB, 0xCB, -0xCD, 0xD9, 0x76, 0x59, 0x4F, 0x4C, 0x4C, 0x4A, 0x4C, 0x54, 0x68, 0xEC, 0xD8, 0xCB, 0xBF, 0xB8, -0xB3, 0xB0, 0xAE, 0xAD, 0xAE, 0xBC, 0xF5, 0x4C, 0x43, 0x39, 0x2E, 0x2A, 0x2D, 0x32, 0x37, 0x3B, -0x44, 0x5F, 0xD5, 0xC8, 0xC7, 0xC9, 0xCB, 0xCE, 0xD3, 0xE9, 0x5A, 0x4D, 0x4D, 0x4D, 0x4B, 0x4B, -0x50, 0x63, 0xF6, 0xDE, 0xCE, 0xC5, 0xBD, 0xB7, 0xB2, 0xB0, 0xAF, 0xAD, 0xAF, 0xBF, 0x5E, 0x45, -0x40, 0x37, 0x2C, 0x29, 0x2D, 0x34, 0x38, 0x3C, 0x48, 0x77, 0xCD, 0xC6, 0xC7, 0xCB, 0xCB, 0xCF, -0xE9, 0x59, 0x4E, 0x4B, 0x47, 0x44, 0x47, 0x4D, 0x57, 0x69, 0xEB, 0xD7, 0xCA, 0xBF, 0xB9, 0xB3, -0xAF, 0xAE, 0xAD, 0xAC, 0xB5, 0xDE, 0x49, 0x43, 0x3B, 0x2D, 0x28, 0x2A, 0x30, 0x36, 0x3A, 0x44, -0x6A, 0xCD, 0xC2, 0xC2, 0xC6, 0xCA, 0xCC, 0xD8, 0x60, 0x4C, 0x48, 0x46, 0x44, 0x43, 0x49, 0x54, -0x68, 0xEC, 0xD8, 0xCB, 0xC2, 0xBC, 0xB8, 0xB2, 0xAF, 0xAE, 0xAE, 0xAE, 0xBA, 0x74, 0x45, 0x3F, -0x36, 0x2C, 0x29, 0x2C, 0x32, 0x37, 0x3E, 0x4E, 0xE3, 0xC7, 0xC2, 0xC5, 0xC6, 0xC8, 0xD2, 0x71, -0x52, 0x4D, 0x49, 0x42, 0x41, 0x47, 0x51, 0x60, 0x7B, 0xDE, 0xCE, 0xC6, 0xC0, 0xBE, 0xB9, 0xB2, -0xAF, 0xAF, 0xAE, 0xAE, 0xBC, 0x6B, 0x47, 0x3F, 0x34, 0x2C, 0x2A, 0x2D, 0x32, 0x39, 0x3F, 0x4F, -0xDF, 0xC5, 0xC4, 0xCD, 0xCA, 0xC7, 0xDB, 0x5A, 0x4E, 0x4D, 0x48, 0x42, 0x40, 0x45, 0x54, 0x6F, -0x74, 0xEC, 0xCD, 0xC4, 0xC4, 0xC1, 0xBB, 0xB3, 0xAF, 0xB0, 0xAE, 0xAE, 0xBC, 0x6F, 0x4A, 0x3F, -0x34, 0x2C, 0x2B, 0x2E, 0x34, 0x3B, 0x42, 0x56, 0xCF, 0xBF, 0xC2, 0xCB, 0xC6, 0xC6, 0xE6, 0x52, -0x4B, 0x47, 0x45, 0x3F, 0x3D, 0x45, 0x5E, 0x7A, 0x72, 0xDB, 0xC7, 0xC3, 0xC5, 0xC2, 0xBC, 0xB5, -0xB1, 0xB3, 0xB0, 0xAE, 0xB9, 0xF0, 0x4C, 0x43, 0x38, 0x2E, 0x2B, 0x2D, 0x34, 0x3A, 0x3E, 0x4F, -0xD3, 0xC1, 0xC4, 0xCD, 0xCC, 0xC8, 0xDE, 0x4D, 0x45, 0x47, 0x47, 0x41, 0x3D, 0x47, 0x6D, 0xF7, -0x79, 0xDA, 0xC9, 0xC6, 0xC8, 0xC9, 0xC0, 0xB8, 0xB4, 0xB5, 0xB0, 0xAC, 0xB1, 0xCF, 0x5A, 0x4E, -0x3E, 0x30, 0x2B, 0x2D, 0x33, 0x38, 0x3B, 0x48, 0xDC, 0xC4, 0xC5, 0xCA, 0xCB, 0xCB, 0xD9, 0x50, -0x46, 0x4B, 0x46, 0x3E, 0x3F, 0x48, 0x55, 0x76, 0x7E, 0xE3, 0xCA, 0xC9, 0xCE, 0xCB, 0xC6, 0xBE, -0xBA, 0xB8, 0xB4, 0xAE, 0xAE, 0xBD, 0xEA, 0x62, 0x48, 0x35, 0x2D, 0x2C, 0x30, 0x35, 0x37, 0x3F, -0x6F, 0xCB, 0xCA, 0xC9, 0xC7, 0xCE, 0xD9, 0x60, 0x46, 0x46, 0x48, 0x40, 0x40, 0x49, 0x52, 0x69, -0xED, 0xE1, 0xD1, 0xCC, 0xD0, 0xD2, 0xD0, 0xCD, 0xC2, 0xBD, 0xB9, 0xB2, 0xAE, 0xAF, 0xBA, 0xE0, -0x67, 0x4C, 0x34, 0x2D, 0x2E, 0x30, 0x34, 0x37, 0x41, 0xF4, 0xCD, 0xCC, 0xC7, 0xC5, 0xD0, 0xED, -0x64, 0x4D, 0x45, 0x47, 0x43, 0x44, 0x4F, 0x51, 0x69, 0xD9, 0xDD, 0xD1, 0xCB, 0xD1, 0xCF, 0xD2, -0xCD, 0xBF, 0xBC, 0xB8, 0xB0, 0xAD, 0xAE, 0xBC, 0xD9, 0x76, 0x48, 0x32, 0x2D, 0x2F, 0x30, 0x32, -0x38, 0x49, 0xE6, 0xD1, 0xCB, 0xC1, 0xC1, 0xD2, 0x7A, 0x6F, 0x51, 0x42, 0x43, 0x45, 0x4A, 0x4D, -0x4E, 0x72, 0xD7, 0xDB, 0xD8, 0xCE, 0xCF, 0xD7, 0xDD, 0xD3, 0xC6, 0xBF, 0xBB, 0xB3, 0xAD, 0xAE, -0xB8, 0xCD, 0xE2, 0x52, 0x35, 0x2E, 0x2F, 0x2F, 0x2F, 0x35, 0x43, 0x62, 0xE5, 0xCF, 0xC1, 0xC0, -0xD1, 0xE1, 0xDB, 0x5E, 0x46, 0x49, 0x4D, 0x4A, 0x49, 0x51, 0x6A, 0xEE, 0xEB, 0xDE, 0xD0, 0xD4, -0xDF, 0xDC, 0xD7, 0xCF, 0xC5, 0xBE, 0xB7, 0xB1, 0xAE, 0xAF, 0xBC, 0xD3, 0xE7, 0x48, 0x31, 0x2E, -0x2F, 0x2E, 0x2F, 0x36, 0x44, 0x5B, 0xF4, 0xCC, 0xBF, 0xC2, 0xD4, 0xD1, 0xCF, 0x59, 0x4B, 0x51, -0x4B, 0x46, 0x44, 0x4C, 0x56, 0x51, 0x66, 0xE5, 0xE6, 0xE0, 0xDF, 0xD6, 0xD1, 0xCD, 0xC0, 0xBB, -0xB7, 0xB0, 0xAD, 0xB0, 0xBD, 0xCE, 0xEF, 0x44, 0x31, 0x2F, 0x30, 0x2E, 0x2E, 0x39, 0x46, 0x56, -0xF0, 0xC7, 0xBD, 0xC2, 0xC9, 0xC8, 0xCC, 0x7A, 0x50, 0x57, 0x4F, 0x42, 0x42, 0x4A, 0x4C, 0x4C, -0x5D, 0xEF, 0xEE, 0xE3, 0xD6, 0xD1, 0xD2, 0xCC, 0xC0, 0xBC, 0xBA, 0xB3, 0xAE, 0xAF, 0xBA, 0xC9, -0xD6, 0x4F, 0x36, 0x30, 0x30, 0x2E, 0x2D, 0x34, 0x3E, 0x45, 0x5C, 0xCF, 0xC1, 0xC0, 0xC1, 0xC0, -0xC9, 0xD9, 0xF5, 0x54, 0x4A, 0x47, 0x40, 0x41, 0x42, 0x45, 0x4E, 0x53, 0x68, 0xE8, 0xE1, 0xD1, -0xCD, 0xCC, 0xC5, 0xBF, 0xBB, 0xB8, 0xB4, 0xAF, 0xB0, 0xBD, 0xCB, 0xD8, 0x4B, 0x36, 0x34, 0x33, -0x2E, 0x2E, 0x37, 0x3D, 0x44, 0x62, 0xCD, 0xC4, 0xC0, 0xBE, 0xBF, 0xC5, 0xCF, 0xEE, 0x66, 0x4F, -0x45, 0x43, 0x40, 0x41, 0x44, 0x47, 0x51, 0x5B, 0x71, 0xDD, 0xD8, 0xCE, 0xC8, 0xC6, 0xC1, 0xBD, -0xB9, 0xB7, 0xB2, 0xAF, 0xB9, 0xC3, 0xCC, 0x71, 0x40, 0x37, 0x36, 0x31, 0x2E, 0x33, 0x3A, 0x3D, -0x4A, 0xE6, 0xCF, 0xC7, 0xBE, 0xBF, 0xC2, 0xCA, 0xD3, 0xE6, 0x50, 0x4C, 0x4B, 0x3E, 0x3E, 0x43, -0x41, 0x47, 0x4D, 0x59, 0x75, 0xE4, 0xD0, 0xCC, 0xC9, 0xC3, 0xBF, 0xBD, 0xBB, 0xB8, 0xB3, 0xB3, -0xBB, 0xC3, 0xCD, 0x6A, 0x42, 0x3A, 0x38, 0x31, 0x30, 0x36, 0x39, 0x3C, 0x4B, 0x7A, 0xDB, 0xCB, -0xC1, 0xC3, 0xC5, 0xC5, 0xD5, 0xE5, 0x6B, 0x4E, 0x4C, 0x43, 0x40, 0x45, 0x42, 0x48, 0x50, 0x55, -0x6C, 0xE8, 0xD7, 0xCD, 0xCC, 0xC7, 0xC3, 0xC0, 0xBD, 0xBC, 0xB8, 0xB2, 0xB5, 0xBD, 0xC2, 0xD0, -0x5D, 0x45, 0x3C, 0x38, 0x32, 0x32, 0x37, 0x37, 0x3C, 0x4C, 0x5E, 0xEE, 0xCD, 0xC5, 0xC8, 0xC6, -0xC5, 0xD0, 0xE2, 0xF9, 0x5D, 0x4D, 0x47, 0x46, 0x42, 0x41, 0x47, 0x4B, 0x4E, 0x63, 0xEA, 0xE3, -0xD3, 0xC9, 0xCB, 0xC8, 0xC0, 0xBF, 0xBD, 0xBA, 0xB5, 0xB6, 0xBC, 0xC1, 0xCC, 0x7E, 0x4B, 0x3F, -0x3B, 0x35, 0x32, 0x37, 0x37, 0x3A, 0x45, 0x50, 0x6D, 0xD7, 0xC8, 0xC6, 0xC7, 0xC2, 0xCA, 0xD7, -0xDB, 0x6D, 0x59, 0x4F, 0x48, 0x48, 0x45, 0x46, 0x4D, 0x4F, 0x5E, 0xFF, 0xE6, 0xD7, 0xD4, 0xCF, -0xD1, 0xD5, 0xD0, 0xD3, 0xCD, 0xC6, 0xC1, 0xBA, 0xB8, 0xBB, 0xC2, 0xC4, 0xCD, 0x58, 0x4C, 0x48, -0x39, 0x36, 0x39, 0x36, 0x37, 0x3E, 0x44, 0x4B, 0x66, 0xDC, 0xD4, 0xCA, 0xC3, 0xC5, 0xC7, 0xCA, -0xCE, 0xDD, 0x6D, 0x5F, 0x4F, 0x46, 0x47, 0x46, 0x43, 0x49, 0x4E, 0x53, 0x65, 0xF1, 0xE4, 0xD9, -0xCF, 0xCE, 0xCD, 0xC6, 0xC3, 0xC0, 0xBA, 0xB7, 0xB7, 0xBD, 0xC4, 0xC5, 0xFD, 0x4A, 0x4C, 0x3B, -0x33, 0x37, 0x34, 0x32, 0x3A, 0x3F, 0x47, 0x5B, 0xDC, 0xCB, 0xC8, 0xBE, 0xBC, 0xC3, 0xC0, 0xC7, -0xDE, 0xEC, 0x5B, 0x49, 0x45, 0x3F, 0x3E, 0x3F, 0x40, 0x49, 0x4E, 0x5B, 0xEF, 0xDF, 0xD4, 0xCC, -0xCA, 0xC7, 0xC5, 0xC3, 0xBF, 0xBD, 0xBB, 0xB8, 0xB8, 0xC0, 0xCB, 0xCA, 0x68, 0x45, 0x4D, 0x3D, -0x35, 0x3C, 0x3A, 0x38, 0x41, 0x49, 0x4D, 0x69, 0xDB, 0xD3, 0xCD, 0xC5, 0xC6, 0xCC, 0xCB, 0xD0, -0xEB, 0x76, 0x5C, 0x4C, 0x48, 0x44, 0x41, 0x41, 0x44, 0x49, 0x4E, 0x5D, 0x7E, 0xE6, 0xD4, 0xCE, -0xCE, 0xCB, 0xCB, 0xCE, 0xCE, 0xCA, 0xC9, 0xC6, 0xBE, 0xBC, 0xC6, 0xCA, 0xC4, 0xE0, 0x58, 0x77, -0x4A, 0x3D, 0x45, 0x3D, 0x39, 0x3F, 0x41, 0x40, 0x4C, 0x61, 0x6D, 0xE7, 0xCE, 0xCC, 0xCC, 0xC9, -0xCA, 0xD1, 0xDB, 0xE2, 0x66, 0x54, 0x50, 0x48, 0x45, 0x47, 0x47, 0x4B, 0x51, 0x5A, 0x71, 0xEB, -0xDD, 0xD5, 0xD2, 0xCF, 0xCC, 0xCC, 0xCA, 0xC4, 0xC3, 0xBF, 0xB9, 0xBD, 0xCB, 0xC0, 0xC9, 0x56, -0x71, 0x5A, 0x3A, 0x3F, 0x3E, 0x34, 0x3A, 0x3E, 0x3C, 0x42, 0x54, 0x62, 0x73, 0xCF, 0xC8, 0xCC, -0xC3, 0xC3, 0xCD, 0xCF, 0xDD, 0x6D, 0x56, 0x4D, 0x48, 0x42, 0x42, 0x44, 0x45, 0x4D, 0x57, 0x61, -0xED, 0xDB, 0xD5, 0xCD, 0xCD, 0xCD, 0xCD, 0xD0, 0xCD, 0xD1, 0xCA, 0xC4, 0xC7, 0xBA, 0xC2, 0xD8, -0xBB, 0xD7, 0x53, 0xCC, 0x4E, 0x3E, 0x57, 0x3E, 0x3B, 0x43, 0x3F, 0x3E, 0x46, 0x52, 0x50, 0x60, -0xD6, 0xD9, 0xD4, 0xC6, 0xCA, 0xCF, 0xCB, 0xD5, 0xF4, 0xFB, 0x5D, 0x4E, 0x4C, 0x4B, 0x46, 0x45, -0x4F, 0x4E, 0x4D, 0x7E, 0x6F, 0x71, 0xD4, 0xE1, 0xDF, 0xCE, 0xD9, 0xD5, 0xCD, 0xCD, 0xC5, 0xBF, -0xB9, 0xBA, 0xC6, 0xBA, 0xBF, 0x6C, 0xCE, 0xFB, 0x3D, 0x4D, 0x40, 0x35, 0x3C, 0x3B, 0x38, 0x3E, -0x47, 0x4B, 0x52, 0xDF, 0xD8, 0xD6, 0xC3, 0xC6, 0xCB, 0xC5, 0xCD, 0xDD, 0xE4, 0x6B, 0x50, 0x4D, -0x49, 0x44, 0x45, 0x47, 0x48, 0x49, 0x50, 0x5D, 0x5C, 0xEE, 0xDD, 0xE7, 0xD1, 0xD5, 0xDC, 0xD0, -0xDA, 0xD8, 0xD1, 0xCD, 0xC6, 0xBF, 0xBA, 0xC1, 0xC4, 0xBA, 0xD3, 0xE1, 0xCC, 0x4D, 0x49, 0x4F, -0x3B, 0x3B, 0x3E, 0x3A, 0x3C, 0x42, 0x4A, 0x4C, 0x6D, 0xD9, 0xDC, 0xC9, 0xC4, 0xCA, 0xC6, 0xC8, -0xD0, 0xD8, 0xE5, 0x68, 0x58, 0x53, 0x4C, 0x4A, 0x4B, 0x4C, 0x4E, 0x56, 0x5F, 0x69, 0xEA, 0xE0, -0xE8, 0xD5, 0xDD, 0xE7, 0xD9, 0xFB, 0xF9, 0xF5, 0x64, 0x75, 0x6D, 0xF5, 0xE5, 0xD8, 0xC8, 0xC4, -0xBB, 0xBF, 0xC4, 0xB7, 0xCC, 0xD6, 0xC3, 0x56, 0x52, 0x5F, 0x3D, 0x3E, 0x3E, 0x39, 0x3A, 0x3D, -0x41, 0x41, 0x4F, 0x6B, 0x63, 0xD6, 0xCD, 0xD1, 0xC7, 0xC8, 0xCE, 0xCE, 0xD6, 0xE8, 0x71, 0x67, -0x55, 0x4F, 0x52, 0x4D, 0x4F, 0x56, 0x56, 0x5E, 0x6D, 0x7E, 0xF5, 0xDF, 0xE3, 0xEE, 0xDC, 0x7B, -0x73, 0xED, 0x5C, 0x6A, 0x69, 0x5B, 0x70, 0x6D, 0xEF, 0xE1, 0xCF, 0xC8, 0xC4, 0xB9, 0xC5, 0xC2, -0xB6, 0xDC, 0xCD, 0xC3, 0x49, 0x60, 0x57, 0x3A, 0x40, 0x3D, 0x38, 0x3A, 0x3E, 0x3F, 0x3E, 0x53, -0x58, 0x59, 0xD3, 0xD7, 0xD2, 0xC4, 0xC9, 0xCA, 0xC8, 0xCD, 0xD8, 0xDE, 0xEE, 0x5F, 0x5D, 0x59, -0x4F, 0x54, 0x56, 0x54, 0x5D, 0x69, 0x6D, 0xF2, 0xE1, 0xDF, 0xDB, 0xD8, 0xDD, 0xE8, 0xEB, 0x71, -0x5D, 0x66, 0x56, 0x52, 0x62, 0x52, 0x5C, 0x74, 0x63, 0xE2, 0xDD, 0xD4, 0xCA, 0xC9, 0xBF, 0xC0, -0xBB, 0xBB, 0xCC, 0xBB, 0xC8, 0x68, 0xC8, 0x58, 0x44, 0x5D, 0x3C, 0x3B, 0x40, 0x3A, 0x3B, 0x3F, -0x44, 0x43, 0x52, 0x7A, 0x62, 0xD4, 0xCB, 0xD1, 0xC3, 0xC4, 0xC8, 0xC5, 0xCA, 0xD0, 0xD9, 0xE1, -0x6C, 0x5C, 0x5B, 0x4E, 0x4D, 0x50, 0x4C, 0x50, 0x58, 0x58, 0x63, 0x79, 0xFE, 0xED, 0xE1, 0xE7, -0xEE, 0xE6, 0xFB, 0x6D, 0x7A, 0x61, 0x5D, 0x62, 0x59, 0x5B, 0x5E, 0x5C, 0x64, 0x69, 0x72, 0xFE, -0xF1, 0xE6, 0xE2, 0xDB, 0xD9, 0xD6, 0xD3, 0xD3, 0xD0, 0xD0, 0xCF, 0xCE, 0xCD, 0xCD, 0xDA, 0xDB, -0xDA, 0x64, 0x69, 0x63, 0x4C, 0x4F, 0x4D, 0x46, 0x4A, 0x4A, 0x48, 0x4D, 0x52, 0x52, 0x5C, 0x70, -0x71, 0xEB, 0xDC, 0xDE, 0xD7, 0xD4, 0xD8, 0xD5, 0xD7, 0xDD, 0xDF, 0xE7, 0xFD, 0x71, 0x69, 0x5D, -0x5A, 0x5A, 0x57, 0x56, 0x5B, 0x59, 0x5A, 0x69, 0x62, 0x6A, 0xF5, 0x73, 0xF1, 0xE7, 0xF4, 0xE6, -0xE6, 0xEE, 0xEA, 0xED, 0xF5, 0xF1, 0xED, 0xF0, 0xEA, 0xE4, 0xE7, 0xDF, 0xDE, 0xDF, 0xDC, 0xDE, -0xDF, 0xE1, 0xE8, 0xEE, 0xFD, 0x77, 0x6B, 0x64, 0x61, 0x5C, 0x5C, 0x5C, 0x5B, 0x5F, 0x61, 0x67, -0x6E, 0x78, 0xF8, 0xF1, 0xEA, 0xE5, 0xE4, 0xE2, 0xE1, 0xE5, 0xEA, 0xED, 0xFA, 0x77, 0x6E, 0x66, -0x62, 0x5D, 0x5C, 0x5A, 0x59, 0x59, 0x59, 0x5B, 0x5C, 0x5D, 0x64, 0x64, 0x6C, 0x77, 0x7C, 0xEE, -0xEB, 0xE0, 0xDB, 0xD7, 0xCF, 0xCF, 0xCA, 0xC8, 0xC5, 0xC4, 0xCD, 0xC7, 0xCB, 0xE8, 0xD3, 0xFD, -0x55, 0x67, 0x4B, 0x45, 0x48, 0x40, 0x3F, 0x42, 0x43, 0x43, 0x4A, 0x50, 0x50, 0x6C, 0xF5, 0xF2, -0xD4, 0xD2, 0xD1, 0xCB, 0xCC, 0xCE, 0xCE, 0xD0, 0xDA, 0xDC, 0xDF, 0xFD, 0x7D, 0x6F, 0x5E, 0x5F, -0x5D, 0x59, 0x5A, 0x5C, 0x5C, 0x5F, 0x68, 0x68, 0x6F, 0xFC, 0xFC, 0xEF, 0xE9, 0xEB, 0xE9, 0xE9, -0xED, 0xEF, 0xF2, 0xF8, 0xFE, 0xFE, 0x7C, 0x7C, 0x7E, 0x79, 0xFE, 0xFB, 0xFE, 0xF7, 0xF6, 0xF9, -0xF6, 0xF8, 0xFD, 0xFF, 0x7C, 0x73, 0x70, 0x6E, 0x6A, 0x6A, 0x69, 0x68, 0x6A, 0x6B, 0x6C, 0x6F, -0x74, 0x79, 0xFF, 0xFA, 0xF8, 0xF2, 0xF4, 0xF6, 0xF3, 0xFE, 0xFB, 0x74, 0x62, 0x69, 0x5F, 0x5A, -0x66, 0x5B, 0x5D, 0x70, 0x61, 0x78, 0xED, 0xF4, 0xDB, 0xD7, 0xD0, 0xCB, 0xC9, 0xC3, 0xCC, 0xC9, -0xC4, 0xDD, 0xD2, 0xD7, 0x59, 0x6E, 0x57, 0x45, 0x4B, 0x45, 0x3F, 0x43, 0x44, 0x43, 0x49, 0x51, -0x4F, 0x5E, 0xFB, 0x70, 0xDE, 0xD8, 0xDC, 0xD1, 0xD2, 0xD7, 0xD4, 0xD6, 0xDD, 0xDF, 0xDF, 0xF1, -0xF2, 0xF2, 0x6F, 0x73, 0x72, 0x69, 0x6D, 0x6F, 0x6D, 0x72, 0x7B, 0x79, 0x7E, 0xF8, 0xFD, 0xF9, -0xF6, 0xFD, 0xFA, 0xFA, 0xFD, 0xFB, 0xFB, 0xFD, 0xFA, 0xF6, 0xF8, 0xF3, 0xF2, 0xF4, 0xEF, 0xF1, -0xF4, 0xF2, 0xF6, 0xF9, 0xF8, 0xF9, 0xFD, 0xFD, 0xFC, 0x7F, 0x7E, 0x7D, 0x79, 0x76, 0x74, 0x71, -0x6F, 0x6E, 0x6C, 0x6C, 0x6D, 0x6B, 0x6C, 0x6D, 0x6C, 0x71, 0x71, 0x70, 0x7E, 0x79, 0x7C, 0xFA, -0x7B, 0xFD, 0xFC, 0x7A, 0xFE, 0x7C, 0x78, 0x7B, 0x76, 0x76, 0x78, 0x77, 0x77, 0x7C, 0x7E, 0xFF, -0xF2, 0xF3, 0xED, 0xE7, 0xE8, 0xE0, 0xDE, 0xDC, 0xD7, 0xD8, 0xD3, 0xD4, 0xDA, 0xD7, 0xDF, 0xEB, -0xED, 0x6A, 0x60, 0x5C, 0x52, 0x4F, 0x4D, 0x4B, 0x4A, 0x4B, 0x4B, 0x4D, 0x50, 0x54, 0x5B, 0x66, -0x6F, 0xF1, 0xE6, 0xDF, 0xDA, 0xD8, 0xD8, 0xD7, 0xD9, 0xDB, 0xDE, 0xE2, 0xEA, 0xF1, 0xFA, 0x78, -0x70, 0x6D, 0x69, 0x68, 0x66, 0x65, 0x65, 0x66, 0x66, 0x67, 0x6A, 0x6B, 0x6C, 0x70, 0x74, 0x79, -0xFB, 0xF5, 0xEF, 0xEB, 0xE9, 0xE6, 0xE3, 0xE2, 0xE1, 0xE0, 0xE0, 0xE0, 0xE1, 0xE3, 0xE3, 0xE6, -0xE9, 0xEB, 0xEF, 0xF7, 0x7F, 0x75, 0x6E, 0x6A, 0x66, 0x62, 0x61, 0x5F, 0x5F, 0x60, 0x5F, 0x62, -0x65, 0x66, 0x6C, 0x6E, 0x72, 0x7D, 0xFE, 0xF6, 0xEF, 0xED, 0xE9, 0xE7, 0xE4, 0xE3, 0xE0, 0xDF, -0xE1, 0xDF, 0xE1, 0xE3, 0xE3, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xED, 0xF5, 0xF6, 0xF9, 0x75, -0x76, 0x6E, 0x66, 0x65, 0x5E, 0x5B, 0x5A, 0x56, 0x55, 0x54, 0x53, 0x54, 0x55, 0x57, 0x59, 0x5D, -0x60, 0x66, 0x70, 0x79, 0xFA, 0xF0, 0xEE, 0xEC, 0xED, 0xED, 0xF0, 0xF5, 0xF8, 0xFF, 0xFD, 0x7E, -0x7D, 0xFE, 0x7E, 0xFD, 0xF8, 0xF6, 0xEF, 0xED, 0xEB, 0xE8, 0xE4, 0xE3, 0xE0, 0xDF, 0xDE, 0xDC, -0xDD, 0xDC, 0xDD, 0xE1, 0xE2, 0xE9, 0xF3, 0x7A, 0x65, 0x61, 0x5B, 0x56, 0x56, 0x51, 0x50, 0x52, -0x50, 0x55, 0x58, 0x59, 0x5F, 0x68, 0x70, 0xFC, 0xEE, 0xE9, 0xE4, 0xE1, 0xE4, 0xE4, 0xE7, 0xED, -0xEE, 0xF8, 0xFF, 0x7D, 0x76, 0x76, 0x7A, 0x7B, 0xFF, 0xF9, 0xF7, 0xF1, 0xED, 0xED, 0xEB, 0xE9, -0xEA, 0xEA, 0xEC, 0xED, 0xEE, 0xF0, 0xF1, 0xF2, 0xF2, 0xF3, 0xF0, 0xF1, 0xF3, 0xEF, 0xF3, 0xF5, -0xF4, 0xFB, 0xFC, 0xFC, 0x7C, 0x7A, 0x76, 0x70, 0x6F, 0x6F, 0x6C, 0x6C, 0x6C, 0x68, 0x6B, 0x6B, -0x68, 0x6D, 0x6B, 0x6B, 0x6F, 0x6E, 0x70, 0x77, 0x76, 0x7A, 0x7F, 0xFF, 0xFD, 0xF6, 0xF7, 0xF5, -0xEF, 0xF4, 0xF1, 0xEF, 0xF2, 0xEE, 0xF0, 0xF1, 0xEE, 0xF0, 0xF1, 0xF1, 0xF2, 0xF6, 0xF9, 0xFA, -0x7F, 0x7E, 0x7A, 0x76, 0x7A, 0x73, 0x72, 0x74, 0x6F, 0x73, 0x75, 0x73, 0x75, 0x74, 0x76, 0x73, -0x77, 0x7A, 0x76, 0x7E, 0x78, 0x76, 0x7E, 0x76, 0x7A, 0x79, 0x74, 0x7D, 0x77, 0x77, 0x79, 0x74, -0x76, 0x77, 0x7A, 0x79, 0x7C, 0xFF, 0x79, 0xFC, 0xFA, 0x7E, 0xF4, 0xF9, 0xFC, 0xF6, 0x7E, 0xFF, -0xFF, 0x7B, 0x7C, 0x77, 0x75, 0x76, 0x78, 0x76, 0x74, 0x7B, 0x74, 0x75, 0x7E, 0x74, 0x7B, 0x7C, -0x72, 0x7A, 0x77, 0x74, 0x7A, 0x75, 0x72, 0x73, 0x72, 0x6E, 0x6E, 0x70, 0x6D, 0x70, 0x71, 0x6E, -0x75, 0x73, 0x72, 0x79, 0x78, 0x7B, 0xFF, 0xFF, 0xFD, 0xFA, 0xFC, 0xFB, 0xF7, 0xFD, 0xFE, 0xFA, -0x7D, 0x7D, 0xFE, 0x79, 0x7B, 0x7C, 0x7B, 0x7E, 0x7E, 0xFD, 0xFA, 0xFA, 0xF7, 0xF8, 0xF9, 0xF9, -0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x7D, 0x7B, 0x77, 0x78, 0x74, 0x71, 0x74, 0x6F, 0x6F, 0x71, 0x6D, -0x6F, 0x71, 0x6F, 0x73, 0x74, 0x77, 0x7B, 0x7D, 0x7F, 0xFF, 0xFC, 0xFE, 0xFB, 0xF8, 0xFB, 0xF7, -0xF9, 0xFE, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0x7E, 0x7C, 0x7E, 0x7B, 0x7B, 0x7E, 0x7C, 0xFF, 0xFE, -0xFE, 0xFB, 0xFE, 0xFF, 0xFD, 0xFE, 0x7E, 0x7F, 0x7A, 0x78, 0x79, 0x75, 0x74, 0x75, 0x73, 0x75, -0x77, 0x77, 0x79, 0x7B, 0x7D, 0xFF, 0xFA, 0xF8, 0xF4, 0xF2, 0xF5, 0xF1, 0xF2, 0xF6, 0xF3, 0xF6, -0xFA, 0xFB, 0xFC, 0x7D, 0x7A, 0x7A, 0x74, 0x77, 0x78, 0x74, 0x7A, 0x77, 0x7A, 0xFF, 0x7F, 0xF9, -0xFB, 0xFB, 0xF9, 0xFF, 0x7F, 0x7C, 0x7A, 0x77, 0x72, 0x73, 0x6E, 0x6E, 0x6E, 0x6D, 0x70, 0x70, -0x75, 0x7D, 0x7B, 0xFE, 0xFD, 0xFF, 0xFC, 0xFF, 0x7E, 0xFF, 0x7E, 0x7A, 0x79, 0x76, 0x6F, 0x72, -0x72, 0x6F, 0x73, 0x6F, 0x6E, 0x74, 0x72, 0x74, 0x7C, 0x7C, 0xFF, 0xF9, 0xFA, 0xF9, 0xF5, 0xF7, -0xF7, 0xF5, 0xFA, 0xFA, 0xF7, 0xFA, 0xF9, 0xF8, 0xFC, 0xF9, 0xF8, 0xFA, 0xF6, 0xF9, 0xFC, 0xFA, -0xFD, 0xFE, 0xFD, 0xFF, 0x7E, 0x7E, 0x7D, 0x7A, 0x7C, 0x7B, 0x79, 0x7C, 0x7B, 0x7B, 0xFF, 0x7E, -0xFF, 0xFC, 0xFE, 0xFE, 0xFB, 0xFD, 0x7C, 0x7F, 0x7F, 0x76, 0x78, 0x78, 0x74, 0x78, 0x78, 0x78, -0x7B, 0x7A, 0x7A, 0x79, 0x77, 0x78, 0x79, 0x78, 0x7A, 0x7B, 0x7A, 0x7C, 0x7F, 0x7D, 0xFF, 0xFC, -0xFD, 0xFA, 0xFB, 0xFD, 0xFE, 0xFF, 0x7F, 0x7D, 0x7C, 0x7A, 0x7B, 0x7D, 0x7D, 0x7E, 0x7E, 0x7D, -0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7F, 0xFF, 0xFE, 0xFC, 0xFC, 0xFB, -0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFB, 0xFB, 0xFD, 0xFF, 0x7D, 0x7B, 0x7B, 0x7A, 0x77, 0x77, 0x78, -0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7B, 0x7D, 0x7E, 0xFF, 0xFE, 0xFE, 0xFD, 0xFC, 0xFC, 0xFC, 0xFC, -0xFE, 0xFF, 0xFF, 0x7E, 0x7B, 0x78, 0x77, 0x76, 0x74, 0x73, 0x73, 0x71, 0x72, 0x73, 0x73, 0x74, -0x75, 0x76, 0x77, 0x77, 0x78, 0x78, 0x7A, 0x7D, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0x7F, 0x7E, 0x7D, 0x7D, 0x7C, 0x7A, 0x79, 0x79, 0x78, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7A, -0x79, 0x7B, 0x7B, 0x7B, 0x7C, 0x7A, 0x7A, 0x79, 0x78, 0x78, 0x76, 0x76, 0x75, 0x73, 0x73, 0x73, -0x74, 0x77, 0x79, 0x7A, 0x7D, 0x7F, 0xFE, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFF, -0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4C, 0x49, 0x53, 0x54, 0x4A, 0x00, -0x00, 0x00, 0x49, 0x4E, 0x46, 0x4F, 0x49, 0x53, 0x46, 0x54, 0x3E, 0x00, 0x00, 0x00, 0x46, 0x69, -0x6C, 0x65, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x6F, -0x6C, 0x64, 0x57, 0x61, 0x76, 0x65, 0x2E, 0x20, 0x20, 0x47, 0x6F, 0x6C, 0x64, 0x57, 0x61, 0x76, -0x65, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, -0x43, 0x68, 0x72, 0x69, 0x73, 0x20, 0x43, 0x72, 0x61, 0x69, 0x67, 0x00 - -}; - -static const uint8_t shaun_png[] PROGMEM = { - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x57, 0x08, 0x06, 0x00, 0x00, 0x00, 0xF2, 0x0C, 0xE0, - 0x57, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0, - 0xBD, 0xA7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x42, 0x8A, 0x00, - 0x00, 0x42, 0x8A, 0x01, 0x34, 0xA8, 0x6C, 0x25, 0x00, 0x00, 0x00, 0x09, 0x76, 0x70, 0x41, 0x67, - 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x57, 0x00, 0x73, 0x4D, 0x3B, 0xD6, 0x00, 0x00, 0x1B, - 0x47, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0xED, 0x9D, 0x79, 0x74, 0x14, 0x55, 0xBE, 0xC7, 0x3F, - 0x55, 0xDD, 0x49, 0x67, 0x5F, 0x3A, 0x7B, 0x42, 0x82, 0x61, 0x49, 0x02, 0x81, 0xB0, 0x29, 0x32, - 0x22, 0x3C, 0x16, 0x41, 0x45, 0x10, 0x15, 0x7D, 0x13, 0x65, 0xD0, 0x81, 0xE3, 0x7B, 0xCC, 0xD3, - 0x51, 0x04, 0xF5, 0xE1, 0xB8, 0xCE, 0xE6, 0x28, 0x22, 0x23, 0x33, 0x2C, 0x2A, 0x22, 0xEE, 0x02, - 0x22, 0x0C, 0x2A, 0x83, 0x28, 0x7B, 0x20, 0xC8, 0x92, 0x10, 0xD9, 0x97, 0x40, 0x08, 0x81, 0x90, - 0x3D, 0x64, 0x21, 0xE9, 0x4E, 0x3A, 0x5D, 0xF7, 0xFD, 0x71, 0xBB, 0x93, 0x0E, 0x10, 0xD2, 0x59, - 0x3A, 0x01, 0xCF, 0xFB, 0x9E, 0xD3, 0xE7, 0xA4, 0x6E, 0xA5, 0x6E, 0xDD, 0xFA, 0xFD, 0xEA, 0xFE, - 0xEE, 0xEF, 0xFE, 0xB6, 0x52, 0xB8, 0xFE, 0xA1, 0x03, 0x7A, 0x01, 0x43, 0x81, 0x9B, 0x80, 0x6A, - 0x60, 0x3F, 0xA0, 0x02, 0x8F, 0x00, 0xB7, 0x03, 0xA1, 0x80, 0x00, 0x72, 0x81, 0xAD, 0xC0, 0xC7, - 0xC0, 0x6E, 0xA0, 0xAE, 0xB3, 0x07, 0xFF, 0x4B, 0x43, 0x30, 0xF0, 0x67, 0x20, 0x1B, 0xB0, 0x20, - 0x89, 0xAE, 0x01, 0x95, 0x40, 0xB9, 0xED, 0xF8, 0x6A, 0xBF, 0x3C, 0xDB, 0x75, 0x81, 0xCD, 0xF4, - 0xAF, 0x03, 0x8C, 0x40, 0x2C, 0xD0, 0x13, 0x88, 0x00, 0x0C, 0x9D, 0xF9, 0xC0, 0x4A, 0x27, 0xDD, - 0xD7, 0x13, 0x88, 0x07, 0xFA, 0x03, 0x51, 0x36, 0x22, 0xE4, 0x03, 0x87, 0x80, 0x83, 0x48, 0x62, - 0x1B, 0x81, 0x85, 0x40, 0x72, 0x2B, 0xC7, 0xA9, 0x01, 0x5F, 0x00, 0x2F, 0x03, 0x35, 0xB6, 0xE3, - 0x0A, 0xDB, 0xDF, 0xDE, 0xC0, 0x48, 0x60, 0x22, 0x30, 0x08, 0xC9, 0x78, 0x3D, 0x92, 0xD1, 0x99, - 0xC0, 0x0F, 0xC0, 0x5A, 0xE0, 0x5C, 0x47, 0x13, 0xA6, 0xA3, 0x19, 0xA2, 0x07, 0x46, 0x00, 0x4F, - 0x22, 0x45, 0x4D, 0xD0, 0x65, 0x63, 0xB8, 0x84, 0x14, 0x47, 0xEF, 0x03, 0x09, 0xC0, 0x4B, 0x48, - 0xD1, 0x44, 0x40, 0x40, 0x00, 0x31, 0x31, 0x31, 0x54, 0x56, 0x56, 0x92, 0x93, 0x93, 0x83, 0xD5, - 0x6A, 0x25, 0x3A, 0x3A, 0x9A, 0x89, 0x13, 0x27, 0x32, 0x60, 0xC0, 0x00, 0xAC, 0x56, 0x2B, 0xBB, - 0x77, 0xEF, 0x66, 0xDD, 0xBA, 0x75, 0x14, 0x16, 0x16, 0xDA, 0xFB, 0xAB, 0x03, 0x4E, 0x23, 0x67, - 0x4D, 0x9D, 0x8D, 0xC0, 0xFB, 0x90, 0x22, 0xF0, 0x1E, 0xC0, 0xAB, 0x89, 0x71, 0x6A, 0xC0, 0x11, - 0xE0, 0x0D, 0xE0, 0x6B, 0xE4, 0xEC, 0xFC, 0xC5, 0xC1, 0x07, 0x78, 0x0D, 0x28, 0xA5, 0x69, 0x51, - 0x63, 0xFF, 0x99, 0x80, 0x2A, 0xFB, 0xF1, 0xC0, 0x81, 0x03, 0xC5, 0xA6, 0x4D, 0x9B, 0x44, 0x49, - 0x49, 0x89, 0xC8, 0xCA, 0xCA, 0x12, 0xAF, 0xBF, 0xFE, 0xBA, 0x78, 0xFC, 0xF1, 0xC7, 0x45, 0x5A, - 0x5A, 0x9A, 0xD0, 0x34, 0x4D, 0xD8, 0x51, 0x57, 0x57, 0x27, 0xB6, 0x6E, 0xDD, 0x2A, 0xFA, 0xF7, - 0xEF, 0xDF, 0x5C, 0xFF, 0x8D, 0x7E, 0x8A, 0xA2, 0x08, 0x55, 0x55, 0xAF, 0x76, 0xAE, 0x02, 0x78, - 0x0E, 0xF9, 0x22, 0x75, 0x08, 0x3A, 0x6A, 0x86, 0x78, 0x02, 0x7F, 0x05, 0x9E, 0x02, 0xDC, 0x00, - 0x14, 0x45, 0x21, 0x24, 0x24, 0x84, 0xE8, 0xE8, 0x68, 0xDC, 0xDD, 0xDD, 0xB9, 0x70, 0xE1, 0x02, - 0xB9, 0xB9, 0xB9, 0xD4, 0xD5, 0x35, 0x5E, 0x87, 0xBD, 0xBC, 0xBC, 0x58, 0xB1, 0x62, 0x05, 0x13, - 0x26, 0x4C, 0xA8, 0x6F, 0x13, 0x42, 0x20, 0x84, 0x40, 0x55, 0xD5, 0xAB, 0xDE, 0x6C, 0xD7, 0xAE, - 0x5D, 0x3C, 0xFC, 0xF0, 0xC3, 0xE4, 0xE4, 0xE4, 0x34, 0xFD, 0xE0, 0x8A, 0x42, 0x7C, 0x7C, 0x3C, - 0xF7, 0xDC, 0x73, 0x0F, 0xFD, 0xFA, 0xF5, 0xC3, 0xC3, 0xC3, 0x83, 0xEC, 0xEC, 0x6C, 0x36, 0x6C, - 0xD8, 0x40, 0x6A, 0x6A, 0x2A, 0x35, 0x35, 0x35, 0xF6, 0x7F, 0xAD, 0xB4, 0x8D, 0xFB, 0x73, 0xC0, - 0xDA, 0x41, 0xF4, 0x72, 0x39, 0x7E, 0x8F, 0x7C, 0xEB, 0x05, 0x20, 0xC2, 0xC2, 0xC2, 0xC4, 0x2B, - 0xAF, 0xBC, 0x22, 0x0E, 0x1E, 0x3C, 0x28, 0x2E, 0x5E, 0xBC, 0x28, 0x2A, 0x2A, 0x2A, 0x44, 0x56, - 0x56, 0x96, 0x58, 0xBC, 0x78, 0xB1, 0x48, 0x48, 0x48, 0x68, 0xF4, 0x96, 0xC6, 0xC4, 0xC4, 0x88, - 0x33, 0x67, 0xCE, 0x88, 0x96, 0xE2, 0xE3, 0x8F, 0x3F, 0x16, 0x77, 0xDE, 0x79, 0xA7, 0x78, 0xFE, - 0xF9, 0xE7, 0xC5, 0xBB, 0xEF, 0xBE, 0x2B, 0xDE, 0x7E, 0xFB, 0x6D, 0xF1, 0xE0, 0x83, 0x0F, 0x0A, - 0xA3, 0xD1, 0x28, 0xDC, 0xDC, 0xDC, 0xC4, 0xD4, 0xA9, 0x53, 0xC5, 0xE9, 0xD3, 0xA7, 0xAF, 0xB8, - 0xAE, 0xA2, 0xA2, 0x42, 0x2C, 0x58, 0xB0, 0x40, 0x04, 0x07, 0x07, 0x3B, 0x8E, 0xA3, 0x00, 0x58, - 0x0D, 0xFC, 0x0E, 0x08, 0xEF, 0x6C, 0x62, 0xB6, 0x15, 0x7D, 0x80, 0x33, 0xF6, 0x87, 0x8B, 0x8D, - 0x8D, 0x15, 0xEB, 0xD7, 0xAF, 0x6F, 0x24, 0x6A, 0x1C, 0x91, 0x91, 0x91, 0x21, 0x06, 0x0F, 0x1E, - 0x2C, 0x00, 0x61, 0x30, 0x18, 0xC4, 0xAF, 0x7F, 0xFD, 0x6B, 0x51, 0x51, 0x51, 0xD1, 0x62, 0x86, - 0x58, 0xAD, 0x56, 0x61, 0x36, 0x9B, 0x1B, 0xDD, 0xA7, 0xA6, 0xA6, 0x46, 0xEC, 0xD8, 0xB1, 0x43, - 0xAC, 0x5A, 0xB5, 0x4A, 0x94, 0x97, 0x97, 0x37, 0x79, 0xAD, 0xA6, 0x69, 0x62, 0xF1, 0xE2, 0xC5, - 0xC2, 0xC3, 0xC3, 0xE3, 0x72, 0x11, 0x66, 0x05, 0x76, 0x02, 0x43, 0x3A, 0x9B, 0xA8, 0x6D, 0xC1, - 0xDB, 0xF6, 0x07, 0xF2, 0xF5, 0xF5, 0x15, 0x2B, 0x56, 0xAC, 0x68, 0x96, 0x98, 0xC7, 0x8E, 0x1D, - 0x13, 0xF3, 0xE7, 0xCF, 0x17, 0x1B, 0x36, 0x6C, 0x10, 0xA5, 0xA5, 0xA5, 0x2D, 0x66, 0x46, 0x7B, - 0xA0, 0xB2, 0xB2, 0x52, 0x4C, 0x98, 0x30, 0xA1, 0xA9, 0x75, 0xE7, 0x00, 0x52, 0x31, 0x68, 0x77, - 0xB8, 0x7A, 0x0D, 0x89, 0x02, 0x36, 0xDA, 0x07, 0x3F, 0x79, 0xF2, 0x64, 0x3E, 0xFC, 0xF0, 0x43, - 0x0C, 0x86, 0x4E, 0x55, 0xF5, 0x9D, 0xC6, 0xC1, 0x83, 0x07, 0x59, 0xBB, 0x76, 0x2D, 0x16, 0x8B, - 0x85, 0x94, 0x94, 0x14, 0x52, 0x53, 0x53, 0xB1, 0x5A, 0xEB, 0x97, 0x91, 0xF7, 0x91, 0xDA, 0xE2, - 0x0D, 0xB5, 0xAE, 0x8C, 0x07, 0xCC, 0x80, 0xF0, 0xF4, 0xF4, 0x14, 0xEB, 0xD6, 0xAD, 0xEB, 0x94, - 0xB7, 0xBD, 0x3D, 0x50, 0x54, 0x54, 0x24, 0x92, 0x93, 0x93, 0x1D, 0x67, 0x49, 0x36, 0xD0, 0xBD, - 0xB3, 0x09, 0xDC, 0x12, 0x84, 0x00, 0xAB, 0xEC, 0x0F, 0x10, 0x1F, 0x1F, 0x2F, 0x72, 0x73, 0x73, - 0x3B, 0x9B, 0xAE, 0x6D, 0xC2, 0x96, 0x2D, 0x5B, 0x84, 0x8F, 0x8F, 0x8F, 0xA3, 0x6A, 0x7E, 0x47, - 0x7B, 0x13, 0x4D, 0x6D, 0x7B, 0x17, 0x57, 0x85, 0x37, 0x72, 0x53, 0x35, 0xC9, 0xDE, 0xD0, 0xAD, - 0x5B, 0x37, 0x8C, 0x46, 0xA3, 0x8B, 0x6E, 0xD7, 0x31, 0xF0, 0xF5, 0xF5, 0x45, 0xAF, 0xAF, 0xDF, - 0x92, 0xA8, 0x80, 0x47, 0x7B, 0xDF, 0xC3, 0x55, 0x0C, 0xF9, 0x4F, 0xE0, 0x37, 0xD8, 0xD6, 0xA8, - 0x84, 0x84, 0x04, 0x9E, 0x7E, 0xFA, 0x69, 0x3C, 0x3C, 0xDA, 0x7D, 0xFC, 0x1D, 0x8A, 0x5D, 0xBB, - 0x76, 0x51, 0x56, 0x56, 0x66, 0x3F, 0xAC, 0x42, 0xDA, 0xCC, 0xDA, 0x15, 0xAE, 0xD8, 0x81, 0x1A, - 0x81, 0xC7, 0xB1, 0x19, 0xE9, 0x12, 0x12, 0x12, 0xF8, 0xEC, 0xB3, 0xCF, 0xB8, 0xF9, 0xE6, 0x9B, - 0x5D, 0x44, 0xA6, 0x8E, 0x43, 0x5E, 0x5E, 0x23, 0xFA, 0x0B, 0x5C, 0xF7, 0x42, 0xB7, 0x2B, 0x46, - 0x21, 0x6D, 0x52, 0x42, 0xAF, 0xD7, 0x8B, 0x25, 0x4B, 0x96, 0x74, 0xB6, 0xE8, 0x6F, 0x37, 0xEC, - 0xDD, 0xBB, 0x57, 0x84, 0x86, 0x86, 0x3A, 0x2E, 0xEC, 0xB3, 0xDB, 0x9B, 0x78, 0xAE, 0xE0, 0x70, - 0x12, 0x72, 0x0D, 0xA1, 0x6B, 0xD7, 0xAE, 0x8C, 0x1D, 0x3B, 0xD6, 0x85, 0xBC, 0xEF, 0x58, 0x24, - 0x25, 0x25, 0x31, 0x64, 0x48, 0xA3, 0x3D, 0xE1, 0x2D, 0xB4, 0xB3, 0x94, 0x71, 0x05, 0x43, 0x22, - 0xED, 0x7F, 0x44, 0x47, 0x47, 0x13, 0x12, 0x12, 0xE2, 0x1A, 0xEA, 0x74, 0x02, 0x0C, 0x06, 0x03, - 0x89, 0x89, 0x89, 0x8E, 0x4D, 0x51, 0x48, 0x3B, 0x5D, 0xBB, 0xC1, 0x15, 0x0C, 0xA9, 0xEF, 0x53, - 0xA7, 0xD3, 0x35, 0x69, 0x00, 0xBC, 0x51, 0xE1, 0xEB, 0xEB, 0xEB, 0x78, 0x68, 0xE0, 0x06, 0x98, - 0x21, 0xF5, 0xCE, 0x88, 0xBC, 0xBC, 0x3C, 0x47, 0xAD, 0xE4, 0x17, 0x81, 0xD2, 0xD2, 0x52, 0xC7, - 0xC3, 0x6A, 0xDA, 0xD9, 0x57, 0xE2, 0x0A, 0x86, 0x1C, 0x46, 0xEE, 0xCE, 0xC9, 0xCA, 0xCA, 0x22, - 0x35, 0x35, 0xD5, 0x65, 0xC4, 0xE9, 0x68, 0x54, 0x55, 0x55, 0x91, 0x91, 0x91, 0xE1, 0xD8, 0x94, - 0x8D, 0x64, 0xCA, 0x75, 0x8D, 0x70, 0xE0, 0x67, 0x6C, 0x9A, 0xC8, 0xD0, 0xA1, 0x43, 0x45, 0x76, - 0x76, 0x76, 0x67, 0x2B, 0x48, 0xED, 0x82, 0x1F, 0x7E, 0xF8, 0x41, 0xF8, 0xF9, 0xF9, 0x39, 0x6A, - 0x59, 0x4F, 0x74, 0x36, 0xB1, 0x9D, 0xC5, 0x73, 0x48, 0xA3, 0x9B, 0x00, 0xC4, 0xC8, 0x91, 0x23, - 0xC5, 0x8F, 0x3F, 0xFE, 0x28, 0xCC, 0x66, 0xB3, 0xCB, 0x88, 0x65, 0xB5, 0x5A, 0x5D, 0xCA, 0x8C, - 0xAC, 0xAC, 0x2C, 0x31, 0x6C, 0xD8, 0x30, 0x47, 0x66, 0x64, 0x01, 0x71, 0x9D, 0x4D, 0x68, 0x67, - 0x61, 0x04, 0xD6, 0x39, 0x0C, 0x5E, 0xF8, 0xF8, 0xF8, 0x88, 0x05, 0x0B, 0x16, 0xB8, 0x84, 0x58, - 0x99, 0x99, 0x99, 0x62, 0xFA, 0xF4, 0xE9, 0x62, 0xD9, 0xB2, 0x65, 0xC2, 0x64, 0x32, 0x5D, 0x71, - 0x5E, 0xD3, 0x34, 0x71, 0xEE, 0xDC, 0x39, 0x91, 0x97, 0x97, 0xD7, 0xAA, 0xFE, 0x4F, 0x9E, 0x3C, - 0x29, 0x46, 0x8C, 0x18, 0x71, 0xB9, 0x09, 0xFE, 0xF5, 0xCE, 0x26, 0xB2, 0xB3, 0x08, 0x46, 0x5A, - 0x79, 0x1B, 0x31, 0x04, 0x10, 0x49, 0x49, 0x49, 0x22, 0x27, 0x27, 0xA7, 0x5D, 0x99, 0x61, 0xB5, - 0x5A, 0xC5, 0x8C, 0x19, 0x33, 0x04, 0x20, 0xBC, 0xBC, 0xBC, 0xC4, 0xA3, 0x8F, 0x3E, 0x2A, 0x36, - 0x6F, 0xDE, 0x2C, 0xCE, 0x9F, 0x3F, 0x2F, 0x0A, 0x0B, 0x0B, 0xC5, 0xE1, 0xC3, 0x87, 0xC5, 0xDC, - 0xB9, 0x73, 0x45, 0x42, 0x42, 0x82, 0x18, 0x33, 0x66, 0x8C, 0x28, 0x28, 0x28, 0x68, 0xF1, 0x3D, - 0x96, 0x2E, 0x5D, 0x7A, 0x39, 0x33, 0x34, 0x60, 0x3B, 0xF0, 0xDF, 0x40, 0x37, 0x64, 0x38, 0xD1, - 0x75, 0x87, 0x28, 0xA4, 0xEF, 0x79, 0x2F, 0x36, 0x93, 0x3B, 0x57, 0x09, 0x26, 0x98, 0x35, 0x6B, - 0x56, 0xBB, 0x8A, 0xAE, 0x6D, 0xDB, 0xB6, 0x89, 0xD0, 0xD0, 0x50, 0xE1, 0xED, 0x69, 0x10, 0xE1, - 0xC1, 0x01, 0x02, 0x10, 0x9E, 0x5E, 0x5E, 0xA2, 0x5B, 0xB7, 0xEE, 0xA2, 0x57, 0xAF, 0x5E, 0x22, - 0x38, 0x24, 0x44, 0x28, 0x8A, 0x22, 0x00, 0xE1, 0xE6, 0xE6, 0x26, 0x3E, 0xFA, 0xE8, 0xA3, 0x16, - 0xDF, 0x63, 0xCD, 0x9A, 0x35, 0x42, 0xAF, 0xD7, 0x5F, 0xCD, 0x51, 0x55, 0x87, 0x14, 0x5D, 0x0B, - 0x80, 0x5B, 0x01, 0xF7, 0xB6, 0x12, 0xB1, 0x3D, 0x38, 0x1B, 0x0A, 0x4C, 0x07, 0xE6, 0x21, 0x0D, - 0x8A, 0x5D, 0x70, 0xD0, 0xCD, 0x75, 0x3A, 0x1D, 0xE1, 0xE1, 0xE1, 0x24, 0x25, 0x25, 0x61, 0x36, - 0x9B, 0x49, 0x4D, 0x4D, 0xC5, 0x64, 0x32, 0xD1, 0xB7, 0x6F, 0x5F, 0x7C, 0x7C, 0x7C, 0x00, 0x19, - 0xB4, 0x50, 0x50, 0x50, 0x40, 0x59, 0x59, 0x19, 0xBE, 0xBE, 0xBE, 0x28, 0x8A, 0x73, 0x7E, 0xB3, - 0xEC, 0xEC, 0x6C, 0x9E, 0x7E, 0xFA, 0x69, 0x8E, 0x1D, 0x3B, 0xC6, 0x8C, 0x87, 0xC7, 0x31, 0x77, - 0xC6, 0x14, 0x02, 0xFD, 0x7C, 0xA8, 0xAA, 0x36, 0x51, 0x5A, 0x5A, 0x42, 0x65, 0x45, 0x39, 0x81, - 0x3E, 0x06, 0xEE, 0xFC, 0x55, 0x7F, 0x86, 0x0D, 0x48, 0x20, 0xFD, 0xE8, 0x69, 0xB2, 0xB3, 0xCF, - 0x72, 0xC7, 0x1D, 0x77, 0xB4, 0xC8, 0xF2, 0xBC, 0x7E, 0xFD, 0x7A, 0x36, 0x6C, 0xD8, 0x80, 0x9F, - 0x9F, 0x1F, 0x3A, 0x9D, 0x0E, 0x8B, 0xA5, 0x5E, 0xD3, 0x55, 0x91, 0xC1, 0x78, 0x83, 0x81, 0xFB, - 0x81, 0xDE, 0x40, 0x11, 0xD2, 0xE8, 0xA8, 0xB5, 0x03, 0x6D, 0x5B, 0x04, 0x37, 0xA4, 0x68, 0x4A, - 0x45, 0xBE, 0x29, 0x8D, 0x66, 0x42, 0x97, 0x2E, 0x5D, 0xC4, 0x23, 0x8F, 0x3C, 0x22, 0x3E, 0xF9, - 0xE4, 0x13, 0x71, 0xEC, 0xD8, 0x31, 0x51, 0x55, 0x55, 0x25, 0x5E, 0x7A, 0xE9, 0x25, 0x01, 0x08, - 0x9D, 0x4E, 0x27, 0x06, 0x0E, 0x1A, 0x24, 0x66, 0xCF, 0x9E, 0x2D, 0xE6, 0xCF, 0x9F, 0x2F, 0x66, - 0xCE, 0x9C, 0x29, 0xFA, 0xF4, 0xE9, 0x23, 0x7A, 0xF7, 0xEE, 0x2D, 0xD6, 0xAC, 0x59, 0xE3, 0xD4, - 0x02, 0x9D, 0x99, 0x99, 0x29, 0xC6, 0x8D, 0x1B, 0x27, 0x95, 0x86, 0x9B, 0x13, 0x45, 0xEE, 0x86, - 0x25, 0x42, 0x64, 0xAC, 0x16, 0x5A, 0xFA, 0x2A, 0x51, 0xB6, 0xED, 0x63, 0x71, 0xFA, 0x9B, 0x05, - 0xE2, 0xF8, 0xD7, 0xF3, 0xC5, 0x85, 0x0D, 0xEF, 0x0B, 0xCB, 0xDE, 0x15, 0xA2, 0x74, 0xFB, 0x27, - 0x62, 0xFC, 0xB0, 0x41, 0x02, 0x10, 0x77, 0xDF, 0x7D, 0xB7, 0x38, 0x7A, 0xF4, 0x68, 0xA3, 0xFE, - 0x34, 0x4D, 0x13, 0xFB, 0xF7, 0xEF, 0x17, 0x6F, 0xBD, 0xF5, 0x96, 0xD8, 0xBD, 0x7B, 0xB7, 0xB0, - 0x58, 0x2C, 0xC2, 0x62, 0xB1, 0x88, 0x6D, 0xDB, 0xB6, 0x89, 0xB8, 0xB8, 0x38, 0xE1, 0xEE, 0xEE, - 0x2E, 0xDE, 0x7B, 0xEF, 0x3D, 0xB1, 0x69, 0xD3, 0x26, 0xF1, 0xDC, 0x73, 0xCF, 0x89, 0x7E, 0xFD, - 0xFA, 0x09, 0x77, 0x77, 0xF7, 0xAB, 0xCD, 0x9A, 0x12, 0xE0, 0x03, 0x64, 0x10, 0x60, 0x87, 0xC5, - 0xBD, 0x45, 0x20, 0x67, 0x44, 0x99, 0xE3, 0x60, 0x74, 0x3A, 0x9D, 0x48, 0x4A, 0x4A, 0x12, 0x6F, - 0xBE, 0xF9, 0xA6, 0x38, 0x76, 0xEC, 0x98, 0xB0, 0x58, 0x2C, 0xF5, 0x0F, 0x6C, 0x32, 0x99, 0xC4, - 0xA4, 0x49, 0x93, 0x04, 0x20, 0xBA, 0x84, 0x1A, 0x85, 0xA7, 0xC1, 0xAD, 0xD1, 0x83, 0x78, 0xB8, - 0xBB, 0x09, 0x9D, 0xAA, 0x8A, 0xA0, 0xA0, 0x20, 0xF1, 0xDA, 0x6B, 0xAF, 0x89, 0xB3, 0x67, 0xCF, - 0x5E, 0x35, 0x10, 0xA2, 0xA2, 0xA2, 0x42, 0xAC, 0x5C, 0xB9, 0x52, 0x0C, 0x18, 0x30, 0x40, 0x00, - 0xE2, 0x96, 0xDE, 0xDD, 0xC5, 0xC1, 0x95, 0x6F, 0x0B, 0xB1, 0xFF, 0x6B, 0x21, 0xD2, 0xBE, 0x92, - 0xBF, 0xF4, 0x55, 0x42, 0xEC, 0x5F, 0x25, 0xDB, 0xD2, 0x57, 0xC9, 0xB6, 0xFD, 0x5F, 0x8B, 0xC3, - 0x5F, 0xFD, 0x5D, 0x0C, 0x4E, 0xEC, 0x21, 0x00, 0xD1, 0xA3, 0x47, 0x0F, 0xF1, 0x87, 0x3F, 0xFC, - 0x41, 0xAC, 0x5A, 0xB5, 0x4A, 0xAC, 0x5C, 0xB9, 0x52, 0xCC, 0x9A, 0x35, 0x4B, 0xC4, 0xC4, 0xC4, - 0x08, 0x40, 0x84, 0x87, 0x87, 0x8B, 0xFB, 0xEE, 0xBB, 0x4F, 0x4C, 0x9C, 0x38, 0xB1, 0xDE, 0x98, - 0x38, 0x79, 0xF2, 0xE4, 0xFA, 0x60, 0x0B, 0x4D, 0xD3, 0x44, 0x7E, 0x7E, 0xBE, 0x58, 0xBE, 0x7C, - 0xB9, 0x18, 0x3F, 0x7E, 0xBC, 0xF0, 0xF5, 0xF5, 0xBD, 0x1A, 0x63, 0xCE, 0x21, 0x8D, 0x8F, 0xC1, - 0x2D, 0x21, 0x6C, 0x4B, 0x39, 0xA8, 0x20, 0x83, 0x9E, 0x5F, 0x07, 0x86, 0x39, 0x5E, 0x1F, 0x17, - 0x17, 0xC7, 0xF4, 0xE9, 0xD3, 0x49, 0x4E, 0x4E, 0x26, 0x32, 0x32, 0xF2, 0x8A, 0x0B, 0x77, 0xEC, - 0xD8, 0xC1, 0x84, 0x09, 0x13, 0xF0, 0xD4, 0x2B, 0x2C, 0xFF, 0xDB, 0x33, 0x58, 0xEA, 0xEA, 0x48, - 0x3B, 0x7A, 0x9A, 0xD2, 0x8A, 0x4B, 0x04, 0x07, 0xF8, 0x31, 0xA8, 0x57, 0x37, 0x52, 0x7F, 0x3E, - 0xCE, 0x3F, 0x96, 0xAF, 0xA7, 0xEC, 0x52, 0x35, 0x71, 0xF1, 0xF1, 0xDC, 0x39, 0x76, 0x2C, 0x03, - 0x07, 0x0E, 0x24, 0x28, 0x28, 0x88, 0xAA, 0xAA, 0x2A, 0x4E, 0x9C, 0x38, 0xC1, 0x96, 0x2D, 0x5B, - 0xD8, 0xB3, 0x67, 0x0F, 0x96, 0xDA, 0x5A, 0xEE, 0xBA, 0xAD, 0x3F, 0x73, 0x9F, 0x99, 0x42, 0xAF, - 0x6E, 0xD1, 0xA0, 0x39, 0x21, 0x21, 0x54, 0x95, 0x13, 0x67, 0xCE, 0xF3, 0xA7, 0x25, 0xAB, 0xF8, - 0x76, 0x7B, 0x1A, 0x55, 0xE6, 0x1A, 0xDB, 0x23, 0x08, 0x00, 0x02, 0x7C, 0xBD, 0x49, 0xEA, 0x19, - 0xC3, 0xD1, 0xAC, 0xF3, 0x14, 0x97, 0x55, 0xA2, 0x28, 0x0A, 0xE1, 0xE1, 0xE1, 0x24, 0x27, 0x27, - 0x33, 0x7B, 0xF6, 0x6C, 0xC2, 0xC2, 0xC2, 0xAE, 0xE8, 0xB2, 0xBA, 0xBA, 0x9A, 0xD4, 0xD4, 0x54, - 0x96, 0x2E, 0x5D, 0xCA, 0xF7, 0xDF, 0x7F, 0x4F, 0x65, 0x65, 0xA5, 0xE3, 0x69, 0x2B, 0xB0, 0x03, - 0xF8, 0x13, 0x90, 0x82, 0x13, 0x62, 0xAC, 0x25, 0x0C, 0x71, 0x03, 0x26, 0x03, 0x7F, 0x41, 0xAE, - 0x13, 0x80, 0xB4, 0xED, 0x4C, 0x99, 0x32, 0x85, 0x99, 0x33, 0x67, 0xD2, 0xA3, 0x47, 0x8F, 0xAB, - 0x5E, 0x28, 0x84, 0x60, 0xC6, 0x8C, 0x19, 0x2C, 0x58, 0xB0, 0x80, 0xA9, 0xF7, 0x8E, 0x64, 0xC9, - 0x2B, 0xBF, 0xB3, 0x79, 0xDE, 0x84, 0xA4, 0x85, 0x22, 0x87, 0x52, 0x67, 0xA9, 0x63, 0xEB, 0xDE, - 0x43, 0xFC, 0x73, 0xE5, 0xF7, 0x6C, 0x4F, 0x3F, 0x42, 0x65, 0xB5, 0x59, 0x0E, 0x52, 0x51, 0x11, - 0x42, 0x3E, 0x8B, 0x5E, 0xA7, 0x92, 0xD8, 0x2D, 0x9A, 0x69, 0x13, 0x47, 0x32, 0xE5, 0x9E, 0xFF, - 0x20, 0xD0, 0xDF, 0xD7, 0x39, 0x66, 0x38, 0x30, 0xA5, 0xDA, 0x64, 0x66, 0xD7, 0x81, 0x13, 0x6C, - 0xD9, 0x77, 0x98, 0xAC, 0xDC, 0x02, 0x54, 0x45, 0xA1, 0x67, 0x4C, 0x04, 0x63, 0x6E, 0x4D, 0x62, - 0x50, 0xAF, 0x6E, 0x7C, 0xBA, 0x6E, 0x3B, 0x4F, 0xCE, 0x59, 0x4A, 0x78, 0x44, 0x24, 0x5F, 0x7E, - 0xF9, 0x25, 0x43, 0x87, 0x0E, 0x45, 0xA7, 0xBB, 0xF6, 0x72, 0x6B, 0x36, 0x9B, 0xD9, 0xB6, 0x6D, - 0x1B, 0x0B, 0x17, 0x2E, 0x64, 0xD3, 0xA6, 0x4D, 0x8E, 0x81, 0x76, 0x20, 0xE3, 0xBA, 0xDE, 0x04, - 0x96, 0xD0, 0xCC, 0xCE, 0xDE, 0x59, 0x86, 0xF8, 0x02, 0xFF, 0x0B, 0x3C, 0x83, 0x0C, 0x09, 0x05, - 0x20, 0x31, 0x31, 0x91, 0x3F, 0xFE, 0xF1, 0x8F, 0xDC, 0x7B, 0xEF, 0xBD, 0xB8, 0xBB, 0x37, 0xAD, - 0x60, 0x9C, 0x39, 0x73, 0x86, 0x31, 0x63, 0xC7, 0x92, 0x9B, 0x73, 0x96, 0x7F, 0xCD, 0x7B, 0x9E, - 0xBB, 0x6E, 0x1F, 0x08, 0xD6, 0x26, 0x88, 0xA8, 0x53, 0xA9, 0xAA, 0x32, 0xF1, 0xF3, 0xF1, 0x33, - 0xEC, 0x3C, 0x70, 0x82, 0xE3, 0xD9, 0xB9, 0x54, 0x5C, 0xAA, 0xC6, 0xD3, 0xC3, 0x40, 0x4C, 0x78, - 0x30, 0x83, 0x13, 0xBB, 0x33, 0xA4, 0x6F, 0x1C, 0xE1, 0x21, 0x81, 0x36, 0xE1, 0x20, 0x9C, 0x67, - 0x86, 0xE3, 0x53, 0xAB, 0x2A, 0x08, 0xD0, 0xEA, 0xAC, 0xA0, 0x80, 0xAA, 0xD3, 0xD5, 0x4F, 0x96, - 0xBC, 0xA2, 0x52, 0xEE, 0x7A, 0xF2, 0xAF, 0x1C, 0x3D, 0x9B, 0xC7, 0x8A, 0xE5, 0xCB, 0x99, 0x34, - 0x69, 0x92, 0xD3, 0x5D, 0x57, 0x56, 0x56, 0xB2, 0x62, 0xC5, 0x0A, 0xE6, 0xCD, 0x9B, 0xC7, 0x89, - 0x13, 0x27, 0x1C, 0x4F, 0xD5, 0x00, 0xCB, 0x80, 0x57, 0x81, 0xE2, 0xB6, 0x30, 0x24, 0x10, 0x29, - 0xA2, 0xFE, 0x0B, 0x9B, 0xF6, 0xA4, 0xD7, 0xEB, 0x79, 0xE0, 0x81, 0x07, 0xF8, 0xF3, 0x9F, 0xFF, - 0x4C, 0x7C, 0x7C, 0x7C, 0xB3, 0x1D, 0x2C, 0x59, 0xB2, 0x84, 0xE9, 0xD3, 0xA7, 0x33, 0x6C, 0x40, - 0x02, 0xDF, 0xBE, 0xF3, 0x02, 0x01, 0xBE, 0xDE, 0xD7, 0x26, 0xA4, 0x9D, 0x60, 0x80, 0xB0, 0x6A, - 0x68, 0x9A, 0x86, 0xAA, 0x28, 0x28, 0x3A, 0x1D, 0x28, 0x8A, 0x9C, 0x11, 0xAD, 0x61, 0x84, 0xB3, - 0x50, 0x14, 0x5E, 0x5A, 0xB4, 0x9C, 0xBF, 0x2D, 0x5B, 0x43, 0x72, 0x72, 0x32, 0x9F, 0x7E, 0xFA, - 0x29, 0x6E, 0x6E, 0x6E, 0x2D, 0xEA, 0x22, 0x33, 0x33, 0x93, 0xD7, 0x5F, 0x7F, 0x9D, 0x15, 0x2B, - 0x56, 0x38, 0xCE, 0x16, 0x0D, 0x19, 0x01, 0x39, 0x13, 0x99, 0xCB, 0x72, 0x05, 0x9A, 0x33, 0x2E, - 0x86, 0x00, 0xFF, 0x40, 0xAA, 0xB5, 0x7A, 0x90, 0x22, 0xEA, 0x85, 0x17, 0x5E, 0x60, 0xC9, 0x92, - 0x25, 0x4E, 0x31, 0xC3, 0x6C, 0x36, 0xB3, 0x6E, 0xDD, 0x3A, 0x00, 0x26, 0x0C, 0xBF, 0x99, 0x00, - 0x7F, 0x9F, 0xE6, 0x89, 0x29, 0x90, 0x33, 0xC8, 0xAA, 0xA1, 0x00, 0x3A, 0x55, 0x95, 0xAA, 0xB0, - 0xA6, 0x81, 0xD5, 0xEA, 0x5A, 0x66, 0x00, 0xA8, 0x0A, 0x13, 0x86, 0x0F, 0x22, 0xC0, 0xD7, 0x8B, - 0x94, 0x94, 0x14, 0x32, 0x33, 0x33, 0x5B, 0xDC, 0x45, 0xCF, 0x9E, 0x3D, 0x59, 0xBC, 0x78, 0x31, - 0x73, 0xE6, 0xCC, 0x71, 0xF4, 0x09, 0xA9, 0xC0, 0x43, 0xC8, 0x7D, 0x4B, 0xC4, 0x55, 0x6F, 0x7D, - 0x8D, 0x3E, 0x8D, 0x34, 0xEC, 0x2D, 0x54, 0x80, 0x90, 0x90, 0x10, 0xDE, 0x79, 0xE7, 0x1D, 0x5E, - 0x7D, 0xF5, 0x55, 0xFC, 0xFD, 0xFD, 0x9D, 0x1A, 0xD8, 0xF1, 0xE3, 0xC7, 0xF9, 0x69, 0xF7, 0x6E, - 0x42, 0x02, 0xFD, 0x18, 0x3B, 0xA4, 0x9F, 0x7D, 0xFD, 0xBC, 0xBE, 0xA1, 0x69, 0xF4, 0xED, 0x11, - 0xC3, 0x2D, 0x89, 0x3D, 0xB8, 0x70, 0xE1, 0x02, 0x5B, 0xB7, 0x6E, 0x6D, 0x55, 0x37, 0x5E, 0x5E, - 0x5E, 0x3C, 0xF5, 0xD4, 0x53, 0x7C, 0xF0, 0xC1, 0x07, 0xC4, 0xC6, 0xC6, 0x3A, 0x9E, 0xBA, 0x1F, - 0x98, 0x03, 0x5C, 0x41, 0xC4, 0xA6, 0x18, 0xE2, 0x89, 0x4C, 0x1D, 0x98, 0x8C, 0x4D, 0xAC, 0x45, - 0x45, 0x45, 0xB1, 0x68, 0xD1, 0x22, 0xA6, 0x4D, 0x9B, 0xD6, 0xA2, 0xE9, 0xBB, 0x7D, 0xFB, 0x76, - 0x8A, 0x8B, 0x8A, 0xB8, 0xB5, 0x4F, 0x4F, 0xE2, 0xBB, 0x46, 0xB6, 0x6C, 0x01, 0xEE, 0x2C, 0x08, - 0xF0, 0xF6, 0xF6, 0x64, 0xDC, 0xD0, 0x01, 0x00, 0x6C, 0xD8, 0xB0, 0x01, 0xB3, 0xD9, 0xDC, 0xAA, - 0xAE, 0x54, 0x55, 0x65, 0xE2, 0xC4, 0x89, 0x2C, 0x5D, 0xBA, 0xF4, 0x72, 0xA5, 0xE7, 0x11, 0xE4, - 0xBA, 0xDC, 0xC8, 0xC1, 0x75, 0x35, 0x86, 0x28, 0xC0, 0xFF, 0x20, 0xC5, 0x94, 0x0A, 0x92, 0x19, - 0xEF, 0xBE, 0xFB, 0x2E, 0x0F, 0x3D, 0xF4, 0x90, 0xD3, 0xBB, 0x68, 0x90, 0xE2, 0x6A, 0xD3, 0xA6, - 0x4D, 0x00, 0x8C, 0x19, 0x92, 0x84, 0x87, 0xE7, 0x8D, 0x11, 0x42, 0x0A, 0x80, 0x80, 0x11, 0x83, - 0x12, 0x09, 0xF2, 0xF7, 0x21, 0x2D, 0x2D, 0x9D, 0xAC, 0xAC, 0xAC, 0x36, 0x75, 0x37, 0x6A, 0xD4, - 0x28, 0x16, 0x2D, 0x5A, 0x44, 0x54, 0x54, 0x94, 0xBD, 0x49, 0x87, 0xCC, 0x0A, 0xB8, 0xDF, 0xF1, - 0xFF, 0xAE, 0xC6, 0x90, 0x31, 0xC8, 0x0D, 0x8D, 0x01, 0xC0, 0x68, 0x34, 0x32, 0x6F, 0xDE, 0xBC, - 0x46, 0xF9, 0x19, 0xCE, 0x22, 0x3B, 0x3B, 0x9B, 0xF4, 0xFD, 0xFB, 0x09, 0xF2, 0xF7, 0x61, 0xF8, - 0x80, 0x5E, 0x37, 0x86, 0xB8, 0xB2, 0x43, 0x68, 0xC4, 0xC5, 0x44, 0x30, 0x20, 0x3E, 0x96, 0xFC, - 0xFC, 0x3C, 0x76, 0xED, 0xDA, 0xD5, 0xE6, 0x2E, 0xC7, 0x8E, 0x1D, 0xCB, 0x1B, 0x6F, 0xBC, 0xE1, - 0xE8, 0x06, 0xF6, 0x43, 0x66, 0x89, 0xDD, 0x64, 0x6F, 0xB8, 0x9C, 0x21, 0x91, 0x48, 0x51, 0x15, - 0x0A, 0xD2, 0xA9, 0xFF, 0xF2, 0xCB, 0x2F, 0xF3, 0xD0, 0x43, 0x0F, 0xB5, 0x6A, 0x00, 0xE9, 0xE9, - 0xE9, 0xE4, 0x5D, 0xC8, 0xA3, 0x4F, 0xF7, 0x18, 0x7A, 0x44, 0x87, 0x3B, 0xBF, 0x18, 0xAB, 0x2A, - 0xA8, 0xAA, 0x4C, 0xCC, 0x01, 0xD0, 0xA9, 0x52, 0xBB, 0x6A, 0x2D, 0x54, 0x05, 0x54, 0x15, 0xAB, - 0xA6, 0x61, 0xD5, 0xB4, 0xFA, 0xFE, 0xAF, 0x09, 0x01, 0x5E, 0x5E, 0x9E, 0x0C, 0x1F, 0xD8, 0x1B, - 0x80, 0x9D, 0x3B, 0x77, 0xA2, 0xB5, 0x83, 0xB8, 0x4D, 0x4E, 0x4E, 0x66, 0xFA, 0xF4, 0xE9, 0x8E, - 0x4D, 0xFD, 0x90, 0x41, 0xDB, 0x2A, 0x34, 0x96, 0x5F, 0x0A, 0x32, 0x21, 0xE5, 0x36, 0x7B, 0xC3, - 0x23, 0x8F, 0x3C, 0xC2, 0xF4, 0xE9, 0xD3, 0x5B, 0x1D, 0xA8, 0x20, 0xDD, 0xB7, 0x82, 0xDB, 0xFA, - 0xC5, 0xE3, 0xE3, 0xED, 0x09, 0x5A, 0x33, 0x0C, 0x51, 0x14, 0xAC, 0x9A, 0x46, 0xFA, 0xA1, 0x93, - 0xFC, 0x7B, 0xE7, 0x7E, 0x4E, 0x9D, 0xCB, 0xC7, 0xDB, 0xD3, 0xC0, 0x6D, 0x49, 0xF1, 0x8C, 0xBB, - 0x7D, 0x20, 0xA1, 0x41, 0x01, 0x2D, 0x5F, 0x83, 0x14, 0x85, 0x53, 0x39, 0x79, 0xFC, 0x6B, 0xCB, - 0x5E, 0xD2, 0x8F, 0x67, 0x61, 0xB5, 0x6A, 0x24, 0x76, 0x8F, 0xE6, 0xFE, 0x11, 0xB7, 0xD0, 0x37, - 0xEE, 0xA6, 0x6B, 0xAB, 0x99, 0x8A, 0xC2, 0xAD, 0x7D, 0x7B, 0xE2, 0xAE, 0xD7, 0x91, 0x91, 0x91, - 0x41, 0x49, 0x49, 0x49, 0x9B, 0xA3, 0x68, 0xDC, 0xDC, 0xDC, 0x78, 0xE6, 0x99, 0x67, 0x48, 0x49, - 0x49, 0x61, 0xEF, 0xDE, 0xBD, 0xF6, 0xE6, 0xC9, 0xC0, 0x72, 0x60, 0xBF, 0x23, 0x43, 0xFA, 0x03, - 0x53, 0xED, 0x07, 0x7D, 0xFA, 0xF4, 0xE1, 0xC5, 0x17, 0x5F, 0xC4, 0xCB, 0xCB, 0xCB, 0xE9, 0x9B, - 0x39, 0xA2, 0xAC, 0xAC, 0x8C, 0xFD, 0xFB, 0xF7, 0xA3, 0x53, 0x15, 0x86, 0xF4, 0xED, 0x09, 0x8A, - 0x4A, 0x73, 0x91, 0xFB, 0xB5, 0x96, 0x3A, 0x16, 0xAE, 0xFC, 0x9E, 0x39, 0x1F, 0x7F, 0x43, 0xE1, - 0xC5, 0xF2, 0xFA, 0xF6, 0x65, 0xDF, 0x6C, 0x65, 0xD8, 0x80, 0x04, 0xDE, 0x79, 0x76, 0x2A, 0xFD, - 0x13, 0x62, 0x9D, 0x67, 0x8A, 0xA2, 0xF0, 0x7D, 0xEA, 0x7E, 0x9E, 0x7D, 0xE7, 0x53, 0x8E, 0x9D, - 0x69, 0x50, 0xFB, 0xBF, 0xDE, 0xBC, 0x9B, 0x0F, 0xD7, 0x6E, 0xE6, 0x2F, 0xFF, 0x93, 0xCC, 0xA3, - 0xE3, 0xFF, 0x03, 0xB5, 0xA9, 0xD9, 0xA7, 0x69, 0xF4, 0x8E, 0xED, 0x42, 0xD7, 0x88, 0x10, 0x4E, - 0x67, 0x65, 0x71, 0xF2, 0xE4, 0xC9, 0x76, 0x09, 0x6B, 0x8A, 0x8A, 0x8A, 0x62, 0xE6, 0xCC, 0x99, - 0x4C, 0x9D, 0x3A, 0xD5, 0xAE, 0x2C, 0x44, 0x00, 0x8F, 0x02, 0x19, 0xF6, 0x17, 0x44, 0x05, 0xA6, - 0x61, 0x33, 0x89, 0xB8, 0xBB, 0xBB, 0x33, 0x6B, 0xD6, 0xAC, 0x26, 0x4D, 0x21, 0xCE, 0xE0, 0xEC, - 0xD9, 0xB3, 0x64, 0x9E, 0x3A, 0x45, 0x44, 0x70, 0x20, 0xBD, 0xBB, 0x75, 0x01, 0xD1, 0x0C, 0x11, - 0x55, 0x95, 0x55, 0x9B, 0x7E, 0xE2, 0xD5, 0xF7, 0xBE, 0x6A, 0xC4, 0x0C, 0x2F, 0x2F, 0x2F, 0xFC, - 0xFC, 0xFD, 0xD9, 0x96, 0x7E, 0x94, 0x67, 0xDE, 0xFE, 0x88, 0x82, 0xE2, 0x8B, 0xCE, 0x89, 0x2F, - 0x55, 0xE5, 0xF0, 0xE9, 0x1C, 0x66, 0xBC, 0xFD, 0x71, 0x23, 0x66, 0x18, 0x0C, 0x06, 0xC2, 0xC2, - 0xC2, 0x28, 0x2C, 0xAB, 0xE2, 0xF9, 0x7F, 0x7C, 0xCE, 0x96, 0x7D, 0x87, 0x9B, 0x16, 0x5F, 0x42, - 0x10, 0x1E, 0xE4, 0x4F, 0xBF, 0xB8, 0x9B, 0xA8, 0xBA, 0x74, 0x89, 0xB4, 0xB4, 0xB4, 0x36, 0x33, - 0xC3, 0x8E, 0x71, 0xE3, 0xC6, 0x31, 0x7C, 0xF8, 0x70, 0xC7, 0xA6, 0x7B, 0x80, 0x04, 0xFB, 0x48, - 0x12, 0x80, 0xFB, 0xEC, 0x67, 0x46, 0x8C, 0x18, 0xC1, 0x03, 0x0F, 0x3C, 0xD0, 0xA6, 0x1B, 0x1E, - 0x3D, 0x7A, 0x94, 0xD2, 0x92, 0x12, 0xE2, 0xBB, 0x46, 0x12, 0x19, 0x62, 0xBC, 0xB6, 0xB8, 0x52, - 0x14, 0xCA, 0x2B, 0x2E, 0xF1, 0xFE, 0xEA, 0x8D, 0x54, 0x99, 0x1A, 0xD4, 0xCB, 0xBE, 0x7D, 0xFB, - 0xB2, 0x72, 0xE5, 0x4A, 0x36, 0x6F, 0xDE, 0xCC, 0x13, 0x4F, 0x3C, 0xC1, 0x4F, 0x87, 0x32, 0xF9, - 0x2E, 0x25, 0x4D, 0xAE, 0x09, 0xCD, 0x41, 0x08, 0xBE, 0x58, 0xBF, 0x83, 0xCC, 0x9C, 0x86, 0x78, - 0x5C, 0xA3, 0xD1, 0xC8, 0xFC, 0xF9, 0xF3, 0x49, 0x49, 0x49, 0xE1, 0xBD, 0xF7, 0xDE, 0x45, 0xE8, - 0xDD, 0xF9, 0x60, 0xCD, 0x26, 0x2C, 0xB5, 0x4D, 0x47, 0xF2, 0xE8, 0xDD, 0xDD, 0xE4, 0x0C, 0x07, - 0xF6, 0xEC, 0xD9, 0xE3, 0x98, 0xB0, 0xD3, 0x26, 0xF8, 0xF9, 0xF9, 0x31, 0x79, 0xF2, 0x64, 0xC7, - 0x68, 0xFA, 0x58, 0x60, 0xBC, 0x9D, 0x21, 0xE3, 0xB1, 0xCD, 0x0E, 0x83, 0xC1, 0xC0, 0xB4, 0x69, - 0xD3, 0x9C, 0xDE, 0xF8, 0x35, 0x85, 0x43, 0x87, 0x0E, 0x01, 0x90, 0xD8, 0x3D, 0x06, 0x2F, 0x8F, - 0x66, 0xD4, 0x5D, 0x45, 0xE1, 0x6C, 0x5E, 0x11, 0xC7, 0xCE, 0x9C, 0x6F, 0xD4, 0xFC, 0xE4, 0x93, - 0x4F, 0x32, 0x7E, 0xFC, 0x78, 0x06, 0x0C, 0x18, 0xC0, 0x8B, 0x2F, 0xBE, 0x48, 0x74, 0xD7, 0x9B, - 0x48, 0xFD, 0xF9, 0x78, 0xD3, 0x76, 0x30, 0x07, 0x98, 0xCC, 0x35, 0xEC, 0x3D, 0x72, 0xAA, 0x51, - 0xDB, 0x98, 0x31, 0x63, 0x78, 0xFC, 0xF1, 0xC7, 0x89, 0x8B, 0x8B, 0xE3, 0xB1, 0xC7, 0x1E, 0x63, - 0xC2, 0x84, 0x09, 0xA4, 0x1F, 0x3B, 0x4D, 0x71, 0x59, 0xE5, 0x35, 0x66, 0x9D, 0x42, 0xBF, 0xB8, - 0x9B, 0x70, 0xD7, 0xEB, 0x38, 0x7E, 0xFC, 0x38, 0xE5, 0xE5, 0xE5, 0xCD, 0xDE, 0xDB, 0x59, 0x8C, - 0x1A, 0x35, 0x8A, 0xEE, 0xDD, 0xEB, 0x73, 0x7E, 0x74, 0xC0, 0x44, 0x15, 0xB9, 0x5B, 0xBC, 0xDB, - 0xDE, 0xDA, 0xB7, 0x6F, 0x5F, 0x46, 0x8F, 0x1E, 0xDD, 0xA6, 0x1B, 0x59, 0x2C, 0x16, 0x8E, 0x1E, - 0x3D, 0x2A, 0xFB, 0xEB, 0x11, 0xD3, 0xBC, 0x46, 0xA3, 0x80, 0xB9, 0xD6, 0x42, 0xAD, 0xA5, 0xF1, - 0xDB, 0x27, 0x1C, 0xB4, 0x32, 0x21, 0x04, 0x08, 0x41, 0xB5, 0xB9, 0x06, 0xAD, 0x39, 0x6D, 0x4D, - 0x01, 0xAB, 0x55, 0xC3, 0x5C, 0xD3, 0xF8, 0xCD, 0xB7, 0x58, 0x2C, 0xF5, 0x9A, 0x92, 0xA6, 0x69, - 0xD4, 0xD6, 0xD6, 0x52, 0x6B, 0xA9, 0xA3, 0xCE, 0x6A, 0x6D, 0xDA, 0xAA, 0x27, 0x34, 0x62, 0x23, - 0x43, 0x09, 0x35, 0xFA, 0x93, 0x9D, 0x9D, 0x4D, 0x4A, 0x4A, 0x0A, 0x15, 0x15, 0x15, 0x8D, 0xC6, - 0xD6, 0x52, 0x54, 0x57, 0x57, 0x93, 0x9E, 0x9E, 0xCE, 0xFB, 0xEF, 0xBF, 0x7F, 0x79, 0xE0, 0x5D, - 0x92, 0x1E, 0x48, 0x44, 0x66, 0xCA, 0x02, 0x70, 0xF7, 0xDD, 0x77, 0x13, 0x1C, 0xDC, 0x22, 0x9F, - 0xCA, 0x15, 0xA8, 0xA8, 0xA8, 0xE0, 0xCC, 0x99, 0x33, 0x78, 0xB8, 0xEB, 0xE9, 0x19, 0x13, 0x4E, - 0xB3, 0x1B, 0x10, 0x21, 0x08, 0x0F, 0x0A, 0x20, 0xD4, 0xE8, 0x47, 0x45, 0x55, 0x83, 0x75, 0x7A, - 0xD1, 0xA2, 0x45, 0x44, 0x44, 0x44, 0x10, 0x15, 0x15, 0xC5, 0x87, 0x1F, 0x7E, 0xC8, 0xE9, 0xAC, - 0xD3, 0x3C, 0x3C, 0xA2, 0x9F, 0xB4, 0xCC, 0x5E, 0x6B, 0x61, 0x17, 0xE0, 0xE5, 0x61, 0xA0, 0x47, - 0x74, 0x38, 0xBB, 0x0E, 0x36, 0x58, 0x5C, 0x37, 0x6E, 0xDC, 0xC8, 0xDC, 0xB9, 0x73, 0x19, 0x33, - 0x66, 0x0C, 0x3B, 0x76, 0xEC, 0xE0, 0xBB, 0xEF, 0xD6, 0x31, 0xA0, 0x47, 0x24, 0x81, 0xBE, 0xDE, - 0x4D, 0x0F, 0x51, 0x40, 0xA8, 0xD1, 0x9F, 0xAE, 0x11, 0x21, 0xA4, 0x1E, 0x38, 0xC1, 0x6F, 0x7F, - 0xFB, 0x5B, 0x12, 0x12, 0x12, 0x18, 0x32, 0x64, 0x08, 0x83, 0x07, 0x0F, 0xA6, 0x7B, 0xF7, 0xEE, - 0x44, 0x45, 0x45, 0x11, 0x18, 0x18, 0x88, 0xC1, 0x60, 0x40, 0xA7, 0xD3, 0xD5, 0x6F, 0x9E, 0x35, - 0x4D, 0xC3, 0x62, 0xB1, 0x50, 0x5D, 0x5D, 0x4D, 0x71, 0x71, 0x31, 0xA7, 0x4F, 0x9F, 0x26, 0x2D, - 0x2D, 0x8D, 0x94, 0x94, 0x14, 0x32, 0x32, 0x32, 0x28, 0x2E, 0xBE, 0xC2, 0xE8, 0x9B, 0xAB, 0x47, - 0xAA, 0xB9, 0x46, 0x00, 0x6F, 0x6F, 0x6F, 0x46, 0x8C, 0x18, 0xD1, 0x26, 0x66, 0x00, 0x14, 0x14, - 0x14, 0x90, 0x97, 0x9F, 0x4F, 0x90, 0xBF, 0x2F, 0x51, 0xA1, 0xC6, 0xE6, 0x37, 0x84, 0x9A, 0xA0, - 0x4B, 0x58, 0x10, 0xE3, 0x6E, 0x1F, 0xC8, 0x3F, 0x97, 0xAF, 0xAF, 0x6F, 0x3E, 0x7C, 0xF8, 0x30, - 0x0F, 0x3F, 0xFC, 0x30, 0xEE, 0xEE, 0xEE, 0x94, 0x57, 0x54, 0x10, 0x66, 0xF4, 0x63, 0xC2, 0xF0, - 0x41, 0x4E, 0x8D, 0x41, 0x75, 0xD3, 0x31, 0x69, 0xF4, 0xAD, 0xAC, 0xD9, 0xBA, 0x87, 0x4B, 0x36, - 0xBF, 0x4A, 0x65, 0x65, 0x25, 0xAF, 0xBD, 0xF6, 0x1A, 0x73, 0xE6, 0xCC, 0xA1, 0xBA, 0xBA, 0x1A, - 0x10, 0x3C, 0x74, 0xC7, 0x6D, 0xF8, 0xF8, 0x78, 0x35, 0xCD, 0x60, 0x21, 0xF0, 0xF1, 0xF2, 0x20, - 0xBE, 0x6B, 0x24, 0xA9, 0x07, 0x4E, 0x50, 0x5E, 0x5E, 0xCE, 0x9E, 0x3D, 0x7B, 0xD8, 0xB3, 0x67, - 0x0F, 0x3A, 0x9D, 0x0E, 0x1F, 0x1F, 0x1F, 0x42, 0x42, 0x42, 0x88, 0x88, 0x88, 0x20, 0x28, 0x28, - 0x08, 0x5F, 0x5F, 0x5F, 0x0C, 0x06, 0x03, 0x9A, 0xA6, 0x51, 0x5D, 0x5D, 0x4D, 0x59, 0x59, 0x19, - 0x85, 0x85, 0x85, 0x14, 0x14, 0x14, 0x50, 0x52, 0x52, 0xD2, 0x94, 0x09, 0x46, 0x43, 0x66, 0xF6, - 0xBE, 0xAA, 0x47, 0x3A, 0xE8, 0x55, 0x80, 0x2E, 0x5D, 0xBA, 0x90, 0x90, 0x90, 0xD0, 0x6A, 0x46, - 0x98, 0xCD, 0x66, 0x32, 0x32, 0x32, 0x58, 0xB8, 0x70, 0x21, 0x45, 0x85, 0x45, 0x0C, 0x4C, 0x88, - 0x25, 0xC8, 0xDF, 0xD7, 0xA9, 0x0D, 0xA1, 0xAA, 0x53, 0x99, 0xF9, 0xC8, 0x3D, 0x1C, 0x3C, 0x79, - 0x96, 0x6D, 0xE9, 0x47, 0xEA, 0xDB, 0x4D, 0x26, 0x13, 0x26, 0x93, 0x09, 0x1F, 0x4F, 0x0F, 0x66, - 0x3F, 0x76, 0x1F, 0x37, 0xF7, 0xEE, 0xEE, 0x9C, 0xDA, 0x6B, 0xD5, 0xB8, 0xEB, 0xB6, 0xFE, 0x3C, - 0x9D, 0x7C, 0x37, 0xF3, 0x3E, 0x5F, 0x47, 0x8D, 0x6D, 0xE1, 0xB6, 0x5A, 0xAD, 0x54, 0x56, 0x56, - 0xA2, 0x53, 0x55, 0x7E, 0x33, 0x6E, 0x38, 0x53, 0xC6, 0x0D, 0x6B, 0x76, 0x7C, 0x8A, 0x4E, 0x27, - 0x35, 0xC5, 0xCB, 0x6F, 0x61, 0xB5, 0x52, 0x5E, 0x5E, 0x4E, 0x79, 0x79, 0x39, 0xA7, 0x4E, 0x9D, - 0xA2, 0x15, 0xA8, 0x46, 0x46, 0x79, 0xAE, 0x04, 0xD6, 0x00, 0xE7, 0xF5, 0xC8, 0x48, 0x09, 0x40, - 0x9A, 0x8C, 0x5B, 0x2A, 0xAE, 0xEA, 0xEA, 0xEA, 0x38, 0x7F, 0xFE, 0x3C, 0x5B, 0xB7, 0x6E, 0x65, - 0xCD, 0x9A, 0x35, 0xEC, 0xDA, 0xB5, 0xAB, 0x5E, 0x2E, 0x46, 0x04, 0x07, 0xE0, 0xED, 0x61, 0x70, - 0x6E, 0x87, 0xAE, 0x09, 0x6E, 0x8A, 0x0A, 0xE5, 0xE3, 0x3F, 0x3D, 0xC9, 0x3F, 0x97, 0xAF, 0x67, - 0xDD, 0xCE, 0x74, 0x8A, 0x4A, 0x2B, 0x70, 0x73, 0xD3, 0xD3, 0x3B, 0xB6, 0x0B, 0xBF, 0x7B, 0x70, - 0x0C, 0xF7, 0x8F, 0xBA, 0x15, 0x55, 0x55, 0x9C, 0x36, 0xC1, 0xB8, 0xBB, 0xB9, 0xF1, 0xF2, 0xE3, - 0x0F, 0xD2, 0xA3, 0x4B, 0x38, 0x1F, 0x7D, 0xB7, 0x8D, 0x53, 0xE7, 0xF2, 0xD1, 0x34, 0x8D, 0xE8, - 0xB0, 0x20, 0x92, 0xEF, 0x1C, 0xCA, 0xB4, 0x89, 0xA3, 0xF1, 0x6F, 0xCE, 0x37, 0x63, 0x43, 0xD7, - 0x88, 0x10, 0x74, 0x3A, 0x15, 0xAB, 0x54, 0x28, 0x34, 0xA4, 0x93, 0xC9, 0x1B, 0x59, 0xC0, 0xC6, - 0x59, 0x33, 0x42, 0x1D, 0x32, 0x0E, 0xE1, 0x14, 0x32, 0x38, 0xE4, 0x47, 0x64, 0xD8, 0x54, 0x99, - 0xFD, 0x1F, 0xF4, 0x38, 0xD8, 0xE5, 0x2D, 0x16, 0x0B, 0x07, 0x0F, 0x1E, 0x24, 0x2A, 0x2A, 0x0A, - 0x3F, 0x3F, 0x3F, 0x0C, 0x06, 0x03, 0xAA, 0xCD, 0x17, 0xA1, 0x69, 0x1A, 0x75, 0x75, 0x75, 0x98, - 0x4C, 0x26, 0x4A, 0x4B, 0x4B, 0xC9, 0xCE, 0xCE, 0xE6, 0xC0, 0x81, 0x03, 0xEC, 0xDE, 0xBD, 0x9B, - 0x7D, 0xFB, 0xF6, 0x71, 0xEE, 0xDC, 0xB9, 0x2B, 0xEA, 0x94, 0x44, 0x86, 0x04, 0xE2, 0xEE, 0xD6, - 0x82, 0x68, 0x7D, 0x4D, 0xD0, 0x35, 0x32, 0x84, 0xB7, 0x9E, 0x99, 0xC2, 0xAC, 0xC9, 0xE3, 0x29, - 0xBC, 0x58, 0x8E, 0xC1, 0xDD, 0x8D, 0xE8, 0xB0, 0x20, 0x7C, 0x7D, 0xBC, 0x6D, 0x8E, 0x29, 0xE7, - 0xBB, 0x43, 0x08, 0x3C, 0x0D, 0x6E, 0x4C, 0xBD, 0x6F, 0x34, 0x93, 0x46, 0x0F, 0x21, 0xBF, 0xF8, - 0x22, 0x56, 0x4D, 0x10, 0x16, 0xE4, 0x4F, 0xA0, 0xBF, 0xAF, 0xA4, 0xA2, 0x53, 0x8B, 0xB3, 0x5C, - 0xE3, 0x3C, 0xDD, 0xDD, 0xB9, 0x24, 0xD5, 0xF2, 0x3A, 0xE0, 0x0F, 0xC8, 0x52, 0x4E, 0x7D, 0x80, - 0x18, 0x64, 0x5C, 0x5A, 0x28, 0x32, 0x11, 0x54, 0x8F, 0xD4, 0x9A, 0xAA, 0x6D, 0xC4, 0x2E, 0x45, - 0xC6, 0x6F, 0x1D, 0x47, 0x56, 0x27, 0x3A, 0x8B, 0x2C, 0x6C, 0x73, 0xC5, 0xCD, 0xF5, 0x38, 0x64, - 0x92, 0x6E, 0xDC, 0xB8, 0x91, 0x3D, 0x7B, 0xF6, 0x10, 0x1A, 0x1A, 0x4A, 0x68, 0x68, 0x28, 0x46, - 0xA3, 0x11, 0x2F, 0x2F, 0x2F, 0x54, 0x55, 0xA5, 0xB6, 0xB6, 0x96, 0xCA, 0xCA, 0x4A, 0x8A, 0x8B, - 0x8B, 0x29, 0x2C, 0x2C, 0xA4, 0xA4, 0xA4, 0x04, 0x93, 0xC9, 0x74, 0x4D, 0x6D, 0x23, 0x24, 0xD0, - 0x5F, 0x6A, 0x58, 0x2D, 0x31, 0x77, 0x68, 0x02, 0x9D, 0xA2, 0x10, 0x15, 0x16, 0x44, 0x54, 0x78, - 0x70, 0x3D, 0x61, 0x5B, 0x6D, 0xB6, 0x17, 0x80, 0xD0, 0xF0, 0xF3, 0xF1, 0xC2, 0xCF, 0xD7, 0xBB, - 0xA1, 0xBF, 0x96, 0x68, 0x49, 0x02, 0x42, 0x02, 0xFD, 0xF0, 0xF5, 0xF6, 0xB0, 0x33, 0xC4, 0x1D, - 0x39, 0x4B, 0x76, 0xD8, 0x7E, 0x20, 0x67, 0x89, 0x3B, 0x52, 0xFC, 0xEB, 0x6C, 0xC7, 0x16, 0x1B, - 0xF3, 0x9C, 0xAE, 0x6C, 0xA7, 0x07, 0x7E, 0x02, 0x46, 0x83, 0xD4, 0x0A, 0xCA, 0xCA, 0xCA, 0x28, - 0x2B, 0x2B, 0xE3, 0xE4, 0xC9, 0x93, 0x2D, 0x7D, 0xF4, 0x3A, 0xE0, 0x02, 0xD2, 0xCB, 0xE8, 0x09, - 0x10, 0xE4, 0xEF, 0xD3, 0x7A, 0xA3, 0x60, 0x4B, 0x89, 0xE6, 0xCA, 0xFE, 0x84, 0x20, 0xD0, 0xD7, - 0x9B, 0x40, 0x3F, 0x1F, 0xF2, 0x8A, 0xCB, 0xEC, 0xAD, 0x51, 0x97, 0xFF, 0x17, 0xD2, 0x6F, 0xDE, - 0x26, 0xE8, 0x91, 0x36, 0xF9, 0x67, 0x80, 0xE1, 0xC8, 0xCD, 0xA1, 0x0F, 0xCE, 0xC9, 0xC4, 0x3A, - 0xE4, 0xB4, 0xCB, 0x46, 0xCA, 0xC1, 0x6D, 0xC0, 0x79, 0x64, 0x15, 0xB7, 0xAE, 0x00, 0x7E, 0xDE, - 0xED, 0x9A, 0xED, 0xD5, 0x89, 0x10, 0x78, 0x7B, 0x7A, 0x60, 0xF4, 0xF3, 0x71, 0x6C, 0x0C, 0x72, - 0xC5, 0x9D, 0xF4, 0x48, 0xB9, 0xF6, 0x7B, 0x64, 0x40, 0x57, 0x37, 0xE4, 0xBE, 0xA4, 0x2B, 0xD2, - 0x14, 0x1F, 0x8C, 0x9C, 0x86, 0x3A, 0xA4, 0x65, 0xB0, 0x0C, 0x29, 0x0F, 0xCF, 0x03, 0x27, 0x69, - 0x90, 0x87, 0x17, 0x91, 0x6F, 0x48, 0x4F, 0x1C, 0xEA, 0x61, 0x79, 0x7A, 0x18, 0x3A, 0xAF, 0x88, - 0x60, 0x7B, 0x42, 0x80, 0x9B, 0x5E, 0x87, 0xBF, 0x4F, 0x23, 0x43, 0x6B, 0xDB, 0x4C, 0x19, 0x4D, - 0xC0, 0xBE, 0xE2, 0xD6, 0x21, 0x6B, 0x1E, 0xE6, 0x03, 0x76, 0x4F, 0x8C, 0x62, 0x3B, 0xEF, 0xB8, - 0xCD, 0xAE, 0xE3, 0xDA, 0x26, 0x5B, 0x9D, 0xFD, 0xFF, 0x55, 0x45, 0xC1, 0x5D, 0xAF, 0xBB, 0xB1, - 0x9C, 0x52, 0xD7, 0x22, 0x94, 0x5E, 0x87, 0x6F, 0xE3, 0x19, 0xEF, 0x47, 0xC3, 0x8B, 0xDA, 0x7E, - 0xF7, 0xB9, 0xC6, 0x39, 0xC1, 0x2F, 0xB4, 0xD6, 0x60, 0x6B, 0xA0, 0x2A, 0x0A, 0x9E, 0x86, 0x46, - 0xB1, 0x67, 0x9E, 0xB8, 0x80, 0x21, 0xED, 0x9D, 0x63, 0x58, 0x3F, 0x1F, 0x84, 0x10, 0xD2, 0x3B, - 0xF7, 0x4B, 0x10, 0x59, 0x00, 0x8A, 0x82, 0xA1, 0xB1, 0x0A, 0x6F, 0xD7, 0xA4, 0xDA, 0x15, 0xED, - 0xCD, 0x90, 0x1A, 0xA0, 0x16, 0x40, 0x13, 0x82, 0x6A, 0x73, 0xED, 0x2F, 0x46, 0x64, 0x01, 0x97, - 0x07, 0x78, 0xDC, 0x30, 0x0C, 0x31, 0xD9, 0x0F, 0x2A, 0xAA, 0x4C, 0x6D, 0xE8, 0xEA, 0x3A, 0x83, - 0x10, 0xD2, 0x2A, 0xDC, 0x00, 0x0D, 0x17, 0xBC, 0x6E, 0xED, 0xCD, 0x10, 0x13, 0xB2, 0xCE, 0x09, - 0x00, 0x45, 0xA5, 0xE5, 0xAE, 0x8F, 0x32, 0xEC, 0x20, 0x08, 0x21, 0x30, 0x35, 0x36, 0xE7, 0x9B, - 0x70, 0x41, 0x35, 0x39, 0x57, 0x30, 0xA4, 0xBE, 0x70, 0xC0, 0x85, 0xE2, 0x8B, 0x88, 0x1B, 0x21, - 0x30, 0xCE, 0x09, 0x58, 0x35, 0x8D, 0x4B, 0xD5, 0x8D, 0x66, 0xFC, 0x0D, 0xC1, 0x90, 0x1A, 0x1C, - 0x82, 0x88, 0xCF, 0xE6, 0x15, 0x61, 0x32, 0xB7, 0x79, 0xF3, 0xDA, 0xF9, 0x50, 0xA0, 0xA6, 0xB6, - 0x8E, 0x92, 0xF2, 0x4B, 0x8E, 0xAD, 0xC5, 0xDC, 0x00, 0x22, 0x0B, 0xE4, 0x66, 0x11, 0x80, 0x9C, - 0xFC, 0x62, 0xF9, 0x10, 0x6D, 0x89, 0xA9, 0xBA, 0x2E, 0xA0, 0x70, 0xC9, 0x64, 0x96, 0xAE, 0xDE, - 0x06, 0xB4, 0x7B, 0xF1, 0x32, 0x70, 0x5D, 0x69, 0x8D, 0x5A, 0x80, 0xFC, 0x92, 0x32, 0x4E, 0x9D, - 0xCB, 0x77, 0x2E, 0x28, 0xE1, 0x7A, 0x86, 0xA2, 0x50, 0x50, 0x5A, 0x4E, 0x51, 0x43, 0x34, 0x8C, - 0x40, 0x5A, 0x2B, 0xDA, 0x1D, 0xAE, 0x60, 0xC8, 0x49, 0x64, 0x26, 0x2A, 0x55, 0xA6, 0x2B, 0x03, - 0x0D, 0x6E, 0x48, 0x28, 0x0A, 0xA7, 0xCE, 0xE5, 0x53, 0x7E, 0xA9, 0xDE, 0xBD, 0x5C, 0x89, 0xF4, - 0x69, 0xB4, 0x3B, 0x5C, 0xC1, 0x90, 0x73, 0xC8, 0xCF, 0x4E, 0x00, 0xB0, 0x65, 0xDF, 0x61, 0xAA, - 0xAB, 0xCD, 0x9D, 0xBF, 0x41, 0x54, 0x14, 0x19, 0x92, 0xDA, 0x9A, 0x28, 0x4C, 0x21, 0xD8, 0x77, - 0xE4, 0x14, 0x96, 0xBA, 0xFA, 0x35, 0x3C, 0x1F, 0x69, 0xC3, 0x6B, 0x77, 0xB8, 0x82, 0x21, 0x26, - 0xE4, 0x57, 0x6E, 0x00, 0x48, 0x3F, 0x96, 0xC5, 0xE1, 0x53, 0x39, 0xAD, 0x23, 0x84, 0x1D, 0x8A, - 0xD2, 0x40, 0xD0, 0x96, 0xAE, 0x47, 0x0A, 0xA0, 0xD3, 0x51, 0x71, 0xA9, 0x9A, 0x9D, 0xE9, 0x47, - 0x39, 0x9E, 0xD5, 0xC2, 0x4F, 0x82, 0x28, 0x0A, 0xE5, 0x95, 0x97, 0xD8, 0x91, 0x71, 0xDC, 0xB1, - 0xF5, 0x20, 0x36, 0x29, 0xD0, 0xDE, 0x70, 0xD5, 0x67, 0x18, 0x36, 0xDB, 0x06, 0x1C, 0x52, 0x52, - 0x5E, 0xC9, 0xAA, 0x4D, 0xBB, 0x19, 0xDC, 0xA7, 0xF5, 0x51, 0x90, 0xCB, 0x37, 0xEC, 0x64, 0xF7, - 0xA1, 0x4C, 0x46, 0xDF, 0xD2, 0x87, 0x61, 0x03, 0x7B, 0x39, 0x9F, 0xE8, 0xA9, 0x28, 0x54, 0x9B, - 0x6B, 0xF8, 0xF1, 0xA7, 0x03, 0x2C, 0x59, 0xB3, 0x91, 0xED, 0xFB, 0x8F, 0xD2, 0x3B, 0x36, 0x9A, - 0xB5, 0xF3, 0x9E, 0x27, 0x2A, 0x2C, 0xC8, 0xB9, 0x3D, 0x92, 0xAA, 0xB0, 0xF7, 0xC8, 0x69, 0x0E, - 0x64, 0x66, 0xDB, 0x5B, 0x84, 0xED, 0xF9, 0x5C, 0x62, 0xE7, 0x73, 0x55, 0x8D, 0x8E, 0x12, 0x64, - 0xAC, 0x70, 0x1F, 0x80, 0x0B, 0xC5, 0xA5, 0x8C, 0x1D, 0xD2, 0x8F, 0x90, 0xA0, 0x80, 0x96, 0x6D, - 0x14, 0x6D, 0x8B, 0xE9, 0xF4, 0xD7, 0xDF, 0xE7, 0xDB, 0x94, 0x34, 0xD6, 0x6E, 0xDF, 0xC7, 0xB6, - 0xB4, 0x23, 0x18, 0xFD, 0x7C, 0xE8, 0xD9, 0x35, 0xB2, 0xE9, 0x98, 0x5C, 0xDB, 0xB5, 0x85, 0x17, - 0xCB, 0xF9, 0xDF, 0x7F, 0x7C, 0xC6, 0x6B, 0xEF, 0x7F, 0xC5, 0xB1, 0xEC, 0x5C, 0x2C, 0x75, 0x56, - 0xAA, 0xCC, 0x35, 0xDC, 0x3F, 0x62, 0x30, 0x51, 0xE1, 0xCE, 0x31, 0xA4, 0xCE, 0x6A, 0xE5, 0x8D, - 0x65, 0xFF, 0x62, 0xEF, 0xE1, 0xFA, 0x25, 0xE3, 0x3C, 0x32, 0x13, 0xB9, 0xB8, 0xD9, 0x8B, 0x5B, - 0x01, 0x57, 0xD5, 0xDF, 0xAB, 0x45, 0x3A, 0xAA, 0xAA, 0x01, 0xB2, 0x2F, 0x14, 0xB1, 0x74, 0xED, - 0x16, 0xB4, 0x56, 0x84, 0x61, 0x6A, 0x9A, 0x46, 0x8D, 0x45, 0x7A, 0x40, 0xCD, 0x35, 0xB5, 0xA4, - 0x1E, 0x38, 0xC1, 0xB4, 0x3F, 0x2D, 0xE6, 0x93, 0xEF, 0xB6, 0x35, 0xBD, 0x2E, 0xD9, 0x66, 0xC6, - 0x4B, 0x0B, 0x97, 0xB3, 0x74, 0xED, 0x16, 0xCC, 0x0E, 0xA1, 0xA2, 0x31, 0xE1, 0xC1, 0x44, 0x85, - 0x19, 0x9B, 0x8F, 0xC4, 0x07, 0xD0, 0xA9, 0xEC, 0x3B, 0x72, 0x8A, 0x75, 0x3B, 0xD2, 0x1D, 0x5B, - 0xBF, 0x47, 0xFA, 0xD2, 0x5D, 0x02, 0x57, 0x16, 0x44, 0xDC, 0x82, 0x8C, 0xAA, 0x00, 0xE0, 0xCB, - 0xEF, 0x77, 0xB0, 0xEB, 0xE0, 0x49, 0xB9, 0x0E, 0x38, 0x0B, 0x21, 0x08, 0x33, 0x06, 0x70, 0xD7, - 0x6D, 0xFD, 0xEB, 0x9B, 0xBC, 0x3D, 0x0D, 0x18, 0xDC, 0xDD, 0x78, 0xE5, 0xDD, 0x15, 0xEC, 0xFC, - 0xF9, 0xC4, 0xD5, 0xD7, 0x26, 0x45, 0x61, 0xD5, 0xC6, 0x9F, 0xF8, 0xF4, 0xDF, 0xDB, 0x19, 0x79, - 0x73, 0x62, 0xFD, 0xF5, 0xC1, 0x01, 0xBE, 0x3C, 0x3F, 0xE5, 0x5E, 0x19, 0x6B, 0xEC, 0x44, 0xF4, - 0xA3, 0xD9, 0x5C, 0xC3, 0xA2, 0xAF, 0x7E, 0xA0, 0xE8, 0x62, 0x85, 0xBD, 0xB5, 0x14, 0x17, 0x7F, - 0xD8, 0xC5, 0x95, 0x65, 0x85, 0x2C, 0x48, 0xD1, 0x75, 0x2F, 0xE0, 0x51, 0x65, 0xAA, 0xA1, 0xE8, - 0x62, 0x05, 0xF7, 0x0C, 0x1D, 0x88, 0x87, 0xC1, 0xF9, 0xA2, 0x39, 0x8A, 0xAA, 0x92, 0xD4, 0xB3, - 0x2B, 0x25, 0x65, 0x95, 0x14, 0x94, 0x94, 0x73, 0xEF, 0xF0, 0x9B, 0x99, 0xFD, 0xD8, 0x44, 0xBE, - 0x4D, 0x49, 0x27, 0x33, 0x27, 0x8F, 0x7B, 0x87, 0x0D, 0xC2, 0xE0, 0xD8, 0x9F, 0xA2, 0x90, 0x5B, - 0x58, 0xC2, 0xEF, 0xDF, 0x5A, 0x86, 0x5E, 0xA7, 0x63, 0xD9, 0x1F, 0x9F, 0xE0, 0x81, 0x91, 0xB7, - 0x12, 0xDF, 0x35, 0x82, 0x19, 0x0F, 0x8F, 0x63, 0xDC, 0xED, 0x03, 0x9D, 0xDB, 0x16, 0xE9, 0x54, - 0x56, 0x6F, 0xDA, 0xCD, 0x9C, 0x8F, 0xBF, 0x71, 0xD4, 0xAE, 0xBE, 0x44, 0x7E, 0x15, 0xC1, 0x65, - 0xF6, 0x20, 0x57, 0xD7, 0x79, 0x3A, 0x87, 0x0C, 0x33, 0x1A, 0x0C, 0x70, 0xE6, 0x42, 0x21, 0x46, - 0x3F, 0x6F, 0x7E, 0x95, 0x14, 0xD7, 0x22, 0x2D, 0xD8, 0xD7, 0xDB, 0x8B, 0x3B, 0x6F, 0xEB, 0xCF, - 0x83, 0xA3, 0x87, 0x30, 0x69, 0xF4, 0x10, 0x92, 0xE2, 0x63, 0x11, 0x42, 0xE3, 0x93, 0x75, 0xDB, - 0xE9, 0xD3, 0x3D, 0x9A, 0xC4, 0x9E, 0x31, 0x0D, 0x6F, 0xBC, 0x4E, 0xE5, 0x8B, 0x7F, 0xA7, 0xF0, - 0xD9, 0xFA, 0x14, 0x5E, 0xFD, 0xAF, 0x87, 0xB8, 0x7F, 0xD4, 0xAD, 0x04, 0xFA, 0x7B, 0x73, 0x4B, - 0xDF, 0x38, 0x62, 0x22, 0x42, 0x9C, 0x13, 0x09, 0xAA, 0xCA, 0x89, 0xEC, 0x5C, 0x9E, 0x7A, 0x6B, - 0x19, 0xB9, 0x85, 0xF5, 0xB1, 0xB7, 0x39, 0xC0, 0xB3, 0x34, 0x91, 0x5F, 0xDE, 0x5E, 0x70, 0x35, - 0x43, 0x34, 0xE4, 0x46, 0x71, 0x14, 0x10, 0xAA, 0x69, 0x82, 0x03, 0x27, 0xCF, 0xD2, 0x3F, 0x3E, - 0x96, 0xEE, 0x31, 0x11, 0x2D, 0x5A, 0xE0, 0xDD, 0x74, 0x3A, 0x8C, 0x81, 0x7E, 0x78, 0xB8, 0xCB, - 0x0C, 0xE0, 0xB8, 0xAE, 0x91, 0x6C, 0xDE, 0x7B, 0x88, 0xFC, 0x92, 0x8B, 0xDC, 0x3F, 0xE2, 0x96, - 0xFA, 0x05, 0xBE, 0xB6, 0xD6, 0xC2, 0x5F, 0x96, 0x7E, 0x8D, 0x97, 0x87, 0x81, 0x37, 0x9F, 0xFE, - 0x0D, 0x3E, 0x9E, 0x86, 0x86, 0x88, 0x13, 0x67, 0xEE, 0xA7, 0x28, 0x94, 0x55, 0x56, 0xF1, 0xEC, - 0xDF, 0x3F, 0x61, 0x6B, 0x5A, 0x7D, 0x04, 0xA5, 0x15, 0xF9, 0x71, 0x81, 0xD5, 0x2E, 0xA6, 0x57, - 0x87, 0xD4, 0x2E, 0x3F, 0x8D, 0xAC, 0x04, 0x51, 0x09, 0x50, 0x50, 0x2A, 0x35, 0x9F, 0xA3, 0xA7, - 0x72, 0x5A, 0xB6, 0x9E, 0x40, 0x43, 0x05, 0x07, 0x21, 0x08, 0x31, 0xFA, 0xF3, 0xDB, 0x09, 0x23, - 0x38, 0x73, 0xA1, 0x88, 0xCA, 0x2A, 0x53, 0xFD, 0x5E, 0xA5, 0xFC, 0x52, 0x35, 0x39, 0xF9, 0xC5, - 0xFC, 0xE7, 0xD8, 0xDB, 0x08, 0x0B, 0x0E, 0x68, 0xB1, 0x56, 0x67, 0xAE, 0xAD, 0xE5, 0xAF, 0x4B, - 0x57, 0xB3, 0x7A, 0xF3, 0x1E, 0xC7, 0x33, 0xDF, 0x21, 0x4B, 0x2E, 0xB9, 0x1C, 0x1D, 0x55, 0xE5, - 0x78, 0x35, 0xF0, 0x1E, 0x36, 0xEB, 0xE8, 0xCF, 0x27, 0xB2, 0x99, 0x31, 0xF7, 0x23, 0x72, 0x72, - 0x0B, 0x5B, 0xBF, 0x61, 0x14, 0x82, 0x31, 0x43, 0xFA, 0xD1, 0x2D, 0x2A, 0x94, 0x3A, 0x87, 0x7C, - 0x91, 0x3A, 0xAB, 0x95, 0x40, 0x3F, 0x1F, 0xC6, 0xDE, 0x9A, 0xD4, 0x32, 0x5B, 0xAC, 0xA2, 0x60, - 0xAE, 0xB5, 0x30, 0xE7, 0xA3, 0xB5, 0x2C, 0xFC, 0x6A, 0x83, 0x74, 0x3F, 0x4B, 0x1C, 0x01, 0x5E, - 0xC1, 0x21, 0xDC, 0xD3, 0x95, 0xE8, 0xA8, 0x5A, 0x81, 0x1A, 0x90, 0x81, 0x0C, 0x13, 0xEA, 0x05, - 0x90, 0x95, 0x5B, 0xC8, 0xC9, 0xB3, 0x17, 0xB8, 0xBD, 0x7F, 0x82, 0x73, 0xE5, 0x36, 0x2E, 0x87, - 0x00, 0x7F, 0x1F, 0x4F, 0x06, 0x27, 0xF6, 0x20, 0xD4, 0xE8, 0x57, 0x2F, 0xB2, 0xF4, 0x3A, 0x1D, - 0x91, 0x21, 0x46, 0x6E, 0xE9, 0xDD, 0x1D, 0x37, 0x9D, 0x93, 0x8F, 0xA7, 0xAA, 0x54, 0x56, 0x9B, - 0xF9, 0xDB, 0xD2, 0xD5, 0xCC, 0xFD, 0xFC, 0xBB, 0xFA, 0xC0, 0x6C, 0x64, 0xE0, 0xDF, 0x13, 0xC8, - 0x60, 0xC2, 0x0E, 0x41, 0x47, 0x16, 0x6F, 0xAC, 0x46, 0x7E, 0x65, 0x73, 0x10, 0x32, 0x16, 0x96, - 0xCC, 0x73, 0xF9, 0x1C, 0x3A, 0x95, 0xC3, 0xA0, 0x84, 0x6E, 0x84, 0xB6, 0x54, 0xBC, 0x20, 0x23, - 0x41, 0x02, 0xFC, 0x7D, 0x1A, 0x6D, 0x10, 0xDD, 0xF4, 0x3A, 0xE2, 0x6E, 0x8A, 0x72, 0x9E, 0x19, - 0x3A, 0x95, 0xF3, 0xF9, 0xC5, 0xBC, 0xF0, 0xCF, 0xCF, 0x79, 0x77, 0xF5, 0x8F, 0xD4, 0x5A, 0xEA, - 0xA3, 0x3E, 0x8B, 0x90, 0x45, 0x62, 0xBE, 0xE9, 0x40, 0x1A, 0x75, 0x78, 0x35, 0xCD, 0x8B, 0x48, - 0xA6, 0x0C, 0xC4, 0x96, 0x42, 0x77, 0x26, 0xB7, 0x90, 0x9D, 0x3F, 0x1F, 0x27, 0x36, 0x3C, 0x84, - 0xD8, 0xE8, 0xF0, 0x6B, 0xEF, 0xBE, 0xAF, 0x86, 0xAB, 0xF1, 0xD0, 0x49, 0x93, 0x88, 0x26, 0x20, - 0x25, 0xED, 0x08, 0x4F, 0xCE, 0x59, 0xCA, 0xB7, 0xDB, 0xD3, 0xB0, 0x36, 0x6C, 0x16, 0x0B, 0x90, - 0xCC, 0x58, 0xD1, 0xC1, 0xF4, 0xE9, 0x94, 0xF2, 0xA6, 0x85, 0xC8, 0x4F, 0x6B, 0xF7, 0xC5, 0x16, - 0x72, 0x5A, 0x50, 0x5A, 0xCE, 0x86, 0x9F, 0x7E, 0xA6, 0xA6, 0xA6, 0x96, 0x5E, 0x37, 0x45, 0xC9, - 0x04, 0x1A, 0x57, 0xC1, 0x66, 0xA4, 0xCC, 0x2D, 0x28, 0xE1, 0xEF, 0x9F, 0x7F, 0xC7, 0xEC, 0x05, - 0x5F, 0x34, 0xCA, 0xD2, 0x45, 0x2A, 0x21, 0x4F, 0x22, 0xF3, 0x35, 0x3A, 0x3C, 0x20, 0xA0, 0xB3, - 0xEA, 0xCD, 0x16, 0x21, 0x2D, 0xC2, 0x5D, 0x90, 0x5F, 0x8D, 0x56, 0x4D, 0xE6, 0x5A, 0x76, 0x64, - 0x1C, 0x27, 0xF5, 0xE7, 0xE3, 0xF8, 0x79, 0x79, 0x10, 0x13, 0x1E, 0x8C, 0xA1, 0xB9, 0x64, 0xD1, - 0x96, 0x40, 0x95, 0x96, 0xE2, 0xC2, 0xD2, 0x32, 0xBE, 0xF8, 0xF7, 0x0E, 0x9E, 0x7D, 0xE7, 0x13, - 0x56, 0x6D, 0xFC, 0xC9, 0x1E, 0xCD, 0x0E, 0x92, 0xF8, 0xDB, 0x91, 0xC5, 0x13, 0x5A, 0x57, 0xFE, - 0xA7, 0x1D, 0xD0, 0xD9, 0x5E, 0x8A, 0x40, 0xA4, 0x68, 0xF8, 0x3D, 0x0E, 0xDF, 0x3E, 0xF7, 0x34, - 0xB8, 0x33, 0x6C, 0x40, 0x2F, 0xA6, 0x8C, 0x1B, 0xCE, 0xE8, 0xC1, 0x7D, 0x09, 0x0F, 0x09, 0x40, - 0x51, 0x75, 0x36, 0x95, 0xD7, 0xC9, 0x1C, 0x11, 0x45, 0xB1, 0x79, 0x2A, 0x15, 0x6A, 0x6B, 0x6A, - 0x38, 0x95, 0x93, 0xCF, 0xBA, 0x9D, 0xE9, 0x7C, 0xB5, 0xF1, 0x27, 0x0E, 0x9C, 0x3C, 0x7B, 0x79, - 0x48, 0x4F, 0x39, 0xF0, 0x21, 0xF2, 0x23, 0x98, 0x2E, 0x71, 0xCD, 0x3A, 0x8B, 0xCE, 0x66, 0x08, - 0x48, 0x17, 0xC0, 0x9D, 0xC0, 0x8B, 0xC8, 0x62, 0xC4, 0xF5, 0xB3, 0xD6, 0x4D, 0xAF, 0x23, 0xBE, - 0x6B, 0x24, 0x23, 0x6F, 0xEE, 0xC3, 0xA8, 0x5B, 0x12, 0xE9, 0xD3, 0x3D, 0x86, 0x88, 0xE0, 0x40, - 0xBC, 0x3C, 0xDC, 0x1B, 0xAA, 0xCB, 0x35, 0x82, 0x00, 0x4D, 0x50, 0x6B, 0xB1, 0x50, 0x56, 0x51, - 0xC5, 0x99, 0x0B, 0x85, 0xEC, 0x3B, 0x7A, 0x9A, 0x2D, 0xFB, 0x0E, 0xB3, 0xFB, 0x50, 0x26, 0xF9, - 0x25, 0x65, 0x97, 0xE7, 0xB3, 0xD4, 0x21, 0x3F, 0xA5, 0x3A, 0x17, 0xF9, 0x01, 0xCC, 0x4E, 0x0F, - 0x9D, 0xBD, 0x1E, 0x18, 0x62, 0x47, 0x28, 0xB2, 0xB4, 0xC7, 0x34, 0xA4, 0x7A, 0xDC, 0x68, 0x6C, - 0xEE, 0x6E, 0x7A, 0x42, 0x8D, 0xFE, 0x74, 0x8B, 0x0C, 0x25, 0x36, 0x2A, 0x8C, 0x2E, 0xA1, 0x46, - 0x82, 0xFC, 0x7D, 0xF0, 0xF2, 0x34, 0xA0, 0x2A, 0x2A, 0xE6, 0x5A, 0x0B, 0x15, 0x97, 0xAA, 0xB9, - 0x50, 0x7C, 0x91, 0x9C, 0xFC, 0x62, 0xCE, 0xE4, 0x16, 0x72, 0xBE, 0xB0, 0x84, 0x8A, 0xAA, 0xAB, - 0x26, 0x15, 0xD5, 0x21, 0x93, 0x2C, 0x97, 0x02, 0x5F, 0x21, 0x8D, 0x86, 0xFF, 0x8F, 0xAB, 0x40, - 0x41, 0xA6, 0x44, 0xBC, 0x88, 0xDC, 0xB7, 0xD4, 0xD0, 0x82, 0xEF, 0xA2, 0x3B, 0xF1, 0x2B, 0x03, - 0x7E, 0x40, 0x32, 0x3D, 0xB4, 0xB3, 0x1F, 0xB6, 0x29, 0x02, 0x5C, 0xAF, 0x08, 0x45, 0xD6, 0x06, - 0xBE, 0x0B, 0xF8, 0x15, 0x72, 0xEF, 0xE2, 0x6C, 0x32, 0x91, 0x1D, 0x16, 0xA4, 0x23, 0xE9, 0x38, - 0x32, 0xA1, 0x68, 0x13, 0x72, 0x66, 0x54, 0x75, 0xF6, 0xC3, 0x35, 0x85, 0xEB, 0x99, 0x21, 0x76, - 0xE8, 0x90, 0x16, 0xE3, 0x3E, 0x48, 0xAB, 0x71, 0x5F, 0xA0, 0x07, 0x92, 0x61, 0x01, 0x34, 0xE4, - 0xF5, 0xD5, 0x22, 0x09, 0x5D, 0x8C, 0xF4, 0xEA, 0x1D, 0x45, 0xA6, 0x1C, 0x67, 0x20, 0x23, 0x44, - 0x2A, 0x5B, 0x76, 0xDB, 0xCE, 0xC1, 0xFF, 0x01, 0xCE, 0x34, 0xF5, 0xEC, 0x2D, 0xA9, 0x9C, 0xA8, - 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x63, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x32, 0x2D, 0x30, 0x31, 0x2D, 0x33, 0x31, 0x54, 0x31, - 0x33, 0x3A, 0x34, 0x31, 0x3A, 0x31, 0x38, 0x2D, 0x30, 0x38, 0x3A, 0x30, 0x30, 0xED, 0x4F, 0xCC, - 0x0D, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x6D, 0x6F, - 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x32, 0x2D, 0x30, 0x31, 0x2D, 0x33, 0x31, 0x54, - 0x31, 0x33, 0x3A, 0x34, 0x31, 0x3A, 0x31, 0x38, 0x2D, 0x30, 0x38, 0x3A, 0x30, 0x30, 0x9C, 0x12, - 0x74, 0xB1, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, - 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2E, - 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, +#include + +static const uint8_t mu_law_wave[] PROGMEM = { +0x52, 0x49, 0x46, 0x46, 0x84, 0x5D, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, +0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x40, 0x1F, 0x00, 0x00, 0x40, 0x1F, 0x00, 0x00, +0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x61, 0x63, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x5D, +0x00, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5D, 0x00, 0x00, 0xFB, 0xFD, 0xFF, 0xFE, 0xFF, 0x7F, +0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7C, 0x7D, +0x7C, 0x7C, 0x7D, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7E, 0xFF, 0x7F, +0x7D, 0x7C, 0x7B, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7C, 0x7C, 0x7B, +0x7B, 0x7B, 0x7A, 0x7A, 0x7B, 0x7A, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x7C, 0x7E, +0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x79, 0x79, 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x7E, 0xFF, 0xFE, 0xFE, +0xFF, 0x7E, 0x7C, 0x7D, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x79, 0x78, 0x79, +0x7A, 0x79, 0x78, 0x78, 0x78, 0x77, 0x78, 0x78, 0x79, 0x79, 0x78, 0x77, 0x77, 0x78, 0x78, 0x79, +0x7A, 0x79, 0x79, 0x78, 0x78, 0x7A, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, +0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFC, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF8, +0xF7, 0xF7, 0xF8, 0xF9, 0xF9, 0xFB, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFE, +0xFF, 0xFF, 0xFE, 0x7E, 0x7D, 0x7D, 0x7C, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7C, +0x7B, 0x7A, 0x79, 0x79, 0x79, 0x77, 0x77, 0x78, 0x79, 0x7B, 0x7C, 0x7B, 0x7B, 0x7C, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x79, 0x79, +0x78, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7B, 0x7B, 0x7A, 0x7C, 0x7E, 0x7D, 0x7E, 0x7E, 0x7C, 0x7C, +0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x79, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x78, 0x78, 0x7A, 0x7A, 0x79, +0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFC, 0xFB, 0xFB, 0xFC, +0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFE, 0xFF, 0x7E, 0x7E, 0xFF, 0xFF, 0x7E, 0x7E, 0x7D, 0x7B, +0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, +0x7C, 0x7B, 0x79, 0x7A, 0x7A, 0x7A, 0x7A, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7C, 0x79, 0x79, 0x7A, +0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7C, 0x7C, 0x7C, 0x7E, 0x7D, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0xFE, +0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, +0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7D, 0x7E, 0x7D, 0x7B, 0x7B, 0x7B, 0x79, 0x78, 0x77, +0x78, 0x78, 0x77, 0x77, 0x77, 0x78, 0x78, 0x76, 0x76, 0x75, 0x73, 0x73, 0x73, 0x72, 0x73, 0x73, +0x74, 0x74, 0x74, 0x75, 0x77, 0x78, 0x78, 0x77, 0x76, 0x77, 0x76, 0x76, 0x78, 0x79, 0x79, 0x79, +0x78, 0x79, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7E, +0x7E, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFD, 0xFE, 0xFF, 0xFD, 0xFE, 0x7F, 0xFF, +0x7F, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7E, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7D, 0x7F, +0xFF, 0xFF, 0xFE, 0xFE, 0x7F, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7C, 0x7D, +0x7D, 0x7D, 0x7D, 0x7E, 0x7F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFF, 0xFE, 0xFC, 0xFD, 0xFC, 0xFC, 0xFD, +0xFC, 0xFB, 0xFB, 0xFC, 0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFD, 0xFE, +0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7D, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7D, 0x7B, 0x7B, 0x79, +0x78, 0x78, 0x78, 0x76, 0x74, 0x74, 0x73, 0x72, 0x75, 0x77, 0x77, 0x76, 0x75, 0x75, 0x76, 0x77, +0x77, 0x76, 0x74, 0x74, 0x74, 0x74, 0x76, 0x76, 0x76, 0x77, 0x75, 0x76, 0x78, 0x79, 0x77, 0x77, +0x79, 0x7B, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7D, 0x7F, 0x7E, 0xFF, 0xFF, 0x7F, 0xFE, 0xFC, 0xFE, +0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFD, 0xFC, 0xFE, 0xFF, 0x7E, 0x7F, 0x7F, 0x7D, 0x7E, 0xFF, 0x7F, +0x7F, 0xFF, 0x7F, 0x7E, 0x7D, 0x7E, 0xFF, 0x7E, 0x7F, 0x7F, 0x7C, 0x7D, 0x7F, 0x7D, 0x7E, 0x7E, +0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7B, 0x7D, 0x7B, 0x7A, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7C, +0x7D, 0x7E, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0xFF, 0xFD, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFB, 0xFB, +0xFA, 0xFB, 0xFB, 0xFB, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x7E, 0x7E, 0x7D, 0x7B, 0x7B, 0x7B, +0x78, 0x79, 0x78, 0x75, 0x76, 0x76, 0x76, 0x76, 0x74, 0x74, 0x73, 0x73, 0x74, 0x73, 0x72, 0x73, +0x75, 0x75, 0x74, 0x76, 0x74, 0x72, 0x73, 0x74, 0x75, 0x75, 0x76, 0x77, 0x77, 0x78, 0x77, 0x77, +0x77, 0x78, 0x78, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x7A, 0x79, 0x7B, 0x7C, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7C, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, +0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, +0xFE, 0x7E, 0x7E, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7E, 0xFF, 0x7E, 0x7E, 0x7E, 0x7D, +0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFC, 0xFE, 0x7F, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, +0x7F, 0x7E, 0x7D, 0x7D, 0x7D, 0x7B, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, 0x7D, 0x7C, 0x7C, +0x7D, 0x7C, 0x7C, 0x7E, 0x7E, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, +0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFB, +0xFB, 0xFB, 0xFA, 0xFB, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, +0x7E, 0x7E, 0x7E, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7F, +0x7D, 0x7B, 0x7C, 0x7C, 0x7D, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7E, +0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x78, 0x77, 0x77, 0x76, 0x74, 0x73, +0x72, 0x73, 0x74, 0x75, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, +0x7C, 0x7D, 0x7E, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7D, 0x7C, 0x7B, +0x7A, 0x7B, 0x7B, 0x7A, 0x7A, 0x79, 0x79, 0x7A, 0x79, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x79, 0x79, +0x79, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7C, 0x7B, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7F, +0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7D, 0x7D, +0x7D, 0x7D, 0x7E, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7F, 0x7F, 0x7E, 0x7F, 0x7E, 0x7E, 0x7F, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7F, 0x7F, 0x7E, +0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, +0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, +0x7D, 0x7E, 0xFF, 0x7E, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7A, +0x7A, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7D, 0x7C, 0x7C, 0x7A, 0x79, 0x79, 0x78, 0x78, +0x78, 0x77, 0x77, 0x76, 0x75, 0x74, 0x74, 0x74, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x76, 0x75, +0x74, 0x75, 0x77, 0x78, 0x78, 0x7A, 0x7B, 0x7D, 0xFF, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, +0xFC, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, +0xF8, 0xFA, 0xF8, 0xF6, 0xF7, 0xF7, 0xF8, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFB, +0xFB, 0xFB, 0xFD, 0xFE, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, +0x7F, 0x7E, 0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0xFD, 0xFE, 0xFF, +0xFE, 0xFE, 0xFD, 0xFE, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7E, 0x7F, +0x7D, 0x7D, 0x7E, 0x7E, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x79, 0x77, 0x78, 0x79, 0x78, 0x77, 0x76, +0x76, 0x75, 0x73, 0x74, 0x73, 0x71, 0x70, 0x70, 0x71, 0x72, 0x71, 0x71, 0x70, 0x6F, 0x6F, 0x6F, +0x70, 0x71, 0x71, 0x72, 0x73, 0x74, 0x74, 0x74, 0x76, 0x77, 0x76, 0x78, 0x79, 0x79, 0x79, 0x78, +0x7A, 0x7B, 0x7B, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, +0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7D, +0x7D, 0x7D, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7C, 0x7A, 0x78, 0x79, 0x78, 0x77, +0x76, 0x78, 0x79, 0x78, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7A, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, +0x7E, 0xFF, 0xFD, 0xFC, 0xFC, 0xFA, 0xF9, 0xFA, 0xFB, 0xFA, 0xF9, 0xF8, 0xF8, 0xF9, 0xFA, 0xF9, +0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF7, 0xF9, 0xF9, 0xF8, 0xF8, 0xFA, 0xFB, 0xFA, 0xFB, 0xFD, 0xFD, +0xFC, 0xFD, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFF, 0x7F, 0x7F, 0x7E, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, +0x7A, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x75, 0x76, 0x77, 0x76, 0x75, 0x76, 0x76, 0x75, 0x76, 0x77, +0x78, 0x79, 0x7B, 0x7B, 0x7B, 0x7A, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7A, 0x7B, 0x7B, 0x7A, +0x7B, 0x7D, 0x7E, 0x7B, 0x7C, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFC, 0xFD, 0xFE, 0xFF, +0xFE, 0xFF, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7D, 0x7F, 0x7F, 0x7C, 0x7B, +0x7A, 0x78, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7C, 0x7C, 0x7A, 0x7B, 0x7C, 0x7C, 0x7B, 0x7C, 0x7C, +0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x79, 0x7A, 0x79, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, +0x7D, 0xFE, 0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFA, 0xF8, 0xF8, 0xF9, 0xF8, 0xF5, 0xF4, 0xF7, 0xF8, +0xF8, 0xF8, 0xF9, 0xFB, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7B, +0x7A, 0x7B, 0x7B, 0x7A, 0x78, 0x78, 0x77, 0x76, 0x76, 0x75, 0x76, 0x76, 0x76, 0x77, 0x75, 0x75, +0x76, 0x75, 0x76, 0x76, 0x78, 0x78, 0x77, 0x78, 0x76, 0x74, 0x75, 0x77, 0x79, 0x7A, 0x7A, 0x7B, +0x7C, 0x7D, 0x7D, 0x7D, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, +0xFE, 0x7F, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0xFF, 0xFD, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, +0xFC, 0xFD, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7C, +0x7B, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x7A, 0x7C, 0x7A, 0x7B, 0x7C, 0x7C, 0x7E, 0x7E, 0xFF, +0xFF, 0x7F, 0x7F, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, +0x7C, 0x7D, 0xFF, 0x7E, 0x7C, 0x7D, 0xFF, 0xFF, 0xFF, 0xFD, 0xFD, 0xFF, 0x7E, 0x7F, 0x7E, 0x7E, +0x7F, 0x7E, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x79, +0x77, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7C, 0x7D, 0x7D, 0x7E, 0xFD, 0xFD, 0xFE, 0xFC, 0xFC, 0xFB, +0xFB, 0xFC, 0xFB, 0xFB, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, +0xFF, 0xFF, 0xFD, 0xFC, 0xFD, 0xFD, 0xFC, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7D, 0x7C, 0x7D, 0x7E, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, +0x7B, 0x7C, 0x7D, 0x7B, 0x7B, 0x7C, 0x7A, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x75, 0x73, 0x72, +0x72, 0x72, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x74, +0x75, 0x76, 0x76, 0x76, 0x77, 0x78, 0x77, 0x78, 0x79, 0x77, 0x78, 0x78, 0x79, 0x7A, 0x7A, 0x7A, +0x7A, 0x79, 0x77, 0x76, 0x76, 0x78, 0x78, 0x77, 0x77, 0x77, 0x75, 0x74, 0x74, 0x75, 0x75, 0x76, +0x79, 0x79, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7D, 0xFF, 0xFD, 0xFD, 0xFE, 0xFF, 0xFE, 0xFC, +0xF9, 0xF9, 0xFB, 0xFA, 0xF9, 0xF8, 0xF8, 0xF8, 0xF6, 0xF4, 0xF6, 0xF8, 0xF7, 0xF7, 0xF9, 0xF9, +0xF9, 0xF8, 0xF8, 0xFB, 0xFA, 0xF9, 0xFA, 0xFB, 0xFC, 0xFE, 0xFC, 0xFD, 0xFF, 0x7E, 0x7F, 0x7E, +0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, 0x7A, 0x7A, 0x79, 0x79, 0x78, 0x77, 0x78, +0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, 0x7F, 0xFE, 0xFE, 0xFD, 0xFD, +0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFC, 0xFB, 0xFC, +0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, +0x7C, 0x7B, 0x7B, 0x7C, 0x79, 0x79, 0x79, 0x78, 0x76, 0x75, 0x76, 0x78, 0x77, 0x76, 0x76, 0x77, +0x76, 0x74, 0x74, 0x75, 0x75, 0x75, 0x74, 0x74, 0x76, 0x77, 0x78, 0x7A, 0x7C, 0x7B, 0x7A, 0x7D, +0x7E, 0x7E, 0x7C, 0x7D, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFE, 0xFF, +0xFF, 0x7F, 0x7E, 0x7F, 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFC, 0xFB, 0xFC, 0xFE, 0xFD, 0xFC, 0xFE, +0xFF, 0xFE, 0xFD, 0xFF, 0x7E, 0x7F, 0xFE, 0xFC, 0xFD, 0xFE, 0xFD, 0xFD, 0xFE, 0x7F, 0x7E, 0xFF, +0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, +0x7E, 0x7D, 0x7E, 0xFF, 0xFF, 0xFE, 0xFD, 0xFF, 0x7D, 0x7A, 0x79, 0x79, 0x7A, 0x7C, 0x7B, 0x7B, +0x7D, 0x7E, 0x7E, 0x7D, 0xFF, 0xFF, 0x7F, 0x7F, 0x7E, 0x7B, 0x7A, 0x7A, 0x7A, 0x78, 0x77, 0x77, +0x77, 0x78, 0x78, 0x76, 0x76, 0x76, 0x76, 0x74, 0x74, 0x73, 0x74, 0x74, 0x75, 0x74, 0x72, 0x74, +0x76, 0x74, 0x74, 0x76, 0x76, 0x74, 0x73, 0x73, 0x72, 0x73, 0x74, 0x76, 0x77, 0x75, 0x73, 0x75, +0x77, 0x78, 0x75, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7B, +0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7D, 0x7C, 0x7D, 0x7B, 0x7C, 0x7F, +0xFF, 0xFF, 0x7E, 0x7D, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x79, 0x77, 0x77, +0x78, 0x76, 0x76, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x7B, 0x7C, 0x7B, 0x7C, 0x7D, 0xFF, +0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, +0xFA, 0xF9, 0xF9, 0xF7, 0xF7, 0xF7, 0xF4, 0xF4, 0xF4, 0xF2, 0xEF, 0xEE, 0xEF, 0xF2, 0xF2, 0xF1, +0xF2, 0xF5, 0xF5, 0xF3, 0xF1, 0xF2, 0xF5, 0xF7, 0xF8, 0xFA, 0xFB, 0xFC, 0xFC, 0xFB, 0xFC, 0xFC, +0xFD, 0xFF, 0x7F, 0x7E, 0x7C, 0x7A, 0x7A, 0x78, 0x77, 0x76, 0x75, 0x75, 0x74, 0x71, 0x70, 0x71, +0x71, 0x71, 0x70, 0x6F, 0x71, 0x71, 0x71, 0x73, 0x75, 0x77, 0x77, 0x76, 0x79, 0x7A, 0x79, 0x79, +0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7F, 0xFF, 0xFE, 0xFF, 0x7E, 0x7D, 0x7E, 0x7E, 0x7D, 0x7D, +0x7E, 0x7C, 0x7C, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x77, 0x75, 0x75, 0x76, 0x78, 0x79, 0x78, +0x7A, 0x7C, 0x7C, 0x7A, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7B, 0x7D, 0x7D, 0x7C, +0x7C, 0x7E, 0xFF, 0x7F, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0xFF, 0x7F, 0x7E, +0x7D, 0x7D, 0xFF, 0xFF, 0x7F, 0xFF, 0xFC, 0xFC, 0xFD, 0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xFB, 0xFB, +0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0x7F, 0x7F, 0x7E, 0x7D, 0x7E, 0x7D, 0x7B, 0x7C, 0x7B, +0x7B, 0x7C, 0x7C, 0x7A, 0x78, 0x78, 0x7B, 0x7A, 0x77, 0x75, 0x76, 0x75, 0x76, 0x76, 0x76, 0x76, +0x78, 0x79, 0x78, 0x75, 0x75, 0x76, 0x77, 0x7A, 0x7D, 0xFF, 0xFC, 0xFB, 0xFA, 0xFA, 0xFB, 0xFA, +0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0x7E, 0x78, 0x76, 0x72, 0x70, 0x71, 0x75, 0x77, 0x77, 0x79, 0x7A, +0x7A, 0x7A, 0x7B, 0xFF, 0xFB, 0xFA, 0xF9, 0xFB, 0xFD, 0xFE, 0x7E, 0x7F, 0xFF, 0xFC, 0xF6, 0xF3, +0xF7, 0xFC, 0xFF, 0x7A, 0x73, 0x6E, 0x6C, 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6F, 0x74, 0x73, 0x72, +0x75, 0x7A, 0x7D, 0x7D, 0xFF, 0xFF, 0x7C, 0x7C, 0x7D, 0x7B, 0x7A, 0x79, 0x7B, 0xFF, 0xFF, 0x7D, +0x7C, 0xFF, 0xFE, 0x7D, 0xFC, 0xF3, 0xF6, 0xFC, 0xFE, 0xFE, 0xFF, 0x78, 0x75, 0x79, 0x7A, 0x7E, +0xF8, 0xF6, 0xF6, 0xF2, 0xEF, 0xEE, 0xF0, 0xF7, 0xFD, 0xFE, 0xFD, 0x7B, 0x77, 0x7C, 0xFF, 0xFB, +0xFD, 0x7D, 0xFF, 0x7C, 0x78, 0x7A, 0x7A, 0xFF, 0xF9, 0xF5, 0xF1, 0xF4, 0xFA, 0xFC, 0xFC, 0xFA, +0xF8, 0xFA, 0xFB, 0xFA, 0xFB, 0xFC, 0xFD, 0xFF, 0x7D, 0x7B, 0x7D, 0x7E, 0x7A, 0x76, 0x76, 0x75, +0x72, 0x75, 0x7B, 0x7D, 0x7A, 0x7A, 0x7D, 0xFF, 0x7C, 0x7C, 0xFF, 0x7D, 0x7A, 0x7B, 0x7C, 0x7E, +0xFC, 0xFC, 0x7F, 0xFE, 0xFD, 0xFE, 0xFC, 0xF8, 0xF9, 0xFA, 0xFB, 0xFE, 0x7E, 0x79, 0x72, 0x72, +0x74, 0x76, 0x78, 0x76, 0x78, 0x7A, 0x75, 0x76, 0x77, 0x75, 0x73, 0x73, 0x73, 0x73, 0x74, 0x73, +0x73, 0x77, 0x78, 0x79, 0x79, 0x7A, 0x79, 0x73, 0x73, 0x7B, 0x7C, 0x7C, 0xFC, 0xFC, 0xFE, 0x7F, +0x76, 0x73, 0x76, 0x73, 0x73, 0x78, 0x7C, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0x7D, 0x7B, 0x7B, +0x7C, 0x7A, 0x78, 0x7B, 0x7B, 0x7D, 0x7F, 0x7A, 0x77, 0x73, 0x6F, 0x70, 0x72, 0x73, 0x72, 0x72, +0x73, 0x74, 0x74, 0x76, 0x7D, 0xFE, 0x7D, 0x7C, 0x7C, 0x78, 0x76, 0x77, 0x79, 0x7B, 0xFF, 0xFD, +0xFE, 0x7E, 0x7B, 0x7A, 0x78, 0x78, 0x7B, 0x7C, 0x7C, 0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x79, 0x7B, +0xFF, 0xFA, 0xF9, 0xFD, 0x7E, 0x7D, 0x7C, 0x7B, 0x7E, 0xFE, 0xFC, 0xFF, 0x7E, 0xFE, 0xFD, 0xFE, +0xFD, 0xFC, 0xFB, 0xFC, 0xFC, 0xFD, 0xF9, 0xF3, 0xF2, 0xF3, 0xF4, 0xF6, 0xF6, 0xF8, 0xFA, 0xFC, +0xFB, 0xF7, 0xF9, 0xFC, 0xFC, 0xFD, 0xFD, 0x7E, 0x7C, 0x7F, 0xFF, 0x7D, 0x7A, 0x7A, 0x7B, 0x78, +0x78, 0x78, 0x75, 0x75, 0x76, 0x79, 0x7A, 0x79, 0x7C, 0x7F, 0xFD, 0xFF, 0x7E, 0xFF, 0x7D, 0x79, +0x77, 0x78, 0x79, 0x78, 0x79, 0x7C, 0x7D, 0x7F, 0x7E, 0x7E, 0xFE, 0xFC, 0xF8, 0xF7, 0xFA, 0xFB, +0xFC, 0xFD, 0xFF, 0x7D, 0x7E, 0x7F, 0xFF, 0x7D, 0x7B, 0x7D, 0xFE, 0xF9, 0xF5, 0xF6, 0xF6, 0xF4, +0xF6, 0xFA, 0xFE, 0x7D, 0x79, 0x78, 0x77, 0x77, 0x7A, 0x7E, 0xFE, 0xFF, 0xFF, 0xFA, 0xFA, 0xFE, +0x7C, 0x75, 0x71, 0x72, 0x74, 0x75, 0x74, 0x75, 0x75, 0x77, 0x79, 0x79, 0x77, 0x74, 0x74, 0x74, +0x72, 0x71, 0x70, 0x71, 0x70, 0x6F, 0x72, 0x73, 0x72, 0x73, 0x71, 0x70, 0x73, 0x78, 0x7A, 0x78, +0x77, 0x77, 0x76, 0x74, 0x73, 0x72, 0x70, 0x71, 0x75, 0x78, 0x7B, 0x7F, 0xFF, 0xFE, 0xFB, 0xFD, +0x7E, 0xFF, 0xFD, 0x7F, 0x7C, 0x7B, 0x7F, 0xFD, 0xFF, 0xFE, 0xFC, 0xFE, 0xFD, 0xFC, 0xFA, 0xF7, +0xF7, 0xFB, 0xFD, 0xFE, 0x7E, 0x7C, 0x7B, 0x7A, 0x7B, 0x79, 0x75, 0x75, 0x76, 0x78, 0x7D, 0xFF, +0x7E, 0x7D, 0x7E, 0x7C, 0x77, 0x75, 0x76, 0x76, 0x78, 0x7E, 0xFD, 0xFB, 0xFC, 0xFD, 0xFE, 0x7C, +0x78, 0x78, 0x7A, 0x7B, 0x7E, 0x7E, 0x7D, 0x7D, 0x7C, 0x7A, 0x78, 0x79, 0x7B, 0x7A, 0x7D, 0xFC, +0xFD, 0x7E, 0xFF, 0xFB, 0xF7, 0xF6, 0xF7, 0xF7, 0xF6, 0xFA, 0xFF, 0xFE, 0xFD, 0xFF, 0x7D, 0xFF, +0xFC, 0xFB, 0xF9, 0xFD, 0xFE, 0xFD, 0x7E, 0x79, 0x76, 0x71, 0x6F, 0x6E, 0x6E, 0x6F, 0x72, 0x76, +0x7A, 0x7E, 0xFF, 0xFF, 0x7C, 0x7B, 0x7C, 0x7B, 0x7A, 0x79, 0x7A, 0x7E, 0xFF, 0xFF, 0x7E, 0x7D, +0x7D, 0x7E, 0x7C, 0x78, 0x79, 0x7A, 0x7B, 0xFF, 0xFF, 0x7F, 0x7E, 0x7B, 0x79, 0x79, 0x76, 0x72, +0x73, 0x7B, 0xFF, 0xFE, 0xFB, 0xFA, 0xFA, 0xFC, 0x7D, 0x78, 0x77, 0x78, 0x79, 0x79, 0x78, 0x79, +0x77, 0x73, 0x74, 0x76, 0x77, 0x79, 0x7A, 0x7B, 0x7F, 0xFD, 0xFE, 0xFF, 0x7F, 0x7E, 0x7E, 0x7C, +0x78, 0x78, 0x7B, 0x7B, 0x7A, 0x7C, 0x7F, 0xFE, 0xFD, 0xFE, 0x7E, 0xFF, 0xFD, 0xFC, 0xF9, 0xF5, +0xF2, 0xF0, 0xF2, 0xF3, 0xF0, 0xF1, 0xF2, 0xF1, 0xF4, 0xF7, 0xF8, 0xFC, 0xFC, 0xF6, 0xF3, 0xF4, +0xF5, 0xF5, 0xF6, 0xFB, 0xFF, 0xFF, 0xFF, 0x7D, 0x7D, 0x7E, 0x7D, 0x79, 0x75, 0x74, 0x75, 0x72, +0x72, 0x75, 0x75, 0x74, 0x77, 0x7A, 0x7A, 0x7A, 0x7A, 0x77, 0x74, 0x73, 0x72, 0x74, 0x75, 0x76, +0x77, 0x74, 0x74, 0x77, 0x79, 0x79, 0x79, 0x78, 0x77, 0x74, 0x70, 0x6F, 0x70, 0x6F, 0x6E, 0x6E, +0x6E, 0x6F, 0x6F, 0x72, 0x75, 0x72, 0x74, 0x79, 0x7B, 0x7B, 0x7B, 0x7D, 0xFF, 0x7E, 0x7F, 0xFE, +0xFE, 0x7F, 0x7D, 0x7D, 0xFF, 0xFD, 0xFE, 0x7E, 0x7D, 0x7D, 0x7E, 0x7C, 0x79, 0x77, 0x75, 0x76, +0x77, 0x78, 0x78, 0x74, 0x75, 0x7A, 0x7F, 0xFB, 0xF9, 0xF9, 0xF8, 0xFD, 0x7E, 0x7B, 0x76, 0x78, +0x7B, 0x7C, 0x7E, 0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x7C, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0x7D, 0x7B, +0x7B, 0x79, 0x79, 0x7A, 0x7D, 0xFF, 0x7F, 0x7F, 0xFF, 0xFD, 0xFB, 0xFD, 0xFE, 0xFE, 0xFF, 0x7D, +0x7C, 0x7F, 0xFB, 0xF7, 0xF6, 0xFC, 0x7F, 0xFF, 0xFE, 0xFB, 0xFD, 0xFE, 0xFC, 0xFD, 0xFE, 0x7C, +0x76, 0x74, 0x74, 0x79, 0x79, 0x76, 0x77, 0x79, 0x7C, 0x7D, 0x7B, 0x7B, 0x7B, 0x7E, 0xFD, 0xFB, +0xF9, 0xF9, 0xFE, 0x7C, 0x79, 0x79, 0x77, 0x76, 0x79, 0x7B, 0x7D, 0x7C, 0x7C, 0x7D, 0x7C, 0x78, +0x75, 0x74, 0x72, 0x72, 0x73, 0x71, 0x70, 0x73, 0x78, 0x7C, 0x7D, 0x7E, 0xFF, 0x7F, 0x7F, 0x7D, +0x7A, 0x78, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x7B, 0xFF, 0xFF, 0xFD, 0xFC, 0xFC, 0xFA, 0xF9, +0xF8, 0xF9, 0xFE, 0x7E, 0xFF, 0xFE, 0xFE, 0x7D, 0x7A, 0x78, 0x75, 0x75, 0x77, 0x7A, 0x7A, 0x79, +0x7B, 0x7D, 0xFF, 0xFD, 0xFC, 0xFC, 0xFB, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9, 0xFB, 0xFA, 0xF9, 0xF7, +0xF8, 0xFA, 0xF8, 0xF9, 0xFC, 0xFD, 0xFD, 0xFC, 0xF9, 0xF7, 0xF8, 0xFC, 0x7E, 0x7B, 0x7A, 0x7A, +0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x77, 0x72, 0x72, 0x74, 0x76, 0x7B, 0x7C, 0x7B, 0x7D, 0x7E, 0x7D, +0x7D, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x78, 0x78, 0x79, 0x79, 0x79, 0x78, 0x79, 0x7B, 0x7C, 0x7C, +0x7A, 0x7A, 0x77, 0x75, 0x75, 0x74, 0x73, 0x70, 0x6E, 0x6E, 0x6E, 0x6F, 0x72, 0x75, 0x77, 0x7A, +0x7D, 0x7D, 0x7D, 0x7E, 0xFF, 0x7D, 0x7A, 0x7A, 0x7A, 0x7B, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, +0x7D, 0x7B, 0x78, 0x75, 0x73, 0x74, 0x75, 0x75, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7D, 0xFE, 0xFC, +0xF9, 0xF8, 0xF8, 0xF8, 0xF6, 0xF5, 0xF6, 0xF8, 0xFB, 0xFC, 0xFB, 0xFD, 0xFF, 0x7E, 0x7D, 0x7C, +0x7C, 0x7B, 0x7C, 0x7B, 0x79, 0x79, 0x7A, 0x79, 0x76, 0x74, 0x72, 0x72, 0x73, 0x74, 0x75, 0x77, +0x78, 0x78, 0x78, 0x77, 0x76, 0x75, 0x75, 0x78, 0x7A, 0x79, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0x7F, +0xFE, 0xFC, 0xFC, 0xFC, 0xFA, 0xF8, 0xF7, 0xF7, 0xF8, 0xF7, 0xF5, 0xF5, 0xF5, 0xF4, 0xF5, 0xF6, +0xF7, 0xF8, 0xF9, 0xFB, 0xFE, 0x7F, 0x7D, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7D, 0x7A, 0x7A, 0x7A, +0x7A, 0x79, 0x79, 0x79, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x7A, 0x7A, 0x79, 0x77, 0x76, +0x77, 0x77, 0x77, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7B, +0x78, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0x7F, 0x7F, 0xFE, +0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFE, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, +0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x76, 0x77, 0x78, 0x77, 0x79, +0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7D, 0x7B, 0x7B, 0x7D, 0x7C, 0x7D, 0xFF, 0x7E, +0xFF, 0xFD, 0xFB, 0xF9, 0xF8, 0xF9, 0xF9, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF3, 0xF5, 0xF6, 0xF6, +0xF7, 0xF9, 0xFB, 0xFB, 0xFA, 0xFA, 0xFB, 0xFC, 0xFB, 0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFA, 0xF8, +0xF8, 0xF9, 0xFB, 0xFD, 0x7E, 0x7B, 0x78, 0x78, 0x77, 0x77, 0x77, 0x76, 0x76, 0x76, 0x75, 0x75, +0x73, 0x71, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6E, 0x6E, 0x6F, 0x6F, 0x6E, 0x6E, 0x6E, 0x6D, +0x6D, 0x6E, 0x6D, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x79, 0x7C, 0x7D, 0x7E, 0xFF, +0xFF, 0xFF, 0xFD, 0xFC, 0xFA, 0xF9, 0xFB, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0x7E, 0x7B, 0x7A, +0x79, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7C, 0x7C, 0x7B, 0x79, 0x79, 0x78, 0x78, 0x79, 0x7A, 0x7C, +0x7E, 0x7E, 0x7E, 0x7C, 0x7B, 0x7A, 0x7A, 0x7A, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7D, 0xFF, 0xFD, +0xFC, 0xFB, 0xFA, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFB, 0xFB, +0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFD, 0xFC, 0xFC, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, 0xF7, +0xF6, 0xF7, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0x7E, 0x7D, 0x7C, 0x7C, +0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, +0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7B, 0x78, 0x77, 0x76, 0x75, 0x75, 0x75, 0x76, 0x76, 0x75, 0x76, +0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7B, 0x7D, 0x7D, 0x7E, 0x7F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, +0xFD, 0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0x7F, 0x7E, 0x7C, 0x7C, 0x7B, +0x7A, 0x7A, 0x7A, 0x78, 0x78, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7C, 0x7D, 0x7B, +0x7A, 0x7B, 0x7C, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7B, 0x7F, 0xFD, 0x7D, 0x79, 0xFE, +0xFA, 0xFE, 0xFC, 0xF8, 0xFC, 0xFF, 0xFF, 0xFE, 0xFB, 0xFC, 0x7F, 0xFF, 0x7F, 0x7C, 0x7D, 0x7D, +0x7E, 0x7E, 0x7B, 0x7A, 0x7A, 0x7B, 0x7C, 0x7E, 0x7E, 0x7C, 0x7B, 0x7A, 0x7A, 0x7B, 0x7C, 0x7D, +0x7D, 0x7E, 0x7F, 0x7E, 0x7F, 0xFF, 0xFE, 0xFD, 0xFE, 0xFF, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7E, +0x7D, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x7A, 0x7A, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x75, 0x74, 0x73, +0x74, 0x75, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x77, 0x76, 0x77, 0x77, 0x79, 0x7B, 0x7C, 0x7D, +0x7D, 0x7D, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFE, 0xFD, 0xFE, 0xFF, 0xFE, 0xFD, 0xFB, 0xFC, 0xFD, +0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7E, +0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, +0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, +0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, 0x7F, 0x7E, +0x7D, 0x7C, 0x7B, 0x7B, 0x79, 0x77, 0x77, 0x78, 0x76, 0x76, 0x78, 0x7A, 0x78, 0x78, 0x78, 0x77, +0x77, 0x76, 0x75, 0x76, 0x75, 0x75, 0x77, 0x77, 0x76, 0x74, 0x74, 0x75, 0x76, 0x75, 0x76, 0x76, +0x75, 0x76, 0x76, 0x75, 0x74, 0x73, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x78, 0x7A, 0x7A, 0x7B, +0x7C, 0x7B, 0x7D, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFE, 0xFD, 0xFD, 0xFD, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0xFE, +0xFE, 0xFE, 0x7F, 0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFD, 0xFD, 0xFD, +0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0xFE, 0xFC, 0xFA, 0xF9, 0xF8, 0xF8, 0xF8, 0xF9, 0xFA, +0xFD, 0xFE, 0xFC, 0xFD, 0xFE, 0xFE, 0xFF, 0x7F, 0xFF, 0x7E, 0x7D, 0x7B, 0x79, 0x79, 0x7B, 0x7C, +0x7C, 0x7D, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7B, 0x7B, 0x7A, 0x77, 0x78, 0x75, 0x75, 0x76, 0x76, +0x78, 0x75, 0x76, 0x77, 0x73, 0x75, 0x73, 0x77, 0x76, 0x73, 0x78, 0x73, 0x78, 0x77, 0x75, 0x7B, +0x70, 0x7E, 0x68, 0x5B, 0xE4, 0xD9, 0x77, 0x66, 0x5F, 0x6B, 0xEB, 0x78, 0x6B, 0xEC, 0xE9, 0x67, +0x5A, 0x62, 0xF8, 0xE2, 0xF1, 0x6B, 0x6F, 0x72, 0x6E, 0x6D, 0x72, 0xEF, 0xE7, 0xF7, 0x6D, 0x6A, +0x70, 0x7B, 0xFC, 0xF5, 0xED, 0xEF, 0x7D, 0x71, 0x70, 0xFF, 0xEE, 0xEF, 0xF8, 0xFC, 0x7B, 0x73, +0x6F, 0x71, 0x7E, 0xF2, 0xF2, 0x76, 0x67, 0x68, 0x78, 0xF7, 0xF5, 0xFC, 0x7E, 0x7B, 0x73, 0x70, +0x79, 0xF4, 0xEB, 0xEC, 0xF8, 0x7C, 0x7B, 0xFF, 0xF6, 0xEF, 0xEF, 0xF4, 0xF8, 0xFE, 0x7D, 0xFE, +0xF8, 0xF4, 0xF4, 0xF9, 0xFE, 0x7E, 0x7C, 0x7C, 0xFD, 0xF8, 0xF8, 0xFD, 0x7D, 0x7A, 0x79, 0x7C, +0xFF, 0xFD, 0xFB, 0xFC, 0x7D, 0x7B, 0x7D, 0x7F, 0xFD, 0xFD, 0xFF, 0x7E, 0x7C, 0x7A, 0x79, 0x7C, +0x7E, 0x7D, 0x7D, 0x7B, 0x78, 0x79, 0x7B, 0x7A, 0x78, 0x79, 0x77, 0x76, 0x78, 0x71, 0x70, 0x78, +0x7E, 0xF6, 0xFE, 0x67, 0x68, 0xF4, 0xEF, 0x74, 0x69, 0x6A, 0xFF, 0x7E, 0x6E, 0xF2, 0xFB, 0x69, +0x66, 0x69, 0xDD, 0xD9, 0x71, 0x7B, 0x74, 0x5F, 0x69, 0x61, 0x6A, 0xE6, 0xEC, 0x66, 0x55, 0x50, +0x5C, 0xFB, 0xED, 0xF5, 0xFA, 0x6F, 0x6E, 0x7B, 0xE8, 0xCF, 0xC7, 0xC6, 0xCA, 0xCB, 0xDB, 0x3A, +0x2E, 0x49, 0xBD, 0xB7, 0xC6, 0x4D, 0x41, 0x4B, 0x49, 0x4D, 0xD9, 0xBF, 0xC2, 0xFD, 0x3F, 0x3D, +0x51, 0xDF, 0xCD, 0xCC, 0xD5, 0xF4, 0x50, 0x46, 0x4D, 0xF0, 0xCB, 0xCA, 0xDA, 0x61, 0x51, 0x52, +0x5B, 0xE6, 0xD0, 0xCE, 0xDC, 0x5D, 0x53, 0x51, 0x6A, 0xF9, 0x48, 0x67, 0xC2, 0xE0, 0x5F, 0x5B, +0x4C, 0x71, 0xFA, 0x6E, 0xCE, 0xCF, 0x7A, 0x64, 0x79, 0xD8, 0xCE, 0xD1, 0xCD, 0xC3, 0xC5, 0xCD, +0xC7, 0xDC, 0x42, 0x3E, 0x53, 0xD2, 0xC0, 0xDE, 0x44, 0x48, 0x58, 0x53, 0x59, 0xFA, 0xD9, 0xD6, +0x5E, 0x43, 0x47, 0x61, 0xE1, 0xD8, 0xEA, 0x64, 0x46, 0x3C, 0x51, 0x7F, 0x77, 0xD0, 0xF6, 0x4B, +0x4B, 0x4A, 0x6F, 0xCA, 0xC6, 0xC9, 0xC7, 0xC2, 0xC8, 0xBD, 0xB0, 0xAB, 0xBB, 0x1F, 0x19, 0x5F, +0xA3, 0xA5, 0xBA, 0x30, 0x30, 0x47, 0x31, 0x37, 0xBC, 0xAB, 0xB8, 0x3D, 0x2B, 0x30, 0x4E, 0xBD, +0xB4, 0xC4, 0x5D, 0x3F, 0x38, 0x41, 0x6E, 0xC8, 0xC1, 0xDC, 0x4B, 0x3B, 0x3F, 0xE5, 0xBF, 0xBC, +0xC8, 0xE5, 0xDE, 0xC0, 0xAE, 0xAD, 0xAF, 0xC1, 0x20, 0x1A, 0x63, 0xA8, 0xA7, 0xB5, 0x36, 0x2E, +0x3D, 0x32, 0x3F, 0xBD, 0xB1, 0xC1, 0x39, 0x2E, 0x42, 0xE8, 0xCA, 0xC3, 0xDB, 0x5F, 0x47, 0x39, +0x47, 0xD5, 0xCB, 0xD1, 0x70, 0x4B, 0x4D, 0xF0, 0xC1, 0xB3, 0xAE, 0xB4, 0xBE, 0xB8, 0xB8, 0x34, +0x1C, 0x27, 0xB6, 0xA3, 0xAC, 0x4F, 0x2C, 0x32, 0x3B, 0x3E, 0xEB, 0xB9, 0xBB, 0x45, 0x2E, 0x39, +0x60, 0xC3, 0xBB, 0xD8, 0x4D, 0x45, 0x41, 0x57, 0xD6, 0xDE, 0x79, 0x5D, 0x50, 0x5B, 0xDB, 0xBE, +0xB4, 0xB3, 0xBC, 0xC4, 0xB6, 0xAC, 0xC2, 0x26, 0x1A, 0x30, 0xAB, 0xA9, 0xBB, 0x61, 0x33, 0x30, +0x36, 0x39, 0xCF, 0xB9, 0x64, 0x41, 0x42, 0x3E, 0x5E, 0xD3, 0xCF, 0xC4, 0xEC, 0x47, 0x56, 0x5C, +0x50, 0x57, 0x62, 0xDF, 0xD2, 0xD3, 0xC4, 0xB6, 0xB3, 0xBA, 0xB8, 0xAD, 0xAF, 0x3C, 0x1C, 0x1E, +0xCB, 0xA1, 0xA9, 0xFE, 0x2D, 0x2C, 0x39, 0x3D, 0x64, 0xBE, 0xD5, 0x4B, 0x42, 0x3A, 0x40, 0xEC, +0xC4, 0xBE, 0xD1, 0x4A, 0x3E, 0x47, 0x62, 0xE4, 0xD7, 0xD6, 0xDC, 0xDE, 0xCD, 0xB6, 0xAD, 0xAE, +0xAC, 0xAD, 0xE6, 0x22, 0x19, 0x2E, 0xA6, 0x9E, 0xB2, 0x39, 0x28, 0x2D, 0x39, 0x4E, 0xC2, 0xBE, +0x5B, 0x3E, 0x3B, 0x3C, 0x58, 0xC6, 0xBD, 0xC7, 0x60, 0x3F, 0x3F, 0x51, 0xED, 0xCF, 0xC8, 0xD1, +0xE0, 0xD9, 0xBC, 0xAC, 0xAB, 0xAB, 0xA9, 0xC2, 0x25, 0x17, 0x22, 0xAE, 0x9D, 0xA9, 0x47, 0x26, +0x29, 0x34, 0x47, 0xC5, 0xBB, 0x77, 0x3F, 0x3A, 0x38, 0x4E, 0xC6, 0xBC, 0xBE, 0xE6, 0x3D, 0x39, +0x43, 0x67, 0xCE, 0xC7, 0xD6, 0xED, 0xD9, 0xBD, 0xAB, 0xAB, 0xAE, 0xA9, 0xB4, 0x30, 0x1A, 0x1B, +0xD5, 0x9D, 0xA3, 0xDA, 0x2A, 0x26, 0x31, 0x3C, 0x6C, 0xBF, 0xCE, 0x5E, 0x42, 0x32, 0x3C, 0xD6, +0xBC, 0xB8, 0xCC, 0x3F, 0x37, 0x3B, 0x51, 0xCC, 0xC1, 0xCC, 0xE2, 0xDE, 0xBD, 0xAC, 0xAA, 0xA9, +0xA7, 0xC5, 0x26, 0x18, 0x1F, 0xB7, 0x9D, 0xA6, 0xDF, 0x2B, 0x26, 0x2D, 0x37, 0xEB, 0xBA, 0xCB, +0x5E, 0x3C, 0x30, 0x44, 0xC9, 0xBB, 0xB8, 0xCF, 0x3D, 0x34, 0x3B, 0x5F, 0xC1, 0xBE, 0xCE, 0xD6, +0xCE, 0xB8, 0xAB, 0xAA, 0xA4, 0xA8, 0x42, 0x1C, 0x18, 0x31, 0xA4, 0x9F, 0xAF, 0x48, 0x29, 0x28, +0x2C, 0x37, 0xCC, 0xBA, 0xC7, 0x57, 0x30, 0x31, 0x5A, 0xC6, 0xB6, 0xB7, 0x5F, 0x38, 0x34, 0x3D, +0xE2, 0xBD, 0xBD, 0xC7, 0xD2, 0xCA, 0xB2, 0xAB, 0xA7, 0xA2, 0xB3, 0x29, 0x18, 0x1C, 0xD2, 0x9F, +0xA5, 0xBC, 0x3A, 0x2A, 0x29, 0x2A, 0x3E, 0xC3, 0xBB, 0xC1, 0x43, 0x2D, 0x3A, 0xF5, 0xC1, 0xB5, +0xBE, 0x4F, 0x36, 0x32, 0x3F, 0xD2, 0xBB, 0xBA, 0xBE, 0xC5, 0xBF, 0xB1, 0xAB, 0xA4, 0xA7, 0x75, +0x1F, 0x18, 0x27, 0xAE, 0xA2, 0xAD, 0xD6, 0x36, 0x2B, 0x28, 0x2C, 0x4E, 0xC2, 0xB8, 0xC9, 0x35, +0x2F, 0x42, 0x71, 0xBA, 0xB4, 0xD2, 0x44, 0x34, 0x34, 0x4C, 0xCD, 0xBE, 0xBB, 0xB9, 0xBC, 0xB3, +0xAE, 0xAB, 0xA3, 0xB0, 0x2C, 0x1A, 0x1C, 0x5F, 0xA4, 0xA9, 0xBA, 0x6F, 0x34, 0x28, 0x26, 0x32, +0x77, 0xB9, 0xB3, 0x5E, 0x32, 0x38, 0x40, 0xD8, 0xB6, 0xBE, 0xF4, 0x40, 0x34, 0x3A, 0x5B, 0xC7, +0xB7, 0xB4, 0xB7, 0xB4, 0xB2, 0xAE, 0xA5, 0xAB, 0x3B, 0x1D, 0x1B, 0x34, 0xAE, 0xAA, 0xB4, 0xC7, +0x42, 0x2C, 0x25, 0x2B, 0x43, 0xCF, 0xB5, 0xBE, 0x3F, 0x38, 0x3D, 0x4D, 0xC4, 0xBD, 0xCF, 0x5D, +0x3E, 0x38, 0x43, 0xE4, 0xBF, 0xB4, 0xAF, 0xB0, 0xAF, 0xAE, 0xA8, 0xA7, 0xF6, 0x21, 0x1A, 0x27, +0xBA, 0xAC, 0xB5, 0xB9, 0xE2, 0x36, 0x26, 0x25, 0x33, 0x4E, 0xBA, 0xB2, 0x64, 0x41, 0x3F, 0x3D, +0xE6, 0xC6, 0xCD, 0xD4, 0x50, 0x3D, 0x3C, 0x48, 0xD4, 0xB9, 0xAF, 0xAD, 0xAE, 0xAE, 0xAA, 0xA7, +0xC0, 0x2A, 0x1B, 0x1F, 0x65, 0xAF, 0xB5, 0xB5, 0xBF, 0x4C, 0x2C, 0x23, 0x2A, 0x37, 0xE6, 0xAF, +0xBC, 0x5B, 0x4B, 0x3B, 0x49, 0xCF, 0xCE, 0xD0, 0xDE, 0x4F, 0x40, 0x3F, 0x57, 0xC7, 0xB3, 0xAA, +0xA9, 0xAC, 0xAE, 0xA9, 0xAE, 0x3B, 0x1E, 0x1E, 0x37, 0xBA, 0xB7, 0xB7, 0xB5, 0xC9, 0x3A, 0x26, +0x27, 0x2E, 0x37, 0xC1, 0xB1, 0xCA, 0xE8, 0x49, 0x3E, 0x62, 0x78, 0xEF, 0xD7, 0x69, 0x4F, 0x44, +0x48, 0xFB, 0xC5, 0xAF, 0xA9, 0xA8, 0xAA, 0xAB, 0xAA, 0xCF, 0x26, 0x1C, 0x22, 0x4A, 0xBD, 0xBB, +0xAF, 0xB1, 0xD7, 0x31, 0x25, 0x27, 0x28, 0x38, 0xB9, 0xB6, 0xC3, 0xCB, 0x4B, 0x45, 0x4E, 0x47, +0x62, 0xE0, 0xF9, 0x5C, 0x4C, 0x5C, 0xE4, 0xBF, 0xAD, 0xA8, 0xA5, 0xA7, 0xA9, 0xB2, 0x36, 0x20, +0x1E, 0x29, 0x56, 0xCC, 0xB8, 0xAC, 0xB5, 0xFA, 0x2F, 0x28, 0x25, 0x25, 0x45, 0xBE, 0xBF, 0xB8, +0xC5, 0x5F, 0x54, 0x41, 0x43, 0x4F, 0x56, 0x75, 0x70, 0xFE, 0xE2, 0xD3, 0xB9, 0xAD, 0xA8, 0xA6, +0xA6, 0xA8, 0xCA, 0x2D, 0x22, 0x21, 0x2E, 0x47, 0x77, 0xB4, 0xAD, 0xB7, 0xDC, 0x39, 0x2D, 0x24, +0x28, 0x40, 0x5A, 0xC7, 0xB5, 0xBD, 0xC0, 0xDB, 0x4E, 0x4C, 0x40, 0x44, 0x4E, 0x56, 0xDA, 0xCC, +0xC0, 0xB1, 0xAC, 0xA7, 0xA5, 0xA6, 0xAD, 0x4F, 0x2A, 0x23, 0x25, 0x2F, 0x39, 0x6C, 0xB6, 0xB1, +0xB7, 0xD6, 0x43, 0x2F, 0x26, 0x2C, 0x35, 0x3A, 0xDF, 0xC7, 0xBE, 0xBA, 0xCB, 0xD4, 0x6E, 0x48, +0x44, 0x3E, 0x4A, 0x6C, 0xD6, 0xB9, 0xB0, 0xA8, 0xA4, 0xA5, 0xA4, 0xB5, 0x42, 0x2C, 0x23, 0x27, +0x2B, 0x2E, 0x55, 0xC2, 0xB9, 0xB6, 0xC5, 0xF4, 0x3C, 0x32, 0x34, 0x2F, 0x37, 0x4A, 0x5B, 0xCF, +0xC9, 0xC6, 0xC0, 0xCA, 0xCF, 0xF4, 0x52, 0x51, 0x4E, 0xF8, 0xC4, 0xB7, 0xAD, 0xA9, 0xA6, 0xA7, +0xB8, 0x5D, 0x38, 0x2F, 0x2E, 0x2B, 0x2C, 0x35, 0x42, 0x5D, 0x7D, 0xE3, 0xDF, 0x6F, 0x73, 0x5A, +0x4D, 0x55, 0x4F, 0x4F, 0x58, 0x5C, 0x6E, 0xFA, 0xE2, 0xD4, 0xD4, 0xD6, 0xD9, 0xD6, 0xCC, 0xC6, +0xBF, 0xBB, 0xB8, 0xB6, 0xBC, 0xC9, 0xDC, 0x60, 0x59, 0x53, 0x4A, 0x49, 0x46, 0x45, 0x46, 0x43, +0x45, 0x45, 0x49, 0x56, 0x5A, 0x5D, 0x6E, 0x72, 0x7C, 0x74, 0x6D, 0x7A, 0x7A, 0xFC, 0xED, 0xE8, +0xEB, 0xFF, 0xFD, 0xEC, 0xDE, 0xD2, 0xCC, 0xC7, 0xC5, 0xCA, 0xD2, 0xD9, 0xDB, 0xD4, 0xCF, 0xD1, +0xD9, 0xE7, 0xFC, 0x6E, 0x60, 0x57, 0x50, 0x4C, 0x49, 0x47, 0x46, 0x45, 0x47, 0x4A, 0x4D, 0x4F, +0x4F, 0x53, 0x5A, 0x5F, 0x62, 0x60, 0x62, 0x6B, 0x77, 0xEC, 0xD8, 0xCC, 0xC7, 0xC7, 0xCB, 0xCF, +0xD3, 0xD3, 0xCE, 0xCB, 0xCA, 0xCC, 0xCF, 0xD4, 0xD9, 0xDF, 0xEB, 0xFE, 0x6A, 0x58, 0x4D, 0x46, +0x43, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x52, 0x54, 0x55, 0x54, 0x57, 0x5C, 0x61, 0x72, 0xE5, +0xD4, 0xCC, 0xCB, 0xCD, 0xD0, 0xD4, 0xD3, 0xD1, 0xD0, 0xCF, 0xD1, 0xD2, 0xD4, 0xD6, 0xD9, 0xDB, +0xDB, 0xDD, 0xEC, 0x6B, 0x59, 0x53, 0x54, 0x57, 0x59, 0x58, 0x57, 0x5A, 0x5C, 0x5A, 0x55, 0x52, +0x52, 0x51, 0x51, 0x57, 0x61, 0xFC, 0xE3, 0xDF, 0xE0, 0xE4, 0xE3, 0xE0, 0xDF, 0xDE, 0xDD, 0xDE, +0xDD, 0xDF, 0xE0, 0xDF, 0xDC, 0xD9, 0xDC, 0xE7, 0x7E, 0x6B, 0x6D, 0x7C, 0xEE, 0xE6, 0xE7, 0xEA, +0xEC, 0xF5, 0x7A, 0x6A, 0x61, 0x5A, 0x51, 0x4F, 0x50, 0x55, 0x5D, 0x62, 0x63, 0x60, 0x5F, 0x61, +0x65, 0x68, 0x6D, 0x75, 0xFA, 0xF1, 0xF1, 0xEE, 0xE6, 0xDD, 0xDB, 0xDE, 0xEB, 0x79, 0x6B, 0x6F, +0xF7, 0xE2, 0xDC, 0xDB, 0xDA, 0xDA, 0xDC, 0xDD, 0xDE, 0xE0, 0xF1, 0x6B, 0x5F, 0x5F, 0x66, 0x6B, +0x6A, 0x65, 0x5E, 0x5B, 0x5A, 0x59, 0x5A, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x68, 0xFC, 0xE8, 0xE5, +0xEB, 0xFB, 0x71, 0x6D, 0x78, 0xEE, 0xE2, 0xDE, 0xDD, 0xDC, 0xDE, 0xDF, 0xDC, 0xD9, 0xD9, 0xE0, +0xED, 0xF0, 0xEC, 0xE4, 0xE2, 0xE6, 0xEE, 0x7C, 0x6D, 0x65, 0x5E, 0x5E, 0x62, 0x64, 0x61, 0x5C, +0x5B, 0x5F, 0x70, 0xF7, 0xF8, 0x78, 0x6B, 0x65, 0x61, 0x69, 0xFA, 0xE9, 0xE5, 0xE2, 0xE5, 0xEA, +0xED, 0xEB, 0xE5, 0xE5, 0xED, 0xF9, 0xFC, 0xEF, 0xE3, 0xDE, 0xDE, 0xE1, 0xE9, 0xF4, 0x74, 0x6A, +0x6B, 0x6F, 0x6F, 0x67, 0x5E, 0x5C, 0x5F, 0x6A, 0x6F, 0x6C, 0x66, 0x5F, 0x5D, 0x5E, 0x64, 0x6F, +0xFE, 0xEF, 0xEC, 0xF2, 0xFD, 0x7E, 0xFB, 0xF6, 0xFF, 0x6F, 0x6A, 0x6A, 0x74, 0xF4, 0xE9, 0xE4, +0xE7, 0xEE, 0x7D, 0x6A, 0x69, 0x6F, 0xFE, 0xF7, 0x7B, 0x6B, 0x68, 0x6E, 0x79, 0x78, 0x6F, 0x69, +0x62, 0x5F, 0x60, 0x66, 0x72, 0xF6, 0xEB, 0xEC, 0xF3, 0xFC, 0xFA, 0xF2, 0xF2, 0xFE, 0x70, 0x69, +0x69, 0x71, 0xF7, 0xE8, 0xE3, 0xE4, 0xED, 0x76, 0x69, 0x6A, 0x6F, 0x7E, 0xFB, 0x7D, 0x75, 0x73, +0x7C, 0xFB, 0xFC, 0x7D, 0x73, 0x6D, 0x6A, 0x69, 0x6F, 0xFD, 0xEC, 0xE8, 0xED, 0xF6, 0xF7, 0xF1, +0xED, 0xEF, 0xF6, 0x7E, 0x76, 0x78, 0xFB, 0xEC, 0xE2, 0xDE, 0xE0, 0xEB, 0xFE, 0x73, 0x73, 0x7E, +0xFA, 0xFC, 0xFF, 0x7B, 0x7D, 0xFC, 0xFE, 0x7B, 0x74, 0x6F, 0x6D, 0x6C, 0x6E, 0x77, 0xFA, 0xEE, +0xED, 0xF6, 0x7A, 0x73, 0x77, 0x7B, 0x7C, 0x78, 0x6E, 0x6B, 0x6F, 0x7C, 0xEF, 0xE7, 0xE2, 0xE6, +0xF2, 0x7A, 0x71, 0x75, 0x7D, 0xFE, 0xFD, 0xFD, 0xFB, 0xF5, 0xF7, 0xFE, 0x77, 0x6E, 0x6A, 0x67, +0x67, 0x6C, 0x76, 0xF7, 0xEE, 0xEF, 0xFA, 0x7B, 0x78, 0x7B, 0xFF, 0x7F, 0x78, 0x6F, 0x6C, 0x6C, +0x72, 0xFE, 0xEF, 0xEC, 0xEF, 0xFD, 0x76, 0x70, 0x71, 0x75, 0x7A, 0x7E, 0x7E, 0xFF, 0xFC, 0xFD, +0x7C, 0x73, 0x6D, 0x69, 0x65, 0x63, 0x65, 0x6B, 0x79, 0xFB, 0xFD, 0x78, 0x70, 0x70, 0x74, 0x79, +0x7C, 0x7B, 0x79, 0x77, 0x78, 0x7F, 0xF4, 0xED, 0xED, 0xF2, 0xFB, 0x7A, 0x74, 0x74, 0x76, 0x7A, +0x7F, 0xFB, 0xF5, 0xF4, 0xF6, 0xFA, 0x7D, 0x75, 0x6E, 0x6B, 0x6B, 0x6F, 0x7D, 0xF3, 0xEF, 0xF4, +0x7E, 0x78, 0x7A, 0xFF, 0xFA, 0xF7, 0xF5, 0xF4, 0xF4, 0xF1, 0xED, 0xE9, 0xE6, 0xE8, 0xEE, 0xF8, +0x7F, 0x7C, 0x7A, 0x7A, 0x7B, 0x7D, 0xFD, 0xF8, 0xF8, 0xF9, 0xFC, 0x7D, 0x74, 0x6C, 0x69, 0x69, +0x6C, 0x76, 0xFA, 0xF6, 0xFD, 0x78, 0x71, 0x6F, 0x6F, 0x6F, 0x71, 0x74, 0x77, 0x7C, 0xFD, 0xF5, +0xEC, 0xE9, 0xEA, 0xEF, 0xFB, 0x7A, 0x74, 0x73, 0x73, 0x73, 0x73, 0x78, 0x7E, 0xFE, 0xFD, 0xFE, +0x7B, 0x74, 0x6D, 0x68, 0x66, 0x69, 0x6F, 0x7B, 0x7F, 0x7C, 0x77, 0x73, 0x72, 0x6F, 0x6D, 0x6D, +0x6D, 0x6D, 0x6E, 0x72, 0x7A, 0xFA, 0xF1, 0xEE, 0xEF, 0xF6, 0xFD, 0x7D, 0x7B, 0x7A, 0x78, 0x78, +0x79, 0x79, 0x7A, 0x7C, 0x7D, 0x7E, 0x7D, 0x77, 0x70, 0x6E, 0x71, 0x79, 0x7E, 0x7E, 0x7E, 0x7D, +0x7E, 0x7D, 0x7C, 0x7A, 0x78, 0x76, 0x74, 0x73, 0x75, 0x7A, 0xFC, 0xF6, 0xF4, 0xF4, 0xF6, 0xF6, +0xF6, 0xF9, 0xF9, 0xF7, 0xF5, 0xF3, 0xF1, 0xF1, 0xF3, 0xF5, 0xF7, 0xFA, 0x7B, 0x6F, 0x6D, 0x6D, +0x6F, 0x6F, 0x6E, 0x6E, 0x70, 0x70, 0x71, 0x74, 0x78, 0x7C, 0x7D, 0x7E, 0x7D, 0xFF, 0xFB, 0xF7, +0xF4, 0xF4, 0xF6, 0xF8, 0xFB, 0xFD, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x7F, 0xFF, 0xFC, 0xF8, +0xF9, 0xFD, 0x7D, 0x7C, 0x7F, 0xFE, 0x7E, 0x7C, 0x7A, 0x79, 0x77, 0x75, 0x75, 0x76, 0x79, 0x76, +0x71, 0x6F, 0x6F, 0x71, 0x76, 0x78, 0x78, 0x78, 0x7B, 0x7D, 0x7A, 0x77, 0x76, 0x76, 0x78, 0x79, +0x78, 0x79, 0x7C, 0xFD, 0xF4, 0xF1, 0xF2, 0xF5, 0xF9, 0xFB, 0x7F, 0x79, 0x76, 0x76, 0x78, 0x77, +0x77, 0x7B, 0xFF, 0xFA, 0xF6, 0xF6, 0xF7, 0xF6, 0xF6, 0xF7, 0xF9, 0xFA, 0xF9, 0xF6, 0xF6, 0xF9, +0xFB, 0xFE, 0x7F, 0x7E, 0x7C, 0x79, 0x7A, 0xFE, 0xF5, 0xEF, 0xEE, 0xEF, 0xF1, 0xF3, 0xF4, 0xFB, +0x79, 0x73, 0x72, 0x6E, 0x6B, 0x68, 0x68, 0x6C, 0x73, 0x7A, 0x7C, 0x7B, 0x7B, 0x7D, 0x7D, 0xFD, +0xF6, 0xF0, 0xEE, 0xEF, 0xF6, 0xFB, 0xFF, 0x7D, 0x7F, 0x7D, 0x7A, 0x7A, 0x7B, 0x7C, 0x7D, 0x7B, +0x7A, 0xFF, 0xFD, 0xFF, 0x7E, 0x7A, 0x75, 0x74, 0x71, 0x6F, 0x6F, 0x70, 0x77, 0x7A, 0x78, 0x75, +0x72, 0x75, 0x73, 0x6F, 0x6F, 0x70, 0x75, 0x77, 0x76, 0x78, 0x75, 0x78, 0x7B, 0x7B, 0x7F, 0x7B, +0x7E, 0x7F, 0x7E, 0x7E, 0x77, 0x79, 0x73, 0x71, 0x71, 0x6B, 0x6F, 0x60, 0x5B, 0x6F, 0x72, 0x69, +0x71, 0x72, 0x7E, 0xFC, 0xF7, 0xEE, 0xF4, 0xFB, 0x7E, 0x7E, 0xFC, 0xF9, 0xFD, 0x7F, 0xFC, 0x72, +0x78, 0x64, 0x53, 0x71, 0xDF, 0xF0, 0xEB, 0xE9, 0xF0, 0x7C, 0x7B, 0xEA, 0xF6, 0x7E, 0x79, 0x6C, +0x79, 0x5F, 0x5B, 0xEC, 0xE2, 0xEF, 0xED, 0xF1, 0xF7, 0xFE, 0x7C, 0xFE, 0x75, 0x6E, 0x75, 0x79, +0x7A, 0x72, 0x6E, 0x75, 0x7A, 0x7B, 0x77, 0x77, 0xFE, 0xF8, 0xF6, 0xF5, 0xEB, 0xE9, 0xEC, 0xE8, +0xEE, 0xEC, 0xED, 0x77, 0xFD, 0x61, 0x51, 0x66, 0xE7, 0xDC, 0xD8, 0xD3, 0xD3, 0x6C, 0x52, 0x63, +0x6F, 0x73, 0x7F, 0xFB, 0xF4, 0x79, 0x7B, 0xF1, 0xED, 0xEC, 0xFA, 0x76, 0x7A, 0x74, 0x6B, 0x6B, +0x75, 0x7C, 0x7C, 0x79, 0xFE, 0xF6, 0xFE, 0x7A, 0x71, 0x75, 0xFF, 0x70, 0x6D, 0x6E, 0x69, 0x66, +0x5E, 0x62, 0xFA, 0xEA, 0xE5, 0xE0, 0xE1, 0xE5, 0xEE, 0xF1, 0xE5, 0xE4, 0xEA, 0xE8, 0xE7, 0xE7, +0xE3, 0xE7, 0xE8, 0xE8, 0xEF, 0xF7, 0x78, 0x6E, 0x6D, 0x60, 0x5A, 0x57, 0x54, 0x53, 0x51, 0x50, +0x52, 0x54, 0x57, 0x59, 0x5D, 0x67, 0x70, 0x7B, 0xF5, 0xE5, 0xDA, 0xD5, 0xD2, 0xCD, 0xC4, 0xBE, +0xBB, 0xB7, 0xB5, 0xBB, 0xCB, 0xDE, 0xE9, 0x56, 0x3F, 0x3A, 0x39, 0x3B, 0x3B, 0x3A, 0x3F, 0x4E, +0x5D, 0x69, 0xF2, 0xDD, 0xD9, 0xE2, 0xF3, 0xF4, 0x72, 0x5C, 0x53, 0x4E, 0x4D, 0x4E, 0x4E, 0x4F, +0x58, 0x7E, 0xDA, 0xCB, 0xBF, 0xBA, 0xB7, 0xB4, 0xB0, 0xAE, 0xB2, 0xBE, 0xD7, 0x70, 0x4E, 0x3B, +0x32, 0x30, 0x33, 0x35, 0x35, 0x3A, 0x49, 0x5F, 0x7E, 0xEF, 0xE1, 0xD2, 0xD1, 0xE6, 0xEF, 0xF7, +0x5F, 0x4F, 0x48, 0x48, 0x4B, 0x48, 0x4B, 0x55, 0x72, 0xE1, 0xD2, 0xC2, 0xBA, 0xB6, 0xB3, 0xB0, +0xAD, 0xAE, 0xBA, 0xD0, 0x64, 0x4C, 0x3C, 0x30, 0x2E, 0x2F, 0x33, 0x35, 0x3A, 0x47, 0x6C, 0xE6, +0xEB, 0xD0, 0xC6, 0xCC, 0xD6, 0xE3, 0xEF, 0x69, 0x4E, 0x4B, 0x4B, 0x47, 0x46, 0x48, 0x4F, 0x61, +0xFE, 0xD1, 0xBE, 0xB8, 0xB5, 0xB2, 0xAF, 0xAD, 0xAE, 0xBA, 0xCD, 0x5F, 0x47, 0x3B, 0x2F, 0x2D, +0x2E, 0x30, 0x35, 0x3B, 0x47, 0x6C, 0xF4, 0xE2, 0xCB, 0xC7, 0xCD, 0xD7, 0xDD, 0xE3, 0x6E, 0x4E, +0x4A, 0x4B, 0x48, 0x47, 0x4A, 0x5B, 0xE4, 0xD3, 0xC0, 0xB7, 0xB3, 0xB0, 0xAF, 0xAC, 0xAC, 0xB3, +0xC4, 0x7D, 0x4C, 0x3E, 0x30, 0x2C, 0x2E, 0x31, 0x35, 0x3A, 0x45, 0x62, 0xFA, 0xEB, 0xCE, 0xCA, +0xD2, 0xDA, 0xE7, 0xE9, 0x6D, 0x4C, 0x49, 0x49, 0x47, 0x48, 0x4C, 0x68, 0xD7, 0xCA, 0xBC, 0xB5, +0xB2, 0xB0, 0xAE, 0xAC, 0xAE, 0xB9, 0xCE, 0x5D, 0x45, 0x39, 0x2F, 0x2D, 0x2E, 0x31, 0x36, 0x3B, +0x47, 0x5C, 0x6E, 0xE4, 0xD3, 0xD3, 0xD4, 0xDA, 0xDE, 0xEB, 0x5B, 0x4D, 0x4A, 0x47, 0x48, 0x49, +0x54, 0xEB, 0xCE, 0xBE, 0xB8, 0xB7, 0xB3, 0xB3, 0xB5, 0xB3, 0xBB, 0xC9, 0xC8, 0xED, 0x47, 0x42, +0x3A, 0x36, 0x37, 0x34, 0x39, 0x3E, 0x3F, 0x47, 0x4E, 0x65, 0xDE, 0xEC, 0xDC, 0xCE, 0xD9, 0xEB, +0x5F, 0x54, 0x51, 0x47, 0x46, 0x4C, 0x58, 0xFC, 0xD8, 0xC4, 0xBB, 0xBA, 0xB8, 0xB5, 0xB2, 0xAF, +0xB0, 0xB6, 0xBD, 0xCC, 0x66, 0x47, 0x3B, 0x34, 0x32, 0x32, 0x34, 0x38, 0x3B, 0x3F, 0x4B, 0x58, +0x69, 0xE9, 0xD9, 0xD4, 0xDB, 0x77, 0x5C, 0x59, 0x4F, 0x4A, 0x4B, 0x51, 0x69, 0xE0, 0xCE, 0xC2, +0xBD, 0xBC, 0xBA, 0xB8, 0xB7, 0xB4, 0xB2, 0xB7, 0xC3, 0xCE, 0xD4, 0x67, 0x44, 0x3D, 0x3C, 0x3B, +0x38, 0x38, 0x3B, 0x3F, 0x42, 0x46, 0x4E, 0x5F, 0x6A, 0x6B, 0xFD, 0xF7, 0x70, 0x5C, 0x54, 0x58, +0x58, 0x53, 0x5B, 0x73, 0xE5, 0xD2, 0xCA, 0xC6, 0xC2, 0xBF, 0xBE, 0xBE, 0xBD, 0xBB, 0xBC, 0xC3, +0xCA, 0xD0, 0xE2, 0x5F, 0x4E, 0x4A, 0x44, 0x3E, 0x3D, 0x3D, 0x3F, 0x42, 0x44, 0x4B, 0x55, 0x57, +0x5F, 0x69, 0x68, 0x63, 0x58, 0x56, 0x5B, 0x56, 0x57, 0x66, 0x79, 0xE8, 0xD9, 0xCF, 0xCB, 0xCB, +0xC8, 0xC4, 0xC5, 0xC6, 0xC9, 0xC9, 0xC6, 0xCD, 0xD4, 0xD8, 0xE2, 0xF1, 0x66, 0x5C, 0x57, 0x4C, +0x49, 0x49, 0x48, 0x49, 0x49, 0x4B, 0x51, 0x51, 0x4F, 0x53, 0x56, 0x58, 0x58, 0x54, 0x58, 0x5F, +0x5E, 0x5B, 0x63, 0xF2, 0xE5, 0xE5, 0xD7, 0xCF, 0xD2, 0xD6, 0xD1, 0xCF, 0xD6, 0xD6, 0xD2, 0xCF, +0xCE, 0xD0, 0xD8, 0xDB, 0xDB, 0xE5, 0x6D, 0x67, 0x65, 0x5C, 0x58, 0x54, 0x59, 0x5D, 0x57, 0x57, +0x5B, 0x5B, 0x59, 0x56, 0x57, 0x5A, 0x56, 0x52, 0x5A, 0x5C, 0x5D, 0x7D, 0xF1, 0xF3, 0xE7, 0xE3, +0xDF, 0xDB, 0xDA, 0xE7, 0xEC, 0xDE, 0xE5, 0xE9, 0xE6, 0xE4, 0xD6, 0xDF, 0xF8, 0xDE, 0xE9, 0x7C, +0xEE, 0xFB, 0x7A, 0x6B, 0x65, 0xFF, 0x79, 0x69, 0x6B, 0x63, 0x65, 0x62, 0x56, 0x5A, 0x60, 0x55, +0x58, 0x62, 0x5E, 0x64, 0x79, 0x7C, 0x78, 0xED, 0xE1, 0xEC, 0xF0, 0xE4, 0xF0, 0x6E, 0x7C, 0xED, +0xDD, 0xDB, 0xFE, 0x73, 0xED, 0xF0, 0xFF, 0xF9, 0xDE, 0xDC, 0x76, 0x6E, 0xFB, 0x7B, 0xFB, 0x6F, +0x6F, 0xEF, 0x7B, 0x6E, 0xF8, 0xE9, 0x7E, 0x5B, 0x5F, 0xF3, 0xFD, 0x67, 0x74, 0xEA, 0xEF, 0x77, +0x6D, 0x7C, 0xE8, 0xE2, 0xEE, 0xFB, 0xE6, 0xED, 0x66, 0x6C, 0x7B, 0x7C, 0xF4, 0xEF, 0xE2, 0xE6, +0x72, 0x70, 0xF0, 0xEE, 0x6E, 0x6B, 0xFB, 0xF5, 0xF6, 0x71, 0x6A, 0x6C, 0x65, 0x67, 0x5F, 0x5D, +0x6B, 0x62, 0x65, 0xFD, 0xED, 0xE9, 0xF2, 0xED, 0xE3, 0xE7, 0xE4, 0xE8, 0xED, 0xEF, 0x66, 0x5E, +0x79, 0x7E, 0x78, 0xF5, 0xFA, 0x79, 0x7A, 0xF5, 0xE7, 0xE2, 0xE4, 0xF2, 0xFF, 0x73, 0x66, 0x6B, +0x70, 0xFD, 0xEF, 0x6F, 0x67, 0x5F, 0x5C, 0x6B, 0x6E, 0x78, 0x77, 0x6D, 0xF1, 0xF4, 0xF8, 0xE5, +0xE9, 0xEB, 0xEC, 0xEF, 0xEF, 0xF0, 0xE7, 0xED, 0x6B, 0x6F, 0xF0, 0xFF, 0x6A, 0x6F, 0x7E, 0x6F, +0x69, 0xED, 0xDF, 0xFF, 0x7C, 0xEB, 0xF3, 0xF8, 0x7E, 0x7A, 0xFB, 0x6E, 0x5E, 0x60, 0x70, 0x7A, +0xFC, 0xF4, 0xFF, 0xEF, 0xF5, 0x72, 0xF1, 0xEC, 0xEA, 0xE1, 0xE9, 0xED, 0xF2, 0xFC, 0xE7, 0xF0, +0x68, 0x76, 0xEF, 0xF4, 0xF9, 0x77, 0x79, 0xFB, 0xFC, 0xF6, 0xEE, 0xE9, 0xF2, 0x6D, 0x70, 0x6F, +0x6F, 0xFE, 0x6A, 0x69, 0x7F, 0x6F, 0x6F, 0x79, 0x78, 0x77, 0x6E, 0xFE, 0xEE, 0xF0, 0xEF, 0x7E, +0xF4, 0xE9, 0xF8, 0xFD, 0x7C, 0x77, 0x7D, 0x78, 0x7D, 0xFE, 0x79, 0x72, 0x6E, 0x72, 0x7B, 0x73, +0x6B, 0x74, 0x76, 0x6C, 0x72, 0x70, 0x75, 0x6D, 0x5A, 0x5C, 0x6A, 0x77, 0xFE, 0x71, 0x7A, 0xF2, +0xE9, 0xE7, 0xEA, 0xDE, 0xE6, 0xF5, 0xEB, 0xF5, 0xEE, 0xEA, 0xF3, 0xEE, 0xF4, 0xEE, 0xF5, 0x73, +0xF4, 0xF6, 0x73, 0x7C, 0xEC, 0xE9, 0x72, 0x67, 0x6C, 0x70, 0x6E, 0x69, 0x6F, 0x68, 0x5D, 0x64, +0x71, 0x75, 0x6B, 0x6D, 0xF9, 0x79, 0x6F, 0xF4, 0xEA, 0xF5, 0x79, 0x7B, 0x7D, 0xFA, 0xF3, 0xF7, +0xF4, 0xF4, 0xF9, 0x7F, 0x77, 0x7F, 0xF5, 0xFD, 0x71, 0x71, 0x7B, 0x78, 0x7A, 0x73, 0x68, 0x71, +0x7A, 0x6B, 0x6C, 0x6E, 0x69, 0x6E, 0x71, 0x6C, 0x69, 0x6C, 0x7A, 0x7D, 0xF6, 0xEB, 0xF4, 0xF2, +0xF4, 0x78, 0xF8, 0xF1, 0xF6, 0xFE, 0x71, 0x75, 0x7C, 0x7B, 0x7D, 0x7E, 0xFB, 0x7E, 0x77, 0x76, +0xFF, 0xF7, 0x79, 0x70, 0x6E, 0x6C, 0x71, 0x6F, 0x6C, 0x6A, 0x70, 0x6E, 0x5F, 0x65, 0x6C, 0x66, +0x6D, 0x7A, 0xF1, 0x78, 0x6B, 0xED, 0xFB, 0x6C, 0x7C, 0x74, 0xF1, 0xEC, 0x76, 0xF9, 0xF8, 0x75, +0x71, 0x7A, 0xEC, 0xFA, 0x6C, 0x76, 0x7C, 0x7F, 0x6E, 0x6A, 0x76, 0x6C, 0x76, 0xF2, 0x7C, 0x76, +0x66, 0x62, 0x7D, 0xF9, 0x78, 0x69, 0x6A, 0xF8, 0x78, 0x6D, 0xFC, 0xF8, 0xF3, 0xF7, 0x7D, 0xEF, +0xF1, 0x7C, 0xF1, 0xE9, 0xEB, 0xEE, 0xF3, 0xFD, 0x73, 0x7D, 0xFA, 0x74, 0x78, 0x7A, 0x6E, 0x70, +0x76, 0x73, 0x6F, 0x6D, 0x6C, 0x68, 0x6D, 0x7D, 0x6E, 0x64, 0x6D, 0xFC, 0xFA, 0x71, 0x6F, 0xFF, +0x70, 0x70, 0xF0, 0xEE, 0xEF, 0xEB, 0xEC, 0xEC, 0xED, 0xF0, 0xEE, 0xE9, 0xEB, 0xF8, 0xFB, 0xED, +0xE9, 0xF7, 0xFF, 0xED, 0xEE, 0xEF, 0xF3, 0x6E, 0x70, 0xF3, 0xFF, 0x6F, 0x6F, 0x6F, 0x79, 0x7C, +0x79, 0x7E, 0x77, 0x6E, 0x6E, 0x7B, 0x7C, 0x6B, 0x72, 0xF6, 0xFF, 0x7D, 0x7D, 0x72, 0x78, 0xFB, +0xFD, 0xFB, 0xFA, 0x7D, 0x7A, 0x6D, 0x68, 0x74, 0x75, 0xF1, 0xE7, 0x7B, 0x76, 0x6B, 0x66, 0xFD, +0x73, 0x68, 0x6B, 0x73, 0x7C, 0x62, 0x64, 0x70, 0x64, 0x6D, 0x79, 0x70, 0x70, 0x74, 0xF8, 0x7C, +0x7C, 0xF8, 0x6B, 0x70, 0xF9, 0x7D, 0xF1, 0xF0, 0xFF, 0x7F, 0xF8, 0xED, 0xF2, 0xFC, 0xFF, 0x76, +0x7B, 0x7C, 0xFE, 0xFE, 0x6C, 0x7C, 0xED, 0x79, 0x77, 0x71, 0x69, 0x76, 0x7A, 0x76, 0x7A, 0x6F, +0x6E, 0x6E, 0x73, 0xFF, 0x78, 0x76, 0x7F, 0x7A, 0x6F, 0x78, 0xFE, 0x77, 0xFB, 0xEE, 0xEE, 0xF1, +0x7A, 0xFB, 0xEE, 0x75, 0x70, 0xFE, 0x7D, 0x72, 0x6D, 0x6F, 0x7B, 0xFB, 0xF9, 0x7C, 0x7E, 0x7A, +0x70, 0x76, 0x7B, 0xF7, 0xF5, 0x70, 0x74, 0xFF, 0x78, 0xFA, 0xFC, 0x79, 0x78, 0x6D, 0x7A, 0xFA, +0x77, 0xFC, 0xF4, 0xF1, 0xF1, 0xF7, 0xEB, 0xED, 0xFB, 0xF7, 0xEF, 0xF2, 0x78, 0x79, 0xF0, 0xF3, +0xFC, 0xFC, 0x7E, 0x77, 0xFF, 0xFC, 0x78, 0xF6, 0xF9, 0x6F, 0x7A, 0x78, 0x6F, 0xFF, 0xF9, 0x7E, +0x76, 0x72, 0x76, 0x78, 0x79, 0xFD, 0xFA, 0x7A, 0x7E, 0xF1, 0xFB, 0x7A, 0xF2, 0xEF, 0xFF, 0x74, +0x75, 0x7E, 0xFF, 0xF6, 0xE9, 0xF4, 0x71, 0x74, 0x74, 0x7C, 0xF8, 0x79, 0x75, 0x74, 0x73, 0xF9, +0xFE, 0xFF, 0xFA, 0x6A, 0x6C, 0xFE, 0x70, 0x72, 0x7C, 0x7D, 0x70, 0x67, 0x6F, 0x76, 0x7B, 0xF0, +0x7E, 0x6E, 0x6E, 0x76, 0xF1, 0xF2, 0x7A, 0x72, 0x7B, 0xFD, 0x79, 0x77, 0x6E, 0x6A, 0x6D, 0x6E, +0x74, 0x72, 0x77, 0xF5, 0x7C, 0x6D, 0x6C, 0x6D, 0x70, 0x76, 0xFD, 0xFC, 0xFF, 0xFE, 0xFE, 0xFA, +0x7D, 0x77, 0x74, 0x6F, 0xFB, 0xFA, 0x71, 0xFC, 0xF8, 0xFE, 0xEB, 0xE5, 0xEE, 0x7F, 0xF6, 0xED, +0xFA, 0x78, 0xF6, 0xF1, 0xF8, 0xF6, 0x79, 0x70, 0x7C, 0x75, 0x78, 0xF6, 0xFA, 0xFC, 0xFB, 0x7B, +0x7D, 0xF9, 0xF7, 0xF7, 0x7E, 0x6B, 0x68, 0xFA, 0xE6, 0xEE, 0x7B, 0x7B, 0x79, 0x7E, 0xFB, 0xF2, +0xEA, 0xEE, 0xF1, 0xF6, 0x79, 0xFB, 0xF0, 0xFB, 0xFF, 0xF0, 0xEE, 0xF4, 0xEF, 0xFB, 0x6F, 0x6C, +0x72, 0xFF, 0x71, 0x6C, 0x6A, 0x6D, 0xF4, 0xFB, 0x7C, 0xF3, 0xFA, 0xFC, 0x6F, 0x73, 0xFB, 0x72, +0x7D, 0x78, 0x76, 0xEF, 0xF3, 0x7C, 0x71, 0xFA, 0xF2, 0xFB, 0xEF, 0xF0, 0xEA, 0xFD, 0x6B, 0xED, +0xF2, 0x77, 0x6E, 0x6D, 0xFD, 0x64, 0xF3, 0xDF, 0x5C, 0x61, 0xED, 0xF2, 0x7E, 0x66, 0x73, 0x6E, +0x66, 0xFF, 0x6F, 0x72, 0x70, 0x66, 0xF3, 0xF7, 0x6F, 0x72, 0x75, 0xED, 0xEF, 0xF4, 0xED, 0xEF, +0xEF, 0x6E, 0x6F, 0xF7, 0x72, 0x7E, 0x78, 0x6F, 0xF9, 0x77, 0xFC, 0xF4, 0x6C, 0x66, 0x6A, 0x76, +0x65, 0x5C, 0x6D, 0xFF, 0xF8, 0xEA, 0xE2, 0xEF, 0x65, 0x70, 0xEB, 0xE8, 0xE2, 0xDF, 0xDA, 0xD9, +0xE3, 0xF0, 0xFA, 0xE6, 0xDD, 0xDF, 0xDF, 0xE0, 0xE4, 0xFC, 0x63, 0x60, 0x64, 0x63, 0x66, 0x78, +0x65, 0x57, 0x60, 0x67, 0x64, 0x67, 0x5F, 0x6E, 0xF3, 0x7F, 0x75, 0xFE, 0xEA, 0xF4, 0xF8, 0xE0, +0xE0, 0xE4, 0xE3, 0xE7, 0xEA, 0xFB, 0x6F, 0x6E, 0x75, 0x72, 0x68, 0x6E, 0x77, 0x74, 0x6D, 0x73, +0xF9, 0x74, 0xF2, 0xE2, 0xEF, 0xDE, 0xDD, 0x79, 0xFD, 0xF4, 0x6F, 0x6A, 0x6E, 0xFE, 0x7A, 0x68, +0x60, 0x63, 0x6B, 0x66, 0x67, 0x76, 0xFE, 0x78, 0x65, 0x63, 0x7A, 0xFF, 0x72, 0x72, 0x74, 0x7D, +0x7C, 0x6B, 0x72, 0xEF, 0xF6, 0x73, 0x74, 0x7C, 0x74, 0x68, 0x68, 0x73, 0xFA, 0xF6, 0x6F, 0x67, +0x6F, 0x6D, 0x6A, 0x69, 0x68, 0x74, 0x6D, 0x64, 0x6F, 0x75, 0x77, 0xFA, 0x7F, 0xF5, 0xEF, 0x78, +0x77, 0x7D, 0x7A, 0xFE, 0x77, 0x73, 0xF8, 0xF4, 0xFE, 0x6F, 0x71, 0xF7, 0x74, 0x79, 0xEF, 0x7B, +0xF9, 0xFA, 0x68, 0x71, 0x7F, 0x76, 0x73, 0x71, 0x7D, 0x7D, 0x65, 0x5D, 0x69, 0x6E, 0x5F, 0x67, +0x6F, 0x6D, 0xFF, 0x7F, 0x6E, 0x6F, 0x73, 0x77, 0xF2, 0xDE, 0xD4, 0xD0, 0xD0, 0xCF, 0xCE, 0xD0, +0xD2, 0xD6, 0xDA, 0xDB, 0xE7, 0x6D, 0x5B, 0x52, 0x4C, 0x47, 0x44, 0x43, 0x44, 0x47, 0x49, 0x4B, +0x4E, 0x52, 0x56, 0x5A, 0x5D, 0x64, 0x75, 0xE6, 0xCF, 0xC5, 0xBF, 0xBD, 0xBB, 0xB7, 0xB5, 0xB1, +0xAF, 0xB5, 0xC1, 0xDF, 0x51, 0x44, 0x3A, 0x33, 0x33, 0x37, 0x3D, 0x44, 0x48, 0x4D, 0x51, 0x54, +0x53, 0x4D, 0x49, 0x44, 0x43, 0x45, 0x46, 0x4C, 0x54, 0x65, 0xE4, 0xCF, 0xC4, 0xBB, 0xB4, 0xAF, +0xAD, 0xAC, 0xAA, 0xAB, 0xB5, 0xD1, 0x49, 0x3B, 0x35, 0x2F, 0x2D, 0x32, 0x3D, 0x4E, 0x57, 0x51, +0x4F, 0x50, 0x4C, 0x42, 0x3D, 0x3F, 0x46, 0x4A, 0x4F, 0x5E, 0xEC, 0xD9, 0xDA, 0xD2, 0xC8, 0xBE, +0xB7, 0xB0, 0xAD, 0xAB, 0xA9, 0xA8, 0xAD, 0xC4, 0x48, 0x36, 0x31, 0x2E, 0x2D, 0x30, 0x3E, 0x67, +0xE2, 0x63, 0x47, 0x43, 0x42, 0x39, 0x36, 0x3B, 0x46, 0x6B, 0xE1, 0xDB, 0xCC, 0xC8, 0xCC, 0xD7, +0xDD, 0xC6, 0xBA, 0xB2, 0xAC, 0xAA, 0xA7, 0xA7, 0xB0, 0x69, 0x32, 0x2D, 0x2D, 0x2C, 0x2D, 0x39, +0xF1, 0xC2, 0xCA, 0x5E, 0x3D, 0x38, 0x34, 0x2E, 0x2F, 0x3E, 0x69, 0xCC, 0xC3, 0xBD, 0xBD, 0xC2, +0xCD, 0xEC, 0xF4, 0xCD, 0xC0, 0xB7, 0xAC, 0xA7, 0xA4, 0xA4, 0xB7, 0x3A, 0x2A, 0x29, 0x2A, 0x2B, +0x30, 0x56, 0xBA, 0xB6, 0xCD, 0x4A, 0x33, 0x2C, 0x2C, 0x2B, 0x34, 0x65, 0xC3, 0xBB, 0xBB, 0xBC, +0xC1, 0xDA, 0x7F, 0x6A, 0x75, 0xD1, 0xC2, 0xB8, 0xAC, 0xA6, 0xA5, 0xA4, 0xB0, 0x35, 0x23, 0x25, +0x29, 0x2F, 0x38, 0x73, 0xB3, 0xAF, 0xC8, 0x3E, 0x2E, 0x29, 0x26, 0x2C, 0x3D, 0xDF, 0xB8, 0xB5, +0xBB, 0xC5, 0xE7, 0x5A, 0x53, 0x68, 0xD9, 0xC8, 0xBA, 0xB3, 0xAD, 0xA8, 0xA7, 0xA6, 0xAF, 0x34, +0x1F, 0x24, 0x2E, 0x3B, 0x48, 0xDA, 0xB3, 0xB0, 0xD6, 0x33, 0x29, 0x29, 0x29, 0x2F, 0x5B, 0xC3, +0xB9, 0xB8, 0xC1, 0xDB, 0x53, 0x46, 0x4E, 0xEE, 0xCB, 0xC5, 0xBF, 0xBA, 0xB6, 0xAE, 0xAA, 0xA8, +0xAA, 0xDB, 0x26, 0x20, 0x2B, 0x3E, 0x5E, 0xEE, 0xC1, 0xB6, 0xC1, 0x3F, 0x2A, 0x29, 0x2A, 0x2F, +0x4F, 0xCA, 0xC0, 0xBE, 0xC5, 0xDC, 0x51, 0x44, 0x4B, 0x7D, 0xCB, 0xC5, 0xC5, 0xC2, 0xBF, 0xBD, +0xB1, 0xA9, 0xA8, 0xAA, 0xCB, 0x28, 0x20, 0x2C, 0x44, 0x7E, 0xDE, 0xC8, 0xBB, 0xC6, 0x3F, 0x2B, +0x29, 0x2E, 0x35, 0x4C, 0xCB, 0xBF, 0xC3, 0xCA, 0xE6, 0x4E, 0x43, 0x44, 0x6A, 0xC8, 0xC3, 0xC3, +0xC8, 0xC8, 0xBE, 0xB5, 0xAB, 0xA7, 0xA8, 0xBC, 0x2D, 0x1F, 0x29, 0x42, 0xD7, 0xD0, 0xCD, 0xBF, +0xC5, 0x4C, 0x2E, 0x2B, 0x2F, 0x36, 0x4A, 0xD7, 0xBE, 0xBD, 0xD5, 0x74, 0x50, 0x42, 0x45, 0x53, +0xD1, 0xBE, 0xBE, 0xC5, 0xD2, 0xCD, 0xBC, 0xAE, 0xA7, 0xA7, 0xB5, 0x36, 0x21, 0x28, 0x41, 0xD1, +0xC9, 0xD4, 0xCB, 0xCB, 0x51, 0x31, 0x2B, 0x2F, 0x39, 0x47, 0xE9, 0xC5, 0xC0, 0xCD, 0xED, 0x50, +0x3F, 0x3F, 0x52, 0xCD, 0xBB, 0xBC, 0xC6, 0xDE, 0xE7, 0xCB, 0xB5, 0xA8, 0xA4, 0xA9, 0xCC, 0x28, +0x20, 0x2E, 0x6F, 0xC2, 0xCF, 0xF7, 0xDA, 0xEB, 0x3F, 0x2E, 0x2D, 0x34, 0x3E, 0x5D, 0xCD, 0xBF, +0xC7, 0x73, 0x53, 0x43, 0x3C, 0x49, 0xDD, 0xBC, 0xB7, 0xC2, 0xE4, 0x62, 0xEC, 0xBD, 0xAA, 0xA3, +0xA4, 0xB3, 0x32, 0x1F, 0x26, 0x42, 0xC3, 0xC0, 0xF2, 0x68, 0x73, 0x4D, 0x37, 0x2D, 0x2F, 0x39, +0x47, 0xDD, 0xC2, 0xBE, 0xD2, 0x4A, 0x3E, 0x3B, 0x42, 0xEB, 0xBE, 0xB5, 0xB9, 0xD5, 0x54, 0x54, +0xCB, 0xAD, 0xA3, 0xA2, 0xAC, 0x4D, 0x23, 0x21, 0x34, 0xCF, 0xBA, 0xD0, 0x5E, 0x73, 0x5D, 0x43, +0x34, 0x30, 0x38, 0x3C, 0x46, 0xCE, 0xB9, 0xBE, 0x5F, 0x3E, 0x3B, 0x3E, 0x62, 0xC0, 0xB5, 0xB6, +0xC9, 0x54, 0x48, 0xE3, 0xB1, 0xA4, 0xA0, 0xA6, 0xC3, 0x2B, 0x1E, 0x29, 0x5D, 0xB9, 0xBD, 0x72, +0x50, 0x5B, 0x50, 0x3C, 0x30, 0x30, 0x36, 0x3F, 0x7C, 0xC0, 0xBA, 0xD0, 0x45, 0x3A, 0x38, 0x46, +0xCB, 0xB7, 0xB5, 0xC4, 0x5A, 0x48, 0x62, 0xBA, 0xA8, 0xA1, 0xA3, 0xB0, 0x3C, 0x20, 0x20, 0x39, +0xBD, 0xB1, 0xC7, 0x4F, 0x4A, 0x4E, 0x48, 0x35, 0x2E, 0x31, 0x39, 0x56, 0xC0, 0xB8, 0xC2, 0x4D, +0x39, 0x37, 0x3E, 0xE2, 0xBC, 0xB6, 0xBB, 0xDC, 0x4B, 0x4A, 0xD3, 0xAE, 0xA3, 0xA0, 0xA8, 0xD5, +0x29, 0x1F, 0x2B, 0xE3, 0xB3, 0xBA, 0x65, 0x47, 0x4C, 0x4F, 0x3D, 0x2F, 0x2D, 0x30, 0x41, 0xCB, +0xB7, 0xBA, 0x76, 0x3D, 0x38, 0x39, 0x51, 0xC5, 0xB6, 0xB6, 0xCC, 0x50, 0x46, 0x7E, 0xB4, 0xA6, +0xA1, 0xA4, 0xB8, 0x35, 0x20, 0x25, 0x48, 0xB8, 0xB5, 0xDB, 0x47, 0x47, 0x52, 0x4A, 0x34, 0x2D, +0x2E, 0x39, 0xEC, 0xBA, 0xB6, 0xCF, 0x3F, 0x38, 0x37, 0x41, 0xD0, 0xB8, 0xB4, 0xBF, 0x6A, 0x4A, +0x5B, 0xBC, 0xA8, 0xA1, 0xA2, 0xAF, 0x3E, 0x22, 0x24, 0x3E, 0xBA, 0xB3, 0xD4, 0x45, 0x41, 0x4F, +0x52, 0x37, 0x2D, 0x2D, 0x36, 0x65, 0xBB, 0xB6, 0xC9, 0x46, 0x38, 0x35, 0x3D, 0xDC, 0xB7, 0xB0, +0xBA, 0xF0, 0x48, 0x4E, 0xC1, 0xAA, 0xA2, 0xA1, 0xAB, 0x5E, 0x27, 0x21, 0x32, 0xC7, 0xB4, 0xC8, +0x48, 0x3E, 0x4B, 0x58, 0x3D, 0x2E, 0x2C, 0x2F, 0x48, 0xBF, 0xB5, 0xBF, 0x4C, 0x36, 0x34, 0x3A, +0x67, 0xBC, 0xB2, 0xB7, 0xD6, 0x4C, 0x4A, 0xCE, 0xAD, 0xA3, 0xA0, 0xA7, 0xD8, 0x29, 0x20, 0x2F, +0xD2, 0xB5, 0xC4, 0x4C, 0x40, 0x4B, 0x64, 0x44, 0x2F, 0x2C, 0x2D, 0x3F, 0xC4, 0xB4, 0xB9, 0x5F, +0x39, 0x36, 0x39, 0x5D, 0xBE, 0xB3, 0xB4, 0xC8, 0x59, 0x4B, 0xDC, 0xAF, 0xA3, 0x9F, 0xA5, 0xC5, +0x2C, 0x21, 0x2C, 0xFB, 0xB9, 0xC1, 0x53, 0x42, 0x4A, 0x5F, 0x49, 0x31, 0x2C, 0x2C, 0x3A, 0xCF, +0xB6, 0xBA, 0xF7, 0x3E, 0x39, 0x3A, 0x4C, 0xCA, 0xB7, 0xB4, 0xBF, 0x79, 0x4D, 0xE5, 0xB1, 0xA4, +0x9F, 0xA4, 0xC6, 0x2B, 0x20, 0x2C, 0xEC, 0xB7, 0xC1, 0x57, 0x43, 0x49, 0x5C, 0x47, 0x31, 0x2C, +0x2C, 0x39, 0xD3, 0xB7, 0xBA, 0xDC, 0x46, 0x3C, 0x39, 0x47, 0xCE, 0xB9, 0xB5, 0xBD, 0xDE, 0x5E, +0xD3, 0xB0, 0xA4, 0xA0, 0xA6, 0xCF, 0x2A, 0x21, 0x2D, 0xF6, 0xBB, 0xC8, 0x55, 0x44, 0x48, 0x51, +0x3F, 0x2F, 0x2C, 0x2D, 0x3B, 0xD8, 0xBC, 0xBF, 0xE7, 0x4E, 0x45, 0x3C, 0x44, 0xEB, 0xBE, 0xB5, +0xBA, 0xCA, 0xE3, 0xC9, 0xAF, 0xA5, 0xA0, 0xA7, 0xE6, 0x28, 0x22, 0x2E, 0xEA, 0xBD, 0xC8, 0x5D, +0x46, 0x4A, 0x4D, 0x3B, 0x2F, 0x2D, 0x2F, 0x3F, 0xD0, 0xBE, 0xC3, 0xE6, 0x56, 0x4B, 0x43, 0x4C, +0xFA, 0xC8, 0xBB, 0xBB, 0xC3, 0xC8, 0xBD, 0xAE, 0xA7, 0xA3, 0xAA, 0x6C, 0x2A, 0x25, 0x30, 0x5A, +0xCD, 0xD3, 0x5F, 0x4D, 0x50, 0x4C, 0x3B, 0x2F, 0x2D, 0x2F, 0x3D, 0xE6, 0xCC, 0xD3, 0xDA, 0xDB, +0x79, 0x55, 0x56, 0x68, 0xE0, 0xCA, 0xC2, 0xC0, 0xBC, 0xB1, 0xAB, 0xA6, 0xA5, 0xAE, 0x53, 0x2C, +0x29, 0x30, 0x41, 0x59, 0x62, 0x53, 0x57, 0x7F, 0x5D, 0x40, 0x35, 0x2E, 0x2F, 0x3D, 0x58, 0x78, +0xE5, 0xCD, 0xC8, 0xCF, 0xDA, 0xEC, 0x7B, 0xE4, 0xD1, 0xCA, 0xC4, 0xBA, 0xB0, 0xAC, 0xAA, 0xAB, +0xBA, 0x4F, 0x39, 0x39, 0x3D, 0x3F, 0x42, 0x3D, 0x3C, 0x45, 0x51, 0x52, 0x4C, 0x42, 0x3B, 0x3E, +0x4A, 0x4C, 0x4D, 0x57, 0x69, 0xEE, 0xDE, 0xE4, 0xFD, 0xED, 0xDC, 0xD3, 0xCD, 0xCA, 0xC3, 0xBD, +0xB9, 0xB6, 0xB8, 0xC3, 0xCE, 0xC8, 0xC1, 0xC5, 0xCE, 0xF9, 0x4A, 0x3F, 0x3F, 0x41, 0x3F, 0x3D, +0x39, 0x38, 0x3B, 0x3C, 0x3A, 0x3C, 0x43, 0x4C, 0x52, 0x58, 0x5B, 0x59, 0x65, 0xDC, 0xCB, 0xC3, +0xBD, 0xB8, 0xB6, 0xB2, 0xAF, 0xB2, 0xB6, 0xB2, 0xB0, 0xB6, 0xBF, 0xD7, 0x4F, 0x40, 0x3F, 0x3D, +0x3A, 0x35, 0x2F, 0x2D, 0x2F, 0x32, 0x33, 0x34, 0x39, 0x3E, 0x46, 0x51, 0x59, 0x5C, 0x6F, 0xD8, +0xC6, 0xBD, 0xB8, 0xB4, 0xB2, 0xAF, 0xAC, 0xAD, 0xAF, 0xAE, 0xAE, 0xB2, 0xBC, 0xCF, 0x55, 0x42, +0x3E, 0x3B, 0x36, 0x31, 0x2D, 0x2A, 0x2B, 0x2F, 0x32, 0x33, 0x36, 0x3B, 0x40, 0x4A, 0x57, 0x69, +0xEE, 0xD6, 0xC8, 0xBF, 0xB9, 0xB3, 0xB1, 0xAF, 0xAC, 0xAB, 0xAE, 0xAF, 0xAF, 0xB1, 0xB9, 0xC6, +0x75, 0x46, 0x3D, 0x3A, 0x36, 0x30, 0x2D, 0x2B, 0x2A, 0x2D, 0x31, 0x34, 0x36, 0x39, 0x3E, 0x46, +0x56, 0x77, 0xE3, 0xD4, 0xCA, 0xC3, 0xBD, 0xB6, 0xB1, 0xAF, 0xAC, 0xAB, 0xAC, 0xAF, 0xAF, 0xB0, +0xB5, 0xBE, 0xDA, 0x4E, 0x3E, 0x3A, 0x36, 0x31, 0x2D, 0x2C, 0x2B, 0x2C, 0x2F, 0x32, 0x34, 0x38, +0x3D, 0x43, 0x4D, 0x66, 0xE7, 0xD6, 0xCB, 0xC5, 0xC0, 0xBA, 0xB3, 0xAF, 0xAD, 0xAB, 0xAC, 0xAE, +0xAF, 0xAF, 0xB3, 0xBB, 0xCD, 0x5A, 0x40, 0x3A, 0x36, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, 0x2F, 0x31, +0x32, 0x38, 0x3D, 0x41, 0x4B, 0x5C, 0xF8, 0xD8, 0xCA, 0xC3, 0xBF, 0xBA, 0xB4, 0xB0, 0xAD, 0xAB, +0xAB, 0xAE, 0xAF, 0xB0, 0xB3, 0xBA, 0xC9, 0x68, 0x46, 0x3C, 0x37, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, +0x2F, 0x30, 0x31, 0x36, 0x3C, 0x3F, 0x49, 0x58, 0x70, 0xDD, 0xCA, 0xC2, 0xBE, 0xB9, 0xB3, 0xB0, +0xAD, 0xAA, 0xAB, 0xAE, 0xAF, 0xAF, 0xB4, 0xBC, 0xCB, 0x61, 0x46, 0x3D, 0x36, 0x30, 0x2E, 0x2C, +0x2B, 0x2D, 0x2F, 0x2F, 0x31, 0x37, 0x3B, 0x3F, 0x4B, 0x5C, 0xFF, 0xD8, 0xC8, 0xC1, 0xBC, 0xB6, +0xB2, 0xAF, 0xAC, 0xAA, 0xAB, 0xAD, 0xAE, 0xAF, 0xB5, 0xBD, 0xCF, 0x5C, 0x45, 0x3C, 0x35, 0x2F, +0x2D, 0x2C, 0x2C, 0x2D, 0x2F, 0x2F, 0x32, 0x37, 0x3B, 0x3F, 0x4B, 0x5F, 0xEE, 0xD4, 0xC8, 0xC1, +0xBC, 0xB5, 0xB0, 0xAE, 0xAB, 0xAA, 0xAB, 0xAD, 0xAF, 0xB1, 0xB7, 0xC0, 0xD9, 0x53, 0x42, 0x3B, +0x34, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x30, 0x33, 0x37, 0x3C, 0x43, 0x4D, 0x5E, 0xEC, 0xD0, +0xC7, 0xC0, 0xBB, 0xB6, 0xB0, 0xAE, 0xAB, 0xAA, 0xAC, 0xAE, 0xAF, 0xB3, 0xB9, 0xC5, 0xE2, 0x4E, +0x3F, 0x39, 0x32, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x2F, 0x33, 0x39, 0x3D, 0x44, 0x4F, 0x65, +0xE3, 0xCE, 0xC5, 0xBF, 0xBA, 0xB4, 0xAF, 0xAD, 0xAA, 0xAA, 0xAC, 0xAE, 0xB0, 0xB5, 0xBB, 0xC8, +0xF8, 0x4C, 0x3E, 0x38, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, 0x2E, 0x2F, 0x31, 0x35, 0x39, 0x3E, 0x4A, +0x5C, 0xF9, 0xD8, 0xCB, 0xC2, 0xBC, 0xB7, 0xB2, 0xAE, 0xAB, 0xA9, 0xAA, 0xAC, 0xAE, 0xB2, 0xB8, +0xBE, 0xCE, 0x72, 0x48, 0x3B, 0x34, 0x2F, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x31, 0x36, 0x3A, +0x3E, 0x4A, 0x5F, 0xEA, 0xD0, 0xC9, 0xC1, 0xBB, 0xB5, 0xB0, 0xAE, 0xAB, 0xA9, 0xAB, 0xAC, 0xAE, +0xB4, 0xBB, 0xC4, 0xD6, 0x60, 0x45, 0x39, 0x30, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x32, +0x35, 0x3A, 0x43, 0x51, 0x6A, 0xDF, 0xCB, 0xC3, 0xBD, 0xB8, 0xB2, 0xAE, 0xAC, 0xAA, 0xAA, 0xAB, +0xAC, 0xAF, 0xB7, 0xBD, 0xCC, 0xF1, 0x51, 0x3F, 0x36, 0x2F, 0x2D, 0x2B, 0x2A, 0x2C, 0x2D, 0x2E, +0x2F, 0x33, 0x37, 0x3B, 0x45, 0x58, 0x77, 0xD5, 0xC8, 0xC0, 0xBB, 0xB6, 0xB1, 0xAE, 0xAB, 0xA9, +0xAA, 0xAB, 0xAC, 0xB1, 0xB9, 0xC0, 0xD3, 0x6A, 0x4A, 0x3C, 0x33, 0x2E, 0x2D, 0x2B, 0x2B, 0x2C, +0x2D, 0x2E, 0x31, 0x34, 0x38, 0x3F, 0x4C, 0x5D, 0xEA, 0xCE, 0xC6, 0xBE, 0xB8, 0xB4, 0xAF, 0xAD, +0xAB, 0xAA, 0xAA, 0xAB, 0xAD, 0xB2, 0xB9, 0xC3, 0xD8, 0x61, 0x47, 0x3A, 0x32, 0x2E, 0x2C, 0x2B, +0x2C, 0x2C, 0x2D, 0x2F, 0x31, 0x34, 0x38, 0x3F, 0x4D, 0x62, 0xDD, 0xCC, 0xC3, 0xBC, 0xB7, 0xB2, +0xAE, 0xAC, 0xAA, 0xAA, 0xAA, 0xAB, 0xAE, 0xB3, 0xBA, 0xC6, 0xE1, 0x55, 0x41, 0x37, 0x30, 0x2D, +0x2B, 0x2A, 0x2B, 0x2C, 0x2D, 0x2F, 0x31, 0x34, 0x39, 0x40, 0x4D, 0x6A, 0xD8, 0xC9, 0xC1, 0xBC, +0xB7, 0xB2, 0xAE, 0xAC, 0xAA, 0xAA, 0xAB, 0xAC, 0xAF, 0xB7, 0xBB, 0xC6, 0x79, 0x55, 0x44, 0x37, +0x30, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2D, 0x2F, 0x33, 0x35, 0x39, 0x42, 0x51, 0x6C, 0xDA, 0xCA, +0xC4, 0xBE, 0xBA, 0xB6, 0xB0, 0xAD, 0xAC, 0xAC, 0xAC, 0xAD, 0xAF, 0xB4, 0xB9, 0xC0, 0xD0, 0x65, +0x47, 0x3A, 0x32, 0x2F, 0x2C, 0x2B, 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x36, 0x3A, 0x3F, 0x4A, 0x5E, +0xDC, 0xCC, 0xC4, 0xBE, 0xBA, 0xB6, 0xB2, 0xAF, 0xAE, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB8, 0xBE, +0xCA, 0xE6, 0x4F, 0x3F, 0x38, 0x31, 0x2E, 0x2C, 0x2C, 0x2C, 0x2D, 0x2F, 0x31, 0x35, 0x3A, 0x3F, +0x4B, 0x64, 0xDD, 0xCB, 0xC3, 0xBD, 0xBA, 0xB7, 0xB4, 0xB1, 0xAF, 0xAE, 0xAE, 0xB0, 0xB3, 0xB5, +0xB9, 0xBE, 0xC6, 0xD3, 0x74, 0x4E, 0x40, 0x3A, 0x35, 0x32, 0x30, 0x2F, 0x2F, 0x30, 0x33, 0x36, +0x3A, 0x3F, 0x48, 0x52, 0x6C, 0xDF, 0xCE, 0xC7, 0xC1, 0xBE, 0xBB, 0xB9, 0xB8, 0xB7, 0xB6, 0xB6, +0xB7, 0xB9, 0xBB, 0xBE, 0xC4, 0xCA, 0xD9, 0x6C, 0x50, 0x45, 0x3D, 0x3A, 0x37, 0x35, 0x35, 0x35, +0x36, 0x37, 0x39, 0x3C, 0x3F, 0x46, 0x4F, 0x5E, 0xF1, 0xD9, 0xCF, 0xCC, 0xC9, 0xC5, 0xC1, 0xBE, +0xBC, 0xBC, 0xBC, 0xBD, 0xBF, 0xC2, 0xC4, 0xC7, 0xCC, 0xD5, 0xE8, 0x64, 0x52, 0x4A, 0x45, 0x41, +0x3F, 0x3E, 0x3D, 0x3D, 0x3E, 0x41, 0x45, 0x49, 0x4D, 0x53, 0x5C, 0x71, 0xE9, 0xDD, 0xD6, 0xD1, +0xCE, 0xCB, 0xC9, 0xC8, 0xC8, 0xC7, 0xC7, 0xC8, 0xC9, 0xCC, 0xCF, 0xD4, 0xDA, 0xE4, 0xF7, 0x69, +0x5B, 0x53, 0x4F, 0x4E, 0x4D, 0x4D, 0x4D, 0x4E, 0x51, 0x58, 0x5F, 0x68, 0x6F, 0x77, 0xFC, 0xEE, +0xE8, 0xE5, 0xE1, 0xDD, 0xDE, 0xDE, 0xDE, 0xE2, 0xE6, 0xE6, 0xEB, 0xF0, 0xED, 0xEA, 0xEC, 0xEE, +0xF8, 0x6A, 0x5C, 0x57, 0x55, 0x56, 0x58, 0x59, 0x58, 0x58, 0x5B, 0x5E, 0x63, 0x71, 0xF7, 0xEE, +0xE9, 0xE3, 0xE4, 0xE8, 0xE7, 0xEA, 0xEE, 0xEE, 0xF2, 0xFB, 0xFF, 0x7B, 0x74, 0x6E, 0x6B, 0x65, +0x60, 0x65, 0x67, 0x61, 0x60, 0x61, 0x5E, 0x5E, 0x62, 0x69, 0x70, 0x7F, 0xF6, 0xF2, 0xEC, 0xE7, +0xE6, 0xE3, 0xDF, 0xDE, 0xDE, 0xDD, 0xDE, 0xE0, 0xE5, 0xEC, 0xF6, 0x7F, 0x78, 0x75, 0x70, 0x6B, +0x64, 0x5E, 0x5A, 0x58, 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5E, 0x61, 0x67, 0x6C, 0x75, 0xF8, 0xEC, +0xE6, 0xE0, 0xDD, 0xDD, 0xDE, 0xDF, 0xE0, 0xE2, 0xE2, 0xE4, 0xE6, 0xE9, 0xEE, 0xF9, 0x7D, 0x75, +0x6E, 0x6A, 0x65, 0x61, 0x5E, 0x5C, 0x5B, 0x5C, 0x5D, 0x5E, 0x60, 0x63, 0x66, 0x6C, 0x76, 0xFA, +0xEE, 0xE9, 0xE4, 0xE1, 0xDF, 0xDD, 0xDE, 0xDF, 0xE2, 0xE6, 0xEA, 0xEE, 0xF4, 0xFA, 0x7E, 0x7A, +0x75, 0x72, 0x74, 0x74, 0x71, 0x70, 0x6D, 0x6A, 0x6A, 0x6B, 0x6D, 0x70, 0x74, 0x78, 0x7A, 0x7D, +0xFA, 0xF0, 0xEA, 0xE5, 0xE3, 0xE2, 0xE0, 0xDF, 0xE1, 0xE3, 0xE4, 0xE8, 0xEB, 0xEE, 0xF4, 0xFB, +0x7E, 0x75, 0x6D, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x65, 0x64, 0x63, 0x64, 0x66, 0x69, 0x6D, 0x72, +0x77, 0x7B, 0xFE, 0xF7, 0xF0, 0xEB, 0xE8, 0xE7, 0xE6, 0xE6, 0xE6, 0xE7, 0xE7, 0xE8, 0xEA, 0xED, +0xF3, 0xFC, 0x79, 0x72, 0x6F, 0x6C, 0x6B, 0x6B, 0x69, 0x66, 0x64, 0x63, 0x62, 0x63, 0x67, 0x6C, +0x73, 0x7C, 0xFE, 0xFD, 0xFA, 0xF4, 0xEE, 0xEA, 0xE5, 0xE1, 0xE1, 0xE2, 0xE5, 0xE9, 0xED, 0xEF, +0xF1, 0xF2, 0xF4, 0xF8, 0xFF, 0x76, 0x6E, 0x6A, 0x68, 0x67, 0x66, 0x65, 0x64, 0x62, 0x61, 0x61, +0x63, 0x67, 0x6B, 0x72, 0x7E, 0xFA, 0xF5, 0xF1, 0xEE, 0xED, 0xEC, 0xE9, 0xE8, 0xE7, 0xE7, 0xE9, +0xEC, 0xF0, 0xF9, 0x7D, 0x77, 0x73, 0x70, 0x6F, 0x6E, 0x6C, 0x69, 0x67, 0x65, 0x66, 0x66, 0x68, +0x69, 0x69, 0x6A, 0x6C, 0x6E, 0x75, 0x7F, 0xF8, 0xF1, 0xED, 0xEB, 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, +0xEA, 0xE9, 0xEA, 0xEC, 0xEF, 0xF4, 0xFB, 0x7D, 0x77, 0x73, 0x71, 0x6F, 0x6D, 0x6B, 0x69, 0x67, +0x66, 0x67, 0x68, 0x69, 0x6B, 0x6D, 0x6F, 0x74, 0x79, 0x7F, 0xF9, 0xF3, 0xEF, 0xEE, 0xEE, 0xEE, +0xEE, 0xED, 0xED, 0xED, 0xEE, 0xEC, 0xEC, 0xF1, 0xF3, 0xF6, 0xFD, 0xFF, 0x7D, 0x78, 0x78, 0x76, +0x70, 0x6F, 0x6E, 0x6D, 0x6D, 0x6E, 0x6F, 0x71, 0x73, 0x77, 0x7B, 0x7D, 0xFF, 0xFB, 0xF8, 0xF8, +0xFA, 0xFB, 0xFE, 0x7E, 0x7D, 0x7A, 0x79, 0x7A, 0x76, 0x76, 0x76, 0x72, 0x70, 0x6F, 0x6D, 0x6E, +0x6D, 0x6B, 0x6E, 0x65, 0x66, 0x57, 0x41, 0x59, 0xC7, 0x62, 0x57, 0xCD, 0x64, 0x6B, 0xCC, 0x6D, +0xF6, 0xD1, 0x69, 0x6E, 0xDA, 0x7D, 0x61, 0xEE, 0xF1, 0xFD, 0xFF, 0x6E, 0xE7, 0x74, 0x66, 0xE9, +0x6A, 0xFC, 0xF2, 0x64, 0xEE, 0x6F, 0x6B, 0x7B, 0x69, 0xF2, 0x68, 0x74, 0xEC, 0x5F, 0xED, 0xFC, +0x5F, 0xDE, 0x72, 0x65, 0xDC, 0x51, 0x4C, 0xE8, 0x5F, 0xEF, 0xD7, 0x4E, 0xF3, 0xF9, 0x52, 0xC3, +0xE2, 0x56, 0xC9, 0x5B, 0x59, 0xE4, 0x50, 0x53, 0x47, 0x66, 0xF9, 0x47, 0xC9, 0xCB, 0x59, 0xD4, +0x55, 0x58, 0xD3, 0x5C, 0xF9, 0xCE, 0xD7, 0x6D, 0x61, 0xDB, 0xE4, 0xE8, 0x70, 0x79, 0xCD, 0x6B, +0x5D, 0xEC, 0x66, 0xDC, 0x6C, 0x5F, 0xD3, 0xF9, 0xFB, 0x66, 0x55, 0xDE, 0xFB, 0x64, 0xD7, 0xDA, +0xF1, 0xF1, 0xF1, 0xE5, 0xDB, 0xF4, 0x75, 0xDF, 0xE7, 0xFD, 0x79, 0xEC, 0xD9, 0xF0, 0x6E, 0xF5, +0xE4, 0xE5, 0x64, 0x74, 0xDF, 0x7D, 0x68, 0x75, 0xF0, 0xFD, 0x7B, 0xFC, 0x7B, 0xDE, 0xEF, 0x64, +0xDF, 0xE8, 0xFF, 0xE9, 0xFF, 0xE2, 0xE1, 0x76, 0xF6, 0xEF, 0xEC, 0xF9, 0x6D, 0x7C, 0x73, 0x6D, +0x69, 0x67, 0x76, 0x75, 0x73, 0x64, 0x66, 0xFD, 0x60, 0x5F, 0x77, 0x67, 0x70, 0x74, 0x60, 0x78, +0x7A, 0x5C, 0x67, 0x79, 0x6C, 0x77, 0x63, 0x63, 0xEF, 0x6C, 0x66, 0x73, 0x6D, 0xF8, 0x72, 0x74, +0xE6, 0xFB, 0x7B, 0xF3, 0xF6, 0xF1, 0xFE, 0x7B, 0xF5, 0xF1, 0x6D, 0x63, 0x75, 0x6E, 0x60, 0x64, +0x67, 0x67, 0x68, 0x67, 0x67, 0x6C, 0x64, 0x5B, 0x65, 0x6E, 0x69, 0x72, 0x76, 0x74, 0xFE, 0xFD, +0xFF, 0xF6, 0xF3, 0x7C, 0x7A, 0xFC, 0xFE, 0xFB, 0x7E, 0x75, 0xF5, 0xEE, 0xFC, 0xF7, 0xF3, 0xFF, +0xFE, 0x74, 0x6B, 0x6F, 0x6D, 0x6A, 0x6C, 0x6A, 0x7A, 0xF9, 0x71, 0x7C, 0xF5, 0x7C, 0x7B, 0x7F, +0xFE, 0x72, 0x6E, 0xFF, 0x6F, 0x66, 0x6B, 0x6A, 0x6E, 0x76, 0x71, 0x7C, 0x7A, 0x6E, 0x6C, 0x69, +0x6C, 0x6D, 0x63, 0x65, 0x6A, 0x66, 0x63, 0x65, 0x6C, 0x68, 0x64, 0x69, 0x6A, 0x6E, 0x79, 0x7B, +0x78, 0x6D, 0x6E, 0x79, 0x77, 0xFA, 0xED, 0xEF, 0xEF, 0xEC, 0xE8, 0xEF, 0xFB, 0xF6, 0xEF, 0xEE, +0xF7, 0xF9, 0xF3, 0xF7, 0xF1, 0xF3, 0xFD, 0xFD, 0x7A, 0x7B, 0xFE, 0x79, 0x7C, 0x7B, 0x6E, 0x72, +0x7A, 0x72, 0x71, 0x79, 0x79, 0x6F, 0x6F, 0x78, 0x74, 0x72, 0x7B, 0x72, 0x78, 0xF6, 0xF7, 0xF9, +0x78, 0x79, 0xEE, 0xF5, 0x74, 0x76, 0x7A, 0xFE, 0x7E, 0x75, 0x7A, 0x7E, 0x74, 0x70, 0x7D, 0xF8, +0xF8, 0x7D, 0x77, 0xF8, 0xF0, 0x7F, 0x7E, 0xF2, 0xED, 0xF0, 0xF4, 0xEB, 0xE9, 0xFE, 0x74, 0xEF, +0xE1, 0xE0, 0xDC, 0xD9, 0xD7, 0xD3, 0xD7, 0xDD, 0xD9, 0xD9, 0xDF, 0xE6, 0xEB, 0xF2, 0x78, 0x65, +0x61, 0x65, 0x5F, 0x5A, 0x5B, 0x5B, 0x5A, 0x5C, 0x5B, 0x5D, 0x5E, 0x5C, 0x5B, 0x5B, 0x5B, 0x5C, +0x5E, 0x6B, 0xEA, 0xD9, 0xD2, 0xD1, 0xCD, 0xC8, 0xC6, 0xC5, 0xC5, 0xC3, 0xC3, 0xC6, 0xCA, 0xD2, +0xE8, 0x67, 0x51, 0x49, 0x42, 0x3D, 0x3D, 0x3E, 0x3F, 0x41, 0x44, 0x49, 0x4E, 0x50, 0x55, 0x5A, +0x5F, 0x6F, 0xEF, 0xDA, 0xCD, 0xCA, 0xC8, 0xC4, 0xBF, 0xBD, 0xBB, 0xB9, 0xB7, 0xB6, 0xBA, 0xC2, +0xCC, 0xE2, 0x56, 0x43, 0x3B, 0x39, 0x37, 0x36, 0x37, 0x3B, 0x3E, 0x42, 0x47, 0x4B, 0x51, 0x5A, +0x5B, 0x5E, 0x67, 0x7A, 0xED, 0xE8, 0xDB, 0xCF, 0xCB, 0xC5, 0xBD, 0xB9, 0xB6, 0xB2, 0xB0, 0xB4, +0xB9, 0xBF, 0xCD, 0xFC, 0x49, 0x3B, 0x37, 0x33, 0x31, 0x32, 0x33, 0x38, 0x3E, 0x45, 0x4F, 0x5F, +0x74, 0xF0, 0xEF, 0xF1, 0xF4, 0xFF, 0x77, 0x72, 0xFB, 0xE4, 0xD9, 0xCE, 0xC3, 0xBA, 0xB6, 0xB2, +0xB0, 0xB2, 0xB6, 0xBB, 0xC8, 0xE4, 0x51, 0x3E, 0x38, 0x33, 0x2F, 0x2F, 0x31, 0x35, 0x3A, 0x3E, +0x49, 0x5D, 0xFE, 0xE4, 0xDD, 0xD9, 0xD9, 0xE1, 0xEB, 0xEE, 0xEE, 0xE7, 0xDD, 0xD2, 0xC7, 0xBD, +0xB9, 0xB5, 0xB2, 0xB5, 0xB8, 0xBB, 0xC6, 0xDA, 0x5F, 0x45, 0x3D, 0x37, 0x33, 0x31, 0x31, 0x35, +0x39, 0x3D, 0x45, 0x53, 0x6F, 0xE3, 0xD9, 0xD0, 0xCF, 0xD2, 0xD5, 0xD9, 0xD9, 0xD8, 0xD4, 0xCE, +0xC8, 0xC0, 0xBD, 0xB9, 0xB8, 0xBB, 0xBD, 0xC1, 0xCD, 0xDF, 0x5F, 0x4A, 0x41, 0x3B, 0x37, 0x36, +0x35, 0x36, 0x3A, 0x3D, 0x44, 0x4E, 0x5F, 0xEC, 0xDB, 0xD6, 0xD2, 0xD4, 0xD6, 0xDA, 0xDD, 0xDB, +0xD8, 0xD2, 0xCD, 0xC9, 0xC3, 0xBF, 0xBE, 0xBF, 0xC3, 0xC4, 0xCA, 0xD6, 0xED, 0x5E, 0x50, 0x48, +0x3F, 0x3C, 0x3B, 0x3A, 0x3A, 0x3D, 0x40, 0x4A, 0x55, 0x6A, 0xE6, 0xDC, 0xD8, 0xD6, 0xD8, 0xD8, +0xDB, 0xDE, 0xDF, 0xE2, 0xDE, 0xDC, 0xD9, 0xD0, 0xCB, 0xC8, 0xC8, 0xCC, 0xCD, 0xCD, 0xD1, 0xDB, +0xF2, 0x67, 0x5B, 0x51, 0x49, 0x44, 0x42, 0x41, 0x42, 0x44, 0x49, 0x4E, 0x55, 0x5C, 0x6A, 0x7E, +0xF3, 0xED, 0xED, 0xEF, 0xEC, 0xED, 0xF4, 0xF7, 0xF0, 0xEB, 0xE4, 0xDF, 0xDA, 0xD2, 0xCD, 0xCC, +0xCC, 0xCF, 0xCF, 0xCE, 0xD3, 0xDB, 0xE7, 0x7C, 0x69, 0x5E, 0x54, 0x4F, 0x4E, 0x4D, 0x4E, 0x4F, +0x52, 0x58, 0x5B, 0x5E, 0x63, 0x67, 0x6B, 0x6B, 0x6A, 0x6B, 0x6C, 0x6E, 0x6F, 0x73, 0x7D, 0xF3, +0xEA, 0xE1, 0xDC, 0xD8, 0xD3, 0xD1, 0xCF, 0xCE, 0xD1, 0xD2, 0xD2, 0xD6, 0xDB, 0xE2, 0xEF, 0xFD, +0x73, 0x66, 0x5F, 0x5C, 0x5A, 0x59, 0x58, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x5A, 0x5C, 0x5D, +0x61, 0x65, 0x6A, 0x74, 0x7E, 0xF4, 0xEA, 0xE2, 0xDD, 0xDA, 0xD7, 0xD5, 0xD2, 0xD1, 0xD0, 0xD1, +0xD3, 0xD3, 0xD4, 0xD7, 0xDB, 0xE0, 0xE8, 0xEF, 0x7B, 0x69, 0x5F, 0x5B, 0x57, 0x53, 0x50, 0x4F, +0x4F, 0x4F, 0x4F, 0x50, 0x52, 0x56, 0x59, 0x5C, 0x60, 0x68, 0x6E, 0x7A, 0xFB, 0xF1, 0xEB, 0xE7, +0xE2, 0xDE, 0xDC, 0xDA, 0xD7, 0xD5, 0xD3, 0xD3, 0xD3, 0xD5, 0xD5, 0xD8, 0xDC, 0xE4, 0xF2, 0x78, +0x6A, 0x5E, 0x59, 0x55, 0x52, 0x50, 0x4F, 0x4F, 0x50, 0x52, 0x55, 0x58, 0x5A, 0x5D, 0x61, 0x64, +0x69, 0x6E, 0x74, 0xFF, 0xF6, 0xEE, 0xE9, 0xE4, 0xDF, 0xDC, 0xD8, 0xD5, 0xD2, 0xD0, 0xD1, 0xD1, +0xD2, 0xD6, 0xD7, 0xDA, 0xDF, 0xE8, 0xF8, 0x71, 0x69, 0x60, 0x5C, 0x58, 0x56, 0x54, 0x53, 0x53, +0x53, 0x55, 0x56, 0x58, 0x5A, 0x5C, 0x5F, 0x63, 0x69, 0x71, 0xFF, 0xEF, 0xEA, 0xE6, 0xE1, 0xDF, +0xDE, 0xDB, 0xDA, 0xDA, 0xD7, 0xD4, 0xD1, 0xD1, 0xD2, 0xD4, 0xD7, 0xD8, 0xDB, 0xE1, 0xED, 0x78, +0x69, 0x61, 0x5A, 0x53, 0x50, 0x4F, 0x4E, 0x4F, 0x4F, 0x51, 0x55, 0x59, 0x5D, 0x60, 0x65, 0x6C, +0x6F, 0x76, 0x7E, 0xFC, 0xF5, 0xF2, 0xF2, 0xED, 0xE7, 0xE1, 0xDD, 0xD9, 0xD4, 0xCE, 0xCB, 0xCA, +0xC8, 0xCA, 0xCF, 0xD0, 0xD7, 0xE6, 0x7C, 0x5E, 0x53, 0x4F, 0x4C, 0x4A, 0x4A, 0x4A, 0x4C, 0x4E, +0x4F, 0x51, 0x57, 0x5D, 0x62, 0x66, 0x69, 0x6D, 0x6D, 0x67, 0x63, 0x65, 0x6B, 0x70, 0x75, 0xFE, +0xEA, 0xDC, 0xD3, 0xCE, 0xC9, 0xC2, 0xBE, 0xBC, 0xBC, 0xC1, 0xC8, 0xCB, 0xDC, 0x69, 0x50, 0x46, +0x42, 0x3F, 0x3D, 0x3D, 0x3F, 0x43, 0x4B, 0x4F, 0x55, 0x61, 0x6F, 0xFC, 0xF0, 0xFA, 0xFD, 0x7B, +0x63, 0x5A, 0x54, 0x52, 0x54, 0x58, 0x62, 0x7D, 0xDE, 0xCC, 0xC4, 0xBC, 0xB6, 0xB1, 0xAE, 0xB2, +0xBA, 0xC1, 0xDA, 0x5A, 0x45, 0x38, 0x33, 0x32, 0x33, 0x36, 0x3A, 0x3E, 0x4B, 0x66, 0xEA, 0xD6, +0xCE, 0xCF, 0xD3, 0xE0, 0x6E, 0x5C, 0x51, 0x4D, 0x4B, 0x4A, 0x4F, 0x5B, 0x7A, 0xD6, 0xC6, 0xBA, +0xB1, 0xAE, 0xAA, 0xAA, 0xAF, 0xBA, 0xD1, 0x4E, 0x3D, 0x31, 0x2B, 0x2B, 0x2C, 0x30, 0x38, 0x3E, +0x4E, 0xEA, 0xCD, 0xC7, 0xC8, 0xCB, 0xCE, 0xDD, 0x64, 0x4F, 0x48, 0x48, 0x47, 0x46, 0x4D, 0x62, +0xDD, 0xCA, 0xBD, 0xB1, 0xAC, 0xA9, 0xA7, 0xAA, 0xB2, 0xC4, 0x51, 0x3A, 0x2F, 0x29, 0x28, 0x2A, +0x2E, 0x39, 0x45, 0x5A, 0xDB, 0xC8, 0xC2, 0xC5, 0xCD, 0xD5, 0xE8, 0x5B, 0x4C, 0x46, 0x47, 0x4C, +0x4E, 0x59, 0xF3, 0xD3, 0xC6, 0xBE, 0xB5, 0xAD, 0xAA, 0xA6, 0xA8, 0xB2, 0xC5, 0x54, 0x38, 0x2F, +0x28, 0x26, 0x2A, 0x2F, 0x3A, 0x4B, 0x73, 0xCF, 0xC5, 0xC4, 0xC9, 0xD9, 0xF8, 0x5F, 0x4C, 0x47, +0x47, 0x48, 0x4F, 0x5A, 0x74, 0xD9, 0xCE, 0xC7, 0xBF, 0xBA, 0xB0, 0xAC, 0xAA, 0xA9, 0xB0, 0xC5, +0x5C, 0x3B, 0x30, 0x2B, 0x27, 0x29, 0x2E, 0x39, 0x49, 0x6C, 0xD2, 0xC7, 0xC5, 0xCA, 0xDA, 0x7A, +0x5E, 0x4D, 0x48, 0x49, 0x4B, 0x52, 0x5E, 0x70, 0xDC, 0xCE, 0xC9, 0xC4, 0xBE, 0xB5, 0xAE, 0xAC, +0xAA, 0xAD, 0xBB, 0xE1, 0x43, 0x35, 0x2E, 0x29, 0x28, 0x2B, 0x32, 0x3D, 0x4E, 0x7E, 0xD2, 0xC9, +0xC7, 0xCC, 0xDF, 0xFE, 0x61, 0x4F, 0x4C, 0x4B, 0x4C, 0x54, 0x5D, 0x72, 0xDA, 0xCE, 0xC7, 0xC0, +0xB9, 0xB0, 0xAD, 0xAA, 0xAA, 0xB1, 0xC5, 0x5D, 0x3D, 0x33, 0x2C, 0x29, 0x29, 0x2D, 0x35, 0x3F, +0x4F, 0x78, 0xD7, 0xCA, 0xC7, 0xCD, 0xD9, 0xE3, 0x71, 0x5C, 0x54, 0x4D, 0x4E, 0x55, 0x5A, 0x6E, +0xE3, 0xD3, 0xC8, 0xBE, 0xB6, 0xAF, 0xAC, 0xAA, 0xAC, 0xB7, 0xCE, 0x53, 0x3D, 0x34, 0x2D, 0x2A, +0x2A, 0x2E, 0x35, 0x3E, 0x4A, 0x5C, 0xE5, 0xCD, 0xC8, 0xCB, 0xCE, 0xD5, 0xE2, 0xF7, 0x66, 0x57, +0x54, 0x56, 0x5B, 0x6E, 0xE7, 0xD5, 0xC9, 0xBE, 0xB6, 0xB1, 0xAE, 0xAE, 0xB4, 0xBE, 0xD3, 0x5C, +0x46, 0x3C, 0x34, 0x30, 0x2F, 0x32, 0x38, 0x3E, 0x45, 0x4E, 0x69, 0xDC, 0xCF, 0xCD, 0xCF, 0xD3, +0xD9, 0xDF, 0xEF, 0x6F, 0x68, 0x67, 0x6F, 0xF7, 0xE7, 0xDC, 0xD2, 0xC8, 0xC1, 0xBE, 0xBC, 0xBD, +0xC3, 0xCB, 0xD5, 0xEA, 0x6A, 0x58, 0x4D, 0x47, 0x43, 0x43, 0x44, 0x47, 0x4A, 0x4D, 0x52, 0x5D, +0x6D, 0x78, 0x77, 0x78, 0x76, 0x73, 0x75, 0x72, 0x72, 0x78, 0x7E, 0xF6, 0xEB, 0xE3, 0xDC, 0xD6, +0xD2, 0xCF, 0xCE, 0xCE, 0xCD, 0xCF, 0xD2, 0xD4, 0xD7, 0xDA, 0xDD, 0xE3, 0xEF, 0x7A, 0x6C, 0x65, +0x5F, 0x5B, 0x57, 0x53, 0x4F, 0x4E, 0x4D, 0x4C, 0x4A, 0x4A, 0x4A, 0x4B, 0x4D, 0x4F, 0x53, 0x59, +0x5F, 0x6C, 0xFE, 0xEC, 0xE3, 0xDE, 0xDC, 0xDA, 0xD9, 0xD8, 0xD7, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, +0xD8, 0xDA, 0xDC, 0xDE, 0xE3, 0xEC, 0xFB, 0x6F, 0x63, 0x5B, 0x55, 0x4F, 0x4D, 0x4C, 0x4B, 0x4C, +0x4C, 0x4D, 0x4F, 0x53, 0x58, 0x5E, 0x67, 0x73, 0xFB, 0xEE, 0xE8, 0xE3, 0xDF, 0xDC, 0xDA, 0xD9, +0xD8, 0xD8, 0xD8, 0xD9, 0xDB, 0xDD, 0xDF, 0xE1, 0xE5, 0xE9, 0xEE, 0xF6, 0x7C, 0x6E, 0x66, 0x5F, +0x5C, 0x5A, 0x58, 0x56, 0x56, 0x57, 0x58, 0x5A, 0x5D, 0x60, 0x66, 0x6D, 0x74, 0x7C, 0xFB, 0xF4, +0xEE, 0xEA, 0xE7, 0xE5, 0xE4, 0xE4, 0xE4, 0xE7, 0xEA, 0xEC, 0xED, 0xED, 0xEC, 0xED, 0xEC, 0xED, +0xEE, 0xF1, 0xF9, 0x7F, 0x79, 0x75, 0x70, 0x6D, 0x6C, 0x6C, 0x6E, 0x73, 0x79, 0xFE, 0xF9, 0xF3, +0xEE, 0xEB, 0xE9, 0xE8, 0xE6, 0xE5, 0xE6, 0xE8, 0xEA, 0xED, 0xF1, 0xF8, 0xFD, 0x7E, 0x7E, 0xFE, +0xFC, 0xF9, 0xF5, 0xF5, 0xF6, 0xFB, 0x7C, 0x77, 0x71, 0x6E, 0x6C, 0x6A, 0x69, 0x69, 0x6B, 0x6E, +0x70, 0x75, 0x7A, 0xFE, 0xF6, 0xF1, 0xEE, 0xEC, 0xEB, 0xEB, 0xEC, 0xEE, 0xF1, 0xF5, 0xFB, 0x7D, +0x7B, 0x7A, 0x7C, 0xFE, 0xFA, 0xF4, 0xF1, 0xF0, 0xF0, 0xF3, 0xF7, 0xFB, 0xFD, 0xFF, 0xFF, 0x7F, +0x7F, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0xFD, 0xFC, 0xFA, 0xF5, 0xF4, 0xF1, 0xEF, 0xEF, 0xEF, 0xF0, +0xF4, 0xF8, 0xFD, 0x7D, 0x78, 0x77, 0x78, 0x7A, 0x7C, 0x7C, 0x7E, 0x7C, 0x7A, 0x79, 0x76, 0x77, +0x78, 0x77, 0x7B, 0x7E, 0xFF, 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0x7E, 0xFE, 0xFB, +0xFA, 0xF9, 0xFA, 0xFB, 0xFE, 0x7F, 0x7C, 0x79, 0x78, 0x77, 0x77, 0x7A, 0x7C, 0x7D, 0x7E, 0x7B, +0x77, 0x74, 0x71, 0x6F, 0x6E, 0x6E, 0x6F, 0x6F, 0x70, 0x71, 0x73, 0x74, 0x76, 0x76, 0x75, 0x76, +0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x77, 0x74, 0x72, 0x70, 0x6F, 0x6E, 0x6E, 0x6E, 0x70, 0x74, +0x78, 0x7B, 0x7D, 0x7D, 0x7C, 0x7C, 0x7A, 0x76, 0x72, 0x71, 0x70, 0x70, 0x70, 0x71, 0x72, 0x72, +0x74, 0x76, 0x78, 0x7B, 0x7F, 0xFE, 0xFC, 0xF9, 0xF6, 0xF5, 0xF7, 0xFC, 0xFF, 0x7C, 0x79, 0x78, +0x77, 0x77, 0x77, 0x7A, 0x7E, 0xFE, 0xFC, 0xFA, 0xF8, 0xF8, 0xFA, 0xFC, 0xFE, 0x7D, 0x7A, 0x76, +0x74, 0x74, 0x73, 0x75, 0x76, 0x76, 0x78, 0x7A, 0x7C, 0x7E, 0xFF, 0xFB, 0xF9, 0xF8, 0xF9, 0xFD, +0x7E, 0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x78, 0x7C, 0x7F, 0xFB, 0xF6, 0xF5, 0xF2, 0xF2, 0xF3, +0xF4, 0xF7, 0xF8, 0xFA, 0xFC, 0xFE, 0xFF, 0xFF, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFA, +0xF7, 0xF6, 0xF8, 0xFC, 0x7F, 0x7C, 0x79, 0x72, 0x6F, 0x6E, 0x6E, 0x6E, 0x6F, 0x73, 0x77, 0x77, +0x7B, 0x7D, 0x7E, 0x7F, 0x7E, 0x7C, 0x7A, 0x77, 0x75, 0x71, 0x6F, 0x6E, 0x6D, 0x6E, 0x6F, 0x70, +0x73, 0x74, 0x77, 0x79, 0x7C, 0x7D, 0x7D, 0x7D, 0x7B, 0x7A, 0x79, 0x76, 0x73, 0x70, 0x6F, 0x71, +0x73, 0x78, 0x7B, 0x7F, 0xFB, 0xF8, 0xF5, 0xF3, 0xF5, 0xF6, 0xF6, 0xF8, 0xF9, 0xFC, 0xFE, 0xFF, +0x7F, 0xFF, 0xFD, 0xFC, 0xFC, 0xFB, 0xF7, 0xF6, 0xF6, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF7, 0xF9, +0xFA, 0xFC, 0xFF, 0xFF, 0x7F, 0x7F, 0xFE, 0xFD, 0xFE, 0xFD, 0xFB, 0xFB, 0xFC, 0xFE, 0x7E, 0x7C, +0x7A, 0x79, 0x77, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7C, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, +0x7D, 0x7E, 0x7C, 0x7E, 0x7F, 0x7E, 0x7E, 0xFF, 0xFD, 0xFC, 0xFB, 0xF8, 0xF8, 0xFA, 0xFA, 0xFC, +0xFE, 0x7D, 0x78, 0x75, 0x72, 0x70, 0x70, 0x73, 0x75, 0x76, 0x78, 0x79, 0x79, 0x7A, 0x79, 0x78, +0x77, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7D, 0x7F, 0xFC, 0xF8, 0xF6, +0xF4, 0xF2, 0xF3, 0xF7, 0xF9, 0xFB, 0x7E, 0x78, 0x75, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, +0x75, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x76, 0x79, 0x7B, +0x7C, 0x7E, 0xFE, 0xFC, 0xF9, 0xF6, 0xF5, 0xF6, 0xF7, 0xF9, 0xFC, 0xFE, 0x7C, 0x79, 0x77, 0x76, +0x75, 0x74, 0x74, 0x75, 0x74, 0x76, 0x77, 0x78, 0x79, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x78, 0x78, +0x77, 0x76, 0x77, 0x77, 0x77, 0x78, 0x7A, 0x7C, 0xFF, 0xFD, 0xFA, 0xF8, 0xF6, 0xF7, 0xF8, 0xF7, +0xF8, 0xF8, 0xF8, 0xF9, 0xFA, 0xF9, 0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0xFD, 0xFD, 0xFC, 0xFD, 0xFE, +0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7B, 0x7A, 0x79, 0x79, 0x79, 0x78, 0x79, 0x7B, 0x7C, 0x7C, 0x7C, +0x7C, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x71, 0x70, 0x6F, 0x6F, 0x6E, +0x6D, 0x6C, 0x6C, 0x6D, 0x6E, 0x6E, 0x6E, 0x6F, 0x6E, 0x6F, 0x70, 0x70, 0x72, 0x75, 0x78, 0x7B, +0x7B, 0x7C, 0x7D, 0xFF, 0xFD, 0xFC, 0xFA, 0xFA, 0xF9, 0xF7, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF9, +0xFA, 0xFA, 0xFA, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFB, +0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFF, 0x7F, 0xFC, 0xFA, 0xFB, 0xFA, 0xFA, 0xF9, +0xFA, 0xFC, 0xFC, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFE, 0xFD, 0xFC, 0xFD, 0xFA, 0xFA, 0xF9, 0xF8, +0xFA, 0xF8, 0xFA, 0xFA, 0xFB, 0xFE, 0xFB, 0xFF, 0xFD, 0xFD, 0xFF, 0xFB, 0xFF, 0xFA, 0xFC, 0x7F, +0xFC, 0x70, 0x6A, 0x64, 0x61, 0x67, 0x6C, 0x73, 0x61, 0x60, 0x5A, 0x47, 0x53, 0xDF, 0x7D, 0x6F, +0x71, 0x69, 0x7F, 0x72, 0x70, 0x68, 0x5A, 0x5B, 0x59, 0x55, 0x5A, 0x5D, 0x4E, 0x46, 0x51, 0x77, +0xF6, 0xEC, 0xE8, 0xE6, 0xE5, 0xE4, 0xE1, 0xE5, 0xFD, 0x60, 0x65, 0xE6, 0xDB, 0xDD, 0xE1, 0xE4, +0xE2, 0xDC, 0xD4, 0xCF, 0xCF, 0xCF, 0xD1, 0xD2, 0xCF, 0xCD, 0xCC, 0xCD, 0xD0, 0xD4, 0xD7, 0xD5, +0xCE, 0xCD, 0xD3, 0xD9, 0xDB, 0xDA, 0xD9, 0xDC, 0xE2, 0xE5, 0xF1, 0xEE, 0xD7, 0xD2, 0xD9, 0xDC, +0xDD, 0xD9, 0xDC, 0xE7, 0xDF, 0xD9, 0xDD, 0x74, 0x62, 0xFC, 0xE9, 0xF2, 0x6C, 0x5D, 0x5D, 0x61, +0x6B, 0x6C, 0x5C, 0x5D, 0x70, 0x64, 0x5B, 0x6D, 0x78, 0x61, 0x57, 0x58, 0x65, 0x62, 0x53, 0x51, +0x69, 0xF5, 0x59, 0x53, 0x69, 0x68, 0x54, 0x4F, 0x67, 0xFA, 0x5B, 0x58, 0x5D, 0x60, 0x5D, 0x4E, +0x53, 0x61, 0x5A, 0x5F, 0x63, 0x61, 0x5E, 0x4C, 0x4C, 0x5A, 0x6B, 0xF7, 0x58, 0x47, 0x51, 0x6D, +0x68, 0x5A, 0x55, 0x53, 0x4A, 0x4E, 0xEE, 0xE1, 0x56, 0x46, 0x4D, 0x74, 0x70, 0x59, 0x53, 0x4C, +0x4E, 0x62, 0xF2, 0xF3, 0x5A, 0x4A, 0x4F, 0x6D, 0x6B, 0x57, 0x63, 0xED, 0x79, 0x69, 0x62, 0x5D, +0x6C, 0x67, 0x5E, 0xF5, 0xEA, 0x69, 0x63, 0x76, 0xFA, 0x6A, 0x59, 0x5D, 0xFB, 0xF6, 0x72, 0xFB, +0x71, 0x5D, 0x65, 0x7D, 0xFC, 0x79, 0xFB, 0xE9, 0xE2, 0xDD, 0xE3, 0xF9, 0xFA, 0xF3, 0xEA, 0xEC, +0x7D, 0xF1, 0xE5, 0xF2, 0x78, 0x6D, 0x6D, 0xED, 0xE4, 0xE5, 0xE4, 0xF6, 0x7A, 0xF8, 0xE5, 0xDC, +0xEA, 0xDF, 0xCF, 0xD3, 0xE7, 0x6C, 0x78, 0xCF, 0xC9, 0xD5, 0x7E, 0x64, 0x7E, 0xD7, 0xCF, 0xD7, +0xE0, 0xE8, 0xDC, 0xCB, 0xC5, 0xCC, 0xE6, 0x73, 0xE9, 0xD2, 0xC9, 0xCA, 0xD3, 0xED, 0x68, 0xF3, +0xD9, 0xDA, 0xDC, 0xDA, 0xD7, 0xDB, 0xE1, 0xE1, 0xEA, 0x69, 0x59, 0x60, 0xEE, 0xE0, 0xDC, 0xDF, +0xE5, 0xDD, 0xE1, 0xED, 0xED, 0xF4, 0xF6, 0xF2, 0xEE, 0xED, 0xFC, 0x6F, 0x64, 0x5C, 0x5C, 0x61, +0x76, 0xEA, 0xE1, 0xEB, 0x73, 0x66, 0x60, 0x69, 0xFB, 0x7E, 0x70, 0x76, 0xFF, 0x78, 0x73, 0xEB, +0xE2, 0x6F, 0x5C, 0x69, 0xE9, 0xDB, 0xDE, 0x73, 0x5E, 0x6D, 0xED, 0xEB, 0xF4, 0xFF, 0x77, 0xFD, +0xE7, 0xE2, 0xFB, 0x66, 0x69, 0xFE, 0xFA, 0x6B, 0x63, 0x69, 0x74, 0x74, 0x66, 0x63, 0x6F, 0xFB, +0xFD, 0x73, 0x71, 0x7B, 0xF4, 0xE8, 0xE2, 0xE8, 0xF2, 0xEB, 0xDE, 0xDC, 0xDE, 0xE2, 0xE7, 0xE5, +0xDF, 0xDF, 0xE8, 0xFC, 0x6D, 0x6A, 0x66, 0x5C, 0x53, 0x51, 0x56, 0x5B, 0x59, 0x56, 0x56, 0x5A, +0x5E, 0x5A, 0x53, 0x53, 0x59, 0x5D, 0x5F, 0x64, 0x74, 0xE9, 0xD6, 0xCB, 0xCB, 0xD3, 0xDC, 0xD4, +0xC8, 0xC1, 0xBF, 0xBE, 0xBE, 0xC5, 0xCE, 0xDC, 0xEA, 0x68, 0x4B, 0x3E, 0x3B, 0x3B, 0x3D, 0x3E, +0x41, 0x45, 0x47, 0x48, 0x4A, 0x4C, 0x4A, 0x47, 0x49, 0x4F, 0x5E, 0x6D, 0xF5, 0xDB, 0xCC, 0xC5, +0xC1, 0xBF, 0xBE, 0xBC, 0xBA, 0xB7, 0xB2, 0xAF, 0xAE, 0xB7, 0xDA, 0x43, 0x38, 0x35, 0x32, 0x31, +0x33, 0x3A, 0x46, 0x54, 0x5D, 0x56, 0x4A, 0x44, 0x43, 0x46, 0x44, 0x3F, 0x40, 0x4B, 0x61, 0x7B, +0xFD, 0xE7, 0xD4, 0xCA, 0xC5, 0xBF, 0xBB, 0xB6, 0xB1, 0xAF, 0xAD, 0xAC, 0xAC, 0xB4, 0xD8, 0x3C, +0x2D, 0x2B, 0x2D, 0x2F, 0x37, 0x41, 0x54, 0x76, 0xFF, 0x68, 0x54, 0x46, 0x40, 0x44, 0x49, 0x4A, +0x49, 0x4C, 0x5C, 0xFB, 0xE9, 0xE5, 0xDB, 0xCE, 0xC8, 0xC3, 0xBE, 0xBA, 0xB6, 0xB1, 0xAE, 0xAB, +0xA9, 0xAB, 0xBD, 0x3F, 0x2A, 0x26, 0x2A, 0x31, 0x3A, 0x43, 0x58, 0xE9, 0xDB, 0xE8, 0x5E, 0x46, +0x3C, 0x3D, 0x48, 0x55, 0x56, 0x55, 0x61, 0xF3, 0xE8, 0xE6, 0xDC, 0xCF, 0xC9, 0xC0, 0xB9, 0xB4, +0xB3, 0xB3, 0xAF, 0xAA, 0xA8, 0xAF, 0x75, 0x2C, 0x22, 0x24, 0x2D, 0x3F, 0x56, 0x72, 0xE0, 0xCF, +0xD4, 0x59, 0x3F, 0x38, 0x38, 0x3E, 0x4C, 0x68, 0xE8, 0xE3, 0xEA, 0x7E, 0x67, 0x64, 0x79, 0xDC, +0xCB, 0xBF, 0xB7, 0xB1, 0xAF, 0xAE, 0xAC, 0xAA, 0xB1, 0x56, 0x29, 0x1F, 0x20, 0x2B, 0x45, 0xD1, +0xC4, 0xC7, 0xCB, 0xD8, 0x4B, 0x33, 0x2E, 0x34, 0x42, 0x6D, 0xCD, 0xC5, 0xC8, 0xD1, 0xE0, 0x69, +0x52, 0x52, 0x6D, 0xD4, 0xC6, 0xBB, 0xB1, 0xAC, 0xAB, 0xAA, 0xA8, 0xAE, 0x68, 0x28, 0x1D, 0x1E, +0x2B, 0x53, 0xBC, 0xB6, 0xBD, 0xCA, 0xE1, 0x4E, 0x33, 0x2A, 0x2C, 0x3B, 0x7D, 0xBF, 0xBB, 0xC1, +0xD5, 0xED, 0x6A, 0x4F, 0x4C, 0x58, 0x7E, 0xD6, 0xC7, 0xBB, 0xB2, 0xAD, 0xA9, 0xA6, 0xA9, 0xC3, +0x2D, 0x1D, 0x1B, 0x23, 0x41, 0xBC, 0xAF, 0xB5, 0xC2, 0xDE, 0x4F, 0x3B, 0x2D, 0x27, 0x2D, 0x49, +0xC3, 0xB5, 0xB9, 0xCB, 0x64, 0x54, 0x56, 0x51, 0x58, 0x75, 0xE3, 0xD1, 0xCA, 0xC1, 0xB6, 0xAB, +0xA6, 0xA3, 0xA6, 0xC0, 0x2B, 0x1C, 0x1A, 0x24, 0x4D, 0xB0, 0xAA, 0xB0, 0xC3, 0xF0, 0x46, 0x38, +0x2D, 0x28, 0x2B, 0x4C, 0xBC, 0xB2, 0xB6, 0xD1, 0x4B, 0x46, 0x4F, 0x58, 0x61, 0xEE, 0xE1, 0xDB, +0xCF, 0xCB, 0xBD, 0xAE, 0xA7, 0xA3, 0xA2, 0xB6, 0x2C, 0x1B, 0x19, 0x21, 0x52, 0xAB, 0xA5, 0xAE, +0xC9, 0x4F, 0x3B, 0x37, 0x32, 0x2A, 0x2A, 0x3D, 0xC9, 0xB2, 0xB1, 0xCA, 0x44, 0x3D, 0x49, 0x5F, +0xDD, 0xD8, 0x77, 0x6E, 0xED, 0xDB, 0xC7, 0xB7, 0xAB, 0xA5, 0xA3, 0xA6, 0xC8, 0x26, 0x1A, 0x1A, +0x27, 0xC5, 0xA4, 0xA3, 0xAF, 0xE9, 0x3B, 0x33, 0x34, 0x31, 0x2D, 0x31, 0x57, 0xBF, 0xB3, 0xBA, +0x78, 0x41, 0x3E, 0x4E, 0xDC, 0xCE, 0xD4, 0x78, 0x5B, 0x67, 0xDC, 0xC4, 0xB7, 0xAC, 0xA6, 0xA5, +0xA5, 0xBA, 0x2C, 0x1B, 0x19, 0x23, 0xD8, 0xA3, 0x9F, 0xAB, 0xDA, 0x34, 0x2D, 0x30, 0x33, 0x33, +0x37, 0x54, 0xC1, 0xB7, 0xBD, 0x6E, 0x41, 0x3D, 0x4A, 0xD8, 0xCA, 0xD0, 0xEB, 0x56, 0x54, 0x74, +0xCE, 0xBD, 0xAF, 0xA8, 0xA6, 0xA5, 0xAE, 0x3B, 0x1E, 0x19, 0x1E, 0x43, 0xA8, 0x9E, 0xA6, 0xC8, +0x33, 0x29, 0x2C, 0x32, 0x39, 0x3D, 0x4E, 0xCD, 0xBE, 0xC2, 0xFF, 0x40, 0x3D, 0x48, 0xE0, 0xC4, +0xCB, 0xEA, 0x4F, 0x48, 0x59, 0xD7, 0xBE, 0xB5, 0xAD, 0xA9, 0xA9, 0xA7, 0xB3, 0x34, 0x1D, 0x19, +0x20, 0xEE, 0xA2, 0x9D, 0xA8, 0x60, 0x2A, 0x26, 0x2D, 0x3B, 0x4A, 0x4E, 0x64, 0xCE, 0xC6, 0xCF, +0x57, 0x42, 0x47, 0x67, 0xCB, 0xC3, 0xD4, 0x5C, 0x48, 0x47, 0x63, 0xCA, 0xBA, 0xB2, 0xAE, 0xAC, +0xAC, 0xAB, 0xB3, 0x3D, 0x1F, 0x1B, 0x20, 0x51, 0xA5, 0x9E, 0xA8, 0x6C, 0x2A, 0x24, 0x2B, 0x3E, +0x5E, 0x6C, 0x66, 0xFA, 0xE0, 0xE4, 0x60, 0x4B, 0x4E, 0x71, 0xD2, 0xC8, 0xD8, 0x5A, 0x4A, 0x49, +0x6E, 0xC6, 0xB9, 0xB3, 0xB1, 0xAF, 0xAE, 0xAC, 0xAF, 0x48, 0x21, 0x1B, 0x1F, 0x4C, 0xA5, 0x9D, +0xA7, 0x64, 0x28, 0x23, 0x2C, 0x4A, 0xD6, 0xD9, 0x61, 0x59, 0x6C, 0xEF, 0xF8, 0x5B, 0x5B, 0xEE, +0xD5, 0xCD, 0xDB, 0x5C, 0x4D, 0x4C, 0x6E, 0xC8, 0xBB, 0xB8, 0xB8, 0xB6, 0xB3, 0xAD, 0xA8, 0xBC, +0x2D, 0x1D, 0x1B, 0x2B, 0xB7, 0x9F, 0xA1, 0xB9, 0x33, 0x23, 0x28, 0x3A, 0xEB, 0xCF, 0x77, 0x50, +0x56, 0x6E, 0xE2, 0x73, 0x55, 0x5D, 0xE6, 0xCF, 0xD9, 0x5B, 0x4B, 0x47, 0x59, 0xD2, 0xC3, 0xBD, +0xBD, 0xBC, 0xB6, 0xAE, 0xA9, 0xAB, 0x68, 0x24, 0x1B, 0x1E, 0x3C, 0xAA, 0x9E, 0xA6, 0xDE, 0x2A, +0x23, 0x2C, 0x47, 0xD1, 0xCE, 0x72, 0x55, 0x58, 0x6A, 0x78, 0x5D, 0x5B, 0xF9, 0xDA, 0xD3, 0xDE, +0x5A, 0x49, 0x4A, 0x5F, 0xD1, 0xC0, 0xBD, 0xBC, 0xB9, 0xB3, 0xAD, 0xA9, 0xB1, 0x3C, 0x1F, 0x1C, +0x24, 0xE1, 0xA4, 0x9F, 0xAD, 0x44, 0x26, 0x25, 0x32, 0x6E, 0xC3, 0xCD, 0x64, 0x4F, 0x4F, 0x62, +0x70, 0x5C, 0x68, 0xE1, 0xD4, 0xD3, 0xF6, 0x4E, 0x45, 0x4B, 0x78, 0xCA, 0xBE, 0xBC, 0xBC, 0xB8, +0xB3, 0xAC, 0xA9, 0xBC, 0x2F, 0x1E, 0x1C, 0x2A, 0xBC, 0xA0, 0xA1, 0xB7, 0x35, 0x24, 0x28, 0x3B, +0xD8, 0xC4, 0xDC, 0x53, 0x4B, 0x4F, 0x67, 0x6D, 0x65, 0xEA, 0xDB, 0xD5, 0xDA, 0x5E, 0x4B, 0x48, +0x53, 0xDB, 0xC4, 0xBD, 0xBD, 0xBB, 0xB5, 0xAE, 0xA8, 0xAB, 0x75, 0x25, 0x1B, 0x1E, 0x3D, 0xAA, +0x9E, 0xA6, 0xDC, 0x2B, 0x25, 0x2E, 0x4E, 0xCC, 0xCC, 0x66, 0x4B, 0x4C, 0x5A, 0x74, 0x6C, 0x6D, +0xDF, 0xD6, 0xD6, 0xED, 0x4D, 0x43, 0x46, 0x59, 0xD0, 0xBF, 0xBC, 0xBB, 0xB8, 0xB3, 0xAD, 0xA9, +0xB3, 0x38, 0x1E, 0x1B, 0x24, 0xCF, 0xA2, 0x9F, 0xAF, 0x3E, 0x26, 0x27, 0x36, 0x6A, 0xCD, 0xE6, +0x4F, 0x4D, 0x55, 0x6E, 0xEF, 0x63, 0x7B, 0xDA, 0xDB, 0xDF, 0x5F, 0x49, 0x47, 0x4F, 0xE8, 0xC5, +0xBD, 0xBC, 0xBB, 0xB6, 0xAF, 0xAA, 0xAA, 0xCD, 0x29, 0x1C, 0x1D, 0x34, 0xAE, 0x9F, 0xA4, 0xC7, +0x2E, 0x25, 0x2C, 0x41, 0xDB, 0xD2, 0x75, 0x5B, 0x59, 0x60, 0x6E, 0x5B, 0x5C, 0xDF, 0xD0, 0xD8, +0x74, 0x4B, 0x43, 0x4B, 0x6E, 0xCC, 0xBF, 0xBD, 0xBE, 0xBC, 0xB5, 0xAD, 0xA8, 0xAD, 0x4B, 0x22, +0x1C, 0x22, 0x65, 0xA6, 0x9F, 0xAC, 0x4C, 0x2A, 0x28, 0x33, 0x50, 0xDE, 0xF2, 0x65, 0x7C, 0xF8, +0x79, 0x5A, 0x4B, 0x5E, 0xD7, 0xCF, 0xD6, 0x5F, 0x45, 0x43, 0x4C, 0xFB, 0xC9, 0xBF, 0xBD, 0xBC, +0xB8, 0xB2, 0xAD, 0xAA, 0xB7, 0x38, 0x20, 0x1D, 0x29, 0xC6, 0xA5, 0xA4, 0xB8, 0x3C, 0x2A, 0x2C, +0x39, 0x53, 0x7F, 0x6F, 0x79, 0xE8, 0xF9, 0x61, 0x4D, 0x4B, 0xFF, 0xD0, 0xD3, 0xEC, 0x4F, 0x45, +0x49, 0x58, 0xDF, 0xC7, 0xBF, 0xBD, 0xBB, 0xB5, 0xAF, 0xA9, 0xAA, 0xCA, 0x2C, 0x1D, 0x1E, 0x36, +0xB1, 0xA2, 0xA8, 0xCE, 0x33, 0x2B, 0x30, 0x3E, 0x4F, 0x5A, 0x6D, 0xD8, 0xD2, 0xF5, 0x4F, 0x46, +0x54, 0xD4, 0xCA, 0xD7, 0x65, 0x48, 0x43, 0x4C, 0x61, 0xD7, 0xC4, 0xBF, 0xBD, 0xB7, 0xB1, 0xAD, +0xAA, 0xB0, 0x48, 0x23, 0x1D, 0x24, 0x5D, 0xAA, 0xA4, 0xB0, 0x56, 0x30, 0x2E, 0x34, 0x3E, 0x47, +0x52, 0xE3, 0xC9, 0xCE, 0x65, 0x45, 0x43, 0x6A, 0xCE, 0xCD, 0xDE, 0x58, 0x49, 0x49, 0x4F, 0x6D, +0xD1, 0xC0, 0xBB, 0xB6, 0xAF, 0xAE, 0xAA, 0xAB, 0xCF, 0x2B, 0x1D, 0x1E, 0x36, 0xB2, 0xA4, 0xA9, +0xC7, 0x3B, 0x2F, 0x31, 0x37, 0x3D, 0x46, 0x6E, 0xC7, 0xC5, 0xE5, 0x4C, 0x41, 0x50, 0xD5, 0xCB, +0xDF, 0x58, 0x4C, 0x49, 0x4E, 0x62, 0xE4, 0xC8, 0xBD, 0xB9, 0xB4, 0xAF, 0xAD, 0xA9, 0xB2, 0x41, +0x22, 0x1D, 0x26, 0xEB, 0xAA, 0xA6, 0xB3, 0x5D, 0x38, 0x32, 0x32, 0x34, 0x39, 0x4D, 0xCC, 0xBD, +0xC7, 0x60, 0x44, 0x47, 0x6D, 0xDC, 0xE2, 0xEF, 0x63, 0x58, 0x50, 0x4D, 0x5A, 0xDB, 0xC3, 0xBA, +0xB3, 0xAF, 0xAD, 0xAC, 0xAE, 0xD3, 0x2D, 0x1F, 0x20, 0x38, 0xB9, 0xA9, 0xAD, 0xC4, 0x4C, 0x39, +0x33, 0x30, 0x32, 0x3C, 0xFA, 0xBE, 0xBE, 0xD5, 0x51, 0x46, 0x4F, 0x6F, 0x7B, 0x65, 0x68, 0x76, +0x60, 0x54, 0x52, 0x61, 0xCF, 0xBF, 0xB7, 0xAE, 0xAC, 0xAB, 0xAB, 0xBC, 0x39, 0x22, 0x1E, 0x2B, +0xE7, 0xAF, 0xAC, 0xB6, 0xD1, 0x4E, 0x3A, 0x2F, 0x2D, 0x31, 0x45, 0xCC, 0xBC, 0xC2, 0xDA, 0x58, +0x4D, 0x55, 0x52, 0x52, 0x68, 0xED, 0xF4, 0x66, 0x55, 0x59, 0xEF, 0xCE, 0xBF, 0xB5, 0xAD, 0xAB, +0xAB, 0xAE, 0xCC, 0x31, 0x22, 0x22, 0x2F, 0xE8, 0xB6, 0xB1, 0xB8, 0xC4, 0x73, 0x3D, 0x2F, 0x2B, +0x2F, 0x3F, 0xDD, 0xC0, 0xBF, 0xC7, 0xD8, 0x73, 0x55, 0x46, 0x44, 0x53, 0x7B, 0xEE, 0xED, 0xF2, +0xED, 0xDC, 0xCF, 0xC1, 0xB3, 0xAC, 0xA9, 0xA9, 0xB2, 0x58, 0x2C, 0x24, 0x28, 0x36, 0x5C, 0xC7, +0xBA, 0xB6, 0xB7, 0xCA, 0x49, 0x34, 0x2D, 0x2E, 0x37, 0x49, 0xE0, 0xC4, 0xBD, 0xBE, 0xC7, 0xEA, +0x4C, 0x42, 0x44, 0x49, 0x50, 0x69, 0xDD, 0xD0, 0xCB, 0xC6, 0xBD, 0xB3, 0xAD, 0xAB, 0xAB, 0xBA, +0x49, 0x2F, 0x2B, 0x2D, 0x32, 0x3A, 0x4B, 0xD6, 0xBC, 0xB6, 0xBD, 0xD7, 0x51, 0x3D, 0x36, 0x34, +0x37, 0x3E, 0x52, 0xDE, 0xC8, 0xC3, 0xC7, 0xCE, 0xDE, 0x72, 0x56, 0x4F, 0x53, 0x5D, 0xFF, 0xDA, +0xC9, 0xBD, 0xB7, 0xB4, 0xB2, 0xB6, 0xC6, 0x62, 0x47, 0x3F, 0x3D, 0x3B, 0x3B, 0x40, 0x4E, 0x6F, +0xEC, 0x7B, 0x67, 0x5E, 0x5B, 0x59, 0x55, 0x5A, 0x65, 0x5E, 0x5A, 0x5F, 0x61, 0x5E, 0x63, 0x65, +0x61, 0x6D, 0xF5, 0xFA, 0x7A, 0x77, 0x77, 0xFF, 0xEB, 0xDC, 0xD5, 0xCE, 0xCA, 0xC8, 0xC8, 0xCD, +0xD9, 0xEC, 0x76, 0x70, 0xFD, 0xED, 0xEA, 0xEE, 0x7D, 0x66, 0x59, 0x53, 0x50, 0x4F, 0x50, 0x54, +0x56, 0x58, 0x59, 0x5A, 0x5A, 0x5C, 0x5F, 0x6B, 0xF6, 0xE5, 0xE1, 0xE7, 0xEF, 0xF5, 0xF2, 0xEA, +0xDF, 0xD8, 0xCE, 0xC8, 0xC4, 0xC5, 0xCB, 0xD4, 0xDF, 0xE9, 0xE7, 0xE1, 0xDD, 0xDB, 0xDE, 0xEE, +0x68, 0x57, 0x4F, 0x4D, 0x4D, 0x4E, 0x4F, 0x4F, 0x52, 0x54, 0x53, 0x51, 0x53, 0x57, 0x5E, 0x6F, +0xFA, 0xEF, 0xEF, 0xF3, 0xF1, 0xF1, 0xEE, 0xE6, 0xDE, 0xD6, 0xCF, 0xCD, 0xCE, 0xD3, 0xDA, 0xDC, +0xDF, 0xDF, 0xD9, 0xD5, 0xD4, 0xD7, 0xE0, 0xFE, 0x6B, 0x5F, 0x5A, 0x58, 0x56, 0x54, 0x54, 0x53, +0x53, 0x50, 0x4E, 0x4F, 0x52, 0x56, 0x5C, 0x64, 0x67, 0x66, 0x69, 0x6C, 0x6D, 0x74, 0xFA, 0xEC, +0xDF, 0xD7, 0xD6, 0xDD, 0xE6, 0xF3, 0x7B, 0xF7, 0xE8, 0xDC, 0xD3, 0xD0, 0xD2, 0xD9, 0xE1, 0xE7, +0xEB, 0xF6, 0x7B, 0x74, 0x6F, 0x6B, 0x66, 0x5E, 0x59, 0x55, 0x53, 0x52, 0x56, 0x59, 0x5C, 0x61, +0x5F, 0x64, 0x65, 0x62, 0x6F, 0x7B, 0xFC, 0xE4, 0xDC, 0xD9, 0xE2, 0x7E, 0xFF, 0xFE, 0xFF, 0xEE, +0xDF, 0xD8, 0xD6, 0xD7, 0xDB, 0xDD, 0xDD, 0xE8, 0xE7, 0xE3, 0xEA, 0xE7, 0xF9, 0x72, 0x7C, 0x5F, +0x56, 0x58, 0x58, 0x56, 0x57, 0x57, 0x53, 0x54, 0x4A, 0x42, 0x4F, 0x67, 0x6A, 0xE0, 0xD4, 0xD8, +0xD7, 0xDD, 0xFD, 0xFE, 0xE4, 0x7B, 0xFF, 0xD9, 0xDF, 0xDE, 0xD7, 0xDA, 0xCF, 0xCF, 0xD3, 0xCD, +0xD3, 0xDF, 0xDD, 0xDE, 0xF3, 0x6D, 0x5F, 0x55, 0x54, 0x55, 0x51, 0x51, 0x50, 0x4F, 0x51, 0x53, +0x57, 0x59, 0x60, 0x73, 0xFB, 0xE7, 0xE1, 0xEA, 0xF4, 0x7D, 0x6D, 0x6F, 0x7F, 0x78, 0xF5, 0xE7, +0xEA, 0xE0, 0xDE, 0xD9, 0xCD, 0xCB, 0xC5, 0xC2, 0xC5, 0xCB, 0xDB, 0xDD, 0xEC, 0x53, 0x4C, 0x45, +0x42, 0x49, 0x48, 0x49, 0x4D, 0x51, 0x5A, 0x55, 0x55, 0x5D, 0x64, 0xF4, 0xED, 0xF5, 0xEB, 0xF2, +0x7A, 0x6D, 0x60, 0x5E, 0x6E, 0xF3, 0xF7, 0xE9, 0xDF, 0xDD, 0xD4, 0xCD, 0xC8, 0xC1, 0xBC, 0xB8, +0xB5, 0xB8, 0xC7, 0xF5, 0x52, 0x3E, 0x38, 0x37, 0x36, 0x3D, 0x4B, 0x59, 0xFD, 0xDF, 0xE3, 0xFE, +0x5C, 0x54, 0x52, 0x4E, 0x50, 0x55, 0x5D, 0xFF, 0xF2, 0xF1, 0xE9, 0xFB, 0xFD, 0x74, 0x5E, 0x62, +0x7A, 0xE3, 0xD2, 0xCA, 0xC0, 0xB9, 0xB1, 0xAD, 0xAE, 0xBC, 0x68, 0x3E, 0x31, 0x2D, 0x2E, 0x30, +0x3B, 0x5B, 0xD4, 0xC7, 0xC9, 0xD6, 0x65, 0x4A, 0x46, 0x3E, 0x3D, 0x47, 0x51, 0x7F, 0xD5, 0xD0, +0xCE, 0xD2, 0xE2, 0x6E, 0x57, 0x55, 0x61, 0xEA, 0xCD, 0xBE, 0xB7, 0xB2, 0xAD, 0xAB, 0xB0, 0xCE, +0x40, 0x2F, 0x2B, 0x2D, 0x2F, 0x38, 0x59, 0xCA, 0xBD, 0xBE, 0xCF, 0x70, 0x45, 0x39, 0x3A, 0x3B, +0x3F, 0x5D, 0xD9, 0xCB, 0xC4, 0xC5, 0xCF, 0xEA, 0x62, 0x52, 0x50, 0x5C, 0x7E, 0xD1, 0xBE, 0xB5, +0xAF, 0xAE, 0xAB, 0xAC, 0xC2, 0x44, 0x2F, 0x2A, 0x2D, 0x32, 0x38, 0x55, 0xC6, 0xBA, 0xBC, 0xCF, +0x5B, 0x40, 0x36, 0x34, 0x38, 0x40, 0x66, 0xCD, 0xC4, 0xC2, 0xC6, 0xD1, 0xFE, 0x52, 0x4C, 0x4F, +0x5C, 0xEF, 0xCF, 0xC1, 0xB7, 0xAF, 0xAD, 0xAB, 0xAD, 0xC9, 0x3C, 0x2D, 0x29, 0x2D, 0x35, 0x3D, +0xF1, 0xBD, 0xB8, 0xBF, 0xE1, 0x4C, 0x3C, 0x32, 0x31, 0x39, 0x47, 0xF7, 0xCB, 0xC4, 0xC2, 0xC7, +0xD9, 0x6F, 0x54, 0x4D, 0x4F, 0x5D, 0xEF, 0xCF, 0xC1, 0xB8, 0xAF, 0xAD, 0xAB, 0xAC, 0xC9, 0x3A, +0x2C, 0x29, 0x2D, 0x37, 0x44, 0xD8, 0xB9, 0xB7, 0xC4, 0x6C, 0x44, 0x38, 0x31, 0x30, 0x39, 0x4E, +0xDF, 0xCA, 0xC5, 0xC6, 0xCD, 0xEF, 0x5E, 0x5A, 0x53, 0x55, 0x64, 0xE8, 0xCD, 0xC4, 0xBB, 0xB0, +0xAC, 0xAA, 0xAC, 0xD0, 0x36, 0x2C, 0x2B, 0x2E, 0x39, 0x4A, 0xCB, 0xB6, 0xB7, 0xC8, 0x5D, 0x43, +0x39, 0x31, 0x32, 0x3D, 0x58, 0xD9, 0xCD, 0xCA, 0xC9, 0xD6, 0x73, 0x62, 0x63, 0x62, 0x68, 0x72, +0xE9, 0xCE, 0xC6, 0xBB, 0xAF, 0xAD, 0xAB, 0xAE, 0xD7, 0x38, 0x2D, 0x2C, 0x2F, 0x3B, 0x4F, 0xCA, +0xB6, 0xB8, 0xCB, 0x5D, 0x41, 0x39, 0x32, 0x33, 0x3E, 0x59, 0xDC, 0xCF, 0xCD, 0xCB, 0xD8, 0x63, +0x53, 0x5A, 0x5E, 0x61, 0x6F, 0xEA, 0xCF, 0xC6, 0xBC, 0xB0, 0xAD, 0xAB, 0xAE, 0xEE, 0x32, 0x2C, +0x2C, 0x30, 0x3B, 0x50, 0xC9, 0xB6, 0xB9, 0xCF, 0x5D, 0x47, 0x3A, 0x32, 0x33, 0x3F, 0x63, 0xDB, +0xD5, 0xCC, 0xC8, 0xD7, 0x66, 0x56, 0x58, 0x5C, 0x5A, 0x5B, 0x7E, 0xCE, 0xC4, 0xBB, 0xB0, 0xAD, +0xAB, 0xAF, 0x7B, 0x2F, 0x2C, 0x2E, 0x31, 0x39, 0x52, 0xC6, 0xB6, 0xBA, 0xD1, 0x5C, 0x4E, 0x3E, +0x32, 0x33, 0x3F, 0x64, 0xEA, 0xFD, 0xCE, 0xC2, 0xD0, 0x6C, 0x57, 0x5D, 0x64, 0x56, 0x53, 0x6C, +0xCE, 0xC4, 0xBD, 0xB1, 0xAD, 0xAA, 0xAE, 0x6F, 0x31, 0x2F, 0x31, 0x31, 0x37, 0x4F, 0xC5, 0xB6, +0xBA, 0xD2, 0xFC, 0x60, 0x45, 0x36, 0x35, 0x41, 0x56, 0xF8, 0xF2, 0xE4, 0xC6, 0xC8, 0x7C, 0x5A, +0x6A, 0x6A, 0x57, 0x52, 0x5B, 0xDA, 0xC6, 0xC0, 0xB6, 0xAE, 0xAA, 0xAC, 0xDD, 0x33, 0x30, 0x35, +0x31, 0x30, 0x42, 0xCE, 0xBA, 0xBA, 0xCC, 0xD9, 0xD9, 0x53, 0x3A, 0x35, 0x3E, 0x4D, 0x52, 0x60, +0xD6, 0xC5, 0xD2, 0x71, 0xE7, 0x7C, 0x55, 0x53, 0x51, 0x5B, 0xEE, 0xDC, 0xD3, 0xBE, 0xB2, 0xB0, +0xAD, 0xAE, 0x67, 0x31, 0x38, 0x39, 0x2F, 0x32, 0x49, 0xD5, 0xBE, 0xBF, 0xCF, 0xCD, 0xCA, 0x5C, +0x3D, 0x3C, 0x41, 0x41, 0x47, 0x5D, 0xE1, 0xC9, 0xC7, 0xD4, 0xDD, 0xFC, 0x51, 0x4C, 0x4C, 0x4C, +0x5F, 0xE2, 0xDC, 0xCA, 0xBF, 0xBD, 0xB9, 0xB5, 0xAF, 0xBA, 0x43, 0x35, 0x44, 0x3E, 0x2F, 0x36, +0x53, 0xD4, 0xC8, 0xCC, 0xD1, 0xC3, 0xC5, 0x5E, 0x41, 0x45, 0x49, 0x42, 0x44, 0x55, 0xE9, 0xD0, +0xD1, 0xDA, 0xD6, 0xD7, 0xFD, 0x5A, 0x58, 0x5B, 0x5A, 0x5B, 0x5F, 0x6C, 0x7A, 0xE1, 0xD3, 0xD2, +0xCC, 0xC8, 0xC4, 0xBF, 0xBD, 0xBA, 0xC2, 0x49, 0x3C, 0x4C, 0x41, 0x35, 0x3B, 0x52, 0xF3, 0xD6, +0xD1, 0xCE, 0xC3, 0xC6, 0x7A, 0x53, 0x57, 0x4E, 0x44, 0x46, 0x4F, 0x64, 0xE8, 0xDF, 0xDD, 0xD4, +0xD6, 0xEC, 0x56, 0x49, 0x54, 0x5E, 0x4F, 0x57, 0xFA, 0xE1, 0xDC, 0xE0, 0xE3, 0xD6, 0xD0, 0xDC, +0xD9, 0xC9, 0xC2, 0xBD, 0xC5, 0x58, 0x50, 0xE6, 0x4B, 0x37, 0x3F, 0x4F, 0x4D, 0x52, 0x6D, 0xDD, +0xC8, 0xC8, 0xDC, 0xDC, 0xD1, 0x72, 0x4A, 0x4A, 0x4E, 0x4B, 0x4E, 0x57, 0x6A, 0xDF, 0xD7, 0xDB, +0xD5, 0xCF, 0xDA, 0xF4, 0x74, 0x67, 0x5E, 0x5E, 0x5E, 0x66, 0xF9, 0xED, 0xEC, 0xE8, 0xE4, 0xE8, +0xF4, 0xF7, 0x60, 0x52, 0x6D, 0xF3, 0x5B, 0x66, 0xE7, 0xE1, 0xE0, 0xDF, 0xDF, 0xD8, 0xD1, 0xEA, +0x6B, 0xD9, 0xD1, 0xE5, 0xE6, 0xCC, 0xC4, 0xE7, 0x52, 0xEA, 0xE4, 0x4C, 0x48, 0x59, 0x5D, 0x59, +0x5D, 0x60, 0xF7, 0xDF, 0x79, 0x6A, 0xDF, 0xDC, 0xFE, 0xF8, 0xE2, 0xF0, 0x6F, 0x6B, 0x61, 0x5F, +0x62, 0x5D, 0x5E, 0x6C, 0x76, 0x70, 0xF7, 0xE5, 0xE6, 0xE7, 0xE5, 0xEA, 0xF4, 0x7D, 0x6C, 0x66, +0x68, 0x66, 0x66, 0x73, 0xF8, 0xF3, 0xF4, 0xF6, 0xFB, 0x7E, 0x7A, 0x7E, 0xF6, 0xEF, 0xED, 0xE9, +0xE9, 0xEF, 0xFB, 0x78, 0x6E, 0x69, 0x64, 0x63, 0x68, 0x6E, 0x74, 0x7B, 0xFA, 0xF6, 0xF3, 0xFF, +0x6B, 0x69, 0x69, 0x60, 0x5F, 0x65, 0x6C, 0x73, 0x7C, 0xF3, 0xEB, 0xE9, 0xEA, 0xE8, 0xE6, 0xE6, +0xE7, 0xE4, 0xDE, 0xDD, 0xE2, 0xE2, 0xE1, 0xE9, 0xF8, 0x77, 0x6B, 0x62, 0x5D, 0x5B, 0x5A, 0x59, +0x5A, 0x5B, 0x5D, 0x5E, 0x5E, 0x5E, 0x5F, 0x62, 0x67, 0x6D, 0x78, 0xFA, 0xF2, 0xEE, 0xEF, 0xF3, +0xF7, 0xF8, 0xFA, 0xFE, 0xFA, 0xF3, 0xF1, 0xEF, 0xEA, 0xE7, 0xE5, 0xE6, 0xE9, 0xEF, 0xFB, 0x79, +0x70, 0x6C, 0x6A, 0x6C, 0x6F, 0x77, 0x7C, 0xFD, 0xFB, 0x7F, 0x73, 0x6C, 0x69, 0x69, 0x6C, 0x73, +0xFA, 0xED, 0xE9, 0xE5, 0xE1, 0xE4, 0xE8, 0xE8, 0xE7, 0xE7, 0xE5, 0xE2, 0xE0, 0xDD, 0xDC, 0xE1, +0xE3, 0xE2, 0xEC, 0x7C, 0x6C, 0x63, 0x5D, 0x5B, 0x59, 0x58, 0x5A, 0x5B, 0x5B, 0x5C, 0x5F, 0x60, +0x5F, 0x60, 0x65, 0x6A, 0x75, 0xF8, 0xEC, 0xE7, 0xE6, 0xE7, 0xEA, 0xF0, 0xF8, 0xF9, 0xF4, 0xED, +0xE9, 0xE5, 0xE3, 0xE3, 0xE6, 0xEB, 0xF6, 0x76, 0x6C, 0x67, 0x62, 0x5F, 0x61, 0x64, 0x69, 0x6F, +0x73, 0x73, 0x75, 0x75, 0x70, 0x6E, 0x6F, 0x6E, 0x6E, 0x75, 0xFE, 0xF3, 0xEC, 0xE9, 0xE9, 0xE9, +0xED, 0xFA, 0x7A, 0x74, 0x71, 0x72, 0x73, 0x74, 0x7A, 0xFF, 0xFF, 0x7B, 0x72, 0x6E, 0x6D, 0x6C, +0x6C, 0x6E, 0x73, 0x7C, 0xFC, 0xF7, 0xF0, 0xEB, 0xE6, 0xE0, 0xDD, 0xDB, 0xDB, 0xDB, 0xDC, 0xDF, +0xE2, 0xE3, 0xE8, 0xF2, 0x7D, 0x6C, 0x61, 0x5D, 0x5A, 0x58, 0x59, 0x5C, 0x5E, 0x61, 0x66, 0x69, +0x6A, 0x6B, 0x6C, 0x6B, 0x6C, 0x75, 0xFE, 0xF7, 0xEE, 0xEA, 0xE8, 0xE6, 0xE9, 0xEC, 0xEB, 0xEB, +0xEE, 0xF0, 0xF2, 0xF6, 0xF9, 0xFD, 0x7F, 0xFF, 0x7C, 0x74, 0x6D, 0x69, 0x66, 0x64, 0x64, 0x68, +0x6B, 0x6D, 0x75, 0x7D, 0xFC, 0xF8, 0xFA, 0xFC, 0xFA, 0xF7, 0xF5, 0xF0, 0xEB, 0xE6, 0xE4, 0xE5, +0xE9, 0xED, 0xF2, 0xFC, 0x7A, 0x74, 0x6E, 0x6C, 0x6A, 0x69, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6E, +0x6D, 0x6E, 0x70, 0x71, 0x74, 0x79, 0x7B, 0x7E, 0xFB, 0xF6, 0xF8, 0xF9, 0xF6, 0xF5, 0xF8, 0xFA, +0xF7, 0xF0, 0xEE, 0xF0, 0xF7, 0xFC, 0x7D, 0x73, 0x6C, 0x6B, 0x6B, 0x6A, 0x6B, 0x6B, 0x6B, 0x6B, +0x6C, 0x6D, 0x6D, 0x6E, 0x71, 0x71, 0x71, 0x72, 0x77, 0x7D, 0xFC, 0xF7, 0xF3, 0xED, 0xEB, 0xEB, +0xEE, 0xF4, 0xF9, 0xFE, 0x79, 0x77, 0x7B, 0x7F, 0x7F, 0xFF, 0xFF, 0x7B, 0x77, 0x76, 0x77, 0x79, +0x79, 0x7A, 0x7C, 0xFF, 0xFC, 0xFC, 0xFA, 0xF8, 0xF9, 0xF9, 0xFA, 0xFD, 0xFE, 0xFD, 0xFA, 0xF8, +0xF5, 0xF2, 0xF1, 0xF2, 0xF4, 0xF8, 0xFE, 0x7C, 0x79, 0x77, 0x77, 0x7A, 0x7E, 0x7F, 0x7C, 0x79, +0x78, 0x75, 0x73, 0x72, 0x71, 0x73, 0x75, 0x76, 0x78, 0x7D, 0xFD, 0xFB, 0xFC, 0xFF, 0x7D, 0x79, +0x76, 0x76, 0x77, 0x7C, 0xFB, 0xF5, 0xF3, 0xF3, 0xF3, 0xF7, 0x7D, 0x74, 0x6F, 0x6D, 0x6B, 0x6C, +0x6E, 0x73, 0x77, 0x77, 0x77, 0x7A, 0x7A, 0x76, 0x73, 0x72, 0x6F, 0x6D, 0x6B, 0x6C, 0x6F, 0x76, +0x7A, 0x7D, 0xFE, 0xFC, 0x7E, 0x7A, 0x75, 0x71, 0x6E, 0x6D, 0x6E, 0x71, 0x77, 0x7D, 0xFE, 0xFC, +0xFC, 0xFE, 0xFF, 0x7D, 0x7B, 0x7C, 0x7E, 0xFF, 0xFF, 0xFC, 0xF9, 0xF7, 0xF6, 0xF8, 0xFA, 0xFC, +0xFF, 0x7E, 0x7F, 0xFF, 0xFD, 0xFB, 0xF7, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFD, 0x7D, 0x7A, 0x7A, +0x7D, 0x7E, 0x7F, 0xFF, 0xFE, 0xFE, 0x7E, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0xFF, 0xFD, 0xFD, 0xFD, +0xFB, 0xF8, 0xF7, 0xF9, 0xFD, 0x7C, 0x79, 0x78, 0x78, 0x77, 0x77, 0x76, 0x75, 0x75, 0x75, 0x75, +0x75, 0x74, 0x76, 0x78, 0x79, 0x7B, 0x7D, 0x7F, 0xFD, 0xFB, 0xFF, 0x7A, 0x79, 0x7D, 0xFE, 0xFD, +0xFD, 0xFC, 0xFD, 0xFA, 0xF5, 0xF2, 0xF3, 0xF6, 0xF8, 0xF9, 0xFC, 0xFF, 0xFD, 0xF8, 0xF5, 0xF5, +0xF6, 0xFA, 0xFC, 0xFD, 0x7F, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x77, 0x7B, 0x7E, 0x7E, 0x7E, 0x7F, +0x7E, 0x7C, 0x79, 0x76, 0x76, 0x78, 0x79, 0x78, 0x7B, 0x7E, 0xFF, 0x7F, 0x7C, 0x7A, 0x78, 0x75, +0x73, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7B, 0x7B, 0x79, 0x79, 0x78, 0x77, 0x78, 0x74, 0x71, 0x72, +0x73, 0x76, 0x77, 0x77, 0x79, 0x79, 0x77, 0x76, 0x75, 0x76, 0x78, 0x7B, 0x7F, 0xFC, 0xFB, 0xFB, +0xFA, 0xFB, 0xFE, 0x7C, 0x79, 0x79, 0x78, 0x78, 0x7B, 0xFF, 0xFD, 0xFD, 0xFC, 0xFC, 0xFE, 0x7E, +0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x78, 0x79, 0x7A, 0x7C, 0x7C, 0x7C, 0x7B, 0x77, 0x78, 0x7A, +0x7A, 0x7A, 0x7C, 0x7E, 0xFF, 0x7F, 0x7F, 0xFF, 0xFF, 0x7F, 0x7E, 0x7F, 0x7E, 0x7C, 0x7A, 0x7A, +0x79, 0x79, 0x7B, 0x7E, 0x7E, 0x7F, 0xFD, 0xFC, 0xFD, 0xFD, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, +0xFF, 0x7E, 0x7D, 0x7F, 0xFF, 0xFF, 0xFE, 0xFC, 0xFB, 0xFC, 0xFC, 0xFE, 0x7E, 0x7F, 0x7E, 0x7B, +0x7C, 0x7D, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x77, 0x7A, +0x7C, 0x7D, 0x7E, 0x7E, 0x7C, 0x79, 0x76, 0x77, 0x79, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0x7D, +0x7D, 0x7C, 0x7A, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x7C, 0x7E, 0x7D, 0x7E, 0x7E, 0x7C, 0x7B, 0x7C, +0x7C, 0x7C, 0x7D, 0xFF, 0xFC, 0xFB, 0xFB, 0xFC, 0xFF, 0x7C, 0x79, 0x77, 0x74, 0x75, 0x77, 0x7A, +0x7D, 0x7E, 0xFF, 0xFD, 0xFD, 0xFE, 0x7E, 0x7D, 0x7D, 0x7B, 0x7A, 0x7B, 0x7D, 0x7E, 0xFE, 0xFD, +0xFF, 0x7F, 0x7D, 0x7B, 0x7A, 0x78, 0x76, 0x76, 0x79, 0x7C, 0x7E, 0xFF, 0xFF, 0x7F, 0x7E, 0x7C, +0x7A, 0x79, 0x78, 0x78, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0x7F, 0x7E, 0x7D, 0x7B, 0x7A, +0x7B, 0x7C, 0x7D, 0xFE, 0xFC, 0xFA, 0xF9, 0xFA, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFA, 0xF8, 0xF7, +0xF6, 0xF7, 0xF9, 0xFB, 0xFE, 0x7E, 0x7C, 0x7A, 0x79, 0x79, 0x7B, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, +0x7E, 0x7C, 0x7B, 0x79, 0x7A, 0x7C, 0x7C, 0x7E, 0x7E, 0x7F, 0xFF, 0x7F, 0x7E, 0x7C, 0x7B, 0x79, +0x77, 0x76, 0x76, 0x78, 0x7B, 0x7B, 0x7B, 0x7A, 0x7A, 0x7A, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7B, +0x7D, 0x79, 0x79, 0x7E, 0x79, 0x78, 0x79, 0x78, 0x7A, 0x78, 0x7D, 0x7D, 0x7C, 0xFF, 0x7D, 0x7F, +0x7E, 0x7B, 0x7A, 0x76, 0x79, 0x76, 0x78, 0x7B, 0x79, 0xFF, 0x7D, 0xFB, 0xFD, 0x7D, 0xF9, 0x7B, +0xFF, 0x79, 0x75, 0xFF, 0x6E, 0x7F, 0x71, 0x73, 0x79, 0x51, 0x60, 0xE2, 0x6F, 0x7D, 0xF7, 0xF5, +0x77, 0x72, 0xE4, 0x50, 0x4C, 0xDE, 0xFB, 0x66, 0xE5, 0xF6, 0x6F, 0x6C, 0xE7, 0xDC, 0x6E, 0xFD, +0xE6, 0x7E, 0xE9, 0x77, 0x62, 0xE3, 0xE9, 0x6C, 0x71, 0xEA, 0xDE, 0x75, 0x7E, 0xE8, 0x75, 0xF8, +0x7A, 0xFC, 0xF2, 0x65, 0xF8, 0xEE, 0xF9, 0xF4, 0x73, 0xE4, 0xF9, 0x6E, 0xE5, 0x75, 0x67, 0x5A, +0x50, 0x57, 0x5A, 0x7D, 0x6C, 0x64, 0xDA, 0xED, 0x64, 0xEA, 0xE9, 0xF5, 0x7E, 0x6F, 0xFC, 0xF2, +0x66, 0x63, 0xF7, 0x7D, 0x78, 0xF6, 0xF8, 0xE1, 0xE2, 0xF9, 0xEB, 0xE4, 0xED, 0xFE, 0xFA, 0xF6, +0xF1, 0xF2, 0x6F, 0xFE, 0xE8, 0xFF, 0x7F, 0xEA, 0xE8, 0xED, 0xEE, 0xEA, 0xEB, 0xED, 0xF8, 0xEF, +0xE8, 0x7F, 0xF5, 0xE6, 0xF7, 0xF2, 0xF3, 0xF2, 0xDF, 0xEB, 0xF5, 0xE3, 0xEC, 0xF2, 0xEF, 0xFC, +0xED, 0xEF, 0xFD, 0xED, 0xF0, 0x7C, 0x77, 0xFE, 0xF1, 0x77, 0x79, 0xEF, 0xF6, 0xF8, 0xFB, 0x72, +0x75, 0x79, 0x78, 0x70, 0x6E, 0x7C, 0x7D, 0x74, 0x79, 0x77, 0x6E, 0x71, 0x7D, 0x6F, 0x6B, 0x7D, +0xFE, 0x76, 0x7A, 0x7D, 0x7F, 0x75, 0x6C, 0x7B, 0xF7, 0x7A, 0x7B, 0x7E, 0x74, 0x79, 0x75, 0x70, +0x7C, 0x79, 0xFD, 0xF6, 0x6E, 0x6E, 0x7B, 0x6B, 0x67, 0x6D, 0x6E, 0x6A, 0x67, 0x6A, 0x6D, 0x6F, +0x6B, 0x67, 0x6D, 0x6C, 0x65, 0x63, 0x5E, 0x65, 0x6A, 0x5F, 0x68, 0x6C, 0x60, 0x6C, 0x7D, 0x6D, +0x6E, 0x7D, 0x7C, 0xFF, 0xEE, 0xEB, 0xEC, 0xE3, 0xDE, 0xE1, 0xE4, 0xE0, 0xE8, 0xF8, 0xEE, 0xFA, +0x6D, 0x69, 0x5C, 0x58, 0x59, 0x53, 0x50, 0x4E, 0x4D, 0x4E, 0x4F, 0x4F, 0x53, 0x51, 0x51, 0x54, +0x55, 0x56, 0x5A, 0x5E, 0x69, 0xF7, 0xE2, 0xD8, 0xCF, 0xCE, 0xCD, 0xCC, 0xCE, 0xCE, 0xCA, 0xC7, +0xC2, 0xBF, 0xBE, 0xBD, 0xC2, 0xD5, 0xF1, 0x62, 0x4B, 0x3F, 0x3D, 0x3D, 0x3E, 0x40, 0x42, 0x4A, +0x51, 0x51, 0x51, 0x55, 0x56, 0x4F, 0x4D, 0x4E, 0x50, 0x52, 0x55, 0x5C, 0x69, 0xFA, 0xE4, 0xD9, +0xCD, 0xC9, 0xC5, 0xC1, 0xBF, 0xBB, 0xBB, 0xBD, 0xB9, 0xB7, 0xB5, 0xB7, 0xC8, 0xDD, 0x61, 0x43, +0x3C, 0x38, 0x38, 0x3D, 0x40, 0x46, 0x4E, 0x5A, 0x60, 0x5D, 0x5B, 0x5B, 0x5A, 0x58, 0x56, 0x58, +0x5C, 0x5E, 0x5E, 0x64, 0x6B, 0x6D, 0xF9, 0xED, 0xE5, 0xDC, 0xD9, 0xD2, 0xCC, 0xC5, 0xBF, 0xBF, +0xBA, 0xB7, 0xB6, 0xB1, 0xB7, 0xCB, 0xFA, 0x49, 0x3A, 0x35, 0x31, 0x33, 0x3A, 0x42, 0x4C, 0x5C, +0xFD, 0xE1, 0xEE, 0x68, 0x66, 0x5C, 0x51, 0x4F, 0x4D, 0x55, 0x5F, 0x5D, 0x64, 0x71, 0xFA, 0xED, +0xEF, 0xEB, 0xDE, 0xD3, 0xCC, 0xC3, 0xBE, 0xBD, 0xB9, 0xB8, 0xB5, 0xAF, 0xB7, 0xCC, 0x60, 0x3F, +0x39, 0x34, 0x2F, 0x31, 0x3A, 0x47, 0x56, 0x6F, 0xE3, 0xDA, 0xD5, 0xEC, 0x56, 0x50, 0x4E, 0x4B, +0x4B, 0x4C, 0x57, 0x7B, 0xE7, 0xE0, 0xDC, 0xD5, 0xD6, 0xDE, 0xEC, 0xEF, 0xDE, 0xD7, 0xCC, 0xC1, +0xBD, 0xB8, 0xB5, 0xB4, 0xB0, 0xB6, 0xCB, 0x58, 0x3E, 0x38, 0x34, 0x2F, 0x2F, 0x38, 0x45, 0x59, +0x7D, 0xDD, 0xD1, 0xCE, 0xDD, 0x63, 0x53, 0x4E, 0x4C, 0x4A, 0x4B, 0x53, 0x69, 0xE7, 0xDB, 0xD5, +0xD0, 0xCE, 0xD3, 0xDC, 0xE4, 0xEA, 0xE8, 0xE2, 0xD5, 0xC8, 0xC0, 0xBB, 0xB8, 0xB5, 0xB2, 0xB9, +0xD1, 0x54, 0x40, 0x3A, 0x34, 0x2F, 0x2F, 0x36, 0x3F, 0x4C, 0x5B, 0x7E, 0xDE, 0xD4, 0xDB, 0xFF, +0x62, 0x58, 0x55, 0x53, 0x4F, 0x52, 0x5D, 0x6F, 0xF0, 0xE4, 0xDE, 0xDA, 0xD8, 0xDC, 0xE1, 0xE5, +0xDF, 0xDC, 0xD6, 0xCC, 0xC6, 0xC1, 0xBE, 0xBB, 0xB8, 0xBC, 0xCE, 0x67, 0x4B, 0x44, 0x3E, 0x38, +0x35, 0x37, 0x3D, 0x45, 0x4B, 0x53, 0x61, 0xFA, 0xE4, 0xEC, 0x7F, 0x79, 0x78, 0x79, 0x70, 0x68, +0x68, 0x70, 0x7B, 0x7D, 0x7D, 0xF9, 0xEE, 0xEA, 0xE8, 0xE6, 0xE1, 0xDB, 0xD6, 0xCF, 0xCB, 0xC8, +0xC5, 0xC1, 0xBE, 0xBF, 0xC7, 0xD5, 0xF9, 0x5F, 0x55, 0x4A, 0x42, 0x3E, 0x3E, 0x41, 0x45, 0x48, +0x4C, 0x56, 0x5F, 0x6F, 0xF8, 0xEF, 0xE7, 0xE4, 0xE6, 0xE2, 0xEA, 0xF5, 0xFD, 0x75, 0x75, 0x79, +0x75, 0x76, 0x7E, 0xFA, 0xF1, 0xE9, 0xE0, 0xDA, 0xD3, 0xCF, 0xCC, 0xCA, 0xC7, 0xC4, 0xC5, 0xCC, +0xD3, 0xDF, 0xFF, 0x69, 0x58, 0x4C, 0x47, 0x43, 0x42, 0x42, 0x43, 0x46, 0x4C, 0x55, 0x59, 0x62, +0x77, 0xFD, 0xEE, 0xEC, 0xF3, 0xEC, 0xF2, 0x76, 0x76, 0x6F, 0x6E, 0x79, 0x79, 0x7F, 0xF3, 0xED, +0xE4, 0xDD, 0xDB, 0xD7, 0xD3, 0xD0, 0xCE, 0xCC, 0xCB, 0xCA, 0xCC, 0xD1, 0xD6, 0xDD, 0xEA, 0x7E, +0x62, 0x56, 0x4F, 0x4C, 0x49, 0x48, 0x49, 0x4C, 0x50, 0x56, 0x58, 0x5C, 0x67, 0x6F, 0x6C, 0x6E, +0x6D, 0x6A, 0x6F, 0x6D, 0x6B, 0x6E, 0x6D, 0x76, 0xFA, 0xF9, 0xF1, 0xEB, 0xE7, 0xE1, 0xDE, 0xDD, +0xDB, 0xD8, 0xD7, 0xD4, 0xD2, 0xD0, 0xCF, 0xD4, 0xD8, 0xDA, 0xDF, 0xEA, 0xF8, 0x6D, 0x60, 0x5C, +0x58, 0x56, 0x56, 0x56, 0x57, 0x59, 0x5B, 0x5B, 0x5A, 0x5C, 0x5F, 0x5F, 0x5F, 0x63, 0x66, 0x6B, +0x72, 0x77, 0x7E, 0xF7, 0xF0, 0xEC, 0xE9, 0xE9, 0xE8, 0xE8, 0xE8, 0xE8, 0xEA, 0xE7, 0xE6, 0xE5, +0xE3, 0xE1, 0xDD, 0xDA, 0xD9, 0xD8, 0xDD, 0xDF, 0xDD, 0xE0, 0xE7, 0xEE, 0xFE, 0x74, 0x6C, 0x62, +0x5C, 0x59, 0x56, 0x54, 0x52, 0x51, 0x51, 0x52, 0x55, 0x58, 0x59, 0x5D, 0x62, 0x68, 0x70, 0x75, +0x7D, 0xF9, 0xF8, 0xF4, 0xF5, 0xF9, 0xF5, 0xF3, 0xF3, 0xF2, 0xF2, 0xEF, 0xED, 0xEB, 0xEA, 0xE6, +0xE3, 0xE0, 0xDC, 0xDA, 0xD7, 0xD8, 0xDB, 0xDB, 0xDA, 0xDC, 0xDF, 0xE8, 0xF6, 0x7F, 0x6E, 0x60, +0x5B, 0x58, 0x56, 0x54, 0x53, 0x52, 0x53, 0x59, 0x5C, 0x5E, 0x63, 0x68, 0x6F, 0x7B, 0x7C, 0xFF, +0xFC, 0xFC, 0xFB, 0xFC, 0xFD, 0xF8, 0xF7, 0xF6, 0xF4, 0xF5, 0xF3, 0xF0, 0xEF, 0xED, 0xEB, 0xE8, +0xE4, 0xE0, 0xDD, 0xDA, 0xD9, 0xDA, 0xDC, 0xDC, 0xDC, 0xE0, 0xE9, 0xF8, 0x76, 0x6B, 0x61, 0x5C, +0x5A, 0x5A, 0x5A, 0x5B, 0x5C, 0x5E, 0x62, 0x67, 0x6B, 0x6D, 0x6F, 0x72, 0x75, 0x76, 0x76, 0x75, +0x74, 0x79, 0x7E, 0x7B, 0x78, 0x7D, 0xFB, 0xFB, 0xFD, 0xFA, 0xF6, 0xF5, 0xF2, 0xEF, 0xEC, 0xE9, +0xE4, 0xDF, 0xDE, 0xDE, 0xE0, 0xE7, 0xEA, 0xEC, 0xF2, 0xFE, 0x76, 0x6F, 0x6F, 0x6D, 0x6A, 0x6A, +0x6B, 0x6C, 0x6C, 0x69, 0x67, 0x67, 0x66, 0x65, 0x64, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6B, 0x6E, +0x71, 0x76, 0x7A, 0x7D, 0xFE, 0xFC, 0xFA, 0xF8, 0xF4, 0xF0, 0xEE, 0xEC, 0xEA, 0xE9, 0xE8, 0xE9, +0xEB, 0xEB, 0xEC, 0xED, 0xEE, 0xED, 0xEB, 0xE9, 0xEA, 0xE9, 0xE9, 0xEA, 0xEC, 0xF0, 0xF6, 0xFD, +0x78, 0x71, 0x6D, 0x69, 0x67, 0x66, 0x65, 0x65, 0x66, 0x67, 0x66, 0x66, 0x67, 0x67, 0x66, 0x66, +0x69, 0x6B, 0x6D, 0x73, 0x7A, 0xFE, 0xF7, 0xF3, 0xEF, 0xEE, 0xEE, 0xEC, 0xEB, 0xEA, 0xE8, 0xE7, +0xE5, 0xE3, 0xE1, 0xE1, 0xE1, 0xE3, 0xE6, 0xE8, 0xEB, 0xEF, 0xF8, 0x7E, 0x75, 0x6F, 0x6B, 0x69, +0x67, 0x66, 0x65, 0x65, 0x66, 0x67, 0x67, 0x68, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, +0x70, 0x6F, 0x6F, 0x6F, 0x72, 0x75, 0x79, 0xFF, 0xFB, 0xF6, 0xF2, 0xEF, 0xEE, 0xED, 0xEE, 0xF0, +0xF3, 0xF6, 0xF8, 0xFC, 0xFF, 0x7D, 0x79, 0x76, 0x72, 0x6E, 0x6D, 0x6B, 0x6B, 0x6C, 0x6C, 0x6D, +0x6E, 0x71, 0x76, 0x7B, 0xFF, 0xFE, 0xFD, 0xFC, 0xFD, 0x7F, 0x7B, 0x78, 0x75, 0x74, 0x75, 0x77, +0x7A, 0x7E, 0xFC, 0xF9, 0xF6, 0xF5, 0xF4, 0xF4, 0xF5, 0xF7, 0xF8, 0xF8, 0xF7, 0xF6, 0xF5, 0xF5, +0xF6, 0xF8, 0xFA, 0xFC, 0x7F, 0x7B, 0x79, 0x78, 0x77, 0x77, 0x79, 0x7D, 0xFD, 0xF9, 0xF4, 0xF2, +0xF1, 0xF1, 0xF3, 0xF5, 0xFA, 0xFE, 0x7F, 0xFF, 0xFD, 0xFC, 0xFB, 0xF7, 0xF5, 0xF4, 0xF4, 0xF6, +0xF8, 0xFB, 0xFD, 0xFF, 0x7E, 0x7E, 0x7E, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7E, 0x7B, 0x79, 0x77, +0x76, 0x75, 0x74, 0x74, 0x75, 0x78, 0x7C, 0x7F, 0xFE, 0xFD, 0xFE, 0xFF, 0x7E, 0x7C, 0x7B, 0x79, +0x79, 0x7A, 0x7D, 0xFE, 0xFC, 0xFA, 0xF8, 0xF8, 0xF9, 0xFB, 0xFD, 0x7F, 0x7B, 0x78, 0x76, 0x75, +0x74, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x7A, 0x7C, +0x7E, 0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7C, 0x7A, 0x78, 0x77, 0x77, 0x76, 0x79, 0x7B, 0x7E, 0xFF, +0xFE, 0xFD, 0xFD, 0xFF, 0x7E, 0x7C, 0x7C, 0x7B, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x74, 0x74, +0x74, 0x74, 0x75, 0x76, 0x79, 0x7C, 0x7E, 0xFF, 0xFC, 0xF8, 0xF7, 0xF6, 0xF7, 0xF7, 0xF7, 0xF9, +0xFC, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7F, 0xFF, 0xFC, 0xFB, 0xFA, 0xF8, 0xF8, 0xF8, 0xF6, 0xF5, +0xF5, 0xF4, 0xF4, 0xF5, 0xF7, 0xF8, 0xFA, 0xFD, 0x7F, 0x7E, 0x7D, 0x7C, 0x7C, 0x7D, 0x7E, 0xFE, +0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF9, 0xF9, 0xFA, 0xFB, 0xFD, 0xFF, 0x7E, 0x7D, 0x79, 0x77, 0x75, +0x72, 0x71, 0x70, 0x70, 0x70, 0x71, 0x71, 0x70, 0x71, 0x72, 0x71, 0x72, 0x71, 0x72, 0x73, 0x72, +0x72, 0x71, 0x71, 0x71, 0x72, 0x74, 0x74, 0x76, 0x77, 0x77, 0x77, 0x78, 0x77, 0x78, 0x78, 0x78, +0x7A, 0x7C, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFD, 0xFF, 0x7E, 0x7D, 0x7B, 0x7C, 0x7B, +0x7B, 0x7B, 0x7B, 0x7B, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7B, 0x7C, 0x7E, 0xFF, 0xFD, +0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0xFF, 0x7F, 0x7D, 0x7C, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7D, +0x7F, 0x7F, 0xFF, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, +0xFF, 0xFF, 0xFF, 0xFD, 0xFA, 0xF9, 0xF7, 0xF5, 0xF4, 0xF3, 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, +0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xFA, 0xFC, 0xFE, 0xFE, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, +0x7F, 0x7D, 0x7C, 0x7D, 0x7B, 0x7A, 0x7D, 0x7B, 0x7B, 0x7C, 0x7B, 0x7B, 0x7B, 0x79, 0x78, 0x77, +0x77, 0x76, 0x75, 0x76, 0x75, 0x74, 0x74, 0x75, 0x74, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73, 0x74, +0x72, 0x70, 0x70, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x71, 0x72, 0x73, 0x73, 0x76, +0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7B, 0x7D, 0x7E, 0x7D, 0x7F, 0x7D, 0x7C, 0x7B, 0x7B, 0x7C, +0x7B, 0x7B, 0x7A, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0xFF, 0x7D, 0x7E, 0x7C, 0x7C, 0x7B, 0x78, +0x7C, 0x7A, 0x7C, 0x7D, 0x7B, 0x7E, 0x7C, 0x7F, 0x7D, 0x7A, 0x7E, 0x78, 0x7B, 0x6F, 0x68, 0x5C, +0x4C, 0x58, 0xDD, 0xE1, 0xEB, 0xE1, 0xE9, 0xEF, 0xF8, 0xE9, 0xE1, 0xED, 0xF9, 0xFC, 0xF2, 0xED, +0x7D, 0x76, 0xFB, 0xF9, 0x7C, 0x70, 0x6F, 0x78, 0x79, 0x6D, 0x6D, 0x76, 0x7D, 0xFE, 0x7A, 0x79, +0xFC, 0xFD, 0xFD, 0xFA, 0xFB, 0xFA, 0xFC, 0xFF, 0xFC, 0xFC, 0xFE, 0xFD, 0xFE, 0xFB, 0xFB, 0xFE, +0xFE, 0x7E, 0x7D, 0x7C, 0x7C, 0x7B, 0x78, 0x7D, 0x7D, 0xFF, 0xFA, 0xFF, 0xF9, 0xF9, 0xFA, 0xF7, +0x7F, 0xF9, 0x7A, 0x7A, 0x6F, 0x51, 0x52, 0x6E, 0x71, 0xF1, 0xD8, 0xD3, 0xDB, 0xEF, 0xE2, 0xDB, +0xED, 0xF6, 0xF3, 0xEF, 0xF4, 0x6A, 0x74, 0x73, 0x57, 0x5E, 0x77, 0x6E, 0xFD, 0xF4, 0xFC, 0x7D, +0x73, 0xE9, 0xDE, 0xE2, 0xDE, 0xE3, 0xE5, 0xE8, 0xFA, 0xF7, 0xFA, 0x6F, 0x6C, 0x6A, 0x6B, 0x6A, +0x66, 0x6B, 0x75, 0x70, 0x74, 0xFA, 0xFB, 0xFD, 0xF8, 0xF3, 0xF2, 0xFB, 0xF5, 0xED, 0xEF, 0xEB, +0xE5, 0xDF, 0xDA, 0xD7, 0xD5, 0xD3, 0xD3, 0xD4, 0xD8, 0xE0, 0xEE, 0x76, 0x5D, 0x53, 0x4D, 0x49, +0x46, 0x43, 0x42, 0x43, 0x43, 0x45, 0x48, 0x4B, 0x4F, 0x57, 0x60, 0x6D, 0xF7, 0xE3, 0xDB, 0xD4, +0xCF, 0xCB, 0xC8, 0xC4, 0xBE, 0xBC, 0xB9, 0xB4, 0xB6, 0xBC, 0xC1, 0xC3, 0xD5, 0x4F, 0x4B, 0x43, +0x36, 0x33, 0x34, 0x32, 0x31, 0x36, 0x3B, 0x3F, 0x48, 0x60, 0xDF, 0xD2, 0xC9, 0xC1, 0xC3, 0xC6, +0xC7, 0xCF, 0xE3, 0x67, 0x56, 0x47, 0x3E, 0x3F, 0x3C, 0x3B, 0x43, 0x48, 0x4F, 0xFA, 0xD5, 0xC5, +0xBD, 0xB7, 0xB1, 0xAE, 0xAC, 0xAE, 0xB1, 0xB5, 0xC0, 0xD7, 0x5D, 0x40, 0x38, 0x31, 0x2E, 0x2D, +0x2C, 0x2E, 0x32, 0x37, 0x3F, 0x4F, 0xF8, 0xD0, 0xC4, 0xBC, 0xBB, 0xBB, 0xBB, 0xBE, 0xC7, 0xD0, +0xF1, 0x56, 0x48, 0x40, 0x3D, 0x3B, 0x3D, 0x42, 0x49, 0x63, 0xDA, 0xCB, 0xBC, 0xB6, 0xB0, 0xAE, +0xAF, 0xAF, 0xB4, 0xBC, 0xC6, 0xFE, 0x4C, 0x3E, 0x34, 0x30, 0x2E, 0x2D, 0x2E, 0x30, 0x35, 0x3C, +0x46, 0x62, 0xDE, 0xCA, 0xBE, 0xBD, 0xBB, 0xBA, 0xBD, 0xC3, 0xCB, 0xDC, 0x6B, 0x59, 0x51, 0x52, +0x60, 0xFF, 0xD5, 0xC4, 0xBE, 0xBC, 0xBA, 0xB9, 0xBB, 0xC3, 0xC8, 0xD6, 0x5A, 0x4C, 0x42, 0x39, +0x36, 0x35, 0x32, 0x34, 0x36, 0x39, 0x41, 0x47, 0x58, 0xE0, 0xDA, 0xC9, 0xC1, 0xC4, 0xC0, 0xC0, +0xC6, 0xCA, 0xD1, 0xDC, 0xF3, 0x6E, 0xFC, 0xE8, 0xDB, 0xCB, 0xC2, 0xBE, 0xBD, 0xBE, 0xBD, 0xC0, +0xCD, 0xCE, 0xEC, 0x4E, 0x4C, 0x40, 0x38, 0x39, 0x37, 0x35, 0x38, 0x38, 0x3B, 0x43, 0x49, 0x54, +0xEA, 0xDB, 0xCE, 0xC5, 0xC5, 0xC3, 0xC1, 0xC7, 0xCA, 0xCF, 0xDB, 0xE9, 0xFD, 0xF7, 0xE9, 0xDD, +0xCE, 0xC6, 0xC1, 0xBF, 0xC0, 0xBF, 0xC3, 0xCF, 0xD0, 0xE6, 0x51, 0x4E, 0x43, 0x3A, 0x3B, 0x38, +0x35, 0x38, 0x38, 0x3A, 0x3F, 0x44, 0x4E, 0x5F, 0xEF, 0xD7, 0xCD, 0xC8, 0xC6, 0xC4, 0xC6, 0xC9, +0xCC, 0xD4, 0xDD, 0xE6, 0xE1, 0xDA, 0xD7, 0xCA, 0xC3, 0xC4, 0xC4, 0xC1, 0xC3, 0xCC, 0xCF, 0xD8, +0x60, 0x54, 0x4E, 0x3F, 0x3D, 0x3D, 0x39, 0x3A, 0x3C, 0x3B, 0x3D, 0x47, 0x48, 0x51, 0x79, 0xFA, +0xDD, 0xCD, 0xCF, 0xCC, 0xC8, 0xCD, 0xCE, 0xCE, 0xD7, 0xDC, 0xDC, 0xD7, 0xD4, 0xCC, 0xC3, 0xC1, +0xBF, 0xBF, 0xC2, 0xC1, 0xCE, 0xDB, 0xDD, 0x54, 0x4C, 0x49, 0x3C, 0x3B, 0x3B, 0x38, 0x3A, 0x3B, +0x3C, 0x3E, 0x48, 0x4C, 0x55, 0xF3, 0xEC, 0xDB, 0xCD, 0xD1, 0xCD, 0xCB, 0xD2, 0xD1, 0xD6, 0xDD, +0xE1, 0xE2, 0xD7, 0xD3, 0xCA, 0xC0, 0xBE, 0xBE, 0xBF, 0xBE, 0xC1, 0xCF, 0xD0, 0xED, 0x4E, 0x4D, +0x41, 0x3A, 0x3A, 0x37, 0x35, 0x38, 0x3A, 0x3A, 0x3F, 0x49, 0x4A, 0x62, 0xE7, 0xEA, 0xCE, 0xCB, +0xCF, 0xC8, 0xCB, 0xD1, 0xCF, 0xD7, 0xE2, 0xE5, 0xE5, 0xDF, 0xD5, 0xCC, 0xC5, 0xBE, 0xBE, 0xC0, +0xBC, 0xC0, 0xCD, 0xC8, 0xDC, 0x58, 0x5B, 0x47, 0x3C, 0x3D, 0x39, 0x36, 0x39, 0x3A, 0x39, 0x3E, +0x47, 0x49, 0x59, 0xEA, 0xEC, 0xD0, 0xC9, 0xCD, 0xC7, 0xC8, 0xCE, 0xCD, 0xD2, 0xDC, 0xDF, 0xDF, +0xDD, 0xD6, 0xCB, 0xC6, 0xBF, 0xBF, 0xC4, 0xBD, 0xC4, 0xD1, 0xC9, 0xEF, 0x55, 0x5D, 0x43, 0x3D, +0x3E, 0x38, 0x37, 0x3A, 0x3A, 0x3A, 0x3E, 0x45, 0x48, 0x56, 0x74, 0xF8, 0xD8, 0xCF, 0xD0, 0xCB, +0xCB, 0xCE, 0xCE, 0xD2, 0xD9, 0xDC, 0xDC, 0xD7, 0xD3, 0xCA, 0xC4, 0xC0, 0xBF, 0xC2, 0xBE, 0xC3, +0xCF, 0xCB, 0xE5, 0x58, 0x5C, 0x45, 0x3D, 0x3E, 0x39, 0x37, 0x39, 0x3A, 0x3A, 0x3D, 0x45, 0x46, +0x52, 0x79, 0x73, 0xD7, 0xCD, 0xD1, 0xC8, 0xC8, 0xCD, 0xCA, 0xCF, 0xD5, 0xD7, 0xDC, 0xDA, 0xD4, +0xCD, 0xC7, 0xC1, 0xC0, 0xC5, 0xBF, 0xC2, 0xD1, 0xCA, 0xDA, 0x5A, 0x68, 0x4C, 0x3E, 0x42, 0x3B, +0x38, 0x3B, 0x3A, 0x3A, 0x3D, 0x42, 0x44, 0x4B, 0x62, 0x66, 0xF1, 0xD0, 0xD6, 0xCD, 0xC8, 0xCE, +0xCA, 0xCB, 0xD1, 0xCF, 0xD2, 0xD2, 0xCE, 0xC9, 0xC5, 0xC1, 0xBF, 0xC5, 0xC1, 0xC0, 0xD3, 0xCE, +0xD6, 0x57, 0x5F, 0x4E, 0x3E, 0x41, 0x3D, 0x39, 0x3B, 0x3B, 0x3A, 0x3D, 0x42, 0x44, 0x4C, 0x5A, +0x5E, 0xEC, 0xDD, 0xDC, 0xCE, 0xD0, 0xD1, 0xCD, 0xD4, 0xD4, 0xD4, 0xDA, 0xD3, 0xCE, 0xCB, 0xC4, +0xBF, 0xBE, 0xC2, 0xBE, 0xBF, 0xCD, 0xCB, 0xD5, 0x5B, 0x5F, 0x4D, 0x3E, 0x3F, 0x3B, 0x37, 0x39, +0x3A, 0x39, 0x3C, 0x3F, 0x42, 0x4B, 0x59, 0x61, 0xEA, 0xDA, 0xD6, 0xCD, 0xCD, 0xCE, 0xCD, 0xCF, +0xD3, 0xD6, 0xDA, 0xD7, 0xD2, 0xCE, 0xC7, 0xC2, 0xBF, 0xC0, 0xC1, 0xBE, 0xC8, 0xCE, 0xCB, 0x79, +0x5A, 0x5C, 0x41, 0x3F, 0x3E, 0x38, 0x39, 0x3A, 0x39, 0x3A, 0x3E, 0x42, 0x45, 0x51, 0x62, 0x65, +0xDD, 0xD5, 0xD7, 0xCA, 0xCC, 0xCE, 0xCA, 0xCE, 0xD0, 0xCF, 0xCF, 0xCD, 0xC9, 0xC4, 0xBF, 0xBD, +0xBE, 0xBF, 0xBD, 0xC5, 0xCE, 0xCB, 0xF8, 0x58, 0x5B, 0x43, 0x3E, 0x3E, 0x39, 0x38, 0x3A, 0x39, +0x3A, 0x3E, 0x44, 0x45, 0x51, 0x6E, 0x69, 0xDC, 0xCF, 0xD7, 0xCA, 0xCB, 0xD0, 0xCC, 0xD1, 0xD5, +0xD5, 0xD5, 0xCF, 0xCB, 0xC5, 0xBF, 0xBC, 0xBD, 0xBF, 0xBB, 0xC3, 0xCC, 0xC8, 0xEF, 0x5B, 0x5D, +0x41, 0x3D, 0x3D, 0x37, 0x37, 0x38, 0x37, 0x38, 0x3B, 0x41, 0x43, 0x4E, 0x6B, 0x67, 0xDC, 0xCE, +0xD4, 0xC9, 0xC8, 0xCE, 0xCA, 0xCE, 0xD5, 0xD4, 0xD5, 0xD3, 0xCE, 0xC7, 0xC3, 0xBE, 0xBE, 0xC3, +0xBD, 0xC2, 0xD0, 0xC9, 0xDE, 0x57, 0x61, 0x47, 0x3D, 0x3F, 0x39, 0x36, 0x38, 0x38, 0x38, 0x3A, +0x41, 0x40, 0x48, 0x6A, 0x5C, 0xF7, 0xCD, 0xDB, 0xCD, 0xC6, 0xD1, 0xCC, 0xCC, 0xD6, 0xD5, 0xD3, +0xCF, 0xCE, 0xC6, 0xC0, 0xBF, 0xBE, 0xBF, 0xBE, 0xC0, 0xCC, 0xCB, 0xDB, 0x5D, 0x5B, 0x49, 0x3E, +0x3E, 0x39, 0x37, 0x38, 0x38, 0x38, 0x3B, 0x40, 0x42, 0x4A, 0x63, 0x66, 0xE5, 0xCE, 0xD0, 0xCA, +0xC7, 0xCA, 0xCA, 0xCC, 0xCE, 0xD1, 0xCF, 0xCC, 0xCC, 0xC4, 0xBF, 0xBF, 0xBE, 0xC0, 0xBE, 0xC2, +0xCE, 0xCC, 0xE2, 0x58, 0x59, 0x47, 0x3D, 0x3D, 0x39, 0x37, 0x39, 0x39, 0x39, 0x3C, 0x40, 0x44, +0x4D, 0x5D, 0x6F, 0xE0, 0xD4, 0xCF, 0xCC, 0xCB, 0xCB, 0xCD, 0xCF, 0xCF, 0xD4, 0xD1, 0xCC, 0xCA, +0xC4, 0xBF, 0xBD, 0xBF, 0xBF, 0xBE, 0xC7, 0xCF, 0xCE, 0x79, 0x52, 0x51, 0x41, 0x3C, 0x3B, 0x38, +0x36, 0x38, 0x39, 0x38, 0x3D, 0x44, 0x44, 0x55, 0x70, 0x76, 0xD5, 0xCF, 0xCF, 0xC9, 0xCB, 0xCB, +0xCD, 0xD1, 0xD1, 0xD9, 0xD2, 0xCD, 0xCD, 0xC4, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xC9, 0xCF, 0xD0, +0x6A, 0x53, 0x4F, 0x3F, 0x3C, 0x3B, 0x38, 0x37, 0x38, 0x39, 0x3A, 0x3E, 0x44, 0x4A, 0x56, 0x75, +0xE7, 0xD7, 0xCD, 0xCB, 0xCA, 0xC9, 0xCA, 0xCD, 0xCE, 0xCF, 0xD3, 0xCE, 0xCA, 0xC7, 0xC0, 0xBE, +0xBE, 0xBF, 0xBF, 0xC1, 0xCD, 0xD2, 0xDB, 0x5C, 0x4F, 0x4A, 0x3E, 0x3C, 0x3B, 0x39, 0x38, 0x3A, +0x3A, 0x3C, 0x43, 0x46, 0x4E, 0x71, 0x7A, 0xDD, 0xCE, 0xD0, 0xCB, 0xCA, 0xCD, 0xCC, 0xD1, 0xD2, +0xD5, 0xD7, 0xCC, 0xCC, 0xC7, 0xBE, 0xBF, 0xBF, 0xBE, 0xC0, 0xC6, 0xCD, 0xD5, 0xEE, 0x54, 0x4D, +0x45, 0x3C, 0x3B, 0x39, 0x37, 0x38, 0x39, 0x3A, 0x3E, 0x44, 0x4A, 0x59, 0x71, 0xE8, 0xD4, 0xCE, +0xCC, 0xC9, 0xCB, 0xCB, 0xCE, 0xD2, 0xD4, 0xD7, 0xD2, 0xCD, 0xCB, 0xC4, 0xBF, 0xBF, 0xC0, 0xC0, +0xC0, 0xC9, 0xD1, 0xD8, 0x73, 0x52, 0x4B, 0x42, 0x3C, 0x3A, 0x39, 0x38, 0x38, 0x39, 0x3C, 0x3F, +0x41, 0x4E, 0x5D, 0x63, 0xDF, 0xD3, 0xD1, 0xCD, 0xCB, 0xCC, 0xD1, 0xD1, 0xD3, 0xDE, 0xDA, 0xD1, +0xCF, 0xCC, 0xC4, 0xBF, 0xC2, 0xC2, 0xBF, 0xC6, 0xCD, 0xD2, 0xE3, 0x63, 0x4F, 0x4A, 0x42, 0x3C, +0x3B, 0x3A, 0x39, 0x3A, 0x3B, 0x3F, 0x42, 0x47, 0x5A, 0x62, 0x7C, 0xD5, 0xD2, 0xCF, 0xCC, 0xCD, +0xCE, 0xD5, 0xD6, 0xD9, 0xE0, 0xD9, 0xD2, 0xCE, 0xCB, 0xC4, 0xBF, 0xC2, 0xC2, 0xBF, 0xC6, 0xCD, +0xD4, 0xE2, 0x67, 0x4F, 0x4B, 0x43, 0x3D, 0x3C, 0x3B, 0x3B, 0x3B, 0x3C, 0x42, 0x43, 0x49, 0x60, +0x6B, 0xF5, 0xD4, 0xD2, 0xD0, 0xD2, 0xD2, 0xD4, 0xDF, 0xDD, 0xDF, 0xEA, 0xDC, 0xD5, 0xD0, 0xCB, +0xC4, 0xC0, 0xC2, 0xBF, 0xC0, 0xC7, 0xC9, 0xD0, 0xDD, 0x7A, 0x57, 0x52, 0x48, 0x3F, 0x3F, 0x3D, +0x3C, 0x3C, 0x3D, 0x42, 0x44, 0x49, 0x5B, 0x64, 0x7C, 0xDE, 0xDB, 0xDB, 0xDC, 0xDA, 0xDF, 0xEE, +0xE9, 0xE6, 0xE8, 0xE3, 0xDB, 0xD0, 0xCD, 0xCC, 0xC5, 0xC3, 0xC5, 0xC2, 0xC3, 0xC8, 0xCD, 0xD1, +0xDE, 0x6F, 0x5B, 0x50, 0x4A, 0x44, 0x40, 0x3F, 0x3E, 0x3E, 0x42, 0x43, 0x47, 0x4F, 0x58, 0x5F, +0x69, 0xF6, 0xED, 0xF7, 0xEB, 0xE8, 0xEA, 0xEC, 0xE8, 0xE0, 0xE0, 0xDD, 0xD7, 0xD0, 0xCE, 0xCC, +0xC8, 0xC7, 0xC6, 0xC4, 0xC8, 0xC9, 0xCB, 0xD2, 0xDA, 0xEF, 0x71, 0x5B, 0x4F, 0x4E, 0x49, 0x45, +0x46, 0x45, 0x47, 0x47, 0x4A, 0x4E, 0x4E, 0x54, 0x5A, 0x5D, 0x62, 0x65, 0x70, 0x6C, 0x69, 0xFA, +0x7A, 0x7A, 0xE6, 0xE2, 0xDF, 0xDA, 0xD5, 0xCF, 0xD1, 0xD1, 0xCB, 0xCE, 0xD4, 0xCE, 0xD1, 0xD9, +0xDB, 0xE0, 0xE1, 0xEE, 0x6A, 0x74, 0x6C, 0x5A, 0x5B, 0x5A, 0x56, 0x56, 0x53, 0x56, 0x57, 0x53, +0x57, 0x5B, 0x59, 0x59, 0x5D, 0x65, 0x60, 0x61, 0x6F, 0x73, 0xF7, 0xEF, 0xEA, 0xDD, 0xDF, 0xDC, +0xD5, 0xD8, 0xDC, 0xDC, 0xDA, 0xDF, 0xE5, 0xE1, 0xEB, 0xED, 0xED, 0xFC, 0xFF, 0x70, 0x6C, 0x6C, +0x66, 0x5F, 0x5F, 0x62, 0x5F, 0x60, 0x60, 0x5A, 0x5F, 0x64, 0x5C, 0x64, 0x6E, 0x5F, 0x5E, 0x69, +0x6B, 0x7B, 0xF0, 0xFA, 0xE9, 0xE4, 0xE8, 0xDF, 0xE6, 0xEB, 0xE1, 0xE2, 0xE6, 0xE3, 0xE8, 0xED, +0xE5, 0xFC, 0x71, 0xE9, 0xFE, 0x7A, 0xEC, 0x73, 0x7E, 0x77, 0x64, 0xFD, 0x74, 0x66, 0x7B, 0x6C, +0x6B, 0x72, 0x6A, 0x79, 0x73, 0x71, 0xF4, 0x79, 0xFC, 0xEF, 0xF9, 0xEB, 0xF1, 0xF0, 0xE2, 0xE3, +0xE0, 0xE2, 0xE3, 0xEB, 0xFC, 0xEA, 0xF8, 0x6F, 0x70, 0x69, 0x77, 0x6C, 0x6D, 0xEF, 0x6B, 0x67, +0x6D, 0x65, 0x76, 0x75, 0x6F, 0x7E, 0x69, 0x67, 0x6F, 0x68, 0x6F, 0x73, 0x68, 0x69, 0x68, 0x69, +0x75, 0xFA, 0xEE, 0xF2, 0xEA, 0xDE, 0xE2, 0xE7, 0xE5, 0xEB, 0xF3, 0xED, 0xE8, 0xF7, 0x7F, 0xFA, +0x74, 0x6A, 0x68, 0x65, 0x66, 0x68, 0x64, 0x65, 0x68, 0x64, 0x6D, 0x77, 0x72, 0x70, 0x69, 0x77, +0x78, 0x64, 0x6B, 0x68, 0x60, 0x66, 0x67, 0x67, 0x61, 0x6D, 0xEB, 0xE8, 0xEC, 0xEB, 0xEA, 0xF7, +0xF5, 0xE2, 0xE5, 0xF6, 0xF8, 0xF0, 0x7E, 0x77, 0xFA, 0x76, 0x77, 0x7D, 0x6E, 0x74, 0x74, 0x72, +0x72, 0x6D, 0x75, 0x74, 0x74, 0x75, 0x76, 0xEF, 0xEE, 0xEF, 0xEA, 0xFA, 0x7F, 0xF2, 0xF6, 0xF7, +0xEF, 0xEA, 0xE4, 0xE5, 0xE7, 0xE3, 0xE9, 0xEC, 0xE8, 0xEB, 0xF0, 0xF8, 0xFC, 0x7F, 0x73, 0x73, +0x70, 0x72, 0x75, 0x69, 0x67, 0x6A, 0x6C, 0x6D, 0x6C, 0x70, 0x6D, 0x6D, 0x78, 0x72, 0x6F, 0x6E, +0x6C, 0x6F, 0x77, 0xF7, 0xEF, 0xF1, 0xF6, 0xF4, 0xF1, 0xFC, 0xF8, 0xEE, 0xF0, 0xEE, 0xEF, 0xEF, +0xEC, 0xEE, 0xF3, 0xF4, 0x76, 0x69, 0x77, 0xFA, 0x70, 0x75, 0x7E, 0x6E, 0x6D, 0x6E, 0x6E, 0x6E, +0x6D, 0x70, 0x74, 0x79, 0xFE, 0x7D, 0x78, 0x7C, 0x7A, 0x75, 0x78, 0x75, 0x70, 0x7C, 0xFC, 0xFB, +0xF4, 0xF3, 0xED, 0xEC, 0xF6, 0xF1, 0xEF, 0xF6, 0xF0, 0xFB, 0x7A, 0x7C, 0x74, 0x79, 0x74, 0x6C, +0x6C, 0x63, 0x67, 0x6C, 0x62, 0x66, 0x67, 0x68, 0x6C, 0x6A, 0x7D, 0x78, 0x6B, 0x7B, 0x71, 0x75, +0xFB, 0x75, 0x76, 0x7E, 0xEE, 0xED, 0xFA, 0xE8, 0xEE, 0x7F, 0xE4, 0xE9, 0xED, 0xE1, 0xEC, 0xEE, +0xE6, 0xF6, 0xFE, 0xF7, 0xFF, 0x7B, 0x72, 0x7C, 0x7F, 0x6B, 0x6C, 0x66, 0x67, 0x71, 0x66, 0x72, +0xFF, 0x69, 0x7B, 0xF7, 0xFF, 0xF3, 0xF6, 0xF3, 0xF2, 0xEE, 0xED, 0xFF, 0xF6, 0xED, 0xFB, 0xF2, +0xE9, 0xF0, 0xEC, 0xE6, 0xF4, 0xF2, 0xF5, 0x7C, 0xED, 0x7E, 0x6B, 0x7B, 0x77, 0xFE, 0x7A, 0x69, +0x68, 0x60, 0x65, 0x66, 0x61, 0x71, 0x74, 0x74, 0xFC, 0x7E, 0xFA, 0xFF, 0x7E, 0xF9, 0xFB, 0xEE, +0xED, 0xEF, 0xEF, 0xF4, 0xEC, 0xEC, 0xF2, 0xF0, 0xEF, 0xED, 0xF4, 0xF6, 0xEF, 0xFD, 0xF8, 0xF1, +0x77, 0x74, 0x7A, 0x70, 0x6F, 0x79, 0x76, 0x6A, 0x68, 0x6C, 0x6C, 0x69, 0x65, 0x66, 0x6E, 0x73, +0x6C, 0x6D, 0x7A, 0x79, 0x7A, 0xFE, 0x73, 0x72, 0x7A, 0x7E, 0xF3, 0xEF, 0xEE, 0xF1, 0xF6, 0xEC, +0xEF, 0xFA, 0xEE, 0xF5, 0xFE, 0xF2, 0xF0, 0xF7, 0xFA, 0xF9, 0xFB, 0xFB, 0x7A, 0x6B, 0x6B, 0x72, +0x6C, 0x6A, 0x76, 0x74, 0x6E, 0x72, 0x6C, 0x6B, 0x6F, 0x6B, 0x6E, 0x71, 0x6D, 0x75, 0x76, 0x70, +0x78, 0x7C, 0xFA, 0xF2, 0xF7, 0xF1, 0xED, 0xF3, 0xF4, 0xF6, 0xFA, 0xF0, 0xEF, 0xFD, 0x7B, 0xFF, +0x78, 0x6C, 0x70, 0x72, 0x6E, 0x73, 0x6D, 0x6D, 0x6D, 0x65, 0x65, 0x69, 0x6F, 0x70, 0x6B, 0x6E, +0x71, 0x6E, 0x6E, 0x6F, 0x7A, 0x7D, 0x7E, 0xEF, 0xF4, 0x7D, 0xFB, 0xF3, 0xEC, 0xEB, 0xF0, 0xEF, +0xEE, 0xEE, 0xF3, 0xF0, 0xED, 0xFF, 0xFF, 0xF3, 0x7E, 0xFB, 0xFF, 0x73, 0x7E, 0x7A, 0x76, 0x6F, +0x6C, 0x7A, 0x74, 0x6F, 0xFF, 0x7B, 0x79, 0xF7, 0xF5, 0xFB, 0xF6, 0xF3, 0x7E, 0x7D, 0xFA, 0xFD, +0xF6, 0xF5, 0x7D, 0x7B, 0x7A, 0xFF, 0xFB, 0x7D, 0x75, 0x76, 0xF3, 0xF3, 0x78, 0xFE, 0x76, 0x6B, +0x7B, 0xFB, 0x75, 0x69, 0x6C, 0xF6, 0xF6, 0x7B, 0x6F, 0x69, 0x6E, 0x72, 0x70, 0x74, 0x78, 0xFF, +0x7F, 0xFD, 0xF5, 0xF8, 0xF5, 0xF9, 0x75, 0x74, 0x7D, 0xF7, 0xFB, 0x70, 0x7E, 0xE9, 0xEF, 0xF7, +0xE6, 0xED, 0x74, 0x7A, 0xF7, 0x7D, 0x71, 0x77, 0xFE, 0xF6, 0xFC, 0x6B, 0x6B, 0x72, 0x69, 0x6D, +0x7B, 0x7C, 0xFD, 0x6F, 0x6B, 0xFC, 0x7F, 0x73, 0xF9, 0xF5, 0x70, 0x6E, 0xFD, 0xFF, 0x7C, 0xFB, +0x70, 0x76, 0xEF, 0x7D, 0x75, 0xFB, 0xF6, 0xEF, 0xF6, 0x7C, 0x79, 0x76, 0xFE, 0x7D, 0x73, 0xFD, +0xFE, 0x76, 0x6E, 0x66, 0x6B, 0x75, 0x6D, 0x7D, 0xF2, 0x6D, 0x75, 0xED, 0x7A, 0x6D, 0x7E, 0xF9, +0xFE, 0x6E, 0x78, 0xF4, 0x6E, 0x73, 0xF8, 0x74, 0xFF, 0xFE, 0x77, 0xF6, 0x7C, 0x71, 0x7F, 0x7E, +0x7E, 0x79, 0x78, 0x7C, 0x6E, 0x6F, 0x70, 0x6D, 0xFD, 0xFA, 0x6C, 0x6B, 0x71, 0x70, 0x7B, 0x7A, +0x7C, 0xFD, 0x6D, 0x75, 0xED, 0xF8, 0xFC, 0xF7, 0xFB, 0xEE, 0xEF, 0x79, 0xFF, 0xED, 0xF8, 0x7A, +0xF1, 0xED, 0xF7, 0xFC, 0xF8, 0xF1, 0xF8, 0x79, 0x7D, 0xF6, 0x78, 0x6E, 0xFD, 0xFB, 0x72, 0x6E, +0x6C, 0x74, 0xFE, 0xFF, 0xF7, 0xFE, 0x6D, 0x75, 0x79, 0x6F, 0x7C, 0x7D, 0x76, 0x78, 0x7A, 0x7F, +0x75, 0x7D, 0xF7, 0xF8, 0xEF, 0x7B, 0x7A, 0xF3, 0xFF, 0xEF, 0xF8, 0xFE, 0xF6, 0x6E, 0xF4, 0xED, +0x6F, 0x7C, 0x74, 0x75, 0xF2, 0x7C, 0x75, 0xF9, 0xEE, 0xFF, 0x70, 0x7C, 0x7F, 0xFD, 0xFD, 0xFA, +0x79, 0x6C, 0x7C, 0x7F, 0xFD, 0xF3, 0x78, 0xFE, 0xF7, 0xFC, 0xED, 0xF1, 0xFD, 0xFE, 0x7D, 0xF4, +0xED, 0xF4, 0xFA, 0xFD, 0x70, 0x73, 0xF6, 0xFF, 0x7D, 0xF7, 0x79, 0x72, 0x78, 0x7D, 0x77, 0x6E, +0x71, 0x6C, 0x6A, 0x7D, 0x74, 0x71, 0x7D, 0x6E, 0x79, 0xF8, 0x70, 0x7C, 0xFE, 0x6D, 0x6F, 0x6E, +0x6D, 0x7D, 0xFD, 0xFB, 0xFA, 0x7C, 0xFD, 0xFA, 0xF7, 0xF4, 0xFD, 0x7B, 0x76, 0x7D, 0xF3, 0xF5, +0xFD, 0xF5, 0xED, 0x7A, 0x6D, 0xF5, 0x7C, 0x76, 0xEF, 0x77, 0x6E, 0xFF, 0x74, 0x79, 0xFD, 0x76, +0x7A, 0x7E, 0x7B, 0x7D, 0x78, 0x73, 0x7A, 0xFB, 0xFB, 0x7E, 0xFB, 0xF2, 0xF8, 0xF9, 0xFB, 0xFE, +0xF5, 0xF6, 0xF9, 0x7E, 0x73, 0xF7, 0xFA, 0x74, 0xFC, 0x7B, 0x70, 0xFF, 0xFC, 0x7E, 0x7C, 0xFE, +0xFF, 0x7C, 0xFC, 0x7E, 0x79, 0xFF, 0x7C, 0x79, 0x79, 0x79, 0x7A, 0x79, 0x7A, 0x7C, 0x7A, 0x75, +0x72, 0x7C, 0xFC, 0xFE, 0xFE, 0xFC, 0xF9, 0xFE, 0xFE, 0xFA, 0x7C, 0xFD, 0xFC, 0x77, 0x7B, 0x7A, +0x73, 0x78, 0x7A, 0x78, 0x7B, 0x77, 0x6E, 0x70, 0x7B, 0x7A, 0x72, 0x74, 0x76, 0x75, 0x77, 0x75, +0x70, 0x6F, 0x6F, 0x6F, 0x74, 0x77, 0x72, 0x6F, 0x70, 0x79, 0x79, 0x6F, 0x7E, 0xFA, 0x72, 0x79, +0x79, 0x78, 0xFE, 0x78, 0xFF, 0xFE, 0x76, 0xFF, 0xFF, 0x7D, 0xFF, 0x7E, 0x7B, 0x78, 0x7C, 0x75, +0x75, 0xFF, 0xFF, 0xF8, 0xF6, 0xFD, 0xF5, 0xF4, 0xF6, 0xFC, 0x7C, 0x7C, 0x7B, 0xFC, 0xFD, 0xFD, +0xFD, 0x77, 0x7A, 0x7F, 0x7E, 0xFC, 0xFA, 0xF7, 0xFF, 0xFE, 0xF1, 0xFD, 0xFD, 0xF0, 0xF9, 0xF8, +0xEE, 0xEF, 0xF8, 0x7E, 0x79, 0x77, 0x6C, 0x66, 0x6A, 0x68, 0x67, 0x71, 0x74, 0x77, 0x7E, 0x7B, +0xFD, 0xFD, 0x7F, 0xFF, 0x79, 0xFE, 0xFE, 0x75, 0x78, 0x7A, 0x74, 0x70, 0x76, 0x77, 0x75, 0x7C, +0x7C, 0x79, 0x78, 0x77, 0x78, 0x7C, 0x7E, 0x77, 0x74, 0x79, 0x77, 0x78, 0x78, 0x77, 0x7B, 0x78, +0x77, 0x77, 0x7A, 0xFE, 0x7D, 0xFE, 0xF6, 0xFB, 0xFC, 0xF8, 0xF6, 0xFA, 0xFD, 0xFB, 0xFC, 0x7D, +0x7B, 0xFB, 0xF5, 0xFC, 0xFF, 0xFD, 0xFE, 0xFF, 0x7F, 0xFC, 0xF8, 0xFF, 0x7F, 0xF7, 0xF9, 0xFA, +0xF9, 0xFB, 0xFA, 0xFA, 0xFA, 0xF8, 0xF8, 0xFD, 0x7E, 0xF8, 0xF7, 0xEF, 0xE0, 0xE1, 0xF7, 0x6E, +0x69, 0x65, 0x5C, 0x5B, 0x61, 0x69, 0x6E, 0x76, 0xF8, 0xEF, 0xF2, 0xEB, 0xE3, 0xDE, 0xE2, 0xFA, +0x66, 0x5B, 0x5F, 0x6E, 0x6E, 0xFB, 0xED, 0xED, 0xEC, 0xF8, 0x7E, 0x7B, 0x6E, 0x67, 0x60, 0x65, +0x6E, 0x6F, 0x78, 0xFB, 0x7E, 0x7D, 0xFA, 0xF9, 0xF7, 0xF5, 0xF7, 0xEE, 0xEB, 0xF3, 0xFA, 0x7A, +0x6D, 0x69, 0x6A, 0x69, 0x64, 0x69, 0x6E, 0x6F, 0x78, 0xFB, 0xFB, 0x7C, 0xF8, 0xF1, 0xFB, 0xF4, +0xF9, 0x7D, 0xF8, 0x7D, 0xFD, 0xF3, 0x7C, 0xFD, 0xF4, 0x7A, 0x6F, 0x79, 0xFF, 0x75, 0x78, 0xFA, +0xFB, 0xFE, 0xFB, 0xF9, 0xFE, 0xFF, 0xFF, 0xFC, 0xF5, 0xFD, 0x79, 0xFF, 0xF9, 0xFA, 0xFF, 0xFF, +0x7B, 0x74, 0x75, 0x6F, 0x71, 0x7D, 0x74, 0x75, 0x79, 0x71, 0x77, 0x7E, 0x7E, 0x7C, 0x74, 0x71, +0x77, 0x7A, 0x7F, 0xFB, 0x72, 0x69, 0x74, 0x74, 0x6A, 0x74, 0x7E, 0x79, 0x76, 0x74, 0x7F, 0x7C, +0x76, 0xF8, 0xF8, 0x7E, 0x7D, 0x7E, 0xFE, 0x77, 0x7B, 0xF8, 0x7B, 0xFF, 0xF3, 0xFC, 0xFF, 0xFE, +0xFD, 0xF5, 0xF6, 0xF3, 0xF2, 0xFA, 0xF8, 0xF3, 0xFB, 0x7E, 0xFA, 0xFA, 0x7E, 0xFE, 0xFC, 0x7C, +0x78, 0x7D, 0xFB, 0xF3, 0xFD, 0x74, 0xF7, 0xF5, 0x76, 0xF9, 0xF8, 0xFF, 0xF5, 0x76, 0x7B, 0xFA, +0x77, 0xFD, 0x7C, 0x77, 0x7D, 0x6F, 0x7D, 0xF7, 0xFC, 0xFD, 0x7B, 0xF5, 0xF8, 0x7A, 0xF4, 0xFB, +0x77, 0x7B, 0x76, 0x74, 0x7D, 0x7E, 0x72, 0x71, 0x70, 0x70, 0x77, 0x70, 0x7B, 0xFD, 0x6F, 0x72, +0x7D, 0x7A, 0x71, 0x79, 0xF8, 0x77, 0x6F, 0x74, 0x7A, 0x78, 0x7C, 0xF6, 0x7C, 0xFB, 0x7D, 0x6C, +0xEF, 0xFC, 0x6D, 0xF1, 0xF5, 0x7D, 0x79, 0xFA, 0xF5, 0x75, 0xF4, 0x7C, 0xFC, 0xE6, 0x68, 0x78, +0xE4, 0x6E, 0x77, 0xF2, 0x7E, 0x70, 0x69, 0xF9, 0xF7, 0x6C, 0x74, 0xF3, 0xEE, 0x79, 0x7E, 0xFB, +0x7A, 0xF6, 0x6C, 0x6B, 0xED, 0x77, 0x6A, 0x70, 0x6F, 0xFC, 0x7E, 0x79, 0xF2, 0xEE, 0xF8, 0x7D, +0xEF, 0xEB, 0x7E, 0x72, 0x7D, 0x74, 0x6B, 0xFA, 0xE5, 0xE7, 0xE4, 0xEB, 0xF8, 0xEC, 0xEA, 0xF3, +0xFB, 0xFA, 0xEF, 0xF6, 0x7C, 0xFF, 0x7B, 0x72, 0x78, 0x7C, 0x6F, 0x6E, 0xFF, 0xFF, 0x75, 0x74, +0x74, 0x76, 0x6C, 0x6A, 0x7F, 0x78, 0x6D, 0x74, 0x6E, 0x76, 0x7B, 0x69, 0x6B, 0x79, 0x72, 0x6A, +0x6D, 0x77, 0xFD, 0xFC, 0x6F, 0x7C, 0xEE, 0x76, 0x69, 0x74, 0xFB, 0x74, 0x6A, 0x7D, 0xF0, 0xFF, +0x6B, 0x71, 0xEF, 0x7D, 0x74, 0xF8, 0x75, 0x74, 0x77, 0x6C, 0x6E, 0x71, 0x73, 0x72, 0x70, 0xF4, +0xF0, 0x79, 0x7B, 0xFB, 0xF3, 0xF4, 0x78, 0x79, 0xF7, 0xFC, 0x6E, 0x70, 0xF8, 0xF8, 0x79, 0x6D, +0x70, 0xFB, 0x6E, 0x64, 0x6B, 0x72, 0x6F, 0x65, 0x71, 0xFC, 0x71, 0x76, 0x6E, 0x71, 0xF9, 0xFF, +0xFD, 0x73, 0x7A, 0xFF, 0x66, 0x70, 0xFE, 0x79, 0xFD, 0x7D, 0xF1, 0xF6, 0x76, 0x79, 0x6D, 0x79, +0xFF, 0x72, 0x7F, 0xF8, 0xF0, 0xFF, 0x71, 0xEC, 0xE9, 0x7C, 0x7C, 0xF1, 0xF7, 0xF7, 0xF5, 0xFA, +0xF1, 0x7C, 0x70, 0x7D, 0xFB, 0xF4, 0x7C, 0x7D, 0xF6, 0xFD, 0xEF, 0xF6, 0xEE, 0xE1, 0xEE, 0xF4, +0xF3, 0xEE, 0xF4, 0x78, 0xEC, 0xF7, 0x72, 0x74, 0x6E, 0xF5, 0x6A, 0x7B, 0xDF, 0x69, 0x7F, 0xE7, +0x6F, 0x7C, 0x68, 0xF4, 0xEE, 0x5C, 0x72, 0x6B, 0x6D, 0xEC, 0x60, 0x7E, 0xEB, 0x66, 0x6D, 0x6A, +0x7A, 0xFF, 0x6A, 0x6E, 0x74, 0xED, 0x79, 0x6B, 0xED, 0xFA, 0xFC, 0x70, 0x65, 0xF6, 0x75, 0x67, +0x78, 0x78, 0xF4, 0xFF, 0x5F, 0xF9, 0xE3, 0x6D, 0xF1, 0x7A, 0x70, 0xDB, 0x6A, 0xF9, 0xDC, 0x66, +0xDB, 0xF8, 0x65, 0xD6, 0x6A, 0xF2, 0xE6, 0x5E, 0xE1, 0x76, 0x6F, 0xF5, 0x65, 0xEF, 0x5F, 0x66, +0x6F, 0x5A, 0xFB, 0x5E, 0x65, 0x7E, 0x60, 0xF2, 0x5D, 0x72, 0xE8, 0x5A, 0xEA, 0x6E, 0x62, 0xE4, +0x5E, 0x6F, 0x74, 0x67, 0xEA, 0x64, 0x77, 0xF3, 0x69, 0xF1, 0x6B, 0x6E, 0xEB, 0x74, 0x74, 0x74, +0xF6, 0xF5, 0x66, 0xF5, 0xF7, 0x6C, 0xE9, 0x70, 0x6F, 0xE4, 0x6E, 0xF0, 0xF4, 0x63, 0xE1, 0xFE, +0x6D, 0xE4, 0x6D, 0xF2, 0xEF, 0x6C, 0xE8, 0x7B, 0xFC, 0xED, 0x74, 0xEB, 0xFE, 0xFC, 0xEF, 0x6D, +0xEC, 0xFB, 0x71, 0xEB, 0x77, 0xF3, 0xF8, 0x6F, 0xE9, 0xFE, 0xFC, 0xEE, 0x6F, 0xEB, 0xED, 0x7A, +0xEE, 0xF4, 0xF3, 0xF8, 0xF1, 0xEE, 0x79, 0xF4, 0xF3, 0xFC, 0xF1, 0x7C, 0xF4, 0xF9, 0x76, 0xE8, +0xF8, 0x75, 0xE3, 0x7B, 0x6E, 0xE0, 0x75, 0x72, 0xE3, 0x6C, 0xF8, 0xE7, 0x6D, 0xEA, 0xF4, 0x75, +0xEA, 0x71, 0xFA, 0xED, 0x6A, 0xF2, 0xFB, 0x70, 0xEB, 0x6F, 0x71, 0xEE, 0x6C, 0xF6, 0xF2, 0x68, +0xF3, 0xF8, 0x6D, 0x7A, 0xFC, 0x75, 0x6D, 0xF3, 0x6E, 0x6E, 0xEE, 0x61, 0x7C, 0xFE, 0x60, 0xF2, +0x6D, 0x78, 0x7C, 0x63, 0xEB, 0x64, 0x71, 0xED, 0x5C, 0xEB, 0x6F, 0x69, 0xEA, 0x5D, 0xE7, 0xF8, +0x5E, 0xE6, 0x6F, 0xFA, 0x79, 0x72, 0xE8, 0x5E, 0xE9, 0xFB, 0x5F, 0xDE, 0x61, 0xFA, 0xE3, 0x5A, +0xE3, 0x79, 0x62, 0xDF, 0x64, 0x76, 0xE4, 0x63, 0xFE, 0xE9, 0x64, 0xF8, 0xE6, 0x5F, 0xF2, 0xE8, +0x62, 0xE7, 0xFB, 0x6A, 0xF0, 0x77, 0xF9, 0x77, 0xE9, 0x78, 0x59, 0xE3, 0x71, 0x6C, 0xDF, 0x5F, +0xEF, 0xE9, 0x5F, 0xFA, 0x76, 0xF9, 0x7D, 0x67, 0xEE, 0x7B, 0x6F, 0x7E, 0x6B, 0x6D, 0xF7, 0x6E, +0x6B, 0xF0, 0x63, 0xF0, 0x75, 0x57, 0xD4, 0x59, 0x57, 0xCD, 0x4F, 0xEE, 0xDE, 0x4B, 0xCF, 0x68, +0x5B, 0xD4, 0x50, 0xE0, 0xEF, 0x54, 0xD5, 0x57, 0x6A, 0xD3, 0x54, 0x79, 0xDF, 0x5E, 0xFC, 0xE6, +0x5F, 0x71, 0xE0, 0x64, 0x76, 0xFC, 0x5D, 0xEA, 0xF8, 0x58, 0x79, 0xDB, 0x68, 0x59, 0xDF, 0x76, +0x64, 0xDA, 0x63, 0x5A, 0xD9, 0xE0, 0x51, 0xF3, 0xD3, 0x4D, 0xDE, 0xCF, 0x3F, 0xDA, 0xC2, 0x41, +0x6A, 0xC3, 0x50, 0x55, 0xC6, 0x5A, 0x4B, 0xC2, 0x7A, 0x46, 0xCA, 0xDF, 0x4C, 0xD8, 0xDE, 0x4F, +0xE2, 0xD2, 0x4D, 0x6B, 0xCD, 0x5C, 0x56, 0xD8, 0xEB, 0x54, 0xEF, 0xDE, 0x4F, 0x78, 0xD7, 0x54, +0x5B, 0xDA, 0xFA, 0x56, 0xF6, 0xE9, 0x58, 0xF1, 0xE5, 0x59, 0x6D, 0xE8, 0x7B, 0x64, 0x7E, 0xE2, +0x60, 0x6D, 0xDC, 0x63, 0x67, 0xDC, 0x6F, 0x62, 0xE2, 0x7B, 0x60, 0xEC, 0xF3, 0x67, 0x77, 0xF1, +0x7C, 0x75, 0xF0, 0x79, 0x6F, 0xED, 0x76, 0x6B, 0xF3, 0xFF, 0x74, 0xF4, 0xF8, 0x6B, 0x6C, 0xE6, +0xE7, 0x61, 0x79, 0xDD, 0x6F, 0x77, 0xDE, 0x6D, 0x6E, 0xE4, 0x7E, 0xF9, 0xE8, 0x6D, 0x6F, 0xDE, +0xEF, 0x5C, 0xEF, 0xDB, 0x64, 0x6B, 0xDF, 0xF9, 0x6C, 0xF4, 0xF5, 0x72, 0xF5, 0xF7, 0x66, 0x7D, +0xE9, 0x7D, 0x70, 0x79, 0xF6, 0x7B, 0x6C, 0xF3, 0xF2, 0x6A, 0x76, 0xED, 0x79, 0x6B, 0xF2, 0xF1, +0x6B, 0x78, 0xEF, 0x73, 0x74, 0xED, 0x73, 0x6A, 0xEB, 0xF2, 0x64, 0x6F, 0xE2, 0xF8, 0x5E, 0xF3, +0xE8, 0x64, 0x74, 0xEF, 0x7B, 0x77, 0x74, 0x78, 0x6D, 0xF8, 0xEA, 0x63, 0x68, 0xEC, 0xEF, 0x6E, +0x63, 0xEE, 0xFA, 0x5F, 0xE5, 0xEB, 0x58, 0x73, 0xD1, 0xF3, 0x4D, 0xF2, 0xCD, 0x5D, 0x54, 0xDF, +0xDD, 0x61, 0x5B, 0xD9, 0xDF, 0x50, 0xF0, 0xD3, 0x5F, 0x5D, 0xE4, 0xDF, 0x6E, 0x5B, 0xED, 0xD8, +0x68, 0x56, 0xEA, 0xD3, 0x70, 0x52, 0xF0, 0xD3, 0x74, 0x57, 0xF5, 0xD8, 0x6A, 0x58, 0xE4, 0xE2, +0x5C, 0x7A, 0xD8, 0x77, 0x5A, 0xE8, 0xD9, 0x73, 0x5F, 0x7D, 0xE3, 0xEC, 0x73, 0x72, 0x6E, 0xF6, +0xDF, 0xF7, 0x62, 0x6B, 0xE5, 0xDD, 0x6B, 0x58, 0xF7, 0xDB, 0x73, 0x5E, 0x75, 0x7E, 0xF6, 0xFE, +0x66, 0x71, 0x7B, 0x7E, 0xEE, 0x6C, 0x6B, 0xEB, 0x76, 0x6C, 0xEA, 0x7A, 0x67, 0xE5, 0xE8, 0x5F, +0x75, 0xDE, 0xEE, 0x6F, 0x7A, 0xED, 0xE8, 0xF8, 0xFB, 0xF4, 0x78, 0xF1, 0xE4, 0x6E, 0x62, 0xEB, +0xEC, 0x65, 0x6D, 0x7E, 0x6B, 0x69, 0x6E, 0x72, 0x78, 0x68, 0x5E, 0x74, 0xE9, 0x6F, 0x5E, 0x72, +0xEB, 0x7A, 0x6F, 0xF1, 0x78, 0x75, 0xE5, 0xE6, 0xE2, 0xDD, 0xE0, 0xD6, 0xD1, 0xD5, 0xD1, 0xD3, +0xDE, 0xE0, 0xDD, 0xE9, 0x68, 0x57, 0x52, 0x50, 0x4B, 0x48, 0x48, 0x48, 0x48, 0x4B, 0x51, 0x56, +0x56, 0x5D, 0x68, 0x6A, 0x69, 0x7C, 0xE8, 0xED, 0xED, 0xDC, 0xD5, 0xCD, 0xCB, 0xCD, 0xC5, 0xBE, +0xBE, 0xBC, 0xBC, 0xBF, 0xC5, 0xD2, 0x72, 0x52, 0x48, 0x40, 0x3C, 0x39, 0x39, 0x3B, 0x3D, 0x40, +0x4A, 0x5A, 0x6C, 0x7E, 0xDF, 0xCF, 0xCE, 0xDB, 0x6F, 0x63, 0x6E, 0x60, 0x4D, 0x47, 0x4D, 0x5E, +0x7C, 0xFA, 0xE4, 0xCD, 0xC1, 0xBD, 0xBC, 0xBA, 0xB7, 0xB4, 0xB5, 0xBE, 0xD7, 0xEB, 0xF2, 0x4E, +0x3B, 0x36, 0x37, 0x39, 0x38, 0x39, 0x3D, 0x48, 0x58, 0xFE, 0xDA, 0xD6, 0xD8, 0xCF, 0xC8, 0xCD, +0xF3, 0x5A, 0x59, 0x58, 0x4E, 0x47, 0x48, 0x4F, 0x5F, 0xF2, 0xD9, 0xCE, 0xC6, 0xBF, 0xBB, 0xBA, +0xB9, 0xB7, 0xB5, 0xB7, 0xC0, 0xD9, 0x68, 0x57, 0x49, 0x3B, 0x35, 0x35, 0x38, 0x3A, 0x3B, 0x3F, +0x4B, 0x60, 0xE7, 0xD8, 0xD5, 0xD4, 0xCE, 0xCA, 0xCF, 0xF9, 0x59, 0x51, 0x4E, 0x4C, 0x48, 0x46, +0x49, 0x56, 0xFB, 0xD9, 0xD1, 0xC9, 0xBE, 0xB8, 0xB6, 0xB5, 0xB3, 0xB2, 0xB6, 0xC3, 0xE5, 0x60, +0x4E, 0x3F, 0x37, 0x32, 0x34, 0x37, 0x39, 0x3C, 0x41, 0x4E, 0x6F, 0xDA, 0xD2, 0xD4, 0xD1, 0xCA, +0xC9, 0xD7, 0x6F, 0x59, 0x4D, 0x47, 0x47, 0x48, 0x45, 0x46, 0x52, 0xEE, 0xD7, 0xD0, 0xC7, 0xBC, +0xB5, 0xB3, 0xB3, 0xB1, 0xB0, 0xB7, 0xCA, 0x68, 0x4F, 0x45, 0x3B, 0x32, 0x2E, 0x30, 0x35, 0x39, +0x3D, 0x44, 0x52, 0xEC, 0xD0, 0xCF, 0xD3, 0xD0, 0xCD, 0xCF, 0xE3, 0x63, 0x5B, 0x59, 0x52, 0x4D, +0x4C, 0x4F, 0x5A, 0x6D, 0xE5, 0xD2, 0xC8, 0xBE, 0xB9, 0xB5, 0xB3, 0xB1, 0xAF, 0xB1, 0xBD, 0xE3, +0x53, 0x4B, 0x40, 0x35, 0x2E, 0x2F, 0x34, 0x39, 0x3B, 0x3F, 0x4C, 0x75, 0xDA, 0xD6, 0xD2, 0xCE, +0xCE, 0xD0, 0xD9, 0xEF, 0x62, 0x56, 0x55, 0x55, 0x4F, 0x4E, 0x52, 0x61, 0xEF, 0xDB, 0xCC, 0xBF, +0xB9, 0xB5, 0xB3, 0xB0, 0xAE, 0xB4, 0xC8, 0x63, 0x4D, 0x45, 0x39, 0x2E, 0x2C, 0x2F, 0x35, 0x38, +0x3B, 0x43, 0x5A, 0xDD, 0xCE, 0xCD, 0xCC, 0xCB, 0xCD, 0xD2, 0xDE, 0x76, 0x5A, 0x52, 0x53, 0x51, +0x4E, 0x4F, 0x5C, 0x7C, 0xE2, 0xD2, 0xC5, 0xBB, 0xB5, 0xB2, 0xB0, 0xAE, 0xAE, 0xB6, 0xCF, 0x55, +0x48, 0x3F, 0x34, 0x2C, 0x2C, 0x2F, 0x36, 0x39, 0x3D, 0x4A, 0x7D, 0xCE, 0xCA, 0xCB, 0xCB, 0xCB, +0xCD, 0xD9, 0x76, 0x59, 0x4F, 0x4C, 0x4C, 0x4A, 0x4C, 0x54, 0x68, 0xEC, 0xD8, 0xCB, 0xBF, 0xB8, +0xB3, 0xB0, 0xAE, 0xAD, 0xAE, 0xBC, 0xF5, 0x4C, 0x43, 0x39, 0x2E, 0x2A, 0x2D, 0x32, 0x37, 0x3B, +0x44, 0x5F, 0xD5, 0xC8, 0xC7, 0xC9, 0xCB, 0xCE, 0xD3, 0xE9, 0x5A, 0x4D, 0x4D, 0x4D, 0x4B, 0x4B, +0x50, 0x63, 0xF6, 0xDE, 0xCE, 0xC5, 0xBD, 0xB7, 0xB2, 0xB0, 0xAF, 0xAD, 0xAF, 0xBF, 0x5E, 0x45, +0x40, 0x37, 0x2C, 0x29, 0x2D, 0x34, 0x38, 0x3C, 0x48, 0x77, 0xCD, 0xC6, 0xC7, 0xCB, 0xCB, 0xCF, +0xE9, 0x59, 0x4E, 0x4B, 0x47, 0x44, 0x47, 0x4D, 0x57, 0x69, 0xEB, 0xD7, 0xCA, 0xBF, 0xB9, 0xB3, +0xAF, 0xAE, 0xAD, 0xAC, 0xB5, 0xDE, 0x49, 0x43, 0x3B, 0x2D, 0x28, 0x2A, 0x30, 0x36, 0x3A, 0x44, +0x6A, 0xCD, 0xC2, 0xC2, 0xC6, 0xCA, 0xCC, 0xD8, 0x60, 0x4C, 0x48, 0x46, 0x44, 0x43, 0x49, 0x54, +0x68, 0xEC, 0xD8, 0xCB, 0xC2, 0xBC, 0xB8, 0xB2, 0xAF, 0xAE, 0xAE, 0xAE, 0xBA, 0x74, 0x45, 0x3F, +0x36, 0x2C, 0x29, 0x2C, 0x32, 0x37, 0x3E, 0x4E, 0xE3, 0xC7, 0xC2, 0xC5, 0xC6, 0xC8, 0xD2, 0x71, +0x52, 0x4D, 0x49, 0x42, 0x41, 0x47, 0x51, 0x60, 0x7B, 0xDE, 0xCE, 0xC6, 0xC0, 0xBE, 0xB9, 0xB2, +0xAF, 0xAF, 0xAE, 0xAE, 0xBC, 0x6B, 0x47, 0x3F, 0x34, 0x2C, 0x2A, 0x2D, 0x32, 0x39, 0x3F, 0x4F, +0xDF, 0xC5, 0xC4, 0xCD, 0xCA, 0xC7, 0xDB, 0x5A, 0x4E, 0x4D, 0x48, 0x42, 0x40, 0x45, 0x54, 0x6F, +0x74, 0xEC, 0xCD, 0xC4, 0xC4, 0xC1, 0xBB, 0xB3, 0xAF, 0xB0, 0xAE, 0xAE, 0xBC, 0x6F, 0x4A, 0x3F, +0x34, 0x2C, 0x2B, 0x2E, 0x34, 0x3B, 0x42, 0x56, 0xCF, 0xBF, 0xC2, 0xCB, 0xC6, 0xC6, 0xE6, 0x52, +0x4B, 0x47, 0x45, 0x3F, 0x3D, 0x45, 0x5E, 0x7A, 0x72, 0xDB, 0xC7, 0xC3, 0xC5, 0xC2, 0xBC, 0xB5, +0xB1, 0xB3, 0xB0, 0xAE, 0xB9, 0xF0, 0x4C, 0x43, 0x38, 0x2E, 0x2B, 0x2D, 0x34, 0x3A, 0x3E, 0x4F, +0xD3, 0xC1, 0xC4, 0xCD, 0xCC, 0xC8, 0xDE, 0x4D, 0x45, 0x47, 0x47, 0x41, 0x3D, 0x47, 0x6D, 0xF7, +0x79, 0xDA, 0xC9, 0xC6, 0xC8, 0xC9, 0xC0, 0xB8, 0xB4, 0xB5, 0xB0, 0xAC, 0xB1, 0xCF, 0x5A, 0x4E, +0x3E, 0x30, 0x2B, 0x2D, 0x33, 0x38, 0x3B, 0x48, 0xDC, 0xC4, 0xC5, 0xCA, 0xCB, 0xCB, 0xD9, 0x50, +0x46, 0x4B, 0x46, 0x3E, 0x3F, 0x48, 0x55, 0x76, 0x7E, 0xE3, 0xCA, 0xC9, 0xCE, 0xCB, 0xC6, 0xBE, +0xBA, 0xB8, 0xB4, 0xAE, 0xAE, 0xBD, 0xEA, 0x62, 0x48, 0x35, 0x2D, 0x2C, 0x30, 0x35, 0x37, 0x3F, +0x6F, 0xCB, 0xCA, 0xC9, 0xC7, 0xCE, 0xD9, 0x60, 0x46, 0x46, 0x48, 0x40, 0x40, 0x49, 0x52, 0x69, +0xED, 0xE1, 0xD1, 0xCC, 0xD0, 0xD2, 0xD0, 0xCD, 0xC2, 0xBD, 0xB9, 0xB2, 0xAE, 0xAF, 0xBA, 0xE0, +0x67, 0x4C, 0x34, 0x2D, 0x2E, 0x30, 0x34, 0x37, 0x41, 0xF4, 0xCD, 0xCC, 0xC7, 0xC5, 0xD0, 0xED, +0x64, 0x4D, 0x45, 0x47, 0x43, 0x44, 0x4F, 0x51, 0x69, 0xD9, 0xDD, 0xD1, 0xCB, 0xD1, 0xCF, 0xD2, +0xCD, 0xBF, 0xBC, 0xB8, 0xB0, 0xAD, 0xAE, 0xBC, 0xD9, 0x76, 0x48, 0x32, 0x2D, 0x2F, 0x30, 0x32, +0x38, 0x49, 0xE6, 0xD1, 0xCB, 0xC1, 0xC1, 0xD2, 0x7A, 0x6F, 0x51, 0x42, 0x43, 0x45, 0x4A, 0x4D, +0x4E, 0x72, 0xD7, 0xDB, 0xD8, 0xCE, 0xCF, 0xD7, 0xDD, 0xD3, 0xC6, 0xBF, 0xBB, 0xB3, 0xAD, 0xAE, +0xB8, 0xCD, 0xE2, 0x52, 0x35, 0x2E, 0x2F, 0x2F, 0x2F, 0x35, 0x43, 0x62, 0xE5, 0xCF, 0xC1, 0xC0, +0xD1, 0xE1, 0xDB, 0x5E, 0x46, 0x49, 0x4D, 0x4A, 0x49, 0x51, 0x6A, 0xEE, 0xEB, 0xDE, 0xD0, 0xD4, +0xDF, 0xDC, 0xD7, 0xCF, 0xC5, 0xBE, 0xB7, 0xB1, 0xAE, 0xAF, 0xBC, 0xD3, 0xE7, 0x48, 0x31, 0x2E, +0x2F, 0x2E, 0x2F, 0x36, 0x44, 0x5B, 0xF4, 0xCC, 0xBF, 0xC2, 0xD4, 0xD1, 0xCF, 0x59, 0x4B, 0x51, +0x4B, 0x46, 0x44, 0x4C, 0x56, 0x51, 0x66, 0xE5, 0xE6, 0xE0, 0xDF, 0xD6, 0xD1, 0xCD, 0xC0, 0xBB, +0xB7, 0xB0, 0xAD, 0xB0, 0xBD, 0xCE, 0xEF, 0x44, 0x31, 0x2F, 0x30, 0x2E, 0x2E, 0x39, 0x46, 0x56, +0xF0, 0xC7, 0xBD, 0xC2, 0xC9, 0xC8, 0xCC, 0x7A, 0x50, 0x57, 0x4F, 0x42, 0x42, 0x4A, 0x4C, 0x4C, +0x5D, 0xEF, 0xEE, 0xE3, 0xD6, 0xD1, 0xD2, 0xCC, 0xC0, 0xBC, 0xBA, 0xB3, 0xAE, 0xAF, 0xBA, 0xC9, +0xD6, 0x4F, 0x36, 0x30, 0x30, 0x2E, 0x2D, 0x34, 0x3E, 0x45, 0x5C, 0xCF, 0xC1, 0xC0, 0xC1, 0xC0, +0xC9, 0xD9, 0xF5, 0x54, 0x4A, 0x47, 0x40, 0x41, 0x42, 0x45, 0x4E, 0x53, 0x68, 0xE8, 0xE1, 0xD1, +0xCD, 0xCC, 0xC5, 0xBF, 0xBB, 0xB8, 0xB4, 0xAF, 0xB0, 0xBD, 0xCB, 0xD8, 0x4B, 0x36, 0x34, 0x33, +0x2E, 0x2E, 0x37, 0x3D, 0x44, 0x62, 0xCD, 0xC4, 0xC0, 0xBE, 0xBF, 0xC5, 0xCF, 0xEE, 0x66, 0x4F, +0x45, 0x43, 0x40, 0x41, 0x44, 0x47, 0x51, 0x5B, 0x71, 0xDD, 0xD8, 0xCE, 0xC8, 0xC6, 0xC1, 0xBD, +0xB9, 0xB7, 0xB2, 0xAF, 0xB9, 0xC3, 0xCC, 0x71, 0x40, 0x37, 0x36, 0x31, 0x2E, 0x33, 0x3A, 0x3D, +0x4A, 0xE6, 0xCF, 0xC7, 0xBE, 0xBF, 0xC2, 0xCA, 0xD3, 0xE6, 0x50, 0x4C, 0x4B, 0x3E, 0x3E, 0x43, +0x41, 0x47, 0x4D, 0x59, 0x75, 0xE4, 0xD0, 0xCC, 0xC9, 0xC3, 0xBF, 0xBD, 0xBB, 0xB8, 0xB3, 0xB3, +0xBB, 0xC3, 0xCD, 0x6A, 0x42, 0x3A, 0x38, 0x31, 0x30, 0x36, 0x39, 0x3C, 0x4B, 0x7A, 0xDB, 0xCB, +0xC1, 0xC3, 0xC5, 0xC5, 0xD5, 0xE5, 0x6B, 0x4E, 0x4C, 0x43, 0x40, 0x45, 0x42, 0x48, 0x50, 0x55, +0x6C, 0xE8, 0xD7, 0xCD, 0xCC, 0xC7, 0xC3, 0xC0, 0xBD, 0xBC, 0xB8, 0xB2, 0xB5, 0xBD, 0xC2, 0xD0, +0x5D, 0x45, 0x3C, 0x38, 0x32, 0x32, 0x37, 0x37, 0x3C, 0x4C, 0x5E, 0xEE, 0xCD, 0xC5, 0xC8, 0xC6, +0xC5, 0xD0, 0xE2, 0xF9, 0x5D, 0x4D, 0x47, 0x46, 0x42, 0x41, 0x47, 0x4B, 0x4E, 0x63, 0xEA, 0xE3, +0xD3, 0xC9, 0xCB, 0xC8, 0xC0, 0xBF, 0xBD, 0xBA, 0xB5, 0xB6, 0xBC, 0xC1, 0xCC, 0x7E, 0x4B, 0x3F, +0x3B, 0x35, 0x32, 0x37, 0x37, 0x3A, 0x45, 0x50, 0x6D, 0xD7, 0xC8, 0xC6, 0xC7, 0xC2, 0xCA, 0xD7, +0xDB, 0x6D, 0x59, 0x4F, 0x48, 0x48, 0x45, 0x46, 0x4D, 0x4F, 0x5E, 0xFF, 0xE6, 0xD7, 0xD4, 0xCF, +0xD1, 0xD5, 0xD0, 0xD3, 0xCD, 0xC6, 0xC1, 0xBA, 0xB8, 0xBB, 0xC2, 0xC4, 0xCD, 0x58, 0x4C, 0x48, +0x39, 0x36, 0x39, 0x36, 0x37, 0x3E, 0x44, 0x4B, 0x66, 0xDC, 0xD4, 0xCA, 0xC3, 0xC5, 0xC7, 0xCA, +0xCE, 0xDD, 0x6D, 0x5F, 0x4F, 0x46, 0x47, 0x46, 0x43, 0x49, 0x4E, 0x53, 0x65, 0xF1, 0xE4, 0xD9, +0xCF, 0xCE, 0xCD, 0xC6, 0xC3, 0xC0, 0xBA, 0xB7, 0xB7, 0xBD, 0xC4, 0xC5, 0xFD, 0x4A, 0x4C, 0x3B, +0x33, 0x37, 0x34, 0x32, 0x3A, 0x3F, 0x47, 0x5B, 0xDC, 0xCB, 0xC8, 0xBE, 0xBC, 0xC3, 0xC0, 0xC7, +0xDE, 0xEC, 0x5B, 0x49, 0x45, 0x3F, 0x3E, 0x3F, 0x40, 0x49, 0x4E, 0x5B, 0xEF, 0xDF, 0xD4, 0xCC, +0xCA, 0xC7, 0xC5, 0xC3, 0xBF, 0xBD, 0xBB, 0xB8, 0xB8, 0xC0, 0xCB, 0xCA, 0x68, 0x45, 0x4D, 0x3D, +0x35, 0x3C, 0x3A, 0x38, 0x41, 0x49, 0x4D, 0x69, 0xDB, 0xD3, 0xCD, 0xC5, 0xC6, 0xCC, 0xCB, 0xD0, +0xEB, 0x76, 0x5C, 0x4C, 0x48, 0x44, 0x41, 0x41, 0x44, 0x49, 0x4E, 0x5D, 0x7E, 0xE6, 0xD4, 0xCE, +0xCE, 0xCB, 0xCB, 0xCE, 0xCE, 0xCA, 0xC9, 0xC6, 0xBE, 0xBC, 0xC6, 0xCA, 0xC4, 0xE0, 0x58, 0x77, +0x4A, 0x3D, 0x45, 0x3D, 0x39, 0x3F, 0x41, 0x40, 0x4C, 0x61, 0x6D, 0xE7, 0xCE, 0xCC, 0xCC, 0xC9, +0xCA, 0xD1, 0xDB, 0xE2, 0x66, 0x54, 0x50, 0x48, 0x45, 0x47, 0x47, 0x4B, 0x51, 0x5A, 0x71, 0xEB, +0xDD, 0xD5, 0xD2, 0xCF, 0xCC, 0xCC, 0xCA, 0xC4, 0xC3, 0xBF, 0xB9, 0xBD, 0xCB, 0xC0, 0xC9, 0x56, +0x71, 0x5A, 0x3A, 0x3F, 0x3E, 0x34, 0x3A, 0x3E, 0x3C, 0x42, 0x54, 0x62, 0x73, 0xCF, 0xC8, 0xCC, +0xC3, 0xC3, 0xCD, 0xCF, 0xDD, 0x6D, 0x56, 0x4D, 0x48, 0x42, 0x42, 0x44, 0x45, 0x4D, 0x57, 0x61, +0xED, 0xDB, 0xD5, 0xCD, 0xCD, 0xCD, 0xCD, 0xD0, 0xCD, 0xD1, 0xCA, 0xC4, 0xC7, 0xBA, 0xC2, 0xD8, +0xBB, 0xD7, 0x53, 0xCC, 0x4E, 0x3E, 0x57, 0x3E, 0x3B, 0x43, 0x3F, 0x3E, 0x46, 0x52, 0x50, 0x60, +0xD6, 0xD9, 0xD4, 0xC6, 0xCA, 0xCF, 0xCB, 0xD5, 0xF4, 0xFB, 0x5D, 0x4E, 0x4C, 0x4B, 0x46, 0x45, +0x4F, 0x4E, 0x4D, 0x7E, 0x6F, 0x71, 0xD4, 0xE1, 0xDF, 0xCE, 0xD9, 0xD5, 0xCD, 0xCD, 0xC5, 0xBF, +0xB9, 0xBA, 0xC6, 0xBA, 0xBF, 0x6C, 0xCE, 0xFB, 0x3D, 0x4D, 0x40, 0x35, 0x3C, 0x3B, 0x38, 0x3E, +0x47, 0x4B, 0x52, 0xDF, 0xD8, 0xD6, 0xC3, 0xC6, 0xCB, 0xC5, 0xCD, 0xDD, 0xE4, 0x6B, 0x50, 0x4D, +0x49, 0x44, 0x45, 0x47, 0x48, 0x49, 0x50, 0x5D, 0x5C, 0xEE, 0xDD, 0xE7, 0xD1, 0xD5, 0xDC, 0xD0, +0xDA, 0xD8, 0xD1, 0xCD, 0xC6, 0xBF, 0xBA, 0xC1, 0xC4, 0xBA, 0xD3, 0xE1, 0xCC, 0x4D, 0x49, 0x4F, +0x3B, 0x3B, 0x3E, 0x3A, 0x3C, 0x42, 0x4A, 0x4C, 0x6D, 0xD9, 0xDC, 0xC9, 0xC4, 0xCA, 0xC6, 0xC8, +0xD0, 0xD8, 0xE5, 0x68, 0x58, 0x53, 0x4C, 0x4A, 0x4B, 0x4C, 0x4E, 0x56, 0x5F, 0x69, 0xEA, 0xE0, +0xE8, 0xD5, 0xDD, 0xE7, 0xD9, 0xFB, 0xF9, 0xF5, 0x64, 0x75, 0x6D, 0xF5, 0xE5, 0xD8, 0xC8, 0xC4, +0xBB, 0xBF, 0xC4, 0xB7, 0xCC, 0xD6, 0xC3, 0x56, 0x52, 0x5F, 0x3D, 0x3E, 0x3E, 0x39, 0x3A, 0x3D, +0x41, 0x41, 0x4F, 0x6B, 0x63, 0xD6, 0xCD, 0xD1, 0xC7, 0xC8, 0xCE, 0xCE, 0xD6, 0xE8, 0x71, 0x67, +0x55, 0x4F, 0x52, 0x4D, 0x4F, 0x56, 0x56, 0x5E, 0x6D, 0x7E, 0xF5, 0xDF, 0xE3, 0xEE, 0xDC, 0x7B, +0x73, 0xED, 0x5C, 0x6A, 0x69, 0x5B, 0x70, 0x6D, 0xEF, 0xE1, 0xCF, 0xC8, 0xC4, 0xB9, 0xC5, 0xC2, +0xB6, 0xDC, 0xCD, 0xC3, 0x49, 0x60, 0x57, 0x3A, 0x40, 0x3D, 0x38, 0x3A, 0x3E, 0x3F, 0x3E, 0x53, +0x58, 0x59, 0xD3, 0xD7, 0xD2, 0xC4, 0xC9, 0xCA, 0xC8, 0xCD, 0xD8, 0xDE, 0xEE, 0x5F, 0x5D, 0x59, +0x4F, 0x54, 0x56, 0x54, 0x5D, 0x69, 0x6D, 0xF2, 0xE1, 0xDF, 0xDB, 0xD8, 0xDD, 0xE8, 0xEB, 0x71, +0x5D, 0x66, 0x56, 0x52, 0x62, 0x52, 0x5C, 0x74, 0x63, 0xE2, 0xDD, 0xD4, 0xCA, 0xC9, 0xBF, 0xC0, +0xBB, 0xBB, 0xCC, 0xBB, 0xC8, 0x68, 0xC8, 0x58, 0x44, 0x5D, 0x3C, 0x3B, 0x40, 0x3A, 0x3B, 0x3F, +0x44, 0x43, 0x52, 0x7A, 0x62, 0xD4, 0xCB, 0xD1, 0xC3, 0xC4, 0xC8, 0xC5, 0xCA, 0xD0, 0xD9, 0xE1, +0x6C, 0x5C, 0x5B, 0x4E, 0x4D, 0x50, 0x4C, 0x50, 0x58, 0x58, 0x63, 0x79, 0xFE, 0xED, 0xE1, 0xE7, +0xEE, 0xE6, 0xFB, 0x6D, 0x7A, 0x61, 0x5D, 0x62, 0x59, 0x5B, 0x5E, 0x5C, 0x64, 0x69, 0x72, 0xFE, +0xF1, 0xE6, 0xE2, 0xDB, 0xD9, 0xD6, 0xD3, 0xD3, 0xD0, 0xD0, 0xCF, 0xCE, 0xCD, 0xCD, 0xDA, 0xDB, +0xDA, 0x64, 0x69, 0x63, 0x4C, 0x4F, 0x4D, 0x46, 0x4A, 0x4A, 0x48, 0x4D, 0x52, 0x52, 0x5C, 0x70, +0x71, 0xEB, 0xDC, 0xDE, 0xD7, 0xD4, 0xD8, 0xD5, 0xD7, 0xDD, 0xDF, 0xE7, 0xFD, 0x71, 0x69, 0x5D, +0x5A, 0x5A, 0x57, 0x56, 0x5B, 0x59, 0x5A, 0x69, 0x62, 0x6A, 0xF5, 0x73, 0xF1, 0xE7, 0xF4, 0xE6, +0xE6, 0xEE, 0xEA, 0xED, 0xF5, 0xF1, 0xED, 0xF0, 0xEA, 0xE4, 0xE7, 0xDF, 0xDE, 0xDF, 0xDC, 0xDE, +0xDF, 0xE1, 0xE8, 0xEE, 0xFD, 0x77, 0x6B, 0x64, 0x61, 0x5C, 0x5C, 0x5C, 0x5B, 0x5F, 0x61, 0x67, +0x6E, 0x78, 0xF8, 0xF1, 0xEA, 0xE5, 0xE4, 0xE2, 0xE1, 0xE5, 0xEA, 0xED, 0xFA, 0x77, 0x6E, 0x66, +0x62, 0x5D, 0x5C, 0x5A, 0x59, 0x59, 0x59, 0x5B, 0x5C, 0x5D, 0x64, 0x64, 0x6C, 0x77, 0x7C, 0xEE, +0xEB, 0xE0, 0xDB, 0xD7, 0xCF, 0xCF, 0xCA, 0xC8, 0xC5, 0xC4, 0xCD, 0xC7, 0xCB, 0xE8, 0xD3, 0xFD, +0x55, 0x67, 0x4B, 0x45, 0x48, 0x40, 0x3F, 0x42, 0x43, 0x43, 0x4A, 0x50, 0x50, 0x6C, 0xF5, 0xF2, +0xD4, 0xD2, 0xD1, 0xCB, 0xCC, 0xCE, 0xCE, 0xD0, 0xDA, 0xDC, 0xDF, 0xFD, 0x7D, 0x6F, 0x5E, 0x5F, +0x5D, 0x59, 0x5A, 0x5C, 0x5C, 0x5F, 0x68, 0x68, 0x6F, 0xFC, 0xFC, 0xEF, 0xE9, 0xEB, 0xE9, 0xE9, +0xED, 0xEF, 0xF2, 0xF8, 0xFE, 0xFE, 0x7C, 0x7C, 0x7E, 0x79, 0xFE, 0xFB, 0xFE, 0xF7, 0xF6, 0xF9, +0xF6, 0xF8, 0xFD, 0xFF, 0x7C, 0x73, 0x70, 0x6E, 0x6A, 0x6A, 0x69, 0x68, 0x6A, 0x6B, 0x6C, 0x6F, +0x74, 0x79, 0xFF, 0xFA, 0xF8, 0xF2, 0xF4, 0xF6, 0xF3, 0xFE, 0xFB, 0x74, 0x62, 0x69, 0x5F, 0x5A, +0x66, 0x5B, 0x5D, 0x70, 0x61, 0x78, 0xED, 0xF4, 0xDB, 0xD7, 0xD0, 0xCB, 0xC9, 0xC3, 0xCC, 0xC9, +0xC4, 0xDD, 0xD2, 0xD7, 0x59, 0x6E, 0x57, 0x45, 0x4B, 0x45, 0x3F, 0x43, 0x44, 0x43, 0x49, 0x51, +0x4F, 0x5E, 0xFB, 0x70, 0xDE, 0xD8, 0xDC, 0xD1, 0xD2, 0xD7, 0xD4, 0xD6, 0xDD, 0xDF, 0xDF, 0xF1, +0xF2, 0xF2, 0x6F, 0x73, 0x72, 0x69, 0x6D, 0x6F, 0x6D, 0x72, 0x7B, 0x79, 0x7E, 0xF8, 0xFD, 0xF9, +0xF6, 0xFD, 0xFA, 0xFA, 0xFD, 0xFB, 0xFB, 0xFD, 0xFA, 0xF6, 0xF8, 0xF3, 0xF2, 0xF4, 0xEF, 0xF1, +0xF4, 0xF2, 0xF6, 0xF9, 0xF8, 0xF9, 0xFD, 0xFD, 0xFC, 0x7F, 0x7E, 0x7D, 0x79, 0x76, 0x74, 0x71, +0x6F, 0x6E, 0x6C, 0x6C, 0x6D, 0x6B, 0x6C, 0x6D, 0x6C, 0x71, 0x71, 0x70, 0x7E, 0x79, 0x7C, 0xFA, +0x7B, 0xFD, 0xFC, 0x7A, 0xFE, 0x7C, 0x78, 0x7B, 0x76, 0x76, 0x78, 0x77, 0x77, 0x7C, 0x7E, 0xFF, +0xF2, 0xF3, 0xED, 0xE7, 0xE8, 0xE0, 0xDE, 0xDC, 0xD7, 0xD8, 0xD3, 0xD4, 0xDA, 0xD7, 0xDF, 0xEB, +0xED, 0x6A, 0x60, 0x5C, 0x52, 0x4F, 0x4D, 0x4B, 0x4A, 0x4B, 0x4B, 0x4D, 0x50, 0x54, 0x5B, 0x66, +0x6F, 0xF1, 0xE6, 0xDF, 0xDA, 0xD8, 0xD8, 0xD7, 0xD9, 0xDB, 0xDE, 0xE2, 0xEA, 0xF1, 0xFA, 0x78, +0x70, 0x6D, 0x69, 0x68, 0x66, 0x65, 0x65, 0x66, 0x66, 0x67, 0x6A, 0x6B, 0x6C, 0x70, 0x74, 0x79, +0xFB, 0xF5, 0xEF, 0xEB, 0xE9, 0xE6, 0xE3, 0xE2, 0xE1, 0xE0, 0xE0, 0xE0, 0xE1, 0xE3, 0xE3, 0xE6, +0xE9, 0xEB, 0xEF, 0xF7, 0x7F, 0x75, 0x6E, 0x6A, 0x66, 0x62, 0x61, 0x5F, 0x5F, 0x60, 0x5F, 0x62, +0x65, 0x66, 0x6C, 0x6E, 0x72, 0x7D, 0xFE, 0xF6, 0xEF, 0xED, 0xE9, 0xE7, 0xE4, 0xE3, 0xE0, 0xDF, +0xE1, 0xDF, 0xE1, 0xE3, 0xE3, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xED, 0xF5, 0xF6, 0xF9, 0x75, +0x76, 0x6E, 0x66, 0x65, 0x5E, 0x5B, 0x5A, 0x56, 0x55, 0x54, 0x53, 0x54, 0x55, 0x57, 0x59, 0x5D, +0x60, 0x66, 0x70, 0x79, 0xFA, 0xF0, 0xEE, 0xEC, 0xED, 0xED, 0xF0, 0xF5, 0xF8, 0xFF, 0xFD, 0x7E, +0x7D, 0xFE, 0x7E, 0xFD, 0xF8, 0xF6, 0xEF, 0xED, 0xEB, 0xE8, 0xE4, 0xE3, 0xE0, 0xDF, 0xDE, 0xDC, +0xDD, 0xDC, 0xDD, 0xE1, 0xE2, 0xE9, 0xF3, 0x7A, 0x65, 0x61, 0x5B, 0x56, 0x56, 0x51, 0x50, 0x52, +0x50, 0x55, 0x58, 0x59, 0x5F, 0x68, 0x70, 0xFC, 0xEE, 0xE9, 0xE4, 0xE1, 0xE4, 0xE4, 0xE7, 0xED, +0xEE, 0xF8, 0xFF, 0x7D, 0x76, 0x76, 0x7A, 0x7B, 0xFF, 0xF9, 0xF7, 0xF1, 0xED, 0xED, 0xEB, 0xE9, +0xEA, 0xEA, 0xEC, 0xED, 0xEE, 0xF0, 0xF1, 0xF2, 0xF2, 0xF3, 0xF0, 0xF1, 0xF3, 0xEF, 0xF3, 0xF5, +0xF4, 0xFB, 0xFC, 0xFC, 0x7C, 0x7A, 0x76, 0x70, 0x6F, 0x6F, 0x6C, 0x6C, 0x6C, 0x68, 0x6B, 0x6B, +0x68, 0x6D, 0x6B, 0x6B, 0x6F, 0x6E, 0x70, 0x77, 0x76, 0x7A, 0x7F, 0xFF, 0xFD, 0xF6, 0xF7, 0xF5, +0xEF, 0xF4, 0xF1, 0xEF, 0xF2, 0xEE, 0xF0, 0xF1, 0xEE, 0xF0, 0xF1, 0xF1, 0xF2, 0xF6, 0xF9, 0xFA, +0x7F, 0x7E, 0x7A, 0x76, 0x7A, 0x73, 0x72, 0x74, 0x6F, 0x73, 0x75, 0x73, 0x75, 0x74, 0x76, 0x73, +0x77, 0x7A, 0x76, 0x7E, 0x78, 0x76, 0x7E, 0x76, 0x7A, 0x79, 0x74, 0x7D, 0x77, 0x77, 0x79, 0x74, +0x76, 0x77, 0x7A, 0x79, 0x7C, 0xFF, 0x79, 0xFC, 0xFA, 0x7E, 0xF4, 0xF9, 0xFC, 0xF6, 0x7E, 0xFF, +0xFF, 0x7B, 0x7C, 0x77, 0x75, 0x76, 0x78, 0x76, 0x74, 0x7B, 0x74, 0x75, 0x7E, 0x74, 0x7B, 0x7C, +0x72, 0x7A, 0x77, 0x74, 0x7A, 0x75, 0x72, 0x73, 0x72, 0x6E, 0x6E, 0x70, 0x6D, 0x70, 0x71, 0x6E, +0x75, 0x73, 0x72, 0x79, 0x78, 0x7B, 0xFF, 0xFF, 0xFD, 0xFA, 0xFC, 0xFB, 0xF7, 0xFD, 0xFE, 0xFA, +0x7D, 0x7D, 0xFE, 0x79, 0x7B, 0x7C, 0x7B, 0x7E, 0x7E, 0xFD, 0xFA, 0xFA, 0xF7, 0xF8, 0xF9, 0xF9, +0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x7D, 0x7B, 0x77, 0x78, 0x74, 0x71, 0x74, 0x6F, 0x6F, 0x71, 0x6D, +0x6F, 0x71, 0x6F, 0x73, 0x74, 0x77, 0x7B, 0x7D, 0x7F, 0xFF, 0xFC, 0xFE, 0xFB, 0xF8, 0xFB, 0xF7, +0xF9, 0xFE, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0x7E, 0x7C, 0x7E, 0x7B, 0x7B, 0x7E, 0x7C, 0xFF, 0xFE, +0xFE, 0xFB, 0xFE, 0xFF, 0xFD, 0xFE, 0x7E, 0x7F, 0x7A, 0x78, 0x79, 0x75, 0x74, 0x75, 0x73, 0x75, +0x77, 0x77, 0x79, 0x7B, 0x7D, 0xFF, 0xFA, 0xF8, 0xF4, 0xF2, 0xF5, 0xF1, 0xF2, 0xF6, 0xF3, 0xF6, +0xFA, 0xFB, 0xFC, 0x7D, 0x7A, 0x7A, 0x74, 0x77, 0x78, 0x74, 0x7A, 0x77, 0x7A, 0xFF, 0x7F, 0xF9, +0xFB, 0xFB, 0xF9, 0xFF, 0x7F, 0x7C, 0x7A, 0x77, 0x72, 0x73, 0x6E, 0x6E, 0x6E, 0x6D, 0x70, 0x70, +0x75, 0x7D, 0x7B, 0xFE, 0xFD, 0xFF, 0xFC, 0xFF, 0x7E, 0xFF, 0x7E, 0x7A, 0x79, 0x76, 0x6F, 0x72, +0x72, 0x6F, 0x73, 0x6F, 0x6E, 0x74, 0x72, 0x74, 0x7C, 0x7C, 0xFF, 0xF9, 0xFA, 0xF9, 0xF5, 0xF7, +0xF7, 0xF5, 0xFA, 0xFA, 0xF7, 0xFA, 0xF9, 0xF8, 0xFC, 0xF9, 0xF8, 0xFA, 0xF6, 0xF9, 0xFC, 0xFA, +0xFD, 0xFE, 0xFD, 0xFF, 0x7E, 0x7E, 0x7D, 0x7A, 0x7C, 0x7B, 0x79, 0x7C, 0x7B, 0x7B, 0xFF, 0x7E, +0xFF, 0xFC, 0xFE, 0xFE, 0xFB, 0xFD, 0x7C, 0x7F, 0x7F, 0x76, 0x78, 0x78, 0x74, 0x78, 0x78, 0x78, +0x7B, 0x7A, 0x7A, 0x79, 0x77, 0x78, 0x79, 0x78, 0x7A, 0x7B, 0x7A, 0x7C, 0x7F, 0x7D, 0xFF, 0xFC, +0xFD, 0xFA, 0xFB, 0xFD, 0xFE, 0xFF, 0x7F, 0x7D, 0x7C, 0x7A, 0x7B, 0x7D, 0x7D, 0x7E, 0x7E, 0x7D, +0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7F, 0xFF, 0xFE, 0xFC, 0xFC, 0xFB, +0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFB, 0xFB, 0xFD, 0xFF, 0x7D, 0x7B, 0x7B, 0x7A, 0x77, 0x77, 0x78, +0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7B, 0x7D, 0x7E, 0xFF, 0xFE, 0xFE, 0xFD, 0xFC, 0xFC, 0xFC, 0xFC, +0xFE, 0xFF, 0xFF, 0x7E, 0x7B, 0x78, 0x77, 0x76, 0x74, 0x73, 0x73, 0x71, 0x72, 0x73, 0x73, 0x74, +0x75, 0x76, 0x77, 0x77, 0x78, 0x78, 0x7A, 0x7D, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0x7F, 0x7E, 0x7D, 0x7D, 0x7C, 0x7A, 0x79, 0x79, 0x78, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7A, +0x79, 0x7B, 0x7B, 0x7B, 0x7C, 0x7A, 0x7A, 0x79, 0x78, 0x78, 0x76, 0x76, 0x75, 0x73, 0x73, 0x73, +0x74, 0x77, 0x79, 0x7A, 0x7D, 0x7F, 0xFE, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFF, +0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4C, 0x49, 0x53, 0x54, 0x4A, 0x00, +0x00, 0x00, 0x49, 0x4E, 0x46, 0x4F, 0x49, 0x53, 0x46, 0x54, 0x3E, 0x00, 0x00, 0x00, 0x46, 0x69, +0x6C, 0x65, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x6F, +0x6C, 0x64, 0x57, 0x61, 0x76, 0x65, 0x2E, 0x20, 0x20, 0x47, 0x6F, 0x6C, 0x64, 0x57, 0x61, 0x76, +0x65, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, +0x43, 0x68, 0x72, 0x69, 0x73, 0x20, 0x43, 0x72, 0x61, 0x69, 0x67, 0x00 + +}; + +static const uint8_t shaun_png[] PROGMEM = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x57, 0x08, 0x06, 0x00, 0x00, 0x00, 0xF2, 0x0C, 0xE0, + 0x57, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0, + 0xBD, 0xA7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x42, 0x8A, 0x00, + 0x00, 0x42, 0x8A, 0x01, 0x34, 0xA8, 0x6C, 0x25, 0x00, 0x00, 0x00, 0x09, 0x76, 0x70, 0x41, 0x67, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x57, 0x00, 0x73, 0x4D, 0x3B, 0xD6, 0x00, 0x00, 0x1B, + 0x47, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0xED, 0x9D, 0x79, 0x74, 0x14, 0x55, 0xBE, 0xC7, 0x3F, + 0x55, 0xDD, 0x49, 0x67, 0x5F, 0x3A, 0x7B, 0x42, 0x82, 0x61, 0x49, 0x02, 0x81, 0xB0, 0x29, 0x32, + 0x22, 0x3C, 0x16, 0x41, 0x45, 0x10, 0x15, 0x7D, 0x13, 0x65, 0xD0, 0x81, 0xE3, 0x7B, 0xCC, 0xD3, + 0x51, 0x04, 0xF5, 0xE1, 0xB8, 0xCE, 0xE6, 0x28, 0x22, 0x23, 0x33, 0x2C, 0x2A, 0x22, 0xEE, 0x02, + 0x22, 0x0C, 0x2A, 0x83, 0x28, 0x7B, 0x20, 0xC8, 0x92, 0x10, 0xD9, 0x97, 0x40, 0x08, 0x81, 0x90, + 0x3D, 0x64, 0x21, 0xE9, 0x4E, 0x3A, 0x5D, 0xF7, 0xFD, 0x71, 0xBB, 0x93, 0x0E, 0x10, 0xD2, 0x59, + 0x3A, 0x01, 0xCF, 0xFB, 0x9E, 0xD3, 0xE7, 0xA4, 0x6E, 0xA5, 0x6E, 0xDD, 0xFA, 0xFD, 0xEA, 0xFE, + 0xEE, 0xEF, 0xFE, 0xB6, 0x52, 0xB8, 0xFE, 0xA1, 0x03, 0x7A, 0x01, 0x43, 0x81, 0x9B, 0x80, 0x6A, + 0x60, 0x3F, 0xA0, 0x02, 0x8F, 0x00, 0xB7, 0x03, 0xA1, 0x80, 0x00, 0x72, 0x81, 0xAD, 0xC0, 0xC7, + 0xC0, 0x6E, 0xA0, 0xAE, 0xB3, 0x07, 0xFF, 0x4B, 0x43, 0x30, 0xF0, 0x67, 0x20, 0x1B, 0xB0, 0x20, + 0x89, 0xAE, 0x01, 0x95, 0x40, 0xB9, 0xED, 0xF8, 0x6A, 0xBF, 0x3C, 0xDB, 0x75, 0x81, 0xCD, 0xF4, + 0xAF, 0x03, 0x8C, 0x40, 0x2C, 0xD0, 0x13, 0x88, 0x00, 0x0C, 0x9D, 0xF9, 0xC0, 0x4A, 0x27, 0xDD, + 0xD7, 0x13, 0x88, 0x07, 0xFA, 0x03, 0x51, 0x36, 0x22, 0xE4, 0x03, 0x87, 0x80, 0x83, 0x48, 0x62, + 0x1B, 0x81, 0x85, 0x40, 0x72, 0x2B, 0xC7, 0xA9, 0x01, 0x5F, 0x00, 0x2F, 0x03, 0x35, 0xB6, 0xE3, + 0x0A, 0xDB, 0xDF, 0xDE, 0xC0, 0x48, 0x60, 0x22, 0x30, 0x08, 0xC9, 0x78, 0x3D, 0x92, 0xD1, 0x99, + 0xC0, 0x0F, 0xC0, 0x5A, 0xE0, 0x5C, 0x47, 0x13, 0xA6, 0xA3, 0x19, 0xA2, 0x07, 0x46, 0x00, 0x4F, + 0x22, 0x45, 0x4D, 0xD0, 0x65, 0x63, 0xB8, 0x84, 0x14, 0x47, 0xEF, 0x03, 0x09, 0xC0, 0x4B, 0x48, + 0xD1, 0x44, 0x40, 0x40, 0x00, 0x31, 0x31, 0x31, 0x54, 0x56, 0x56, 0x92, 0x93, 0x93, 0x83, 0xD5, + 0x6A, 0x25, 0x3A, 0x3A, 0x9A, 0x89, 0x13, 0x27, 0x32, 0x60, 0xC0, 0x00, 0xAC, 0x56, 0x2B, 0xBB, + 0x77, 0xEF, 0x66, 0xDD, 0xBA, 0x75, 0x14, 0x16, 0x16, 0xDA, 0xFB, 0xAB, 0x03, 0x4E, 0x23, 0x67, + 0x4D, 0x9D, 0x8D, 0xC0, 0xFB, 0x90, 0x22, 0xF0, 0x1E, 0xC0, 0xAB, 0x89, 0x71, 0x6A, 0xC0, 0x11, + 0xE0, 0x0D, 0xE0, 0x6B, 0xE4, 0xEC, 0xFC, 0xC5, 0xC1, 0x07, 0x78, 0x0D, 0x28, 0xA5, 0x69, 0x51, + 0x63, 0xFF, 0x99, 0x80, 0x2A, 0xFB, 0xF1, 0xC0, 0x81, 0x03, 0xC5, 0xA6, 0x4D, 0x9B, 0x44, 0x49, + 0x49, 0x89, 0xC8, 0xCA, 0xCA, 0x12, 0xAF, 0xBF, 0xFE, 0xBA, 0x78, 0xFC, 0xF1, 0xC7, 0x45, 0x5A, + 0x5A, 0x9A, 0xD0, 0x34, 0x4D, 0xD8, 0x51, 0x57, 0x57, 0x27, 0xB6, 0x6E, 0xDD, 0x2A, 0xFA, 0xF7, + 0xEF, 0xDF, 0x5C, 0xFF, 0x8D, 0x7E, 0x8A, 0xA2, 0x08, 0x55, 0x55, 0xAF, 0x76, 0xAE, 0x02, 0x78, + 0x0E, 0xF9, 0x22, 0x75, 0x08, 0x3A, 0x6A, 0x86, 0x78, 0x02, 0x7F, 0x05, 0x9E, 0x02, 0xDC, 0x00, + 0x14, 0x45, 0x21, 0x24, 0x24, 0x84, 0xE8, 0xE8, 0x68, 0xDC, 0xDD, 0xDD, 0xB9, 0x70, 0xE1, 0x02, + 0xB9, 0xB9, 0xB9, 0xD4, 0xD5, 0x35, 0x5E, 0x87, 0xBD, 0xBC, 0xBC, 0x58, 0xB1, 0x62, 0x05, 0x13, + 0x26, 0x4C, 0xA8, 0x6F, 0x13, 0x42, 0x20, 0x84, 0x40, 0x55, 0xD5, 0xAB, 0xDE, 0x6C, 0xD7, 0xAE, + 0x5D, 0x3C, 0xFC, 0xF0, 0xC3, 0xE4, 0xE4, 0xE4, 0x34, 0xFD, 0xE0, 0x8A, 0x42, 0x7C, 0x7C, 0x3C, + 0xF7, 0xDC, 0x73, 0x0F, 0xFD, 0xFA, 0xF5, 0xC3, 0xC3, 0xC3, 0x83, 0xEC, 0xEC, 0x6C, 0x36, 0x6C, + 0xD8, 0x40, 0x6A, 0x6A, 0x2A, 0x35, 0x35, 0x35, 0xF6, 0x7F, 0xAD, 0xB4, 0x8D, 0xFB, 0x73, 0xC0, + 0xDA, 0x41, 0xF4, 0x72, 0x39, 0x7E, 0x8F, 0x7C, 0xEB, 0x05, 0x20, 0xC2, 0xC2, 0xC2, 0xC4, 0x2B, + 0xAF, 0xBC, 0x22, 0x0E, 0x1E, 0x3C, 0x28, 0x2E, 0x5E, 0xBC, 0x28, 0x2A, 0x2A, 0x2A, 0x44, 0x56, + 0x56, 0x96, 0x58, 0xBC, 0x78, 0xB1, 0x48, 0x48, 0x48, 0x68, 0xF4, 0x96, 0xC6, 0xC4, 0xC4, 0x88, + 0x33, 0x67, 0xCE, 0x88, 0x96, 0xE2, 0xE3, 0x8F, 0x3F, 0x16, 0x77, 0xDE, 0x79, 0xA7, 0x78, 0xFE, + 0xF9, 0xE7, 0xC5, 0xBB, 0xEF, 0xBE, 0x2B, 0xDE, 0x7E, 0xFB, 0x6D, 0xF1, 0xE0, 0x83, 0x0F, 0x0A, + 0xA3, 0xD1, 0x28, 0xDC, 0xDC, 0xDC, 0xC4, 0xD4, 0xA9, 0x53, 0xC5, 0xE9, 0xD3, 0xA7, 0xAF, 0xB8, + 0xAE, 0xA2, 0xA2, 0x42, 0x2C, 0x58, 0xB0, 0x40, 0x04, 0x07, 0x07, 0x3B, 0x8E, 0xA3, 0x00, 0x58, + 0x0D, 0xFC, 0x0E, 0x08, 0xEF, 0x6C, 0x62, 0xB6, 0x15, 0x7D, 0x80, 0x33, 0xF6, 0x87, 0x8B, 0x8D, + 0x8D, 0x15, 0xEB, 0xD7, 0xAF, 0x6F, 0x24, 0x6A, 0x1C, 0x91, 0x91, 0x91, 0x21, 0x06, 0x0F, 0x1E, + 0x2C, 0x00, 0x61, 0x30, 0x18, 0xC4, 0xAF, 0x7F, 0xFD, 0x6B, 0x51, 0x51, 0x51, 0xD1, 0x62, 0x86, + 0x58, 0xAD, 0x56, 0x61, 0x36, 0x9B, 0x1B, 0xDD, 0xA7, 0xA6, 0xA6, 0x46, 0xEC, 0xD8, 0xB1, 0x43, + 0xAC, 0x5A, 0xB5, 0x4A, 0x94, 0x97, 0x97, 0x37, 0x79, 0xAD, 0xA6, 0x69, 0x62, 0xF1, 0xE2, 0xC5, + 0xC2, 0xC3, 0xC3, 0xE3, 0x72, 0x11, 0x66, 0x05, 0x76, 0x02, 0x43, 0x3A, 0x9B, 0xA8, 0x6D, 0xC1, + 0xDB, 0xF6, 0x07, 0xF2, 0xF5, 0xF5, 0x15, 0x2B, 0x56, 0xAC, 0x68, 0x96, 0x98, 0xC7, 0x8E, 0x1D, + 0x13, 0xF3, 0xE7, 0xCF, 0x17, 0x1B, 0x36, 0x6C, 0x10, 0xA5, 0xA5, 0xA5, 0x2D, 0x66, 0x46, 0x7B, + 0xA0, 0xB2, 0xB2, 0x52, 0x4C, 0x98, 0x30, 0xA1, 0xA9, 0x75, 0xE7, 0x00, 0x52, 0x31, 0x68, 0x77, + 0xB8, 0x7A, 0x0D, 0x89, 0x02, 0x36, 0xDA, 0x07, 0x3F, 0x79, 0xF2, 0x64, 0x3E, 0xFC, 0xF0, 0x43, + 0x0C, 0x86, 0x4E, 0x55, 0xF5, 0x9D, 0xC6, 0xC1, 0x83, 0x07, 0x59, 0xBB, 0x76, 0x2D, 0x16, 0x8B, + 0x85, 0x94, 0x94, 0x14, 0x52, 0x53, 0x53, 0xB1, 0x5A, 0xEB, 0x97, 0x91, 0xF7, 0x91, 0xDA, 0xE2, + 0x0D, 0xB5, 0xAE, 0x8C, 0x07, 0xCC, 0x80, 0xF0, 0xF4, 0xF4, 0x14, 0xEB, 0xD6, 0xAD, 0xEB, 0x94, + 0xB7, 0xBD, 0x3D, 0x50, 0x54, 0x54, 0x24, 0x92, 0x93, 0x93, 0x1D, 0x67, 0x49, 0x36, 0xD0, 0xBD, + 0xB3, 0x09, 0xDC, 0x12, 0x84, 0x00, 0xAB, 0xEC, 0x0F, 0x10, 0x1F, 0x1F, 0x2F, 0x72, 0x73, 0x73, + 0x3B, 0x9B, 0xAE, 0x6D, 0xC2, 0x96, 0x2D, 0x5B, 0x84, 0x8F, 0x8F, 0x8F, 0xA3, 0x6A, 0x7E, 0x47, + 0x7B, 0x13, 0x4D, 0x6D, 0x7B, 0x17, 0x57, 0x85, 0x37, 0x72, 0x53, 0x35, 0xC9, 0xDE, 0xD0, 0xAD, + 0x5B, 0x37, 0x8C, 0x46, 0xA3, 0x8B, 0x6E, 0xD7, 0x31, 0xF0, 0xF5, 0xF5, 0x45, 0xAF, 0xAF, 0xDF, + 0x92, 0xA8, 0x80, 0x47, 0x7B, 0xDF, 0xC3, 0x55, 0x0C, 0xF9, 0x4F, 0xE0, 0x37, 0xD8, 0xD6, 0xA8, + 0x84, 0x84, 0x04, 0x9E, 0x7E, 0xFA, 0x69, 0x3C, 0x3C, 0xDA, 0x7D, 0xFC, 0x1D, 0x8A, 0x5D, 0xBB, + 0x76, 0x51, 0x56, 0x56, 0x66, 0x3F, 0xAC, 0x42, 0xDA, 0xCC, 0xDA, 0x15, 0xAE, 0xD8, 0x81, 0x1A, + 0x81, 0xC7, 0xB1, 0x19, 0xE9, 0x12, 0x12, 0x12, 0xF8, 0xEC, 0xB3, 0xCF, 0xB8, 0xF9, 0xE6, 0x9B, + 0x5D, 0x44, 0xA6, 0x8E, 0x43, 0x5E, 0x5E, 0x23, 0xFA, 0x0B, 0x5C, 0xF7, 0x42, 0xB7, 0x2B, 0x46, + 0x21, 0x6D, 0x52, 0x42, 0xAF, 0xD7, 0x8B, 0x25, 0x4B, 0x96, 0x74, 0xB6, 0xE8, 0x6F, 0x37, 0xEC, + 0xDD, 0xBB, 0x57, 0x84, 0x86, 0x86, 0x3A, 0x2E, 0xEC, 0xB3, 0xDB, 0x9B, 0x78, 0xAE, 0xE0, 0x70, + 0x12, 0x72, 0x0D, 0xA1, 0x6B, 0xD7, 0xAE, 0x8C, 0x1D, 0x3B, 0xD6, 0x85, 0xBC, 0xEF, 0x58, 0x24, + 0x25, 0x25, 0x31, 0x64, 0x48, 0xA3, 0x3D, 0xE1, 0x2D, 0xB4, 0xB3, 0x94, 0x71, 0x05, 0x43, 0x22, + 0xED, 0x7F, 0x44, 0x47, 0x47, 0x13, 0x12, 0x12, 0xE2, 0x1A, 0xEA, 0x74, 0x02, 0x0C, 0x06, 0x03, + 0x89, 0x89, 0x89, 0x8E, 0x4D, 0x51, 0x48, 0x3B, 0x5D, 0xBB, 0xC1, 0x15, 0x0C, 0xA9, 0xEF, 0x53, + 0xA7, 0xD3, 0x35, 0x69, 0x00, 0xBC, 0x51, 0xE1, 0xEB, 0xEB, 0xEB, 0x78, 0x68, 0xE0, 0x06, 0x98, + 0x21, 0xF5, 0xCE, 0x88, 0xBC, 0xBC, 0x3C, 0x47, 0xAD, 0xE4, 0x17, 0x81, 0xD2, 0xD2, 0x52, 0xC7, + 0xC3, 0x6A, 0xDA, 0xD9, 0x57, 0xE2, 0x0A, 0x86, 0x1C, 0x46, 0xEE, 0xCE, 0xC9, 0xCA, 0xCA, 0x22, + 0x35, 0x35, 0xD5, 0x65, 0xC4, 0xE9, 0x68, 0x54, 0x55, 0x55, 0x91, 0x91, 0x91, 0xE1, 0xD8, 0x94, + 0x8D, 0x64, 0xCA, 0x75, 0x8D, 0x70, 0xE0, 0x67, 0x6C, 0x9A, 0xC8, 0xD0, 0xA1, 0x43, 0x45, 0x76, + 0x76, 0x76, 0x67, 0x2B, 0x48, 0xED, 0x82, 0x1F, 0x7E, 0xF8, 0x41, 0xF8, 0xF9, 0xF9, 0x39, 0x6A, + 0x59, 0x4F, 0x74, 0x36, 0xB1, 0x9D, 0xC5, 0x73, 0x48, 0xA3, 0x9B, 0x00, 0xC4, 0xC8, 0x91, 0x23, + 0xC5, 0x8F, 0x3F, 0xFE, 0x28, 0xCC, 0x66, 0xB3, 0xCB, 0x88, 0x65, 0xB5, 0x5A, 0x5D, 0xCA, 0x8C, + 0xAC, 0xAC, 0x2C, 0x31, 0x6C, 0xD8, 0x30, 0x47, 0x66, 0x64, 0x01, 0x71, 0x9D, 0x4D, 0x68, 0x67, + 0x61, 0x04, 0xD6, 0x39, 0x0C, 0x5E, 0xF8, 0xF8, 0xF8, 0x88, 0x05, 0x0B, 0x16, 0xB8, 0x84, 0x58, + 0x99, 0x99, 0x99, 0x62, 0xFA, 0xF4, 0xE9, 0x62, 0xD9, 0xB2, 0x65, 0xC2, 0x64, 0x32, 0x5D, 0x71, + 0x5E, 0xD3, 0x34, 0x71, 0xEE, 0xDC, 0x39, 0x91, 0x97, 0x97, 0xD7, 0xAA, 0xFE, 0x4F, 0x9E, 0x3C, + 0x29, 0x46, 0x8C, 0x18, 0x71, 0xB9, 0x09, 0xFE, 0xF5, 0xCE, 0x26, 0xB2, 0xB3, 0x08, 0x46, 0x5A, + 0x79, 0x1B, 0x31, 0x04, 0x10, 0x49, 0x49, 0x49, 0x22, 0x27, 0x27, 0xA7, 0x5D, 0x99, 0x61, 0xB5, + 0x5A, 0xC5, 0x8C, 0x19, 0x33, 0x04, 0x20, 0xBC, 0xBC, 0xBC, 0xC4, 0xA3, 0x8F, 0x3E, 0x2A, 0x36, + 0x6F, 0xDE, 0x2C, 0xCE, 0x9F, 0x3F, 0x2F, 0x0A, 0x0B, 0x0B, 0xC5, 0xE1, 0xC3, 0x87, 0xC5, 0xDC, + 0xB9, 0x73, 0x45, 0x42, 0x42, 0x82, 0x18, 0x33, 0x66, 0x8C, 0x28, 0x28, 0x28, 0x68, 0xF1, 0x3D, + 0x96, 0x2E, 0x5D, 0x7A, 0x39, 0x33, 0x34, 0x60, 0x3B, 0xF0, 0xDF, 0x40, 0x37, 0x64, 0x38, 0xD1, + 0x75, 0x87, 0x28, 0xA4, 0xEF, 0x79, 0x2F, 0x36, 0x93, 0x3B, 0x57, 0x09, 0x26, 0x98, 0x35, 0x6B, + 0x56, 0xBB, 0x8A, 0xAE, 0x6D, 0xDB, 0xB6, 0x89, 0xD0, 0xD0, 0x50, 0xE1, 0xED, 0x69, 0x10, 0xE1, + 0xC1, 0x01, 0x02, 0x10, 0x9E, 0x5E, 0x5E, 0xA2, 0x5B, 0xB7, 0xEE, 0xA2, 0x57, 0xAF, 0x5E, 0x22, + 0x38, 0x24, 0x44, 0x28, 0x8A, 0x22, 0x00, 0xE1, 0xE6, 0xE6, 0x26, 0x3E, 0xFA, 0xE8, 0xA3, 0x16, + 0xDF, 0x63, 0xCD, 0x9A, 0x35, 0x42, 0xAF, 0xD7, 0x5F, 0xCD, 0x51, 0x55, 0x87, 0x14, 0x5D, 0x0B, + 0x80, 0x5B, 0x01, 0xF7, 0xB6, 0x12, 0xB1, 0x3D, 0x38, 0x1B, 0x0A, 0x4C, 0x07, 0xE6, 0x21, 0x0D, + 0x8A, 0x5D, 0x70, 0xD0, 0xCD, 0x75, 0x3A, 0x1D, 0xE1, 0xE1, 0xE1, 0x24, 0x25, 0x25, 0x61, 0x36, + 0x9B, 0x49, 0x4D, 0x4D, 0xC5, 0x64, 0x32, 0xD1, 0xB7, 0x6F, 0x5F, 0x7C, 0x7C, 0x7C, 0x00, 0x19, + 0xB4, 0x50, 0x50, 0x50, 0x40, 0x59, 0x59, 0x19, 0xBE, 0xBE, 0xBE, 0x28, 0x8A, 0x73, 0x7E, 0xB3, + 0xEC, 0xEC, 0x6C, 0x9E, 0x7E, 0xFA, 0x69, 0x8E, 0x1D, 0x3B, 0xC6, 0x8C, 0x87, 0xC7, 0x31, 0x77, + 0xC6, 0x14, 0x02, 0xFD, 0x7C, 0xA8, 0xAA, 0x36, 0x51, 0x5A, 0x5A, 0x42, 0x65, 0x45, 0x39, 0x81, + 0x3E, 0x06, 0xEE, 0xFC, 0x55, 0x7F, 0x86, 0x0D, 0x48, 0x20, 0xFD, 0xE8, 0x69, 0xB2, 0xB3, 0xCF, + 0x72, 0xC7, 0x1D, 0x77, 0xB4, 0xC8, 0xF2, 0xBC, 0x7E, 0xFD, 0x7A, 0x36, 0x6C, 0xD8, 0x80, 0x9F, + 0x9F, 0x1F, 0x3A, 0x9D, 0x0E, 0x8B, 0xA5, 0x5E, 0xD3, 0x55, 0x91, 0xC1, 0x78, 0x83, 0x81, 0xFB, + 0x81, 0xDE, 0x40, 0x11, 0xD2, 0xE8, 0xA8, 0xB5, 0x03, 0x6D, 0x5B, 0x04, 0x37, 0xA4, 0x68, 0x4A, + 0x45, 0xBE, 0x29, 0x8D, 0x66, 0x42, 0x97, 0x2E, 0x5D, 0xC4, 0x23, 0x8F, 0x3C, 0x22, 0x3E, 0xF9, + 0xE4, 0x13, 0x71, 0xEC, 0xD8, 0x31, 0x51, 0x55, 0x55, 0x25, 0x5E, 0x7A, 0xE9, 0x25, 0x01, 0x08, + 0x9D, 0x4E, 0x27, 0x06, 0x0E, 0x1A, 0x24, 0x66, 0xCF, 0x9E, 0x2D, 0xE6, 0xCF, 0x9F, 0x2F, 0x66, + 0xCE, 0x9C, 0x29, 0xFA, 0xF4, 0xE9, 0x23, 0x7A, 0xF7, 0xEE, 0x2D, 0xD6, 0xAC, 0x59, 0xE3, 0xD4, + 0x02, 0x9D, 0x99, 0x99, 0x29, 0xC6, 0x8D, 0x1B, 0x27, 0x95, 0x86, 0x9B, 0x13, 0x45, 0xEE, 0x86, + 0x25, 0x42, 0x64, 0xAC, 0x16, 0x5A, 0xFA, 0x2A, 0x51, 0xB6, 0xED, 0x63, 0x71, 0xFA, 0x9B, 0x05, + 0xE2, 0xF8, 0xD7, 0xF3, 0xC5, 0x85, 0x0D, 0xEF, 0x0B, 0xCB, 0xDE, 0x15, 0xA2, 0x74, 0xFB, 0x27, + 0x62, 0xFC, 0xB0, 0x41, 0x02, 0x10, 0x77, 0xDF, 0x7D, 0xB7, 0x38, 0x7A, 0xF4, 0x68, 0xA3, 0xFE, + 0x34, 0x4D, 0x13, 0xFB, 0xF7, 0xEF, 0x17, 0x6F, 0xBD, 0xF5, 0x96, 0xD8, 0xBD, 0x7B, 0xB7, 0xB0, + 0x58, 0x2C, 0xC2, 0x62, 0xB1, 0x88, 0x6D, 0xDB, 0xB6, 0x89, 0xB8, 0xB8, 0x38, 0xE1, 0xEE, 0xEE, + 0x2E, 0xDE, 0x7B, 0xEF, 0x3D, 0xB1, 0x69, 0xD3, 0x26, 0xF1, 0xDC, 0x73, 0xCF, 0x89, 0x7E, 0xFD, + 0xFA, 0x09, 0x77, 0x77, 0xF7, 0xAB, 0xCD, 0x9A, 0x12, 0xE0, 0x03, 0x64, 0x10, 0x60, 0x87, 0xC5, + 0xBD, 0x45, 0x20, 0x67, 0x44, 0x99, 0xE3, 0x60, 0x74, 0x3A, 0x9D, 0x48, 0x4A, 0x4A, 0x12, 0x6F, + 0xBE, 0xF9, 0xA6, 0x38, 0x76, 0xEC, 0x98, 0xB0, 0x58, 0x2C, 0xF5, 0x0F, 0x6C, 0x32, 0x99, 0xC4, + 0xA4, 0x49, 0x93, 0x04, 0x20, 0xBA, 0x84, 0x1A, 0x85, 0xA7, 0xC1, 0xAD, 0xD1, 0x83, 0x78, 0xB8, + 0xBB, 0x09, 0x9D, 0xAA, 0x8A, 0xA0, 0xA0, 0x20, 0xF1, 0xDA, 0x6B, 0xAF, 0x89, 0xB3, 0x67, 0xCF, + 0x5E, 0x35, 0x10, 0xA2, 0xA2, 0xA2, 0x42, 0xAC, 0x5C, 0xB9, 0x52, 0x0C, 0x18, 0x30, 0x40, 0x00, + 0xE2, 0x96, 0xDE, 0xDD, 0xC5, 0xC1, 0x95, 0x6F, 0x0B, 0xB1, 0xFF, 0x6B, 0x21, 0xD2, 0xBE, 0x92, + 0xBF, 0xF4, 0x55, 0x42, 0xEC, 0x5F, 0x25, 0xDB, 0xD2, 0x57, 0xC9, 0xB6, 0xFD, 0x5F, 0x8B, 0xC3, + 0x5F, 0xFD, 0x5D, 0x0C, 0x4E, 0xEC, 0x21, 0x00, 0xD1, 0xA3, 0x47, 0x0F, 0xF1, 0x87, 0x3F, 0xFC, + 0x41, 0xAC, 0x5A, 0xB5, 0x4A, 0xAC, 0x5C, 0xB9, 0x52, 0xCC, 0x9A, 0x35, 0x4B, 0xC4, 0xC4, 0xC4, + 0x08, 0x40, 0x84, 0x87, 0x87, 0x8B, 0xFB, 0xEE, 0xBB, 0x4F, 0x4C, 0x9C, 0x38, 0xB1, 0xDE, 0x98, + 0x38, 0x79, 0xF2, 0xE4, 0xFA, 0x60, 0x0B, 0x4D, 0xD3, 0x44, 0x7E, 0x7E, 0xBE, 0x58, 0xBE, 0x7C, + 0xB9, 0x18, 0x3F, 0x7E, 0xBC, 0xF0, 0xF5, 0xF5, 0xBD, 0x1A, 0x63, 0xCE, 0x21, 0x8D, 0x8F, 0xC1, + 0x2D, 0x21, 0x6C, 0x4B, 0x39, 0xA8, 0x20, 0x83, 0x9E, 0x5F, 0x07, 0x86, 0x39, 0x5E, 0x1F, 0x17, + 0x17, 0xC7, 0xF4, 0xE9, 0xD3, 0x49, 0x4E, 0x4E, 0x26, 0x32, 0x32, 0xF2, 0x8A, 0x0B, 0x77, 0xEC, + 0xD8, 0xC1, 0x84, 0x09, 0x13, 0xF0, 0xD4, 0x2B, 0x2C, 0xFF, 0xDB, 0x33, 0x58, 0xEA, 0xEA, 0x48, + 0x3B, 0x7A, 0x9A, 0xD2, 0x8A, 0x4B, 0x04, 0x07, 0xF8, 0x31, 0xA8, 0x57, 0x37, 0x52, 0x7F, 0x3E, + 0xCE, 0x3F, 0x96, 0xAF, 0xA7, 0xEC, 0x52, 0x35, 0x71, 0xF1, 0xF1, 0xDC, 0x39, 0x76, 0x2C, 0x03, + 0x07, 0x0E, 0x24, 0x28, 0x28, 0x88, 0xAA, 0xAA, 0x2A, 0x4E, 0x9C, 0x38, 0xC1, 0x96, 0x2D, 0x5B, + 0xD8, 0xB3, 0x67, 0x0F, 0x96, 0xDA, 0x5A, 0xEE, 0xBA, 0xAD, 0x3F, 0x73, 0x9F, 0x99, 0x42, 0xAF, + 0x6E, 0xD1, 0xA0, 0x39, 0x21, 0x21, 0x54, 0x95, 0x13, 0x67, 0xCE, 0xF3, 0xA7, 0x25, 0xAB, 0xF8, + 0x76, 0x7B, 0x1A, 0x55, 0xE6, 0x1A, 0xDB, 0x23, 0x08, 0x00, 0x02, 0x7C, 0xBD, 0x49, 0xEA, 0x19, + 0xC3, 0xD1, 0xAC, 0xF3, 0x14, 0x97, 0x55, 0xA2, 0x28, 0x0A, 0xE1, 0xE1, 0xE1, 0x24, 0x27, 0x27, + 0x33, 0x7B, 0xF6, 0x6C, 0xC2, 0xC2, 0xC2, 0xAE, 0xE8, 0xB2, 0xBA, 0xBA, 0x9A, 0xD4, 0xD4, 0x54, + 0x96, 0x2E, 0x5D, 0xCA, 0xF7, 0xDF, 0x7F, 0x4F, 0x65, 0x65, 0xA5, 0xE3, 0x69, 0x2B, 0xB0, 0x03, + 0xF8, 0x13, 0x90, 0x82, 0x13, 0x62, 0xAC, 0x25, 0x0C, 0x71, 0x03, 0x26, 0x03, 0x7F, 0x41, 0xAE, + 0x13, 0x80, 0xB4, 0xED, 0x4C, 0x99, 0x32, 0x85, 0x99, 0x33, 0x67, 0xD2, 0xA3, 0x47, 0x8F, 0xAB, + 0x5E, 0x28, 0x84, 0x60, 0xC6, 0x8C, 0x19, 0x2C, 0x58, 0xB0, 0x80, 0xA9, 0xF7, 0x8E, 0x64, 0xC9, + 0x2B, 0xBF, 0xB3, 0x79, 0xDE, 0x84, 0xA4, 0x85, 0x22, 0x87, 0x52, 0x67, 0xA9, 0x63, 0xEB, 0xDE, + 0x43, 0xFC, 0x73, 0xE5, 0xF7, 0x6C, 0x4F, 0x3F, 0x42, 0x65, 0xB5, 0x59, 0x0E, 0x52, 0x51, 0x11, + 0x42, 0x3E, 0x8B, 0x5E, 0xA7, 0x92, 0xD8, 0x2D, 0x9A, 0x69, 0x13, 0x47, 0x32, 0xE5, 0x9E, 0xFF, + 0x20, 0xD0, 0xDF, 0xD7, 0x39, 0x66, 0x38, 0x30, 0xA5, 0xDA, 0x64, 0x66, 0xD7, 0x81, 0x13, 0x6C, + 0xD9, 0x77, 0x98, 0xAC, 0xDC, 0x02, 0x54, 0x45, 0xA1, 0x67, 0x4C, 0x04, 0x63, 0x6E, 0x4D, 0x62, + 0x50, 0xAF, 0x6E, 0x7C, 0xBA, 0x6E, 0x3B, 0x4F, 0xCE, 0x59, 0x4A, 0x78, 0x44, 0x24, 0x5F, 0x7E, + 0xF9, 0x25, 0x43, 0x87, 0x0E, 0x45, 0xA7, 0xBB, 0xF6, 0x72, 0x6B, 0x36, 0x9B, 0xD9, 0xB6, 0x6D, + 0x1B, 0x0B, 0x17, 0x2E, 0x64, 0xD3, 0xA6, 0x4D, 0x8E, 0x81, 0x76, 0x20, 0xE3, 0xBA, 0xDE, 0x04, + 0x96, 0xD0, 0xCC, 0xCE, 0xDE, 0x59, 0x86, 0xF8, 0x02, 0xFF, 0x0B, 0x3C, 0x83, 0x0C, 0x09, 0x05, + 0x20, 0x31, 0x31, 0x91, 0x3F, 0xFE, 0xF1, 0x8F, 0xDC, 0x7B, 0xEF, 0xBD, 0xB8, 0xBB, 0x37, 0xAD, + 0x60, 0x9C, 0x39, 0x73, 0x86, 0x31, 0x63, 0xC7, 0x92, 0x9B, 0x73, 0x96, 0x7F, 0xCD, 0x7B, 0x9E, + 0xBB, 0x6E, 0x1F, 0x08, 0xD6, 0x26, 0x88, 0xA8, 0x53, 0xA9, 0xAA, 0x32, 0xF1, 0xF3, 0xF1, 0x33, + 0xEC, 0x3C, 0x70, 0x82, 0xE3, 0xD9, 0xB9, 0x54, 0x5C, 0xAA, 0xC6, 0xD3, 0xC3, 0x40, 0x4C, 0x78, + 0x30, 0x83, 0x13, 0xBB, 0x33, 0xA4, 0x6F, 0x1C, 0xE1, 0x21, 0x81, 0x36, 0xE1, 0x20, 0x9C, 0x67, + 0x86, 0xE3, 0x53, 0xAB, 0x2A, 0x08, 0xD0, 0xEA, 0xAC, 0xA0, 0x80, 0xAA, 0xD3, 0xD5, 0x4F, 0x96, + 0xBC, 0xA2, 0x52, 0xEE, 0x7A, 0xF2, 0xAF, 0x1C, 0x3D, 0x9B, 0xC7, 0x8A, 0xE5, 0xCB, 0x99, 0x34, + 0x69, 0x92, 0xD3, 0x5D, 0x57, 0x56, 0x56, 0xB2, 0x62, 0xC5, 0x0A, 0xE6, 0xCD, 0x9B, 0xC7, 0x89, + 0x13, 0x27, 0x1C, 0x4F, 0xD5, 0x00, 0xCB, 0x80, 0x57, 0x81, 0xE2, 0xB6, 0x30, 0x24, 0x10, 0x29, + 0xA2, 0xFE, 0x0B, 0x9B, 0xF6, 0xA4, 0xD7, 0xEB, 0x79, 0xE0, 0x81, 0x07, 0xF8, 0xF3, 0x9F, 0xFF, + 0x4C, 0x7C, 0x7C, 0x7C, 0xB3, 0x1D, 0x2C, 0x59, 0xB2, 0x84, 0xE9, 0xD3, 0xA7, 0x33, 0x6C, 0x40, + 0x02, 0xDF, 0xBE, 0xF3, 0x02, 0x01, 0xBE, 0xDE, 0xD7, 0x26, 0xA4, 0x9D, 0x60, 0x80, 0xB0, 0x6A, + 0x68, 0x9A, 0x86, 0xAA, 0x28, 0x28, 0x3A, 0x1D, 0x28, 0x8A, 0x9C, 0x11, 0xAD, 0x61, 0x84, 0xB3, + 0x50, 0x14, 0x5E, 0x5A, 0xB4, 0x9C, 0xBF, 0x2D, 0x5B, 0x43, 0x72, 0x72, 0x32, 0x9F, 0x7E, 0xFA, + 0x29, 0x6E, 0x6E, 0x6E, 0x2D, 0xEA, 0x22, 0x33, 0x33, 0x93, 0xD7, 0x5F, 0x7F, 0x9D, 0x15, 0x2B, + 0x56, 0x38, 0xCE, 0x16, 0x0D, 0x19, 0x01, 0x39, 0x13, 0x99, 0xCB, 0x72, 0x05, 0x9A, 0x33, 0x2E, + 0x86, 0x00, 0xFF, 0x40, 0xAA, 0xB5, 0x7A, 0x90, 0x22, 0xEA, 0x85, 0x17, 0x5E, 0x60, 0xC9, 0x92, + 0x25, 0x4E, 0x31, 0xC3, 0x6C, 0x36, 0xB3, 0x6E, 0xDD, 0x3A, 0x00, 0x26, 0x0C, 0xBF, 0x99, 0x00, + 0x7F, 0x9F, 0xE6, 0x89, 0x29, 0x90, 0x33, 0xC8, 0xAA, 0xA1, 0x00, 0x3A, 0x55, 0x95, 0xAA, 0xB0, + 0xA6, 0x81, 0xD5, 0xEA, 0x5A, 0x66, 0x00, 0xA8, 0x0A, 0x13, 0x86, 0x0F, 0x22, 0xC0, 0xD7, 0x8B, + 0x94, 0x94, 0x14, 0x32, 0x33, 0x33, 0x5B, 0xDC, 0x45, 0xCF, 0x9E, 0x3D, 0x59, 0xBC, 0x78, 0x31, + 0x73, 0xE6, 0xCC, 0x71, 0xF4, 0x09, 0xA9, 0xC0, 0x43, 0xC8, 0x7D, 0x4B, 0xC4, 0x55, 0x6F, 0x7D, + 0x8D, 0x3E, 0x8D, 0x34, 0xEC, 0x2D, 0x54, 0x80, 0x90, 0x90, 0x10, 0xDE, 0x79, 0xE7, 0x1D, 0x5E, + 0x7D, 0xF5, 0x55, 0xFC, 0xFD, 0xFD, 0x9D, 0x1A, 0xD8, 0xF1, 0xE3, 0xC7, 0xF9, 0x69, 0xF7, 0x6E, + 0x42, 0x02, 0xFD, 0x18, 0x3B, 0xA4, 0x9F, 0x7D, 0xFD, 0xBC, 0xBE, 0xA1, 0x69, 0xF4, 0xED, 0x11, + 0xC3, 0x2D, 0x89, 0x3D, 0xB8, 0x70, 0xE1, 0x02, 0x5B, 0xB7, 0x6E, 0x6D, 0x55, 0x37, 0x5E, 0x5E, + 0x5E, 0x3C, 0xF5, 0xD4, 0x53, 0x7C, 0xF0, 0xC1, 0x07, 0xC4, 0xC6, 0xC6, 0x3A, 0x9E, 0xBA, 0x1F, + 0x98, 0x03, 0x5C, 0x41, 0xC4, 0xA6, 0x18, 0xE2, 0x89, 0x4C, 0x1D, 0x98, 0x8C, 0x4D, 0xAC, 0x45, + 0x45, 0x45, 0xB1, 0x68, 0xD1, 0x22, 0xA6, 0x4D, 0x9B, 0xD6, 0xA2, 0xE9, 0xBB, 0x7D, 0xFB, 0x76, + 0x8A, 0x8B, 0x8A, 0xB8, 0xB5, 0x4F, 0x4F, 0xE2, 0xBB, 0x46, 0xB6, 0x6C, 0x01, 0xEE, 0x2C, 0x08, + 0xF0, 0xF6, 0xF6, 0x64, 0xDC, 0xD0, 0x01, 0x00, 0x6C, 0xD8, 0xB0, 0x01, 0xB3, 0xD9, 0xDC, 0xAA, + 0xAE, 0x54, 0x55, 0x65, 0xE2, 0xC4, 0x89, 0x2C, 0x5D, 0xBA, 0xF4, 0x72, 0xA5, 0xE7, 0x11, 0xE4, + 0xBA, 0xDC, 0xC8, 0xC1, 0x75, 0x35, 0x86, 0x28, 0xC0, 0xFF, 0x20, 0xC5, 0x94, 0x0A, 0x92, 0x19, + 0xEF, 0xBE, 0xFB, 0x2E, 0x0F, 0x3D, 0xF4, 0x90, 0xD3, 0xBB, 0x68, 0x90, 0xE2, 0x6A, 0xD3, 0xA6, + 0x4D, 0x00, 0x8C, 0x19, 0x92, 0x84, 0x87, 0xE7, 0x8D, 0x11, 0x42, 0x0A, 0x80, 0x80, 0x11, 0x83, + 0x12, 0x09, 0xF2, 0xF7, 0x21, 0x2D, 0x2D, 0x9D, 0xAC, 0xAC, 0xAC, 0x36, 0x75, 0x37, 0x6A, 0xD4, + 0x28, 0x16, 0x2D, 0x5A, 0x44, 0x54, 0x54, 0x94, 0xBD, 0x49, 0x87, 0xCC, 0x0A, 0xB8, 0xDF, 0xF1, + 0xFF, 0xAE, 0xC6, 0x90, 0x31, 0xC8, 0x0D, 0x8D, 0x01, 0xC0, 0x68, 0x34, 0x32, 0x6F, 0xDE, 0xBC, + 0x46, 0xF9, 0x19, 0xCE, 0x22, 0x3B, 0x3B, 0x9B, 0xF4, 0xFD, 0xFB, 0x09, 0xF2, 0xF7, 0x61, 0xF8, + 0x80, 0x5E, 0x37, 0x86, 0xB8, 0xB2, 0x43, 0x68, 0xC4, 0xC5, 0x44, 0x30, 0x20, 0x3E, 0x96, 0xFC, + 0xFC, 0x3C, 0x76, 0xED, 0xDA, 0xD5, 0xE6, 0x2E, 0xC7, 0x8E, 0x1D, 0xCB, 0x1B, 0x6F, 0xBC, 0xE1, + 0xE8, 0x06, 0xF6, 0x43, 0x66, 0x89, 0xDD, 0x64, 0x6F, 0xB8, 0x9C, 0x21, 0x91, 0x48, 0x51, 0x15, + 0x0A, 0xD2, 0xA9, 0xFF, 0xF2, 0xCB, 0x2F, 0xF3, 0xD0, 0x43, 0x0F, 0xB5, 0x6A, 0x00, 0xE9, 0xE9, + 0xE9, 0xE4, 0x5D, 0xC8, 0xA3, 0x4F, 0xF7, 0x18, 0x7A, 0x44, 0x87, 0x3B, 0xBF, 0x18, 0xAB, 0x2A, + 0xA8, 0xAA, 0x4C, 0xCC, 0x01, 0xD0, 0xA9, 0x52, 0xBB, 0x6A, 0x2D, 0x54, 0x05, 0x54, 0x15, 0xAB, + 0xA6, 0x61, 0xD5, 0xB4, 0xFA, 0xFE, 0xAF, 0x09, 0x01, 0x5E, 0x5E, 0x9E, 0x0C, 0x1F, 0xD8, 0x1B, + 0x80, 0x9D, 0x3B, 0x77, 0xA2, 0xB5, 0x83, 0xB8, 0x4D, 0x4E, 0x4E, 0x66, 0xFA, 0xF4, 0xE9, 0x8E, + 0x4D, 0xFD, 0x90, 0x41, 0xDB, 0x2A, 0x34, 0x96, 0x5F, 0x0A, 0x32, 0x21, 0xE5, 0x36, 0x7B, 0xC3, + 0x23, 0x8F, 0x3C, 0xC2, 0xF4, 0xE9, 0xD3, 0x5B, 0x1D, 0xA8, 0x20, 0xDD, 0xB7, 0x82, 0xDB, 0xFA, + 0xC5, 0xE3, 0xE3, 0xED, 0x09, 0x5A, 0x33, 0x0C, 0x51, 0x14, 0xAC, 0x9A, 0x46, 0xFA, 0xA1, 0x93, + 0xFC, 0x7B, 0xE7, 0x7E, 0x4E, 0x9D, 0xCB, 0xC7, 0xDB, 0xD3, 0xC0, 0x6D, 0x49, 0xF1, 0x8C, 0xBB, + 0x7D, 0x20, 0xA1, 0x41, 0x01, 0x2D, 0x5F, 0x83, 0x14, 0x85, 0x53, 0x39, 0x79, 0xFC, 0x6B, 0xCB, + 0x5E, 0xD2, 0x8F, 0x67, 0x61, 0xB5, 0x6A, 0x24, 0x76, 0x8F, 0xE6, 0xFE, 0x11, 0xB7, 0xD0, 0x37, + 0xEE, 0xA6, 0x6B, 0xAB, 0x99, 0x8A, 0xC2, 0xAD, 0x7D, 0x7B, 0xE2, 0xAE, 0xD7, 0x91, 0x91, 0x91, + 0x41, 0x49, 0x49, 0x49, 0x9B, 0xA3, 0x68, 0xDC, 0xDC, 0xDC, 0x78, 0xE6, 0x99, 0x67, 0x48, 0x49, + 0x49, 0x61, 0xEF, 0xDE, 0xBD, 0xF6, 0xE6, 0xC9, 0xC0, 0x72, 0x60, 0xBF, 0x23, 0x43, 0xFA, 0x03, + 0x53, 0xED, 0x07, 0x7D, 0xFA, 0xF4, 0xE1, 0xC5, 0x17, 0x5F, 0xC4, 0xCB, 0xCB, 0xCB, 0xE9, 0x9B, + 0x39, 0xA2, 0xAC, 0xAC, 0x8C, 0xFD, 0xFB, 0xF7, 0xA3, 0x53, 0x15, 0x86, 0xF4, 0xED, 0x09, 0x8A, + 0x4A, 0x73, 0x91, 0xFB, 0xB5, 0x96, 0x3A, 0x16, 0xAE, 0xFC, 0x9E, 0x39, 0x1F, 0x7F, 0x43, 0xE1, + 0xC5, 0xF2, 0xFA, 0xF6, 0x65, 0xDF, 0x6C, 0x65, 0xD8, 0x80, 0x04, 0xDE, 0x79, 0x76, 0x2A, 0xFD, + 0x13, 0x62, 0x9D, 0x67, 0x8A, 0xA2, 0xF0, 0x7D, 0xEA, 0x7E, 0x9E, 0x7D, 0xE7, 0x53, 0x8E, 0x9D, + 0x69, 0x50, 0xFB, 0xBF, 0xDE, 0xBC, 0x9B, 0x0F, 0xD7, 0x6E, 0xE6, 0x2F, 0xFF, 0x93, 0xCC, 0xA3, + 0xE3, 0xFF, 0x03, 0xB5, 0xA9, 0xD9, 0xA7, 0x69, 0xF4, 0x8E, 0xED, 0x42, 0xD7, 0x88, 0x10, 0x4E, + 0x67, 0x65, 0x71, 0xF2, 0xE4, 0xC9, 0x76, 0x09, 0x6B, 0x8A, 0x8A, 0x8A, 0x62, 0xE6, 0xCC, 0x99, + 0x4C, 0x9D, 0x3A, 0xD5, 0xAE, 0x2C, 0x44, 0x00, 0x8F, 0x02, 0x19, 0xF6, 0x17, 0x44, 0x05, 0xA6, + 0x61, 0x33, 0x89, 0xB8, 0xBB, 0xBB, 0x33, 0x6B, 0xD6, 0xAC, 0x26, 0x4D, 0x21, 0xCE, 0xE0, 0xEC, + 0xD9, 0xB3, 0x64, 0x9E, 0x3A, 0x45, 0x44, 0x70, 0x20, 0xBD, 0xBB, 0x75, 0x01, 0xD1, 0x0C, 0x11, + 0x55, 0x95, 0x55, 0x9B, 0x7E, 0xE2, 0xD5, 0xF7, 0xBE, 0x6A, 0xC4, 0x0C, 0x2F, 0x2F, 0x2F, 0xFC, + 0xFC, 0xFD, 0xD9, 0x96, 0x7E, 0x94, 0x67, 0xDE, 0xFE, 0x88, 0x82, 0xE2, 0x8B, 0xCE, 0x89, 0x2F, + 0x55, 0xE5, 0xF0, 0xE9, 0x1C, 0x66, 0xBC, 0xFD, 0x71, 0x23, 0x66, 0x18, 0x0C, 0x06, 0xC2, 0xC2, + 0xC2, 0x28, 0x2C, 0xAB, 0xE2, 0xF9, 0x7F, 0x7C, 0xCE, 0x96, 0x7D, 0x87, 0x9B, 0x16, 0x5F, 0x42, + 0x10, 0x1E, 0xE4, 0x4F, 0xBF, 0xB8, 0x9B, 0xA8, 0xBA, 0x74, 0x89, 0xB4, 0xB4, 0xB4, 0x36, 0x33, + 0xC3, 0x8E, 0x71, 0xE3, 0xC6, 0x31, 0x7C, 0xF8, 0x70, 0xC7, 0xA6, 0x7B, 0x80, 0x04, 0xFB, 0x48, + 0x12, 0x80, 0xFB, 0xEC, 0x67, 0x46, 0x8C, 0x18, 0xC1, 0x03, 0x0F, 0x3C, 0xD0, 0xA6, 0x1B, 0x1E, + 0x3D, 0x7A, 0x94, 0xD2, 0x92, 0x12, 0xE2, 0xBB, 0x46, 0x12, 0x19, 0x62, 0xBC, 0xB6, 0xB8, 0x52, + 0x14, 0xCA, 0x2B, 0x2E, 0xF1, 0xFE, 0xEA, 0x8D, 0x54, 0x99, 0x1A, 0xD4, 0xCB, 0xBE, 0x7D, 0xFB, + 0xB2, 0x72, 0xE5, 0x4A, 0x36, 0x6F, 0xDE, 0xCC, 0x13, 0x4F, 0x3C, 0xC1, 0x4F, 0x87, 0x32, 0xF9, + 0x2E, 0x25, 0x4D, 0xAE, 0x09, 0xCD, 0x41, 0x08, 0xBE, 0x58, 0xBF, 0x83, 0xCC, 0x9C, 0x86, 0x78, + 0x5C, 0xA3, 0xD1, 0xC8, 0xFC, 0xF9, 0xF3, 0x49, 0x49, 0x49, 0xE1, 0xBD, 0xF7, 0xDE, 0x45, 0xE8, + 0xDD, 0xF9, 0x60, 0xCD, 0x26, 0x2C, 0xB5, 0x4D, 0x47, 0xF2, 0xE8, 0xDD, 0xDD, 0xE4, 0x0C, 0x07, + 0xF6, 0xEC, 0xD9, 0xE3, 0x98, 0xB0, 0xD3, 0x26, 0xF8, 0xF9, 0xF9, 0x31, 0x79, 0xF2, 0x64, 0xC7, + 0x68, 0xFA, 0x58, 0x60, 0xBC, 0x9D, 0x21, 0xE3, 0xB1, 0xCD, 0x0E, 0x83, 0xC1, 0xC0, 0xB4, 0x69, + 0xD3, 0x9C, 0xDE, 0xF8, 0x35, 0x85, 0x43, 0x87, 0x0E, 0x01, 0x90, 0xD8, 0x3D, 0x06, 0x2F, 0x8F, + 0x66, 0xD4, 0x5D, 0x45, 0xE1, 0x6C, 0x5E, 0x11, 0xC7, 0xCE, 0x9C, 0x6F, 0xD4, 0xFC, 0xE4, 0x93, + 0x4F, 0x32, 0x7E, 0xFC, 0x78, 0x06, 0x0C, 0x18, 0xC0, 0x8B, 0x2F, 0xBE, 0x48, 0x74, 0xD7, 0x9B, + 0x48, 0xFD, 0xF9, 0x78, 0xD3, 0x76, 0x30, 0x07, 0x98, 0xCC, 0x35, 0xEC, 0x3D, 0x72, 0xAA, 0x51, + 0xDB, 0x98, 0x31, 0x63, 0x78, 0xFC, 0xF1, 0xC7, 0x89, 0x8B, 0x8B, 0xE3, 0xB1, 0xC7, 0x1E, 0x63, + 0xC2, 0x84, 0x09, 0xA4, 0x1F, 0x3B, 0x4D, 0x71, 0x59, 0xE5, 0x35, 0x66, 0x9D, 0x42, 0xBF, 0xB8, + 0x9B, 0x70, 0xD7, 0xEB, 0x38, 0x7E, 0xFC, 0x38, 0xE5, 0xE5, 0xE5, 0xCD, 0xDE, 0xDB, 0x59, 0x8C, + 0x1A, 0x35, 0x8A, 0xEE, 0xDD, 0xEB, 0x73, 0x7E, 0x74, 0xC0, 0x44, 0x15, 0xB9, 0x5B, 0xBC, 0xDB, + 0xDE, 0xDA, 0xB7, 0x6F, 0x5F, 0x46, 0x8F, 0x1E, 0xDD, 0xA6, 0x1B, 0x59, 0x2C, 0x16, 0x8E, 0x1E, + 0x3D, 0x2A, 0xFB, 0xEB, 0x11, 0xD3, 0xBC, 0x46, 0xA3, 0x80, 0xB9, 0xD6, 0x42, 0xAD, 0xA5, 0xF1, + 0xDB, 0x27, 0x1C, 0xB4, 0x32, 0x21, 0x04, 0x08, 0x41, 0xB5, 0xB9, 0x06, 0xAD, 0x39, 0x6D, 0x4D, + 0x01, 0xAB, 0x55, 0xC3, 0x5C, 0xD3, 0xF8, 0xCD, 0xB7, 0x58, 0x2C, 0xF5, 0x9A, 0x92, 0xA6, 0x69, + 0xD4, 0xD6, 0xD6, 0x52, 0x6B, 0xA9, 0xA3, 0xCE, 0x6A, 0x6D, 0xDA, 0xAA, 0x27, 0x34, 0x62, 0x23, + 0x43, 0x09, 0x35, 0xFA, 0x93, 0x9D, 0x9D, 0x4D, 0x4A, 0x4A, 0x0A, 0x15, 0x15, 0x15, 0x8D, 0xC6, + 0xD6, 0x52, 0x54, 0x57, 0x57, 0x93, 0x9E, 0x9E, 0xCE, 0xFB, 0xEF, 0xBF, 0x7F, 0x79, 0xE0, 0x5D, + 0x92, 0x1E, 0x48, 0x44, 0x66, 0xCA, 0x02, 0x70, 0xF7, 0xDD, 0x77, 0x13, 0x1C, 0xDC, 0x22, 0x9F, + 0xCA, 0x15, 0xA8, 0xA8, 0xA8, 0xE0, 0xCC, 0x99, 0x33, 0x78, 0xB8, 0xEB, 0xE9, 0x19, 0x13, 0x4E, + 0xB3, 0x1B, 0x10, 0x21, 0x08, 0x0F, 0x0A, 0x20, 0xD4, 0xE8, 0x47, 0x45, 0x55, 0x83, 0x75, 0x7A, + 0xD1, 0xA2, 0x45, 0x44, 0x44, 0x44, 0x10, 0x15, 0x15, 0xC5, 0x87, 0x1F, 0x7E, 0xC8, 0xE9, 0xAC, + 0xD3, 0x3C, 0x3C, 0xA2, 0x9F, 0xB4, 0xCC, 0x5E, 0x6B, 0x61, 0x17, 0xE0, 0xE5, 0x61, 0xA0, 0x47, + 0x74, 0x38, 0xBB, 0x0E, 0x36, 0x58, 0x5C, 0x37, 0x6E, 0xDC, 0xC8, 0xDC, 0xB9, 0x73, 0x19, 0x33, + 0x66, 0x0C, 0x3B, 0x76, 0xEC, 0xE0, 0xBB, 0xEF, 0xD6, 0x31, 0xA0, 0x47, 0x24, 0x81, 0xBE, 0xDE, + 0x4D, 0x0F, 0x51, 0x40, 0xA8, 0xD1, 0x9F, 0xAE, 0x11, 0x21, 0xA4, 0x1E, 0x38, 0xC1, 0x6F, 0x7F, + 0xFB, 0x5B, 0x12, 0x12, 0x12, 0x18, 0x32, 0x64, 0x08, 0x83, 0x07, 0x0F, 0xA6, 0x7B, 0xF7, 0xEE, + 0x44, 0x45, 0x45, 0x11, 0x18, 0x18, 0x88, 0xC1, 0x60, 0x40, 0xA7, 0xD3, 0xD5, 0x6F, 0x9E, 0x35, + 0x4D, 0xC3, 0x62, 0xB1, 0x50, 0x5D, 0x5D, 0x4D, 0x71, 0x71, 0x31, 0xA7, 0x4F, 0x9F, 0x26, 0x2D, + 0x2D, 0x8D, 0x94, 0x94, 0x14, 0x32, 0x32, 0x32, 0x28, 0x2E, 0xBE, 0xC2, 0xE8, 0x9B, 0xAB, 0x47, + 0xAA, 0xB9, 0x46, 0x00, 0x6F, 0x6F, 0x6F, 0x46, 0x8C, 0x18, 0xD1, 0x26, 0x66, 0x00, 0x14, 0x14, + 0x14, 0x90, 0x97, 0x9F, 0x4F, 0x90, 0xBF, 0x2F, 0x51, 0xA1, 0xC6, 0xE6, 0x37, 0x84, 0x9A, 0xA0, + 0x4B, 0x58, 0x10, 0xE3, 0x6E, 0x1F, 0xC8, 0x3F, 0x97, 0xAF, 0xAF, 0x6F, 0x3E, 0x7C, 0xF8, 0x30, + 0x0F, 0x3F, 0xFC, 0x30, 0xEE, 0xEE, 0xEE, 0x94, 0x57, 0x54, 0x10, 0x66, 0xF4, 0x63, 0xC2, 0xF0, + 0x41, 0x4E, 0x8D, 0x41, 0x75, 0xD3, 0x31, 0x69, 0xF4, 0xAD, 0xAC, 0xD9, 0xBA, 0x87, 0x4B, 0x36, + 0xBF, 0x4A, 0x65, 0x65, 0x25, 0xAF, 0xBD, 0xF6, 0x1A, 0x73, 0xE6, 0xCC, 0xA1, 0xBA, 0xBA, 0x1A, + 0x10, 0x3C, 0x74, 0xC7, 0x6D, 0xF8, 0xF8, 0x78, 0x35, 0xCD, 0x60, 0x21, 0xF0, 0xF1, 0xF2, 0x20, + 0xBE, 0x6B, 0x24, 0xA9, 0x07, 0x4E, 0x50, 0x5E, 0x5E, 0xCE, 0x9E, 0x3D, 0x7B, 0xD8, 0xB3, 0x67, + 0x0F, 0x3A, 0x9D, 0x0E, 0x1F, 0x1F, 0x1F, 0x42, 0x42, 0x42, 0x88, 0x88, 0x88, 0x20, 0x28, 0x28, + 0x08, 0x5F, 0x5F, 0x5F, 0x0C, 0x06, 0x03, 0x9A, 0xA6, 0x51, 0x5D, 0x5D, 0x4D, 0x59, 0x59, 0x19, + 0x85, 0x85, 0x85, 0x14, 0x14, 0x14, 0x50, 0x52, 0x52, 0xD2, 0x94, 0x09, 0x46, 0x43, 0x66, 0xF6, + 0xBE, 0xAA, 0x47, 0x3A, 0xE8, 0x55, 0x80, 0x2E, 0x5D, 0xBA, 0x90, 0x90, 0x90, 0xD0, 0x6A, 0x46, + 0x98, 0xCD, 0x66, 0x32, 0x32, 0x32, 0x58, 0xB8, 0x70, 0x21, 0x45, 0x85, 0x45, 0x0C, 0x4C, 0x88, + 0x25, 0xC8, 0xDF, 0xD7, 0xA9, 0x0D, 0xA1, 0xAA, 0x53, 0x99, 0xF9, 0xC8, 0x3D, 0x1C, 0x3C, 0x79, + 0x96, 0x6D, 0xE9, 0x47, 0xEA, 0xDB, 0x4D, 0x26, 0x13, 0x26, 0x93, 0x09, 0x1F, 0x4F, 0x0F, 0x66, + 0x3F, 0x76, 0x1F, 0x37, 0xF7, 0xEE, 0xEE, 0x9C, 0xDA, 0x6B, 0xD5, 0xB8, 0xEB, 0xB6, 0xFE, 0x3C, + 0x9D, 0x7C, 0x37, 0xF3, 0x3E, 0x5F, 0x47, 0x8D, 0x6D, 0xE1, 0xB6, 0x5A, 0xAD, 0x54, 0x56, 0x56, + 0xA2, 0x53, 0x55, 0x7E, 0x33, 0x6E, 0x38, 0x53, 0xC6, 0x0D, 0x6B, 0x76, 0x7C, 0x8A, 0x4E, 0x27, + 0x35, 0xC5, 0xCB, 0x6F, 0x61, 0xB5, 0x52, 0x5E, 0x5E, 0x4E, 0x79, 0x79, 0x39, 0xA7, 0x4E, 0x9D, + 0xA2, 0x15, 0xA8, 0x46, 0x46, 0x79, 0xAE, 0x04, 0xD6, 0x00, 0xE7, 0xF5, 0xC8, 0x48, 0x09, 0x40, + 0x9A, 0x8C, 0x5B, 0x2A, 0xAE, 0xEA, 0xEA, 0xEA, 0x38, 0x7F, 0xFE, 0x3C, 0x5B, 0xB7, 0x6E, 0x65, + 0xCD, 0x9A, 0x35, 0xEC, 0xDA, 0xB5, 0xAB, 0x5E, 0x2E, 0x46, 0x04, 0x07, 0xE0, 0xED, 0x61, 0x70, + 0x6E, 0x87, 0xAE, 0x09, 0x6E, 0x8A, 0x0A, 0xE5, 0xE3, 0x3F, 0x3D, 0xC9, 0x3F, 0x97, 0xAF, 0x67, + 0xDD, 0xCE, 0x74, 0x8A, 0x4A, 0x2B, 0x70, 0x73, 0xD3, 0xD3, 0x3B, 0xB6, 0x0B, 0xBF, 0x7B, 0x70, + 0x0C, 0xF7, 0x8F, 0xBA, 0x15, 0x55, 0x55, 0x9C, 0x36, 0xC1, 0xB8, 0xBB, 0xB9, 0xF1, 0xF2, 0xE3, + 0x0F, 0xD2, 0xA3, 0x4B, 0x38, 0x1F, 0x7D, 0xB7, 0x8D, 0x53, 0xE7, 0xF2, 0xD1, 0x34, 0x8D, 0xE8, + 0xB0, 0x20, 0x92, 0xEF, 0x1C, 0xCA, 0xB4, 0x89, 0xA3, 0xF1, 0x6F, 0xCE, 0x37, 0x63, 0x43, 0xD7, + 0x88, 0x10, 0x74, 0x3A, 0x15, 0xAB, 0x54, 0x28, 0x34, 0xA4, 0x93, 0xC9, 0x1B, 0x59, 0xC0, 0xC6, + 0x59, 0x33, 0x42, 0x1D, 0x32, 0x0E, 0xE1, 0x14, 0x32, 0x38, 0xE4, 0x47, 0x64, 0xD8, 0x54, 0x99, + 0xFD, 0x1F, 0xF4, 0x38, 0xD8, 0xE5, 0x2D, 0x16, 0x0B, 0x07, 0x0F, 0x1E, 0x24, 0x2A, 0x2A, 0x0A, + 0x3F, 0x3F, 0x3F, 0x0C, 0x06, 0x03, 0xAA, 0xCD, 0x17, 0xA1, 0x69, 0x1A, 0x75, 0x75, 0x75, 0x98, + 0x4C, 0x26, 0x4A, 0x4B, 0x4B, 0xC9, 0xCE, 0xCE, 0xE6, 0xC0, 0x81, 0x03, 0xEC, 0xDE, 0xBD, 0x9B, + 0x7D, 0xFB, 0xF6, 0x71, 0xEE, 0xDC, 0xB9, 0x2B, 0xEA, 0x94, 0x44, 0x86, 0x04, 0xE2, 0xEE, 0xD6, + 0x82, 0x68, 0x7D, 0x4D, 0xD0, 0x35, 0x32, 0x84, 0xB7, 0x9E, 0x99, 0xC2, 0xAC, 0xC9, 0xE3, 0x29, + 0xBC, 0x58, 0x8E, 0xC1, 0xDD, 0x8D, 0xE8, 0xB0, 0x20, 0x7C, 0x7D, 0xBC, 0x6D, 0x8E, 0x29, 0xE7, + 0xBB, 0x43, 0x08, 0x3C, 0x0D, 0x6E, 0x4C, 0xBD, 0x6F, 0x34, 0x93, 0x46, 0x0F, 0x21, 0xBF, 0xF8, + 0x22, 0x56, 0x4D, 0x10, 0x16, 0xE4, 0x4F, 0xA0, 0xBF, 0xAF, 0xA4, 0xA2, 0x53, 0x8B, 0xB3, 0x5C, + 0xE3, 0x3C, 0xDD, 0xDD, 0xB9, 0x24, 0xD5, 0xF2, 0x3A, 0xE0, 0x0F, 0xC8, 0x52, 0x4E, 0x7D, 0x80, + 0x18, 0x64, 0x5C, 0x5A, 0x28, 0x32, 0x11, 0x54, 0x8F, 0xD4, 0x9A, 0xAA, 0x6D, 0xC4, 0x2E, 0x45, + 0xC6, 0x6F, 0x1D, 0x47, 0x56, 0x27, 0x3A, 0x8B, 0x2C, 0x6C, 0x73, 0xC5, 0xCD, 0xF5, 0x38, 0x64, + 0x92, 0x6E, 0xDC, 0xB8, 0x91, 0x3D, 0x7B, 0xF6, 0x10, 0x1A, 0x1A, 0x4A, 0x68, 0x68, 0x28, 0x46, + 0xA3, 0x11, 0x2F, 0x2F, 0x2F, 0x54, 0x55, 0xA5, 0xB6, 0xB6, 0x96, 0xCA, 0xCA, 0x4A, 0x8A, 0x8B, + 0x8B, 0x29, 0x2C, 0x2C, 0xA4, 0xA4, 0xA4, 0x04, 0x93, 0xC9, 0x74, 0x4D, 0x6D, 0x23, 0x24, 0xD0, + 0x5F, 0x6A, 0x58, 0x2D, 0x31, 0x77, 0x68, 0x02, 0x9D, 0xA2, 0x10, 0x15, 0x16, 0x44, 0x54, 0x78, + 0x70, 0x3D, 0x61, 0x5B, 0x6D, 0xB6, 0x17, 0x80, 0xD0, 0xF0, 0xF3, 0xF1, 0xC2, 0xCF, 0xD7, 0xBB, + 0xA1, 0xBF, 0x96, 0x68, 0x49, 0x02, 0x42, 0x02, 0xFD, 0xF0, 0xF5, 0xF6, 0xB0, 0x33, 0xC4, 0x1D, + 0x39, 0x4B, 0x76, 0xD8, 0x7E, 0x20, 0x67, 0x89, 0x3B, 0x52, 0xFC, 0xEB, 0x6C, 0xC7, 0x16, 0x1B, + 0xF3, 0x9C, 0xAE, 0x6C, 0xA7, 0x07, 0x7E, 0x02, 0x46, 0x83, 0xD4, 0x0A, 0xCA, 0xCA, 0xCA, 0x28, + 0x2B, 0x2B, 0xE3, 0xE4, 0xC9, 0x93, 0x2D, 0x7D, 0xF4, 0x3A, 0xE0, 0x02, 0xD2, 0xCB, 0xE8, 0x09, + 0x10, 0xE4, 0xEF, 0xD3, 0x7A, 0xA3, 0x60, 0x4B, 0x89, 0xE6, 0xCA, 0xFE, 0x84, 0x20, 0xD0, 0xD7, + 0x9B, 0x40, 0x3F, 0x1F, 0xF2, 0x8A, 0xCB, 0xEC, 0xAD, 0x51, 0x97, 0xFF, 0x17, 0xD2, 0x6F, 0xDE, + 0x26, 0xE8, 0x91, 0x36, 0xF9, 0x67, 0x80, 0xE1, 0xC8, 0xCD, 0xA1, 0x0F, 0xCE, 0xC9, 0xC4, 0x3A, + 0xE4, 0xB4, 0xCB, 0x46, 0xCA, 0xC1, 0x6D, 0xC0, 0x79, 0x64, 0x15, 0xB7, 0xAE, 0x00, 0x7E, 0xDE, + 0xED, 0x9A, 0xED, 0xD5, 0x89, 0x10, 0x78, 0x7B, 0x7A, 0x60, 0xF4, 0xF3, 0x71, 0x6C, 0x0C, 0x72, + 0xC5, 0x9D, 0xF4, 0x48, 0xB9, 0xF6, 0x7B, 0x64, 0x40, 0x57, 0x37, 0xE4, 0xBE, 0xA4, 0x2B, 0xD2, + 0x14, 0x1F, 0x8C, 0x9C, 0x86, 0x3A, 0xA4, 0x65, 0xB0, 0x0C, 0x29, 0x0F, 0xCF, 0x03, 0x27, 0x69, + 0x90, 0x87, 0x17, 0x91, 0x6F, 0x48, 0x4F, 0x1C, 0xEA, 0x61, 0x79, 0x7A, 0x18, 0x3A, 0xAF, 0x88, + 0x60, 0x7B, 0x42, 0x80, 0x9B, 0x5E, 0x87, 0xBF, 0x4F, 0x23, 0x43, 0x6B, 0xDB, 0x4C, 0x19, 0x4D, + 0xC0, 0xBE, 0xE2, 0xD6, 0x21, 0x6B, 0x1E, 0xE6, 0x03, 0x76, 0x4F, 0x8C, 0x62, 0x3B, 0xEF, 0xB8, + 0xCD, 0xAE, 0xE3, 0xDA, 0x26, 0x5B, 0x9D, 0xFD, 0xFF, 0x55, 0x45, 0xC1, 0x5D, 0xAF, 0xBB, 0xB1, + 0x9C, 0x52, 0xD7, 0x22, 0x94, 0x5E, 0x87, 0x6F, 0xE3, 0x19, 0xEF, 0x47, 0xC3, 0x8B, 0xDA, 0x7E, + 0xF7, 0xB9, 0xC6, 0x39, 0xC1, 0x2F, 0xB4, 0xD6, 0x60, 0x6B, 0xA0, 0x2A, 0x0A, 0x9E, 0x86, 0x46, + 0xB1, 0x67, 0x9E, 0xB8, 0x80, 0x21, 0xED, 0x9D, 0x63, 0x58, 0x3F, 0x1F, 0x84, 0x10, 0xD2, 0x3B, + 0xF7, 0x4B, 0x10, 0x59, 0x00, 0x8A, 0x82, 0xA1, 0xB1, 0x0A, 0x6F, 0xD7, 0xA4, 0xDA, 0x15, 0xED, + 0xCD, 0x90, 0x1A, 0xA0, 0x16, 0x40, 0x13, 0x82, 0x6A, 0x73, 0xED, 0x2F, 0x46, 0x64, 0x01, 0x97, + 0x07, 0x78, 0xDC, 0x30, 0x0C, 0x31, 0xD9, 0x0F, 0x2A, 0xAA, 0x4C, 0x6D, 0xE8, 0xEA, 0x3A, 0x83, + 0x10, 0xD2, 0x2A, 0xDC, 0x00, 0x0D, 0x17, 0xBC, 0x6E, 0xED, 0xCD, 0x10, 0x13, 0xB2, 0xCE, 0x09, + 0x00, 0x45, 0xA5, 0xE5, 0xAE, 0x8F, 0x32, 0xEC, 0x20, 0x08, 0x21, 0x30, 0x35, 0x36, 0xE7, 0x9B, + 0x70, 0x41, 0x35, 0x39, 0x57, 0x30, 0xA4, 0xBE, 0x70, 0xC0, 0x85, 0xE2, 0x8B, 0x88, 0x1B, 0x21, + 0x30, 0xCE, 0x09, 0x58, 0x35, 0x8D, 0x4B, 0xD5, 0x8D, 0x66, 0xFC, 0x0D, 0xC1, 0x90, 0x1A, 0x1C, + 0x82, 0x88, 0xCF, 0xE6, 0x15, 0x61, 0x32, 0xB7, 0x79, 0xF3, 0xDA, 0xF9, 0x50, 0xA0, 0xA6, 0xB6, + 0x8E, 0x92, 0xF2, 0x4B, 0x8E, 0xAD, 0xC5, 0xDC, 0x00, 0x22, 0x0B, 0xE4, 0x66, 0x11, 0x80, 0x9C, + 0xFC, 0x62, 0xF9, 0x10, 0x6D, 0x89, 0xA9, 0xBA, 0x2E, 0xA0, 0x70, 0xC9, 0x64, 0x96, 0xAE, 0xDE, + 0x06, 0xB4, 0x7B, 0xF1, 0x32, 0x70, 0x5D, 0x69, 0x8D, 0x5A, 0x80, 0xFC, 0x92, 0x32, 0x4E, 0x9D, + 0xCB, 0x77, 0x2E, 0x28, 0xE1, 0x7A, 0x86, 0xA2, 0x50, 0x50, 0x5A, 0x4E, 0x51, 0x43, 0x34, 0x8C, + 0x40, 0x5A, 0x2B, 0xDA, 0x1D, 0xAE, 0x60, 0xC8, 0x49, 0x64, 0x26, 0x2A, 0x55, 0xA6, 0x2B, 0x03, + 0x0D, 0x6E, 0x48, 0x28, 0x0A, 0xA7, 0xCE, 0xE5, 0x53, 0x7E, 0xA9, 0xDE, 0xBD, 0x5C, 0x89, 0xF4, + 0x69, 0xB4, 0x3B, 0x5C, 0xC1, 0x90, 0x73, 0xC8, 0xCF, 0x4E, 0x00, 0xB0, 0x65, 0xDF, 0x61, 0xAA, + 0xAB, 0xCD, 0x9D, 0xBF, 0x41, 0x54, 0x14, 0x19, 0x92, 0xDA, 0x9A, 0x28, 0x4C, 0x21, 0xD8, 0x77, + 0xE4, 0x14, 0x96, 0xBA, 0xFA, 0x35, 0x3C, 0x1F, 0x69, 0xC3, 0x6B, 0x77, 0xB8, 0x82, 0x21, 0x26, + 0xE4, 0x57, 0x6E, 0x00, 0x48, 0x3F, 0x96, 0xC5, 0xE1, 0x53, 0x39, 0xAD, 0x23, 0x84, 0x1D, 0x8A, + 0xD2, 0x40, 0xD0, 0x96, 0xAE, 0x47, 0x0A, 0xA0, 0xD3, 0x51, 0x71, 0xA9, 0x9A, 0x9D, 0xE9, 0x47, + 0x39, 0x9E, 0xD5, 0xC2, 0x4F, 0x82, 0x28, 0x0A, 0xE5, 0x95, 0x97, 0xD8, 0x91, 0x71, 0xDC, 0xB1, + 0xF5, 0x20, 0x36, 0x29, 0xD0, 0xDE, 0x70, 0xD5, 0x67, 0x18, 0x36, 0xDB, 0x06, 0x1C, 0x52, 0x52, + 0x5E, 0xC9, 0xAA, 0x4D, 0xBB, 0x19, 0xDC, 0xA7, 0xF5, 0x51, 0x90, 0xCB, 0x37, 0xEC, 0x64, 0xF7, + 0xA1, 0x4C, 0x46, 0xDF, 0xD2, 0x87, 0x61, 0x03, 0x7B, 0x39, 0x9F, 0xE8, 0xA9, 0x28, 0x54, 0x9B, + 0x6B, 0xF8, 0xF1, 0xA7, 0x03, 0x2C, 0x59, 0xB3, 0x91, 0xED, 0xFB, 0x8F, 0xD2, 0x3B, 0x36, 0x9A, + 0xB5, 0xF3, 0x9E, 0x27, 0x2A, 0x2C, 0xC8, 0xB9, 0x3D, 0x92, 0xAA, 0xB0, 0xF7, 0xC8, 0x69, 0x0E, + 0x64, 0x66, 0xDB, 0x5B, 0x84, 0xED, 0xF9, 0x5C, 0x62, 0xE7, 0x73, 0x55, 0x8D, 0x8E, 0x12, 0x64, + 0xAC, 0x70, 0x1F, 0x80, 0x0B, 0xC5, 0xA5, 0x8C, 0x1D, 0xD2, 0x8F, 0x90, 0xA0, 0x80, 0x96, 0x6D, + 0x14, 0x6D, 0x8B, 0xE9, 0xF4, 0xD7, 0xDF, 0xE7, 0xDB, 0x94, 0x34, 0xD6, 0x6E, 0xDF, 0xC7, 0xB6, + 0xB4, 0x23, 0x18, 0xFD, 0x7C, 0xE8, 0xD9, 0x35, 0xB2, 0xE9, 0x98, 0x5C, 0xDB, 0xB5, 0x85, 0x17, + 0xCB, 0xF9, 0xDF, 0x7F, 0x7C, 0xC6, 0x6B, 0xEF, 0x7F, 0xC5, 0xB1, 0xEC, 0x5C, 0x2C, 0x75, 0x56, + 0xAA, 0xCC, 0x35, 0xDC, 0x3F, 0x62, 0x30, 0x51, 0xE1, 0xCE, 0x31, 0xA4, 0xCE, 0x6A, 0xE5, 0x8D, + 0x65, 0xFF, 0x62, 0xEF, 0xE1, 0xFA, 0x25, 0xE3, 0x3C, 0x32, 0x13, 0xB9, 0xB8, 0xD9, 0x8B, 0x5B, + 0x01, 0x57, 0xD5, 0xDF, 0xAB, 0x45, 0x3A, 0xAA, 0xAA, 0x01, 0xB2, 0x2F, 0x14, 0xB1, 0x74, 0xED, + 0x16, 0xB4, 0x56, 0x84, 0x61, 0x6A, 0x9A, 0x46, 0x8D, 0x45, 0x7A, 0x40, 0xCD, 0x35, 0xB5, 0xA4, + 0x1E, 0x38, 0xC1, 0xB4, 0x3F, 0x2D, 0xE6, 0x93, 0xEF, 0xB6, 0x35, 0xBD, 0x2E, 0xD9, 0x66, 0xC6, + 0x4B, 0x0B, 0x97, 0xB3, 0x74, 0xED, 0x16, 0xCC, 0x0E, 0xA1, 0xA2, 0x31, 0xE1, 0xC1, 0x44, 0x85, + 0x19, 0x9B, 0x8F, 0xC4, 0x07, 0xD0, 0xA9, 0xEC, 0x3B, 0x72, 0x8A, 0x75, 0x3B, 0xD2, 0x1D, 0x5B, + 0xBF, 0x47, 0xFA, 0xD2, 0x5D, 0x02, 0x57, 0x16, 0x44, 0xDC, 0x82, 0x8C, 0xAA, 0x00, 0xE0, 0xCB, + 0xEF, 0x77, 0xB0, 0xEB, 0xE0, 0x49, 0xB9, 0x0E, 0x38, 0x0B, 0x21, 0x08, 0x33, 0x06, 0x70, 0xD7, + 0x6D, 0xFD, 0xEB, 0x9B, 0xBC, 0x3D, 0x0D, 0x18, 0xDC, 0xDD, 0x78, 0xE5, 0xDD, 0x15, 0xEC, 0xFC, + 0xF9, 0xC4, 0xD5, 0xD7, 0x26, 0x45, 0x61, 0xD5, 0xC6, 0x9F, 0xF8, 0xF4, 0xDF, 0xDB, 0x19, 0x79, + 0x73, 0x62, 0xFD, 0xF5, 0xC1, 0x01, 0xBE, 0x3C, 0x3F, 0xE5, 0x5E, 0x19, 0x6B, 0xEC, 0x44, 0xF4, + 0xA3, 0xD9, 0x5C, 0xC3, 0xA2, 0xAF, 0x7E, 0xA0, 0xE8, 0x62, 0x85, 0xBD, 0xB5, 0x14, 0x17, 0x7F, + 0xD8, 0xC5, 0x95, 0x65, 0x85, 0x2C, 0x48, 0xD1, 0x75, 0x2F, 0xE0, 0x51, 0x65, 0xAA, 0xA1, 0xE8, + 0x62, 0x05, 0xF7, 0x0C, 0x1D, 0x88, 0x87, 0xC1, 0xF9, 0xA2, 0x39, 0x8A, 0xAA, 0x92, 0xD4, 0xB3, + 0x2B, 0x25, 0x65, 0x95, 0x14, 0x94, 0x94, 0x73, 0xEF, 0xF0, 0x9B, 0x99, 0xFD, 0xD8, 0x44, 0xBE, + 0x4D, 0x49, 0x27, 0x33, 0x27, 0x8F, 0x7B, 0x87, 0x0D, 0xC2, 0xE0, 0xD8, 0x9F, 0xA2, 0x90, 0x5B, + 0x58, 0xC2, 0xEF, 0xDF, 0x5A, 0x86, 0x5E, 0xA7, 0x63, 0xD9, 0x1F, 0x9F, 0xE0, 0x81, 0x91, 0xB7, + 0x12, 0xDF, 0x35, 0x82, 0x19, 0x0F, 0x8F, 0x63, 0xDC, 0xED, 0x03, 0x9D, 0xDB, 0x16, 0xE9, 0x54, + 0x56, 0x6F, 0xDA, 0xCD, 0x9C, 0x8F, 0xBF, 0x71, 0xD4, 0xAE, 0xBE, 0x44, 0x7E, 0x15, 0xC1, 0x65, + 0xF6, 0x20, 0x57, 0xD7, 0x79, 0x3A, 0x87, 0x0C, 0x33, 0x1A, 0x0C, 0x70, 0xE6, 0x42, 0x21, 0x46, + 0x3F, 0x6F, 0x7E, 0x95, 0x14, 0xD7, 0x22, 0x2D, 0xD8, 0xD7, 0xDB, 0x8B, 0x3B, 0x6F, 0xEB, 0xCF, + 0x83, 0xA3, 0x87, 0x30, 0x69, 0xF4, 0x10, 0x92, 0xE2, 0x63, 0x11, 0x42, 0xE3, 0x93, 0x75, 0xDB, + 0xE9, 0xD3, 0x3D, 0x9A, 0xC4, 0x9E, 0x31, 0x0D, 0x6F, 0xBC, 0x4E, 0xE5, 0x8B, 0x7F, 0xA7, 0xF0, + 0xD9, 0xFA, 0x14, 0x5E, 0xFD, 0xAF, 0x87, 0xB8, 0x7F, 0xD4, 0xAD, 0x04, 0xFA, 0x7B, 0x73, 0x4B, + 0xDF, 0x38, 0x62, 0x22, 0x42, 0x9C, 0x13, 0x09, 0xAA, 0xCA, 0x89, 0xEC, 0x5C, 0x9E, 0x7A, 0x6B, + 0x19, 0xB9, 0x85, 0xF5, 0xB1, 0xB7, 0x39, 0xC0, 0xB3, 0x34, 0x91, 0x5F, 0xDE, 0x5E, 0x70, 0x35, + 0x43, 0x34, 0xE4, 0x46, 0x71, 0x14, 0x10, 0xAA, 0x69, 0x82, 0x03, 0x27, 0xCF, 0xD2, 0x3F, 0x3E, + 0x96, 0xEE, 0x31, 0x11, 0x2D, 0x5A, 0xE0, 0xDD, 0x74, 0x3A, 0x8C, 0x81, 0x7E, 0x78, 0xB8, 0xCB, + 0x0C, 0xE0, 0xB8, 0xAE, 0x91, 0x6C, 0xDE, 0x7B, 0x88, 0xFC, 0x92, 0x8B, 0xDC, 0x3F, 0xE2, 0x96, + 0xFA, 0x05, 0xBE, 0xB6, 0xD6, 0xC2, 0x5F, 0x96, 0x7E, 0x8D, 0x97, 0x87, 0x81, 0x37, 0x9F, 0xFE, + 0x0D, 0x3E, 0x9E, 0x86, 0x86, 0x88, 0x13, 0x67, 0xEE, 0xA7, 0x28, 0x94, 0x55, 0x56, 0xF1, 0xEC, + 0xDF, 0x3F, 0x61, 0x6B, 0x5A, 0x7D, 0x04, 0xA5, 0x15, 0xF9, 0x71, 0x81, 0xD5, 0x2E, 0xA6, 0x57, + 0x87, 0xD4, 0x2E, 0x3F, 0x8D, 0xAC, 0x04, 0x51, 0x09, 0x50, 0x50, 0x2A, 0x35, 0x9F, 0xA3, 0xA7, + 0x72, 0x5A, 0xB6, 0x9E, 0x40, 0x43, 0x05, 0x07, 0x21, 0x08, 0x31, 0xFA, 0xF3, 0xDB, 0x09, 0x23, + 0x38, 0x73, 0xA1, 0x88, 0xCA, 0x2A, 0x53, 0xFD, 0x5E, 0xA5, 0xFC, 0x52, 0x35, 0x39, 0xF9, 0xC5, + 0xFC, 0xE7, 0xD8, 0xDB, 0x08, 0x0B, 0x0E, 0x68, 0xB1, 0x56, 0x67, 0xAE, 0xAD, 0xE5, 0xAF, 0x4B, + 0x57, 0xB3, 0x7A, 0xF3, 0x1E, 0xC7, 0x33, 0xDF, 0x21, 0x4B, 0x2E, 0xB9, 0x1C, 0x1D, 0x55, 0xE5, + 0x78, 0x35, 0xF0, 0x1E, 0x36, 0xEB, 0xE8, 0xCF, 0x27, 0xB2, 0x99, 0x31, 0xF7, 0x23, 0x72, 0x72, + 0x0B, 0x5B, 0xBF, 0x61, 0x14, 0x82, 0x31, 0x43, 0xFA, 0xD1, 0x2D, 0x2A, 0x94, 0x3A, 0x87, 0x7C, + 0x91, 0x3A, 0xAB, 0x95, 0x40, 0x3F, 0x1F, 0xC6, 0xDE, 0x9A, 0xD4, 0x32, 0x5B, 0xAC, 0xA2, 0x60, + 0xAE, 0xB5, 0x30, 0xE7, 0xA3, 0xB5, 0x2C, 0xFC, 0x6A, 0x83, 0x74, 0x3F, 0x4B, 0x1C, 0x01, 0x5E, + 0xC1, 0x21, 0xDC, 0xD3, 0x95, 0xE8, 0xA8, 0x5A, 0x81, 0x1A, 0x90, 0x81, 0x0C, 0x13, 0xEA, 0x05, + 0x90, 0x95, 0x5B, 0xC8, 0xC9, 0xB3, 0x17, 0xB8, 0xBD, 0x7F, 0x82, 0x73, 0xE5, 0x36, 0x2E, 0x87, + 0x00, 0x7F, 0x1F, 0x4F, 0x06, 0x27, 0xF6, 0x20, 0xD4, 0xE8, 0x57, 0x2F, 0xB2, 0xF4, 0x3A, 0x1D, + 0x91, 0x21, 0x46, 0x6E, 0xE9, 0xDD, 0x1D, 0x37, 0x9D, 0x93, 0x8F, 0xA7, 0xAA, 0x54, 0x56, 0x9B, + 0xF9, 0xDB, 0xD2, 0xD5, 0xCC, 0xFD, 0xFC, 0xBB, 0xFA, 0xC0, 0x6C, 0x64, 0xE0, 0xDF, 0x13, 0xC8, + 0x60, 0xC2, 0x0E, 0x41, 0x47, 0x16, 0x6F, 0xAC, 0x46, 0x7E, 0x65, 0x73, 0x10, 0x32, 0x16, 0x96, + 0xCC, 0x73, 0xF9, 0x1C, 0x3A, 0x95, 0xC3, 0xA0, 0x84, 0x6E, 0x84, 0xB6, 0x54, 0xBC, 0x20, 0x23, + 0x41, 0x02, 0xFC, 0x7D, 0x1A, 0x6D, 0x10, 0xDD, 0xF4, 0x3A, 0xE2, 0x6E, 0x8A, 0x72, 0x9E, 0x19, + 0x3A, 0x95, 0xF3, 0xF9, 0xC5, 0xBC, 0xF0, 0xCF, 0xCF, 0x79, 0x77, 0xF5, 0x8F, 0xD4, 0x5A, 0xEA, + 0xA3, 0x3E, 0x8B, 0x90, 0x45, 0x62, 0xBE, 0xE9, 0x40, 0x1A, 0x75, 0x78, 0x35, 0xCD, 0x8B, 0x48, + 0xA6, 0x0C, 0xC4, 0x96, 0x42, 0x77, 0x26, 0xB7, 0x90, 0x9D, 0x3F, 0x1F, 0x27, 0x36, 0x3C, 0x84, + 0xD8, 0xE8, 0xF0, 0x6B, 0xEF, 0xBE, 0xAF, 0x86, 0xAB, 0xF1, 0xD0, 0x49, 0x93, 0x88, 0x26, 0x20, + 0x25, 0xED, 0x08, 0x4F, 0xCE, 0x59, 0xCA, 0xB7, 0xDB, 0xD3, 0xB0, 0x36, 0x6C, 0x16, 0x0B, 0x90, + 0xCC, 0x58, 0xD1, 0xC1, 0xF4, 0xE9, 0x94, 0xF2, 0xA6, 0x85, 0xC8, 0x4F, 0x6B, 0xF7, 0xC5, 0x16, + 0x72, 0x5A, 0x50, 0x5A, 0xCE, 0x86, 0x9F, 0x7E, 0xA6, 0xA6, 0xA6, 0x96, 0x5E, 0x37, 0x45, 0xC9, + 0x04, 0x1A, 0x57, 0xC1, 0x66, 0xA4, 0xCC, 0x2D, 0x28, 0xE1, 0xEF, 0x9F, 0x7F, 0xC7, 0xEC, 0x05, + 0x5F, 0x34, 0xCA, 0xD2, 0x45, 0x2A, 0x21, 0x4F, 0x22, 0xF3, 0x35, 0x3A, 0x3C, 0x20, 0xA0, 0xB3, + 0xEA, 0xCD, 0x16, 0x21, 0x2D, 0xC2, 0x5D, 0x90, 0x5F, 0x8D, 0x56, 0x4D, 0xE6, 0x5A, 0x76, 0x64, + 0x1C, 0x27, 0xF5, 0xE7, 0xE3, 0xF8, 0x79, 0x79, 0x10, 0x13, 0x1E, 0x8C, 0xA1, 0xB9, 0x64, 0xD1, + 0x96, 0x40, 0x95, 0x96, 0xE2, 0xC2, 0xD2, 0x32, 0xBE, 0xF8, 0xF7, 0x0E, 0x9E, 0x7D, 0xE7, 0x13, + 0x56, 0x6D, 0xFC, 0xC9, 0x1E, 0xCD, 0x0E, 0x92, 0xF8, 0xDB, 0x91, 0xC5, 0x13, 0x5A, 0x57, 0xFE, + 0xA7, 0x1D, 0xD0, 0xD9, 0x5E, 0x8A, 0x40, 0xA4, 0x68, 0xF8, 0x3D, 0x0E, 0xDF, 0x3E, 0xF7, 0x34, + 0xB8, 0x33, 0x6C, 0x40, 0x2F, 0xA6, 0x8C, 0x1B, 0xCE, 0xE8, 0xC1, 0x7D, 0x09, 0x0F, 0x09, 0x40, + 0x51, 0x75, 0x36, 0x95, 0xD7, 0xC9, 0x1C, 0x11, 0x45, 0xB1, 0x79, 0x2A, 0x15, 0x6A, 0x6B, 0x6A, + 0x38, 0x95, 0x93, 0xCF, 0xBA, 0x9D, 0xE9, 0x7C, 0xB5, 0xF1, 0x27, 0x0E, 0x9C, 0x3C, 0x7B, 0x79, + 0x48, 0x4F, 0x39, 0xF0, 0x21, 0xF2, 0x23, 0x98, 0x2E, 0x71, 0xCD, 0x3A, 0x8B, 0xCE, 0x66, 0x08, + 0x48, 0x17, 0xC0, 0x9D, 0xC0, 0x8B, 0xC8, 0x62, 0xC4, 0xF5, 0xB3, 0xD6, 0x4D, 0xAF, 0x23, 0xBE, + 0x6B, 0x24, 0x23, 0x6F, 0xEE, 0xC3, 0xA8, 0x5B, 0x12, 0xE9, 0xD3, 0x3D, 0x86, 0x88, 0xE0, 0x40, + 0xBC, 0x3C, 0xDC, 0x1B, 0xAA, 0xCB, 0x35, 0x82, 0x00, 0x4D, 0x50, 0x6B, 0xB1, 0x50, 0x56, 0x51, + 0xC5, 0x99, 0x0B, 0x85, 0xEC, 0x3B, 0x7A, 0x9A, 0x2D, 0xFB, 0x0E, 0xB3, 0xFB, 0x50, 0x26, 0xF9, + 0x25, 0x65, 0x97, 0xE7, 0xB3, 0xD4, 0x21, 0x3F, 0xA5, 0x3A, 0x17, 0xF9, 0x01, 0xCC, 0x4E, 0x0F, + 0x9D, 0xBD, 0x1E, 0x18, 0x62, 0x47, 0x28, 0xB2, 0xB4, 0xC7, 0x34, 0xA4, 0x7A, 0xDC, 0x68, 0x6C, + 0xEE, 0x6E, 0x7A, 0x42, 0x8D, 0xFE, 0x74, 0x8B, 0x0C, 0x25, 0x36, 0x2A, 0x8C, 0x2E, 0xA1, 0x46, + 0x82, 0xFC, 0x7D, 0xF0, 0xF2, 0x34, 0xA0, 0x2A, 0x2A, 0xE6, 0x5A, 0x0B, 0x15, 0x97, 0xAA, 0xB9, + 0x50, 0x7C, 0x91, 0x9C, 0xFC, 0x62, 0xCE, 0xE4, 0x16, 0x72, 0xBE, 0xB0, 0x84, 0x8A, 0xAA, 0xAB, + 0x26, 0x15, 0xD5, 0x21, 0x93, 0x2C, 0x97, 0x02, 0x5F, 0x21, 0x8D, 0x86, 0xFF, 0x8F, 0xAB, 0x40, + 0x41, 0xA6, 0x44, 0xBC, 0x88, 0xDC, 0xB7, 0xD4, 0xD0, 0x82, 0xEF, 0xA2, 0x3B, 0xF1, 0x2B, 0x03, + 0x7E, 0x40, 0x32, 0x3D, 0xB4, 0xB3, 0x1F, 0xB6, 0x29, 0x02, 0x5C, 0xAF, 0x08, 0x45, 0xD6, 0x06, + 0xBE, 0x0B, 0xF8, 0x15, 0x72, 0xEF, 0xE2, 0x6C, 0x32, 0x91, 0x1D, 0x16, 0xA4, 0x23, 0xE9, 0x38, + 0x32, 0xA1, 0x68, 0x13, 0x72, 0x66, 0x54, 0x75, 0xF6, 0xC3, 0x35, 0x85, 0xEB, 0x99, 0x21, 0x76, + 0xE8, 0x90, 0x16, 0xE3, 0x3E, 0x48, 0xAB, 0x71, 0x5F, 0xA0, 0x07, 0x92, 0x61, 0x01, 0x34, 0xE4, + 0xF5, 0xD5, 0x22, 0x09, 0x5D, 0x8C, 0xF4, 0xEA, 0x1D, 0x45, 0xA6, 0x1C, 0x67, 0x20, 0x23, 0x44, + 0x2A, 0x5B, 0x76, 0xDB, 0xCE, 0xC1, 0xFF, 0x01, 0xCE, 0x34, 0xF5, 0xEC, 0x2D, 0xA9, 0x9C, 0xA8, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x32, 0x2D, 0x30, 0x31, 0x2D, 0x33, 0x31, 0x54, 0x31, + 0x33, 0x3A, 0x34, 0x31, 0x3A, 0x31, 0x38, 0x2D, 0x30, 0x38, 0x3A, 0x30, 0x30, 0xED, 0x4F, 0xCC, + 0x0D, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x6D, 0x6F, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x32, 0x2D, 0x30, 0x31, 0x2D, 0x33, 0x31, 0x54, + 0x31, 0x33, 0x3A, 0x34, 0x31, 0x3A, 0x31, 0x38, 0x2D, 0x30, 0x38, 0x3A, 0x30, 0x30, 0x9C, 0x12, + 0x74, 0xB1, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2E, + 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_List/Copy_Messages_List.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_List/Copy_Messages_List.ino new file mode 100644 index 000000000..3a1511777 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_List/Copy_Messages_List.ino @@ -0,0 +1,220 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to copy messages from the mailbox to other folder. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Define the MessageList class to add the message to copy */ + MessageList toCopy; + + /* Add message uid to copy to the list */ + toCopy.add(3); + toCopy.add(4); + + // imap.createFolder("test"); + + /* Copy all messages in the list to the folder "test" */ + if (imap.copyMessages(&toCopy, F("test"))) + MailClient.printf("\nMessages copied\n"); + + /* Delete all messages in the list from the opened folder (move to trash) */ + // imap.deleteMessages(&toCopy); + + // imap.deleteolder("test"); + // imap.deleteolder("test2"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_Message_Numbers_Ranges/Copy_Messages_Message_Numbers_Ranges.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_Message_Numbers_Ranges/Copy_Messages_Message_Numbers_Ranges.ino new file mode 100644 index 000000000..958037525 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_Message_Numbers_Ranges/Copy_Messages_Message_Numbers_Ranges.ino @@ -0,0 +1,214 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to copy messages from the mailbox to other folder using message numbers ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Copy all messages using message sequence ranges (last 10 message numbers) to the folder "test"*/ + int msg_last = imap.selectedFolder().msgCount(); + int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last; + + String sequence_set2 = String(msg_begin) + ":" + String(msg_last); + + if (imap.copyMessages(sequence_set2, false /* if sequence set are message numbers not UIDs */, F("test"))) + MailClient.printf("\nCopying messages using message numbers ranges success\n"); + else + MailClient.printf("\nError, copying messages using message numbers ranges\n"); + + // imap.deleteolder("test"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_UIDs_Ranges/Copy_Messages_UIDs_Ranges.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_UIDs_Ranges/Copy_Messages_UIDs_Ranges.ino new file mode 100644 index 000000000..1fdc5c6bf --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Copy_Messages/Copy_Messages_UIDs_Ranges/Copy_Messages_UIDs_Ranges.ino @@ -0,0 +1,214 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to copy messages from the mailbox to other folder using UIDs ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Copy all messages using UIDs ranges (last 10 UIDs) to the folder "test" */ + int uid_last = imap.getUID(imap.selectedFolder().msgCount()); + int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last; + + String sequence_set1 = String(uid_begin) + ":" + String(uid_last); + + if (imap.copyMessages(sequence_set1, true /* if sequence set are the UIDs */, F("test"))) + MailClient.printf("\nCopying messages using UIDs ranges success\n"); + else + MailClient.printf("\nError, copying messages using UIDs ranges\n"); + + // imap.deleteolder("test"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Character_Decoding/Custom_Character_Decoding.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Character_Decoding/Custom_Character_Decoding.ino new file mode 100644 index 000000000..f703bd316 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Character_Decoding/Custom_Character_Decoding.ino @@ -0,0 +1,498 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +// This example shows how to read Email with custom character decoding for local language. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** Assign SD card type and FS used in src/ESP_Mail_FS.h and + * change the config for that card interfaces in src/extras/SDHelper.h + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// Provide the SD card interfaces setting and mounting +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Callback function to decode the string based on character set of the content */ +void customCharacterDecodingCallback(IMAP_Decoding_Info *decoding); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Print all messages from the message list */ +void printMessages(std::vector &msgItems, bool headerOnly); + +/* Print all attachments info from the message */ +void printAttacements(std::vector &atts); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + +#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h + // Mount SD card. + SD_Card_Mounting(); // See src/extras/SDHelper.h +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /* Set the callback function to decode the string based on the caracter set of string */ + imap.characterDecodingCallback(customCharacterDecodingCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_sd; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud + , to allow case sensitive parse, uncomment below line*/ + // imap_data.enable.header_case_sensitive = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /** Message UID to fetch or read e.g. 100. + * In this case we will get the UID from the max message number (lastest message) + */ + imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount()); + + // or fetch via the message sequence number + // imap_data.fetch.number = imap.selectedFolder().msgCount(); + + // if both imap_data.fetch.uid and imap_data.fetch.number were set, + // then total 2 messages will be fetched i.e. one using uid and other using number. + + /* Set seen flag */ + + // The message with "Seen" flagged means the message was already read or seen by user. + // The default value of this option is set to false. + // If you want to set the message flag as "Seen", set this option to true. + // If this option is false, the message flag was unchanged. + // To set or remove flag from message, see Set_Flags.ino example. + + // imap_data.fetch.set_seen = true; + + /* Read or search the Email and close the session */ + + // When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status, + // as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag + // to message, see the Set_Flags.ino example. + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ +} + +void To_UTF8(IMAP_Decoding_Info *decoding) +{ + decoding->decodedString = "fake decoded string "; // return the decoded string +} + +void customCharacterDecodingCallback(IMAP_Decoding_Info *decoding) +{ + // Serial.println("***** Data Type *****"); + // 0 or IMAP_Decoding_Info::message_part_type_header or + // 1 or IMAP_Decoding_Info::message_part_type_text + // Serial.println(decoding->type); + + // Serial.println("***** Charset *****"); + // Serial.println(decoding->charset); + // Serial.println("***** String to Decode *****"); + // Serial.println(decoding->encoded); + + // The original or decoded string should be return to the process via + // decoding->decodedString + + // Then rturn the decoded string back to the process. + if (strlen(decoding->charset) == 0 || strcasecmp(decoding->charset, "utf-8") == 0 || strcasecmp(decoding->charset, "us-ascii") == 0) // return original + decoding->decodedString = decoding->data; + else // decode to UTF-8 or ASCII + To_UTF8(decoding); +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + MailClient.printf(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + /** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and + * the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename + * (> 13 characters) is not support in the SD.h library. + * To show how its original file name, use imap.fileList(). + */ + // Serial.println(imap.fileList()); + + for (size_t i = 0; i < msgItems.size(); i++) + { + + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + /* If the result contains the message info (Fetch mode) */ + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Append_Message/Append_Message.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Append_Message/Append_Message.ino new file mode 100644 index 000000000..9ef89294e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Append_Message/Append_Message.ino @@ -0,0 +1,221 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to append new message to mailbox using the custom IMAP command. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void customCommandCallback(IMAP_Response res) +{ + // The server responses will included tagged and/or untagged data. + + // Tagged data is the status which begins with command identifier (tag) i.e. "A01" in this case. + // Tagged status responses included OK, NO, BAD, PREAUTH and BYE. + + // Untagged data is the information or result of the request which begins with * + + // When you send multiple commands with different tag simultaneously, + // tag will be used as command identifier. + + MailClient.printf("> C: TAG %s\n", res.tag.c_str()); + MailClient.printf("< S: %s\n", res.text.c_str()); + + if (res.completed) + { + MailClient.printf("> C: Response finished with status %s\n\n", res.status.c_str()); + } +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + + /* Connect to the server */ + if (!imap.customConnect(&config, customCommandCallback, F("A01") /* tag */)) + return; + + String cmd = F("LOGIN "); + cmd += AUTHOR_EMAIL; + cmd += F(" "); + cmd += AUTHOR_PASSWORD; + + // You can also assign tag to the begining of the command e.g. "A01 FETCH 1 UID" + // Do not assign tag to command when you assign tag to the last parameter of function. + + imap.sendCustomCommand(cmd, customCommandCallback, F("A02") /* tag */); + + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in.\n"); + else + Serial.println("\nConnected with no Auth.\n"); + + imap.sendCustomCommand(F("SELECT \"INBOX\""), customCommandCallback, F("A03") /* tag */); + + imap.sendCustomCommand(F("LIST \"\" *"), customCommandCallback, F("A04") /* tag */); + + String appendMsg = "Date: Thu, 16 Jun 2022 12:30:25 -0800 (PST)\r\n"; + + appendMsg += "From: Jack \r\n"; + + appendMsg += "Subject: Greeting from ESP Mail\r\n"; + + appendMsg += "To: joe@host.com\r\n"; + + appendMsg += "Message-Id: \r\n"; + + appendMsg += "MIME-Version: 1.0\r\n"; + + appendMsg += "Content-Type: text/plain; charset=\"us-ascii\"\r\n"; + + appendMsg += "Content-transfer-encoding: 7bit\r\n"; + + appendMsg += "\r\n"; + + appendMsg += "Hello Joe, this is the append message\r\n"; + + String appendMsgCmd = "APPEND INBOX {" + String(appendMsg.length()) + "}"; + + imap.sendCustomCommand(appendMsgCmd, customCommandCallback, F("A05") /* tag */); + + imap.sendCustomData(appendMsg, true /* flag states the last data to send */); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Basic_Auth/Basic_Auth.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Basic_Auth/Basic_Auth.ino new file mode 100644 index 000000000..9485ee7e6 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Basic_Auth/Basic_Auth.ino @@ -0,0 +1,197 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send custom IMAP command and get the response. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void customCommandCallback(IMAP_Response res) +{ + // The server responses will included tagged and/or untagged data. + + // Tagged data is the status which begins with command identifier (tag) i.e. "A01" in this case. + // Tagged status responses included OK, NO, BAD, PREAUTH and BYE. + + // Untagged data is the information or result of the request which begins with * + + // When you send multiple commands with different tag simultaneously, + // tag will be used as command identifier. + + MailClient.printf("> C: TAG %s\n", res.tag.c_str()); + MailClient.printf("< S: %s\n", res.text.c_str()); + + if (res.completed) + { + MailClient.printf("> C: Response finished with status %s\n\n", res.status.c_str()); + } +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + // This debug required for showing debug info from imap.connect + imap.debug(1); + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in.\n"); + else + Serial.println("\nConnected with no Auth.\n"); + + // You can also assign tag to the begining of the command e.g. "A01 FETCH 1 UID" + // Do not assign tag to command when you assign tag to the last parameter of function. + + imap.sendCustomCommand(F("SELECT \"INBOX\""), customCommandCallback, F("A01") /* tag */); + + imap.sendCustomCommand(F("LIST \"\" *"), customCommandCallback, F("A02") /* tag */); + + imap.sendCustomCommand(F("FETCH 1 UID"), customCommandCallback, F("A03") /* tag */); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Custom_Auth/Custom_Auth.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Custom_Auth/Custom_Auth.ino new file mode 100644 index 000000000..afb3ef9c2 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Custom_Auth/Custom_Auth.ino @@ -0,0 +1,197 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send custom IMAP command and get the response. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void customCommandCallback(IMAP_Response res) +{ + // The server responses will included tagged and/or untagged data. + + // Tagged data is the status which begins with command identifier (tag) i.e. "A01" in this case. + // Tagged status responses included OK, NO, BAD, PREAUTH and BYE. + + // Untagged data is the information or result of the request which begins with * + + // When you send multiple commands with different tag simultaneously, + // tag will be used as command identifier. + + MailClient.printf("> C: TAG %s\n", res.tag.c_str()); + MailClient.printf("< S: %s\n", res.text.c_str()); + + if (res.completed) + { + MailClient.printf("> C: Response finished with status %s\n\n", res.status.c_str()); + } +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + + /* Connect to the server */ + if (!imap.customConnect(&config, customCommandCallback, F("A01") /* tag */)) + return; + + String cmd = F("LOGIN "); + cmd += AUTHOR_EMAIL; + cmd += F(" "); + cmd += AUTHOR_PASSWORD; + + // You can also assign tag to the begining of the command e.g. "A01 FETCH 1 UID" + // Do not assign tag to command when you assign tag to the last parameter of function. + + imap.sendCustomCommand(cmd, customCommandCallback, F("A02") /* tag */); + + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in.\n"); + else + Serial.println("\nConnected with no Auth.\n"); + + imap.sendCustomCommand(F("SELECT \"INBOX\""), customCommandCallback, F("A03") /* tag */); + + imap.sendCustomCommand(F("LIST \"\" *"), customCommandCallback, F("A04") /* tag */); + + imap.sendCustomCommand(F("FETCH 1 UID"), customCommandCallback, F("A05") /* tag */); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Idle/Idle.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Idle/Idle.ino new file mode 100644 index 000000000..5a704e6bc --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Command/Idle/Idle.ino @@ -0,0 +1,220 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to receive mailbox updates by sending the custom IMAP command IDLE. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +unsigned long lastIdleTerminatedMillis = 0; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void customCommandCallback(IMAP_Response res) +{ + // The server responses will included tagged and/or untagged data. + + // Tagged data is the status which begins with command identifier (tag) i.e. "A01" in this case. + // Tagged status responses included OK, NO, BAD, PREAUTH and BYE. + + // Untagged data is the information or result of the request which begins with * + + // When you send multiple commands with different tag simultaneously, + // tag will be used as command identifier. + + MailClient.printf("> C: TAG %s\n", res.tag.c_str()); + MailClient.printf("< S: %s\n", res.text.c_str()); + + if (res.completed) + { + MailClient.printf("> C: Response finished with status %s\n\n", res.status.c_str()); + } +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + + /* Connect to the server */ + if (!imap.customConnect(&config, customCommandCallback, F("A01") /* tag */)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in.\n"); + else + Serial.println("\nConnected with no Auth.\n"); + + String cmd = F("LOGIN "); + cmd += AUTHOR_EMAIL; + cmd += F(" "); + cmd += AUTHOR_PASSWORD; + + // You can also assign tag to the begining of the command e.g. "A01 FETCH 1 UID" + // Do not assign tag to command when you assign tag to the last parameter of function. + + imap.sendCustomCommand(cmd, customCommandCallback, F("A02") /* tag */); + + imap.sendCustomCommand(F("SELECT \"INBOX\""), customCommandCallback, F("A03") /* tag */); + + imap.sendCustomCommand(F("LIST \"\" *"), customCommandCallback, F("A04") /* tag */); +} + +void loop() +{ + + if (imap.connected()) + { + if (!imap.sendCustomCommand(F("IDLE"), customCommandCallback, F("A05") /* tag */)) + { + // If error, need to re-connect if imap.connected() returns false and re-log in again + Serial.println("\nTCP connection closed!"); + return; + } + + if (millis() - lastIdleTerminatedMillis > 20 * 60 * 1000) // terminate the IDLE every 20 min. + { + lastIdleTerminatedMillis = millis(); + imap.sendCustomCommand(F("DONE"), customCommandCallback, "" /* don't include tag for DONE command */); + } + } +} + +/** + * The server MAY consider a client inactive if it has an IDLE command + * running, and if such a server has an inactivity timeout it MAY log + * the client off implicitly at the end of its timeout period. Because + * of that, clients using IDLE are advised to terminate the IDLE and + * re-issue it at least every 29 minutes to avoid being logged off. + */ \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Ports/Custom_Ports.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Ports/Custom_Ports.ino new file mode 100644 index 000000000..b870aa5ab --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Custom_Ports/Custom_Ports.ino @@ -0,0 +1,256 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to assign the custom ports with protocols to access IMAP server. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 // Plain or TLS with STARTTLS + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT esp_mail_imap_port_143 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Set the ports and protocols + * The port that assigned with config.server.port will map with the + * protocol assigned here + */ + + config.ports_functions.list = new port_function[2]; + config.ports_functions.size = 2; + + config.ports_functions.list[0].port = 143; + config.ports_functions.list[0].protocol = esp_mail_protocol_tls; + + config.ports_functions.list[1].port = 993; + config.ports_functions.list[1].protocol = esp_mail_protocol_ssl; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /* Close the seeion in case the session is still open */ + imap.closeSession(); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Data_Stream_Callback/Data_Stream_Callback.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Data_Stream_Callback/Data_Stream_Callback.ino new file mode 100644 index 000000000..c06f4342e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Data_Stream_Callback/Data_Stream_Callback.ino @@ -0,0 +1,368 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to read Email and collect the stream data to print or store via the callback function. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** Assign SD card type and FS used in src/ESP_Mail_FS.h and + * change the config for that card interfaces in src/extras/SDHelper.h + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// Provide the SD card interfaces setting and mounting +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +void mimeDataStreamCallback(MIME_Data_Stream_Info streaminfo); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +int progress = 0; +int lastProgress = -1; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + +#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h + // Mount SD card. + SD_Card_Mounting(); // See src/extras/SDHelper.h +#endif + + /* Set the callback function to get MIME Data stream */ + imap.mimeDataStreamCallback(mimeDataStreamCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_sd; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud + , to allow case sensitive parse, uncomment below line*/ + // imap_data.enable.header_case_sensitive = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /** Message UID to fetch or read e.g. 100. + * In this case we will get the UID from the max message number (lastest message) + */ + imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount()); + + /* Set seen flag */ + + // The message with "Seen" flagged means the message was already read or seen by user. + // The default value of this option is set to false. + // If you want to set the message flag as "Seen", set this option to true. + // If this option is false, the message flag was unchanged. + // To set or remove flag from message, see Set_Flags.ino example. + + // imap_data.fetch.set_seen = true; + + /* Read or search the Email and close the session */ + + // When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status, + // as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag + // to message, see the Set_Flags.ino example. + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ +} + +void mimeDataStreamCallback(MIME_Data_Stream_Info streaminfo) +{ + if (streaminfo.isFirstData) + { + progress = 0; + lastProgress = -1; + + Serial.print("Message UID: "); + Serial.println(streaminfo.uid); + + Serial.print("Content Type: "); + Serial.println(streaminfo.type); + + Serial.print("Content Disposition: "); + Serial.println(streaminfo.disposition); + + Serial.print("Text Character Set: "); + Serial.println(streaminfo.charSet); + + Serial.print("Content Transfer Encoding: "); + Serial.println(streaminfo.transfer_encoding); + + // The total octets of encoded or non-encoded MIME content. + // The size of decoded content may be different. + Serial.print("Total Octets: "); + Serial.println(streaminfo.octet_size); + + if (strcmp(streaminfo.disposition, "attachment") == 0 || strcmp(streaminfo.disposition, "inline") == 0) + { + + if (strcmp(streaminfo.disposition, "inline") == 0) + { + Serial.print("Content ID: "); + Serial.println(streaminfo.cid); + } + + Serial.print("Name: "); + Serial.println(streaminfo.name); + + Serial.print("File Name: "); + Serial.println(streaminfo.filename); + + Serial.print("Size: "); + Serial.println(streaminfo.size); + + Serial.print("Content Description: "); + Serial.println(streaminfo.description); + + Serial.print("Creation Date: "); + Serial.println(streaminfo.date); + } + + Serial.println("Content:"); + } + + progress = 100 * streaminfo.octet_count / streaminfo.octet_size; + + if (progress != lastProgress && (progress == 0 || progress == 100 || lastProgress + 5 <= progress)) + { + + lastProgress = progress; + + // The size of current decoded chunk data + Serial.print("Data Length: "); + Serial.print(streaminfo.data_size); + + Serial.print(", Reading %: "); + Serial.println(progress); + } + + // Decoded chunk data is available here + if (streaminfo.data) + { + + // If streaminfo.transfer_encoding is 'base64', + // to print or send null terminated string from stream data + + /** + char str[streaminfo.data_size + 1]; + memcpy(str, streaminfo.data, streaminfo.data_size); + str[streaminfo.data_size] = 0; + Serial.print(str); + */ + + // If streaminfo.transfer_encoding is not 'base64', the string can be + // taken directly from casting streaminfo.data as (const char*)streaminfo.data + + // To write data to file (if fs is File class object that open in appended mode) + // fs.write((uint8_t *)streaminfo.data, streaminfo.data_size); + + // streaminfo.data_size is not more than 512 + } + + if (streaminfo.isLastData) + { + Serial.println(); + Serial.println(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_List/Delete_Messages_List.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_List/Delete_Messages_List.ino new file mode 100644 index 000000000..42020a5c9 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_List/Delete_Messages_List.ino @@ -0,0 +1,218 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to delete messages from the mailbox. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Define the MessageList class to add the message to delete */ + MessageList toDelete; + + /** Add message uid to delete to the list + * In this case we will delete last 10 messages by get the UID of these message + * and add it to the list + */ + for (int i = imap.selectedFolder().msgCount(); i > (int)imap.selectedFolder().msgCount() - 10 && i > 0; i--) + toDelete.add(imap.getUID(i)); + + /* Delete all messages in the list (move to trash) */ + if (imap.deleteMessages(&toDelete)) + Serial.println("\nMessages deleted"); + + /* Delete all messages permanently by assign the second param to true*/ + // imap.deleteMessages(&toDelete, true); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_Message_Numbers_Ranges/Delete_Messages_Message_Numbers_Ranges.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_Message_Numbers_Ranges/Delete_Messages_Message_Numbers_Ranges.ino new file mode 100644 index 000000000..8d589e625 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_Message_Numbers_Ranges/Delete_Messages_Message_Numbers_Ranges.ino @@ -0,0 +1,229 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to delete messages from the mailbox using message numbers ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Copy all messages using UIDs ranges (last 10 message numbers) to the folder "test" */ + int msg_last = imap.selectedFolder().msgCount(); + int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last; + + String sequence_set1 = String(msg_begin) + ":" + String(msg_last); + + if (imap.copyMessages(sequence_set1, true /* if sequence set are the UIDs */, F("test"))) + Serial.println("\nCopying messages using message numbers ranges success"); + else + Serial.println("\nError, copying messages using message numbers ranges"); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("test"))) + return; + + delay(10000); + + /* Delete all messages using UIDs ranges (last 10 message numbers) from the folder "test" */ + msg_last = imap.selectedFolder().msgCount(); + msg_begin = msg_last > 10 ? msg_last - 10 : msg_last; + + sequence_set1 = String(msg_begin) + ":" + String(msg_last); + + if (imap.deleteMessages(sequence_set1, true /* if sequence set are the UIDs */, false)) + Serial.println("\nDeleting messages using message numbers ranges success"); + else + Serial.println("\nError, Deleting messages using message numbers ranges"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_UIDs_Ranges/Delete_Messages_UIDs_Ranges.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_UIDs_Ranges/Delete_Messages_UIDs_Ranges.ino new file mode 100644 index 000000000..cb0c90d7f --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Delete_Messages/Delete_Messages_UIDs_Ranges/Delete_Messages_UIDs_Ranges.ino @@ -0,0 +1,229 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to delete messages from the mailbox using UIDs ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Copy all messages using UIDs ranges (last 10 UIDs) to the folder "test" */ + int uid_last = imap.getUID(imap.selectedFolder().msgCount()); + int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last; + + String sequence_set1 = String(uid_begin) + ":" + String(uid_last); + + if (imap.copyMessages(sequence_set1, true /* if sequence set are the UIDs */, F("test"))) + Serial.println("Copying messages using UIDs ranges success"); + else + Serial.println("Error, copying messages using UIDs ranges"); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("test"))) + return; + + delay(10000); + + /* Delete all messages using UIDs ranges (last 10 UIDs) from the folder "test" */ + uid_last = imap.getUID(imap.selectedFolder().msgCount()); + uid_begin = uid_last > 10 ? uid_last - 10 : uid_last; + + sequence_set1 = String(uid_begin) + ":" + String(uid_last); + + if (imap.deleteMessages(sequence_set1, true /* if sequence set are the UIDs */, false)) + Serial.println("Deleting messages using UIDs ranges success"); + else + Serial.println("Error, Deleting messages using UIDs ranges"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/External_Client/External_Client.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/External_Client/External_Client.ino new file mode 100644 index 000000000..65e11b7b3 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/External_Client/External_Client.ino @@ -0,0 +1,334 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +/** + * This example shows how to send Email using EthernetClient. + * + * This example used ESP32 and WIZnet W5500 Ethernet module. + * + * Please see examples/SMTP/Ethernet and examples/SMTP/External_Client for more usage + */ + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include + +#include + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define IMAP_HOST "" +#define IMAP_PORT 993 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +void imapCallback(IMAP_Status status); + +void printAllMailboxesInfo(IMAPSession &imap); + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +void printMessages(std::vector &msgItems, bool headerOnly); + +void printAttacements(std::vector &atts); + +IMAPSession imap; + +EthernetClient eth_client; + +void networkConnection() +{ + // Reset the network connection + WiFi.disconnect(); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + Serial.print("Connecting to Wi-Fi"); + unsigned long ms = millis(); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); + if (millis() - ms >= 5000) + { + Serial.println(" failed!"); + return; + } + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); +} + +void networkStatusRequestCallback() +{ + imap.setNetworkStatus(WiFi.status() == WL_CONNECTED); +} + +void setup() +{ + + Serial.begin(115200); + + Serial.println(); + + MailClient.networkReconnect(true); + + // The WiFi credentials are required for SAMD21 + // due to it does not have reconnect feature. + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); + + networkConnection(); + + imap.debug(1); + + /* + For internal NTP client + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + MailClient.setUDPClient(&udp_client, 0 /* GMT offset */); + + MailClient.networkReconnect(true); + + imap.callback(imapCallback); + + Session_Config config; + + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + IMAP_Data imap_data; + + imap_data.search.criteria.clear(); + + imap_data.search.unseen_msg = true; + + imap_data.storage.saved_path = F("/email_data"); + + imap_data.storage.type = esp_mail_file_storage_type_flash; + + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + imap_data.enable.html = true; + imap_data.enable.text = true; + + imap_data.enable.recent_sort = true; + + imap_data.enable.download_status = true; + + imap_data.limit.search = 5; + + imap_data.limit.msg_size = 512; + + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + imap.setClient(ð_client); + + imap.networkConnectionRequestCallback(networkConnection); + + imap.networkStatusRequestCallback(networkStatusRequestCallback); + + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + printAllMailboxesInfo(imap); + + if (!imap.selectFolder(F("INBOX"))) + return; + + printSelectedMailboxInfo(imap.selectedFolder()); + + imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount()); + + MailClient.readMail(&imap); + + imap.empty(); +} + +void loop() +{ +} + +void imapCallback(IMAP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + FoldersCollection folders; + + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + for (size_t i = 0; i < msgItems.size(); i++) + { + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Firmware_Update_Attachment/Firmware_Update_Attachment.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Firmware_Update_Attachment/Firmware_Update_Attachment.ino new file mode 100644 index 000000000..15f706daa --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Firmware_Update_Attachment/Firmware_Update_Attachment.ino @@ -0,0 +1,464 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to read Email and update firmware if firmware file name in attachments matches. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// Provide the SD card interfaces setting and mounting +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Print all messages from the message list */ +void printMessages(std::vector &msgItems, bool headerOnly); + +/* Print all attachments info from the message */ +void printAttacements(std::vector &atts); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + +#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h + // Mount SD card. + SD_Card_Mounting(); // See src/extras/SDHelper.h +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Assign the attachment filename to compare, update firmware if it matches */ + imap_data.firmware_update.attach_filename = "firmware.bin"; + /* save (download) firmware to file? */ + imap_data.firmware_update.save_to_file = false; + + /** + * Device will reboot in if imap.isFirmwareUpdated() returns true in imapCallback function. + * To disable firmware update, call imap_data.firmware_update.attach_filename.clear(); or + * imap_data.firmware_update.attach_filename = ""; + * + */ + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud + , to allow case sensitive parse, uncomment below line*/ + // imap_data.enable.header_case_sensitive = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /** Message UID to fetch or read e.g. 100. + * In this case we will get the UID from the max message number (lastest message) + */ + imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount()); + + // or fetch via the message sequence number + // imap_data.fetch.number = imap.selectedFolder().msgCount(); + + // if both imap_data.fetch.uid and imap_data.fetch.number were set, + // then total 2 messages will be fetched i.e. one using uid and other using number. + + /* Set seen flag */ + + // The message with "Seen" flagged means the message was already read or seen by user. + // The default value of this option is set to false. + // If you want to set the message flag as "Seen", set this option to true. + // If this option is false, the message flag was unchanged. + // To set or remove flag from message, see Set_Flags.ino example. + + // imap_data.fetch.set_seen = true; + + /* Read or search the Email and close the session */ + + // When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status, + // as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag + // to message, see the Set_Flags.ino example. + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + + if (imap.isFirmwareUpdateSuccess()) + { + Serial.println("****************************"); + Serial.println("Firmware is already updated, restarting device..."); + delay(2000); +#if defined(ESP32) || defined(ESP8266) + ESP.restart(); +#elif defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_NANO_RP2040_CONNECT) + rp2040.restart(); +#endif + } + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + /** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and + * the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename + * (> 13 characters) is not support in the SD.h library. + * To show how its original file name, use imap.fileList(). + */ + // Serial.println(imap.fileList()); + + for (size_t i = 0; i < msgItems.size(); i++) + { + + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + /* If the result contains the message info (Fetch mode) */ + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Get_Quota/Get_Quota.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Get_Quota/Get_Quota.ino new file mode 100644 index 000000000..aae7f050d --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Get_Quota/Get_Quota.ino @@ -0,0 +1,215 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to get the quota root's resource usage and limits. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + IMAP_Quota_Root_Info info; + + Serial.println("\nGet quota root..."); + + if (!imap.getQuota("", &info)) + { + Serial.println("Get quota root failed"); + } + else + { + MailClient.printf("Quota root: %s, Resource name: %s, Usage (k): %d, Limit (k): %d\n", info.quota_root.c_str(), info.name.c_str(), (int)info.usage, (int)info.limit); + } + + IMAP_Quota_Roots_List quota_roots; + + Serial.println("\nGet quota roots list for INBOX folder..."); + + if (!imap.getQuotaRoot("INBOX", "a_roots)) + { + Serial.println("\nGet quota roots list failed"); + } + else + { + for (size_t i = 0; i < quota_roots.size(); i++) + MailClient.printf("%d, Quota root: %s, Resource name: %s, Usage (k): %d, Limit (k): %d\n", (int)i + 1, quota_roots[i].quota_root.c_str(), quota_roots[i].name.c_str(), (int)quota_roots[i].usage, (int)quota_roots[i].limit); + } + + Serial.println("\nSet quota root..."); + + info.name = "STORAGE"; + info.limit = 1024 * 1024; // 1048576 k or 1 G. + + if (!imap.setQuota("", &info)) + { + Serial.println("\nSet quota root failed"); + } + else + { + Serial.println("\nSet quota root success"); + } + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Mailbox_Changes_Notification/Mailbox_Changes_Notification.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Mailbox_Changes_Notification/Mailbox_Changes_Notification.ino new file mode 100644 index 000000000..271a9f53a --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Mailbox_Changes_Notification/Mailbox_Changes_Notification.ino @@ -0,0 +1,446 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to get notification in realtime when incoming message arrived and other mailbox changes. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the selected folder update info */ +void printPollingStatus(IMAPSession &imap); + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Print all messages from the message list */ +void printMessages(std::vector &msgItems, bool headerOnly); + +/* Print all attachments info from the message */ +void printAttacements(std::vector &atts); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +/* Declare the global used Session_Config for user defined session credentials */ +Session_Config config; + +/* Define the IMAP_Data object used for user defined IMAP operating options. */ +IMAP_Data imap_data; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void connectWiFi() +{ + WiFi.disconnect(); + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + connectWiFi(); + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /** Assign internet connection handler function + * in case of lost internet connection for re-listening the mailbox. + */ + config.network_connection_handler = connectWiFi; + + // You can use TCP KeepAlive for more reliable of listen (idle) operation, please read this for detail. + // https://github.com/mobizt/ESP-Mail-Client#using-tcp-session-keepalive-in-esp8266-and-esp32 + // You can use keepAlive in ESP8266 core version newer than v3.1.2. + // Or you can use git version (v3.1.2) https://github.com/esp8266/Arduino +#if defined(ESP32) + imap.keepAlive(5, 5, 1); +#endif + + /* Set the TCP response read timeout in seconds */ + // smtp.setTCPTimeout(10); + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); +} + +void loop() +{ + /* imap.connect and imap.selectFolder or imap.openFolder nedded to be called once prior to listen */ + + // Listen for mailbox changes + if (!imap.listen()) + return; + + // Check the changes + if (imap.folderChanged()) + printPollingStatus(imap); + + // To stop listen, use imap.stopListen(); and to listen again, call imap.listen() +} + +void printPollingStatus(IMAPSession &imap) +{ + /* Declare the selected folder info class to get the info of selected mailbox folder */ + SelectedFolderInfo sFolder = imap.selectedFolder(); + + /* Show the mailbox info */ + MailClient.printf("\nMailbox status changed\n----------------------\nTotal Messages: %d\n", sFolder.msgCount()); + + if (sFolder.pollingStatus().type == imap_polling_status_type_new_message) + { + + MailClient.printf("New message %d, has been addedd, reading message...\n", (int)sFolder.pollingStatus().messageNum); + + // if (sFolder.recentCount() > 0) + // MailClient.printf("\nMesssage count which recent flag set: %d\n", sFolder.recentCount()); + + // we need to stop polling before do anything + imap.stopListen(); + + // Get the UID of new message and fetch + imap_data.fetch.uid = imap.getUID(sFolder.pollingStatus().messageNum); + MailClient.readMail(&imap, false); + } + else if (sFolder.pollingStatus().type == imap_polling_status_type_remove_message) + MailClient.printf("Message %d, has been removed\n\n", (int)sFolder.pollingStatus().messageNum); + else if (sFolder.pollingStatus().type == imap_polling_status_type_fetch_message) + MailClient.printf("Message %d, has been fetched with the argument %s\n\n", (int)sFolder.pollingStatus().messageNum, sFolder.pollingStatus().argument.c_str()); +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + for (size_t i = 0; i < msgItems.size(); i++) + { + + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + /* If the result contains the message info (Fetch mode) */ + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_List/Move_Messages_List.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_List/Move_Messages_List.ino new file mode 100644 index 000000000..bf95fcc20 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_List/Move_Messages_List.ino @@ -0,0 +1,214 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to move messages from the mailbox to other folder. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Define the MessageList class to add the message to move */ + MessageList toMove; + + /* Add message uid to move to the list */ + toMove.add(3); + toMove.add(4); + + // imap.createFolder("test"); + + /* Move all messages in the list to the folder "test" */ + if (imap.moveMessages(&toMove, F("test"))) + Serial.println("\nMessages moved"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_Message_Numbers_Ranges/Move_Messages_Message_Numbers_Ranges.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_Message_Numbers_Ranges/Move_Messages_Message_Numbers_Ranges.ino new file mode 100644 index 000000000..329c9db99 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_Message_Numbers_Ranges/Move_Messages_Message_Numbers_Ranges.ino @@ -0,0 +1,213 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to move messages from the mailbox to other folder using message numbers ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Move all messages using message sequence ranges (last 10 message numbers) to the folder "test"*/ + int msg_last = imap.selectedFolder().msgCount(); + int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last; + + String sequence_set2 = String(msg_begin) + ":" + String(msg_last); + + if (imap.moveMessages(sequence_set2, false /* if sequence set are message numbers not UIDs */, F("test"))) + Serial.println("\nMoving messages using message numbers ranges success"); + else + Serial.println("\nError, moving messages using message numbers ranges"); + + // imap.deleteolder("test"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_UIDs_Ranges/Move_Messages_UIDs_Ranges.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_UIDs_Ranges/Move_Messages_UIDs_Ranges.ino new file mode 100644 index 000000000..3d75cc065 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Move_Messages/Move_Messages_UIDs_Ranges/Move_Messages_UIDs_Ranges.ino @@ -0,0 +1,214 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to move messages from the mailbox to other folder using UIDs ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* Move all messages using UIDs ranges (last 10 UIDs) to the folder "test" */ + int uid_last = imap.getUID(imap.selectedFolder().msgCount()); + int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last; + + String sequence_set1 = String(uid_begin) + ":" + String(uid_last); + + if (imap.moveMessages(sequence_set1, true /* if sequence set are the UIDs */, F("test"))) + Serial.println("\nMoving messages using UIDs ranges success"); + else + Serial.println("\nError, moving messages using UIDs ranges"); + + // imap.deleteolder("test"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Namespaces/Namespaces.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Namespaces/Namespaces.ino new file mode 100644 index 000000000..533d90dcf --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Namespaces/Namespaces.ino @@ -0,0 +1,216 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to get the namespaces. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + IMAP_Namespaces_List ns_list; + + Serial.println("\nGet namespaces..."); + + if (!imap.getNamespace(&ns_list)) + { + Serial.println("\nGet namespaces failed"); + } + else + { + if (ns_list.personal_namespaces.size() > 0) + { + Serial.println("\nPersonal Namespaces..."); + for (size_t i = 0; i < ns_list.personal_namespaces.size(); i++) + { + MailClient.printf("Prefix: %s, Delimiter: %s\n", ns_list.personal_namespaces[i].prefix.c_str(), ns_list.personal_namespaces[i].delimiter.c_str()); + } + } + + if (ns_list.other_users_namespaces.size() > 0) + { + Serial.println("\nOther Users Namespaces..."); + for (size_t i = 0; i < ns_list.other_users_namespaces.size(); i++) + { + MailClient.printf("Prefix: %s, Delimiter: %s\n", ns_list.other_users_namespaces[i].prefix.c_str(), ns_list.other_users_namespaces[i].delimiter.c_str()); + } + } + + if (ns_list.shared_namespaces.size() > 0) + { + Serial.println("\nShared Namespaces..."); + for (size_t i = 0; i < ns_list.shared_namespaces.size(); i++) + { + MailClient.printf("Prefix: %s, Delimiter: %s\n", ns_list.shared_namespaces[i].prefix.c_str(), ns_list.shared_namespaces[i].delimiter.c_str()); + } + } + } + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Email_Access_Token/Read_Email_Access_Token.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Email_Access_Token/Read_Email_Access_Token.ino new file mode 100644 index 000000000..26b32a91b --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Email_Access_Token/Read_Email_Access_Token.ino @@ -0,0 +1,472 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example will log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" + +/** The OAuth2.0 access token + * The generation, exchange and refresh of the access token are not available + * in this library. + * + * To test this using GMail, get the OAuth2.0 access token from this web site + * https://developers.google.com/oauthplayground/ + * + * 1. Select the following scope (in Step 1) from Gmail API V1 + * https://mail.google.com/ + * https://mail.google.com/ + * + * 2. Click Authorize APIs button. + * 3. Cick Exchangeauthorization code for tokens. + * 4. From the response, look at access_token from the JSON payload node. + * 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value. + * + * The token will be expired in 3600 seconds (1 Hr). + * The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services. + */ +#define AUTHOR_ACCESS_TOKEN "" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Print all messages from the message list */ +void printMessages(std::vector &msgItems, bool headerOnly); + +/* Print all attachments info from the message */ +void printAttacements(std::vector &atts); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.accessToken = AUTHOR_ACCESS_TOKEN; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Message UID to fetch or read e.g. 100 */ + imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount()); + + /* Set seen flag*/ + // imap_data.fetch.set_seen = true; + + /* Search criteria */ + imap_data.search.criteria.clear(); + + /* Also search the unseen message */ + imap_data.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud + , to allow case sensitive parse, uncomment below line*/ + // imap_data.enable.header_case_sensitive = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /* Read or search the Email and close the session */ + + // When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status, + // as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag + // to message, see the Set_Flags.ino example. + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + /** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and + * the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename + * (> 13 characters) is not support in the SD.h library. + * To show how its original file name, use imap.fileList(). + */ + // Serial.println(imap.fileList()); + + for (size_t i = 0; i < msgItems.size(); i++) + { + + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + /* If the result contains the message info (Fetch mode) */ + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Sequence_Set/Read_Sequence_Set.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Sequence_Set/Read_Sequence_Set.ino new file mode 100644 index 000000000..63ce16c97 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Sequence_Set/Read_Sequence_Set.ino @@ -0,0 +1,477 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to read Email using UIDs ranges or message numbers ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** Assign SD card type and FS used in src/ESP_Mail_FS.h and + * change the config for that card interfaces in src/extras/SDHelper.h + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Print all messages from the message list */ +void printMessages(std::vector &msgItems, bool headerOnly); + +/* Print all attachments info from the message */ +void printAttacements(std::vector &atts); + +/* Declare the Session_Config for user defined session credentials */ +Session_Config config; + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +/* Define the IMAP_Data object used for user defined IMAP operating options. */ +IMAP_Data imap_data; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void readEmailsUIDS() +{ + + int uid_last = imap.getUID(imap.selectedFolder().msgCount()); + int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last; + + // Fetch last 10 UIDs + String sequence_set = String(uid_begin) + ":" + String(uid_last); + + imap_data.fetch.sequence_set.string = sequence_set; + + imap_data.fetch.sequence_set.UID = true; // The sequence set are UIDs ranges + + imap_data.fetch.sequence_set.headerOnly = true; // Do not fetch the content, header only + + MailClient.readMail(&imap, false /* do not close sessiopn */); + + imap_data.limit.fetch = 5; // Set the limit of number of messages in the fetch results +} + +void readEmailsNumbers() +{ + int msg_last = imap.selectedFolder().msgCount(); + int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last; + + String sequence_set = String(msg_begin) + ":" + String(msg_last); + + imap_data.fetch.sequence_set.string = sequence_set; + + imap_data.fetch.sequence_set.UID = false; // The sequence set are not UIDs + + imap_data.fetch.sequence_set.headerOnly = true; // Do not fetch the content, header only + + imap_data.limit.fetch = 5; // Set the limit of number of messages in the fetch results + + // Read Email and close session + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud + , to allow case sensitive parse, uncomment below line*/ + // imap_data.enable.header_case_sensitive = true; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + // If ID extension was supported by IMAP server, assign the client identification + // name, version, vendor, os, os_version, support_url, address, command, arguments, environment + // Server ID can be optained from imap.serverID() after calling imap.connect and imap.id. + + // imap_data.identification.name = "User"; + // imap_data.identification.version = "1.0"; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + // Client identification can be sent to server later with + /** + * IMAP_Identification iden; + * iden.name = "user"; + * iden.version = "1.0"; + * + * if (imap.id(&iden)) + * { + * Serial.println("\nSend Identification success"); + * Serial.println(imap.serverID()); + * } + * else + * MailClient.printf("nIdentification sending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + */ + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + Serial.println("::::::::::::::::: Reading Emails using the UIDs ranges ::::::::::::::::"); + readEmailsUIDS(); + + Serial.println("::::::::::: Reading Emails using the message numbers ranges :::::::::::"); + readEmailsNumbers(); +} + +void loop() +{ +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + /** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and + * the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename + * (> 13 characters) is not support in the SD.h library. + * To show how its original file name, use imap.fileList(). + */ + // Serial.println(imap.fileList()); + + for (size_t i = 0; i < msgItems.size(); i++) + { + + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + /* If the result contains the message info (Fetch mode) */ + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email/Read_Single_Email.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email/Read_Single_Email.ino new file mode 100644 index 000000000..c8533ed92 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email/Read_Single_Email.ino @@ -0,0 +1,516 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to read Email and store the message in SD card. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** Assign SD card type and FS used in src/ESP_Mail_FS.h and + * change the config for that card interfaces in src/extras/SDHelper.h + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// Provide the SD card interfaces setting and mounting +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Print all messages from the message list */ +void printMessages(std::vector &msgItems, bool headerOnly); + +/* Print all attachments info from the message */ +void printAttacements(std::vector &atts); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + +#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h + // Mount SD card. + SD_Card_Mounting(); // See src/extras/SDHelper.h +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_sd; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud + , to allow case sensitive parse, uncomment below line*/ + // imap_data.enable.header_case_sensitive = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + // If ID extension was supported by IMAP server, assign the client identification + // name, version, vendor, os, os_version, support_url, address, command, arguments, environment + // Server ID can be optained from imap.serverID() after calling imap.connect and imap.id. + + // imap_data.identification.name = "User"; + // imap_data.identification.version = "1.0"; + + /* Set the TCP response read timeout in seconds */ + // imap.setTCPTimeout(10); + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + /** Or connect without log in and log in later + + if (!imap.connect(&config, &imap_data, false)) + return; + + if (!imap.loginWithPassword(AUTHOR_EMAIL, AUTHOR_PASSWORD)) + return; + */ + + // Client identification can be sent to server later with + /** + * IMAP_Identification iden; + * iden.name = "user"; + * iden.version = "1.0"; + * + * if (imap.id(&iden)) + * { + * Serial.println("\nSend Identification success"); + * Serial.println(imap.serverID()); + * } + * else + * MailClient.printf("nIdentification sending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + */ + + if (!imap.isLoggedIn()) + { + Serial.println("\nNot yet logged in."); + } + else + { + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + } + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /** Message UID to fetch or read e.g. 100. + * In this case we will get the UID from the max message number (lastest message) + */ + imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount()); + + // if IMAP server supports CONDSTORE extension, the modification sequence can be assign to fetch command + // Note that modsequence value supports in this library is 32-bit integer + imap_data.fetch.modsequence = 123; + + // To fetch only header part + // imap_data.fetch.headerOnly = true; + + // or fetch via the message sequence number + // imap_data.fetch.number = imap.selectedFolder().msgCount(); + + // if both imap_data.fetch.uid and imap_data.fetch.number were set, + // then total 2 messages will be fetched i.e. one using uid and other using number. + + /* Set seen flag */ + + // The message with "Seen" flagged means the message was already read or seen by user. + // The default value of this option is set to false. + // If you want to set the message flag as "Seen", set this option to true. + // If this option is false, the message flag was unchanged. + // To set or remove flag from message, see Set_Flags.ino example. + + // imap_data.fetch.set_seen = true; + + /* Fetch or read only message header */ + // imap_data.fetch.headerOnly = true; + + /* Read or search the Email and close the session */ + + // When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status, + // as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag + // to message, see the Set_Flags.ino example. + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + /** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and + * the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename + * (> 13 characters) is not support in the SD.h library. + * To show how its original file name, use imap.fileList(). + */ + // Serial.println(imap.fileList()); + + for (size_t i = 0; i < msgItems.size(); i++) + { + + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + /* If the result contains the message info (Fetch mode) */ + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email_Loop/Read_Single_Email_Loop.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email_Loop/Read_Single_Email_Loop.ino new file mode 100644 index 000000000..96d1d5568 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email_Loop/Read_Single_Email_Loop.ino @@ -0,0 +1,561 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to read Email repeatedly. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +/** Assign SD card type and FS used in src/ESP_Mail_FS.h and + * change the config for that card interfaces in src/extras/SDHelper.h + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// Provide the SD card interfaces setting and mounting +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Print all messages from the message list */ +void printMessages(std::vector &msgItems, bool headerOnly); + +/* Print all attachments info from the message */ +void printAttacements(std::vector &atts); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +unsigned long readMillis = 0; +int totalMessage = 0; +int msgNum = 0; +int sign = -1; + +/* Declare the global used Session_Config for user defined session credentials */ +Session_Config config; + +/* Define the IMAP_Data object used for user defined IMAP operating options. */ +IMAP_Data imap_data; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +// For Free Heap checking +#include "HeapStat.h" +HeapStat heapInfo; + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + +#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h + // Mount SD card. + SD_Card_Mounting(); // See src/extras/SDHelper.h +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Message UID to fetch or read */ + imap_data.fetch.uid.clear(); + + /* Search criteria */ + imap_data.search.criteria.clear(); + + /* Also search the unseen message */ + imap_data.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_sd; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = false; + imap_data.download.text = false; + imap_data.download.html = false; + imap_data.download.attachment = false; + imap_data.download.inlineImg = false; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud + , to allow case sensitive parse, uncomment below line*/ + // imap_data.enable.header_case_sensitive = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + // If ID extension was supported by IMAP server, assign the client identification + // name, version, vendor, os, os_version, support_url, address, command, arguments, environment + // Server ID can be optained from imap.serverID() after calling imap.connect and imap.id. + + // imap_data.identification.name = "User"; + // imap_data.identification.version = "1.0"; + + /* Set the TCP response read timeout in seconds */ + // imap.setTCPTimeout(10); + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + // Client identification can be sent to server later with + /** + * IMAP_Identification iden; + * iden.name = "user"; + * iden.version = "1.0"; + * + * if (imap.id(&iden)) + * { + * Serial.println("\nSend Identification success"); + * Serial.println(imap.serverID()); + * } + * else + * MailClient.printf("nIdentification sending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + */ + + if (!imap.isLoggedIn()) + { + Serial.println("\nNot yet logged in."); + } + else + { + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + } + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + totalMessage = imap.selectedFolder().msgCount(); + + /* Start fetch from last message */ + msgNum = totalMessage; + sign = -1; // count down + + /* To start fetch from first message */ + // msgNum = 1; + // sign = 1;// count up +} + +void loop() +{ + if (millis() - readMillis > 10000 || readMillis == 0) + { + readMillis = millis(); + + // If session was closed, reconnect and re-select the mailbox + if (!imap.connected()) + { + if (!imap.connect(&config, &imap_data)) + return; + + if (!imap.selectFolder(F("INBOX"))) + return; + + if (totalMessage == 0) + { + totalMessage = imap.selectedFolder().msgCount(); + msgNum = totalMessage; + sign = -1; + } + } + + if (msgNum <= 0) + { + msgNum = 1; + sign = 1; + } + else if (msgNum >= totalMessage) + { + msgNum = totalMessage; + sign = -1; + } + + /* Message number to fetch or read */ + imap_data.fetch.number = msgNum; + + /* Set seen flag */ + // imap_data.fetch.set_seen = true; + + /* Fetch or read only message header */ + // imap_data.fetch.headerOnly = true; + + /** Read or search the Email and keep the TCP session to open + * The second parameter is for close the session. + */ + + // When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status, + // as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag + // to message, see the Set_Flags.ino example. + if (MailClient.readMail(&imap, false)) + msgNum += sign; + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + + msgNum += sign; + } +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + + // Collect memory info + heapInfo.collect(); + + // Print memory info + heapInfo.print(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + /** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and + * the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename + * (> 13 characters) is not support in the SD.h library. + * To show how its original file name, use imap.fileList(). + */ + // Serial.println(imap.fileList()); + + for (size_t i = 0; i < msgItems.size(); i++) + { + + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + /* If the result contains the message info (Fetch mode) */ + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email_Loop_Silent_Mode/Read_Single_Email_Loop_Silent_Mode.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email_Loop_Silent_Mode/Read_Single_Email_Loop_Silent_Mode.ino new file mode 100644 index 000000000..94183bbd7 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Read_Single_Email_Loop_Silent_Mode/Read_Single_Email_Loop_Silent_Mode.ino @@ -0,0 +1,402 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to read Email repeatedly. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** + * To use library in silent mode (no debug printing and callback), please define this macro in src/ESP_Mail_FS.h. + * #define SILENT_MODE + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define IMAP_HOST "" + +#define IMAP_PORT 993 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +void printImapData(IMAP_Status status); + +void printAllMailboxesInfo(IMAPSession &imap); + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +void printMessages(std::vector &msgItems, bool headerOnly); + +void printAttacements(std::vector &atts); + +IMAPSession imap; + +unsigned long readMillis = 0; +int totalMessage = 0; +int msgNum = 0; +int sign = -1; + +Session_Config config; + +IMAP_Data imap_data; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +// For Free Heap checking +#include "HeapStat.h" +HeapStat heapInfo; + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + MailClient.networkReconnect(true); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + +#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h + // Mount SD card. + SD_Card_Mounting(); // See src/extras/SDHelper.h +#endif + + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + imap_data.fetch.uid.clear(); + + imap_data.search.criteria.clear(); + + imap_data.search.unseen_msg = true; + + imap_data.storage.saved_path = F("/email_data"); + + imap_data.storage.type = esp_mail_file_storage_type_sd; + + imap_data.download.header = false; + imap_data.download.text = false; + imap_data.download.html = false; + imap_data.download.attachment = false; + imap_data.download.inlineImg = false; + + imap_data.enable.html = true; + imap_data.enable.text = true; + + imap_data.enable.recent_sort = true; + + imap_data.enable.download_status = true; + + imap_data.limit.search = 5; + + imap_data.limit.msg_size = 512; + + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + if (!imap.connect(&config, &imap_data)) + { + MailClient.printf("Connection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + return; + } + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + printAllMailboxesInfo(imap); + + if (!imap.selectFolder(F("INBOX"))) + { + MailClient.printf("Folder selection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + return; + } + + printSelectedMailboxInfo(imap.selectedFolder()); + + totalMessage = imap.selectedFolder().msgCount(); + + msgNum = totalMessage; + sign = -1; // count down +} + +void loop() +{ + if (millis() - readMillis > 10000 || readMillis == 0) + { + readMillis = millis(); + + if (!imap.connected()) + { + if (!imap.connect(&config, &imap_data)) + return; + + if (!imap.selectFolder(F("INBOX"))) + return; + + if (totalMessage == 0) + { + totalMessage = imap.selectedFolder().msgCount(); + msgNum = totalMessage; + sign = -1; + } + } + + if (msgNum <= 0) + { + msgNum = 1; + sign = 1; + } + else if (msgNum >= totalMessage) + { + msgNum = totalMessage; + sign = -1; + } + + imap_data.fetch.number = msgNum; + + if (MailClient.readMail(&imap, false)) + { + printImapData(imap.status()); + } + else + { + MailClient.printf("Message reading error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + } + + imap.empty(); + + msgNum += sign; + } +} + +void printImapData(IMAP_Status status) +{ + + if (status.success()) + { + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + imap.empty(); + + heapInfo.collect(); + + heapInfo.print(); + + Serial.println(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + + FoldersCollection folders; + + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + for (size_t i = 0; i < msgItems.size(); i++) + { + + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_And_Read/Search_And_Read.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_And_Read/Search_And_Read.ino new file mode 100644 index 000000000..7ad828a1e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_And_Read/Search_And_Read.ino @@ -0,0 +1,352 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to search the unread messages and read them. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** + * To use library in silent mode (no debug printing and callback), please define this macro in src/ESP_Mail_FS.h. + * #define SILENT_MODE + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define IMAP_HOST "" + +#define IMAP_PORT 993 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +void imapCallback(IMAP_Status status); + +void printAllMailboxesInfo(IMAPSession &imap); + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +void printMessageData(); + +IMAPSession imap; + +Session_Config config; + +IMAP_Data imap_data; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +// Max messages in the search result +int max_result = 5; + +// Array to store the UID of messages in search result +int msg_uid[5]; + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + MailClient.networkReconnect(true); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + // Clear all these fetch options to perform search + imap_data.fetch.uid.clear(); + imap_data.fetch.number.clear(); + imap_data.fetch.sequence_set.string.clear(); + + imap_data.search.unseen_msg = true; + + // Don't download all to filesystem + imap_data.download.header = false; + imap_data.download.text = false; + imap_data.download.html = false; + imap_data.download.attachment = false; + imap_data.download.inlineImg = false; + + // Store html/text message body in IMAPSession object + imap_data.enable.html = true; + imap_data.enable.text = true; + + imap_data.enable.recent_sort = true; + + // Max messages in the search result + imap_data.limit.search = max_result; + + imap_data.limit.msg_size = 128; + + if (!imap.connect(&config, &imap_data)) + { + MailClient.printf("Connection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + return; + } + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + printAllMailboxesInfo(imap); + + if (!imap.selectFolder(F("INBOX"))) + { + MailClient.printf("Folder selection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + return; + } + + printSelectedMailboxInfo(imap.selectedFolder()); + + // We search the unseen messages first to get its UID and stored in msg_uid. + imap_data.search.criteria = F("SEARCH UNSEEN"); + + MailClient.readMail(&imap, false /* keep session open for fetching message in opened mailbox later */); + + // We already get the search result message, fetch it + + // Fetch the messages using UID stored in msg_uid one by one + for (int i = 0; i < max_result; i++) + { + imap_data.search.criteria.clear(); + + // Mark this message as read + MailClient.addFlag(&imap, msg_uid[i], F("\\Seen"), false /* Close session */, false /* Ignore response */); + + // Now Fech message by UID stored in msg_uid + imap_data.fetch.uid = msg_uid[i]; + + MailClient.readMail(&imap, false /* keep session open for fetching message in opened mailbox later */); + } + + imap.closeSession(); + imap.empty(); +} + +void loop() +{ +} + +void imapCallback(IMAP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + // If this is the search result (imap contains only header info), + // store the message UID that we can fetch for its body later. + if (imap.headerOnly()) + { + max_result = imap.data().msgItems.size(); + for (size_t i = 0; i < imap.data().msgItems.size(); i++) + msg_uid[i] = imap.data().msgItems[i].UID; + } + else + { + // This is the fetch result, print the whole message (header + body) + printMessageData(); + } + + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + + FoldersCollection folders; + + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printMessageData() +{ + + IMAP_MSG_Item msg = imap.data().msgItems[0]; // msgItems contains only one message from fetch + + Serial.println("****************************"); + + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + Serial.println(); +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_Emails/Search_Emails.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_Emails/Search_Emails.ino new file mode 100644 index 000000000..597b25652 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_Emails/Search_Emails.ino @@ -0,0 +1,533 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +// This example shows how to search all messages with the keywords in the opened mailbox folder. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 // Plain or TLS with STARTTLS + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT esp_mail_imap_port_143 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Print all messages from the message list */ +void printMessages(std::vector &msgItems, bool headerOnly); + +/* Print all attachments info from the message */ +void printAttacements(std::vector &atts); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Declare the IMAP_Data object used for user defined IMAP operating options + * and contains the IMAP operating result + */ + IMAP_Data imap_data; + + /* We will clear fetching message UID as it used to determine the reading mode i.e., search and fetch */ + imap_data.fetch.uid.clear(); + + /** Search criteria + * + * A search key can also be a parenthesized list of one or more search keys + * (e.g., for use with the OR and NOT keys). + * + * Since IMAP protocol uses Polish notation, the search criteria which in the polish notation form can be. + * + * To search the message from "someone@email.com" with the subject "my subject" since 1 Jan 2021, your search criteria can be + * UID SEARCH (OR SUBJECT "my subject" FROM "someone@email.com") SINCE "Fri, 1 Jan 2021 21:52:25 -0800" + * + * To search the message from "mail1@domain.com" or from "mail2@domain.com", the search criteria will be + * UID SEARCH OR FROM mail1@domain.com FROM mail2@domain.com + * + * For more details on using parentheses, AND, OR and NOT search keys in search criteria. + * https://www.limilabs.com/blog/imap-search-requires-parentheses + * + *For keywords used in search criteria, see + * https://github.com/mobizt/ESP-Mail-Client/tree/master/src#search-criteria + * + * Use "SEARCH UNSEEN" for unread messages search + * Use "SEARCH RECENT" for messages with the \\RECENT flag set + * Use "ON _date_" for messages with Date header matching _date_ + * Use "BEFORE _date_" for messages with Date header before _date_ + */ + imap_data.search.criteria = F("SEARCH RECENT"); + + /* Also search the unseen message */ + imap_data.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud + , to allow case sensitive parse, uncomment below line*/ + // imap_data.enable.header_case_sensitive = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + // If ID extension was supported by IMAP server, assign the client identification + // name, version, vendor, os, os_version, support_url, address, command, arguments, environment + // Server ID can be optained from imap.serverID() after calling imap.connect and imap.id. + + // imap_data.identification.name = "User"; + // imap_data.identification.version = "1.0"; + + /* Set the TCP response read timeout in seconds */ + // imap.setTCPTimeout(10); + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + /** Or connect without log in and log in later + + if (!imap.connect(&config, &imap_data, false)) + return; + + if (!imap.loginWithPassword(AUTHOR_EMAIL, AUTHOR_PASSWORD)) + return; + */ + + // Client identification can be sent to server later with + /** + * IMAP_Identification iden; + * iden.name = "user"; + * iden.version = "1.0"; + * + * if (imap.id(&iden)) + * { + * Serial.println("\nSend Identification success"); + * Serial.println(imap.serverID()); + * } + * else + * MailClient.printf("nIdentification sending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + */ + + if (!imap.isLoggedIn()) + { + Serial.println("\nNot yet logged in."); + } + else + { + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + } + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /** Read or search the Email and keep the TCP session to open + * The second parameter is for close the session. + */ + MailClient.readMail(&imap, false); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + + /** Open or select other mailbox folder + * The folder that previousely opened will be closed + */ + if (imap.selectFolder(F("Junk"))) + { + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /** Config to search all messages in the opened mailboax (Search mode) + * For keywords used in search criteria, see + * https://github.com/mobizt/ESP-Mail-Client/tree/master/src#search-criteria + */ + imap_data.search.criteria = F("SEARCH ALL"); // or "SEARCH NEW" for recent received messages + + /* We will clear fetching message UID as it used to determine the reading mode i.e., search and fetch */ + imap_data.fetch.uid.clear(); + + /* Search the Email and close the session */ + MailClient.readMail(&imap); + } + + /* Close the seeion in case the session is still open */ + imap.closeSession(); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); +} + +void loop() +{ +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + /* Print the result */ + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + /** att.type can be + * esp_mail_att_type_none or 0 + * esp_mail_att_type_attachment or 1 + * esp_mail_att_type_inline or 2 + */ + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + for (size_t i = 0; i < msgItems.size(); i++) + { + + /* Iterate to get each message data through the message item data */ + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + // Message sequence number + MailClient.printf("Number: %d\n", msg.msgNo); + // Message UID + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + /* If the result contains the message info (Fetch mode) */ + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_Emails_Silent_Mode/Search_Emails_Silent_Mode.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_Emails_Silent_Mode/Search_Emails_Silent_Mode.ino new file mode 100644 index 000000000..5f6367ef8 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Search_Emails_Silent_Mode/Search_Emails_Silent_Mode.ino @@ -0,0 +1,327 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to search all messages with the keywords in the opened mailbox folder. + +/** + * To use library in silent mode (no debug printing and callback), please define this macro in src/ESP_Mail_FS.h. + * #define SILENT_MODE + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define IMAP_HOST "" + +#define IMAP_PORT esp_mail_imap_port_143 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +void printImapData(IMAP_Status status); + +void printAllMailboxesInfo(IMAPSession &imap); + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +void printMessages(std::vector &msgItems, bool headerOnly); + +void printAttacements(std::vector &atts); + +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + MailClient.networkReconnect(true); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + Session_Config config; + + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + IMAP_Data imap_data; + + imap_data.fetch.uid.clear(); + + imap_data.search.criteria = F("SEARCH RECENT"); + + imap_data.search.unseen_msg = true; + + imap_data.storage.saved_path = F("/email_data"); + + imap_data.storage.type = esp_mail_file_storage_type_flash; + + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + imap_data.enable.html = true; + imap_data.enable.text = true; + + imap_data.enable.recent_sort = true; + + imap_data.enable.download_status = true; + + imap_data.limit.search = 5; + + imap_data.limit.msg_size = 512; + + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + imap.setTCPTimeout(10); + + if (!imap.connect(&config, &imap_data)) + { + MailClient.printf("Connection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + return; + } + + if (imap.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + printAllMailboxesInfo(imap); + + if (!imap.selectFolder(F("INBOX"))) + { + MailClient.printf("Folder selection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + return; + } + + printSelectedMailboxInfo(imap.selectedFolder()); + + if (MailClient.readMail(&imap, false)) + { + printImapData(imap.status()); + } + else + { + MailClient.printf("Message searching error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str()); + } + + imap.closeSession(); + + imap.empty(); +} + +void loop() +{ +} + +void printImapData(IMAP_Status status) +{ + + if (status.success()) + { + MailClient.printf("\nFound %d messages\n\n", imap.selectedFolder().searchCount()); + + IMAP_MSG_List msgList = imap.data(); + printMessages(msgList.msgItems, imap.headerOnly()); + + imap.empty(); + } +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + FoldersCollection folders; + + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} + +void printAttacements(std::vector &atts) +{ + MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size()); + for (size_t j = 0; j < atts.size(); j++) + { + IMAP_Attach_Item att = atts[j]; + MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate); + } + Serial.println(); +} + +void printMessages(std::vector &msgItems, bool headerOnly) +{ + + for (size_t i = 0; i < msgItems.size(); i++) + { + IMAP_MSG_Item msg = msgItems[i]; + + Serial.println("****************************"); + + MailClient.printf("Number: %d\n", msg.msgNo); + MailClient.printf("UID: %d\n", msg.UID); + + // The attachment status in search may be true in case the "multipart/mixed" + // content type header was set with no real attachtment included. + MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no"); + + MailClient.printf("Messsage-ID: %s\n", msg.ID); + + if (strlen(msg.flags)) + MailClient.printf("Flags: %s\n", msg.flags); + if (strlen(msg.acceptLang)) + MailClient.printf("Accept Language: %s\n", msg.acceptLang); + if (strlen(msg.contentLang)) + MailClient.printf("Content Language: %s\n", msg.contentLang); + if (strlen(msg.from)) + MailClient.printf("From: %s\n", msg.from); + if (strlen(msg.sender)) + MailClient.printf("Sender: %s\n", msg.sender); + if (strlen(msg.to)) + MailClient.printf("To: %s\n", msg.to); + if (strlen(msg.cc)) + MailClient.printf("CC: %s\n", msg.cc); + if (strlen(msg.bcc)) + MailClient.printf("BCC: %s\n", msg.bcc); + if (strlen(msg.date)) + { + MailClient.printf("Date: %s\n", msg.date); + MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date)); + } + if (strlen(msg.subject)) + MailClient.printf("Subject: %s\n", msg.subject); + if (strlen(msg.reply_to)) + MailClient.printf("Reply-To: %s\n", msg.reply_to); + if (strlen(msg.return_path)) + MailClient.printf("Return-Path: %s\n", msg.return_path); + if (strlen(msg.in_reply_to)) + MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to); + if (strlen(msg.references)) + MailClient.printf("References: %s\n", msg.references); + if (strlen(msg.comments)) + MailClient.printf("Comments: %s\n", msg.comments); + if (strlen(msg.keywords)) + MailClient.printf("Keywords: %s\n", msg.keywords); + + if (!headerOnly) + { + if (strlen(msg.text.content)) + MailClient.printf("Text Message: %s\n", msg.text.content); + if (strlen(msg.text.charSet)) + MailClient.printf("Text Message Charset: %s\n", msg.text.charSet); + if (strlen(msg.text.transfer_encoding)) + MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); + if (strlen(msg.html.content)) + MailClient.printf("HTML Message: %s\n", msg.html.content); + if (strlen(msg.html.charSet)) + MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet); + if (strlen(msg.html.transfer_encoding)) + MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); + + if (msg.rfc822.size() > 0) + { + MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); + printMessages(msg.rfc822, headerOnly); + } + + if (msg.attachments.size() > 0) + printAttacements(msg.attachments); + } + + Serial.println(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_List/Set_Flags_List.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_List/Set_Flags_List.ino new file mode 100644 index 000000000..3aedc9021 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_List/Set_Flags_List.ino @@ -0,0 +1,339 @@ +/** + * This example shows how to set messages flags. + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + * + */ + +// This example shows how to set messages flags. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Set seen flag */ + // imap_data.fetch.set_seen = true; + + /* Search criteria */ + imap_data.search.criteria.clear(); + + /* Also search the unseen message */ + imap_data.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /* Message UID to fetch or read e.g. 100 */ + int uid = imap.getUID(imap.selectedFolder().msgCount()); + + /** Set \Seen and \Answered to flags for message with UID + * The seesion will keep open. + */ + if (MailClient.setFlag(&imap, uid, F("\\Seen \\Answered"), false)) + Serial.println("\nSetting FLAG success"); + else + Serial.println("\nError, setting FLAG"); + + /* Add \Seen and \Answered to flags for message with UID 100 */ + // MailClient.addFlag(imap, 100, "\\Seen \\Answered", false); + + /* Remove \Seen and \Answered from flags for message with UID 100 */ + // MailClient.removeFlag(imap, 100, "\\Seen \\Answered", false); + + /* Remove Seen and Answered flags from messages using UID ranges (last 10 UIDs) */ + int uid_last = imap.getUID(imap.selectedFolder().msgCount()); + int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last; + + String sequence_set1 = String(uid_begin) + ":" + String(uid_last); + + if (MailClient.removeFlag(&imap, sequence_set1, true /* if sequence set are the UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */)) + Serial.println("\nRemoving FLAG with UIDs ranges success"); + else + Serial.println("\nError, removing FLAG with UIDs ranges"); + + /* Remove Seen and Answered flags from messages using message sequence ranges (last 10 message numbers) */ + int msg_last = imap.selectedFolder().msgCount(); + int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last; + + String sequence_set2 = String(msg_begin) + ":" + String(msg_last); + + if (MailClient.removeFlag(&imap, sequence_set2, false /* if sequence set are message numbers not UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */)) + Serial.println("\nRemoving FLAG with message numbers ranges success"); + else + Serial.println("\nError, removing FLAG with message numbers ranges"); + + imap_data.fetch.uid = uid; + + /* Read or search the Email and close the session */ + MailClient.readMail(&imap); + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_Message_Numbers_Ranges/Set_Flags_Message_Numbers_Ranges.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_Message_Numbers_Ranges/Set_Flags_Message_Numbers_Ranges.ino new file mode 100644 index 000000000..0e2645f25 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_Message_Numbers_Ranges/Set_Flags_Message_Numbers_Ranges.ino @@ -0,0 +1,309 @@ +/** + * This example shows how to set messages flags. + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + * + */ + +// This example shows how to set messages flags using message numbers ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Set seen flag */ + // imap_data.fetch.set_seen = true; + + /* Search criteria */ + imap_data.search.criteria.clear(); + + /* Also search the unseen message */ + imap_data.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /* Add Seen and Answered flags from messages using message numbers ranges (last 10 message numbers) */ + int msg_last = imap.selectedFolder().msgCount(); + int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last; + + String sequence_set1 = String(msg_begin) + ":" + String(msg_last); + + if (MailClient.addFlag(&imap, sequence_set1, false /* if sequence set are message numbers not UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */)) + Serial.println("\nAdding FLAG with message numbers ranges success"); + else + Serial.println("\nError, adding FLAG with message numbers ranges"); + + /* Remove Seen and Answered flags from messages using message numbers ranges (last 10 message numbers) */ + if (MailClient.removeFlag(&imap, sequence_set1, false /* if sequence set are message numbers not UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */)) + Serial.println("\nRemoving FLAG with message numbers ranges success"); + else + Serial.println("\nError, removing FLAG with message numbers ranges"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_UIDs_Ranges/Set_Flags_UIDs_Ranges.ino b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_UIDs_Ranges/Set_Flags_UIDs_Ranges.ino new file mode 100644 index 000000000..4e3ccc2ad --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/IMAP/Set_Flags/Set_Flags_UIDs_Ranges/Set_Flags_UIDs_Ranges.ino @@ -0,0 +1,310 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to set messages flags. + +// This example shows how to set messages flags using UIDs ranges. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For ESP8266, with BearSSL WiFi Client + * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which + * may cause your device out of memory reset in case the memory + * allocation error. + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en + * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha + * + * Some Gmail user still not able to sign in using account password even above options were set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" + +/** The imap port e.g. + * 143 or esp_mail_imap_port_143 + * 993 or esp_mail_imap_port_993 + */ +#define IMAP_PORT 993 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Print the list of mailbox folders */ +void printAllMailboxesInfo(IMAPSession &imap); + +/* Print the selected folder info */ +void printSelectedMailboxInfo(SelectedFolderInfo sFolder); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + imap.debug(1); + + /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from + * MailClient.sdBegin function which may be different for ESP32 and ESP8266 + * For ESP32, assign all of SPI pins + * MailClient.sdBegin(14,2,15,13) + * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 + * And for ESP8266, assign the CS pins of SPI port + * MailClient.sdBegin(15) + * Which pin 15 is the CS pin of SD card adapter + */ + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = IMAP_HOST; + config.server.port = IMAP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Define the IMAP_Data object used for user defined IMAP operating options. */ + IMAP_Data imap_data; + + /* Set seen flag */ + // imap_data.fetch.set_seen = true; + + /* Search criteria */ + imap_data.search.criteria.clear(); + + /* Also search the unseen message */ + imap_data.search.unseen_msg = true; + + /* Set the storage to save the downloaded files and attachments */ + imap_data.storage.saved_path = F("/email_data"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + imap_data.storage.type = esp_mail_file_storage_type_flash; + + /** Set to download headers, text and html messaeges, + * attachments and inline images respectively. + */ + imap_data.download.header = true; + imap_data.download.text = true; + imap_data.download.html = true; + imap_data.download.attachment = true; + imap_data.download.inlineImg = true; + + /** Set to enable the results i.e. html and text messaeges + * which the content stored in the IMAPSession object is limited + * by the option imap_data.limit.msg_size. + * The whole message can be download through imap_data.download.text + * or imap_data.download.html which not depends on these enable options. + */ + imap_data.enable.html = true; + imap_data.enable.text = true; + + /* Set to enable the sort the result by message UID in the decending order */ + imap_data.enable.recent_sort = true; + + /* Set to report the download progress via the default serial port */ + imap_data.enable.download_status = true; + + /* Set the limit of number of messages in the search results */ + imap_data.limit.search = 5; + + /** Set the maximum size of message stored in + * IMAPSession object in byte + */ + imap_data.limit.msg_size = 512; + + /** Set the maximum attachments and inline images files size + * that can be downloaded in byte. + * The file which its size is largger than this limit may be saved + * as truncated file. + */ + imap_data.limit.attachment_size = 1024 * 1024 * 5; + + /* Connect to the server */ + if (!imap.connect(&config, &imap_data)) + return; + + /* {Optional} */ + printAllMailboxesInfo(imap); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + /* {Optional} */ + printSelectedMailboxInfo(imap.selectedFolder()); + + /* Add Seen and Answered flags from messages using UID ranges (last 10 UIDs) */ + int uid_last = imap.getUID(imap.selectedFolder().msgCount()); + int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last; + + String sequence_set1 = String(uid_begin) + ":" + String(uid_last); + + if (MailClient.addFlag(&imap, sequence_set1, true /* if sequence set are the UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */)) + Serial.println("\nAdding FLAG with UIDs ranges success"); + else + Serial.println("\nError, adding FLAG with UIDs ranges"); + + /* Remove Seen and Answered flags from messages using UID ranges (last 10 UIDs) */ + if (MailClient.removeFlag(&imap, sequence_set1, true /* if sequence set are the UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */)) + Serial.println("\nRemoving FLAG with UIDs ranges success"); + else + Serial.println("\nError, removing FLAG with UIDs ranges"); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void printAllMailboxesInfo(IMAPSession &imap) +{ + /* Declare the folder collection class to get the list of mailbox folders */ + FoldersCollection folders; + + /* Get the mailbox folders */ + if (imap.getFolders(folders)) + { + for (size_t i = 0; i < folders.size(); i++) + { + /* Iterate each folder info using the folder info item data */ + FolderInfo folderInfo = folders.info(i); + MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); + } + } +} + +void printSelectedMailboxInfo(SelectedFolderInfo sFolder) +{ + /* Show the mailbox info */ + MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); + MailClient.printf("UID Validity: %d\n", sFolder.uidValidity()); + MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID()); + if (sFolder.unseenIndex() > 0) + MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex()); + else + MailClient.printf("Unseen Messages: No\n"); + + if (sFolder.modSeqSupported()) + MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq()); + for (size_t i = 0; i < sFolder.flagCount(); i++) + MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); + + if (sFolder.flagCount(true)) + { + for (size_t i = 0; i < sFolder.flagCount(true); i++) + MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : ""); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/Basic_Auth/Basic_Auth.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/Basic_Auth/Basic_Auth.ino new file mode 100644 index 000000000..c43a149eb --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/Basic_Auth/Basic_Auth.ino @@ -0,0 +1,219 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example showes how to send Email using custom commands. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 // See STARTTLS.ino example + */ +#define SMTP_PORT esp_mail_smtp_port_465 // port 465 is not available for Outlook.com + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" + "-----END CERTIFICATE-----\n"; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void customCommandCallback(SMTP_Response res) +{ + + // The res.id is the command identifier number that use to identify the source of command. + + // The command identifier number can be set via the last parameter of customConnect and sendCustomCommand functions. + + // If command identifier number was not set in those functions, the res.id received will be auto increased and begins with 0 + + MailClient.printf("> C: Command ID %d\n", res.id); + MailClient.printf("< S: %s\n", res.text.c_str()); + + if (res.statusCode > 0) + { + MailClient.printf("> C: Response finished with status code %d\n\n", res.statusCode); + } +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* Connect to the server */ + if (!smtp.connect(&config)) + return; + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + // Please don't forget to change sender@xxxxxx.com to your email + if (smtp.sendCustomCommand(F("MAIL FROM:"), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + // Please don't forget to change recipient@xxxxx.com with your recipient email + if (smtp.sendCustomCommand(F("RCPT TO:"), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(F("DATA"), customCommandCallback) != 354) + { + smtp.closeSession(); + return; + } + + // Send data with command which terminated with dot '.' + if (smtp.sendCustomCommand(F("Subject: Test sending Email\r\nHello World!\r\n."), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + // Do not use this command in ESP8266 due to memory leaks in ESP8266 core BearSSL. + // smtp.sendCustomCommand(F("QUIT"), customCommandCallback); + + smtp.closeSession(); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/Custom_Auth/Custom_Auth.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/Custom_Auth/Custom_Auth.ino new file mode 100644 index 000000000..13f50920c --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/Custom_Auth/Custom_Auth.ino @@ -0,0 +1,248 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example showes how to send Email using custom commands. + + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 // See STARTTLS.ino example + */ +#define SMTP_PORT esp_mail_smtp_port_465 // port 465 is not available for Outlook.com + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" + "-----END CERTIFICATE-----\n"; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void customCommandCallback(SMTP_Response res) +{ + + // The res.id is the command identifier number that use to identify the source of command. + + // The command identifier number can be set via the last parameter of customConnect and sendCustomCommand functions. + + // If command identifier number was not set in those functions, the res.id received will be auto increased and begins with 0 + + MailClient.printf("> C: Command ID %d\n", res.id); + MailClient.printf("< S: %s\n", res.text.c_str()); + + if (res.statusCode > 0) + { + MailClient.printf("> C: Response finished with status code %d\n\n", res.statusCode); + } +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /* Connect to the server */ + if (smtp.customConnect(&config /* session credentials */, customCommandCallback) != 220) + { + Serial.println("! E: Unable to connect to server"); + return; + } + + if (smtp.sendCustomCommand(F("EHLO 127.0.0.1"), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(F("AUTH LOGIN"), customCommandCallback) != 334) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(MailClient.toBase64(config.login.email), customCommandCallback) != 334) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(MailClient.toBase64(config.login.password), customCommandCallback) != 235) + { + smtp.closeSession(); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("Successfully logged in.\n"); + else + Serial.println("Connected with no Auth.\n"); + + // Please don't forget to change sender@xxxxxx.com to your email + if (smtp.sendCustomCommand(F("MAIL FROM:"), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + // Please don't forget to change recipient@xxxxx.com with your recipient email + if (smtp.sendCustomCommand(F("RCPT TO:"), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(F("DATA"), customCommandCallback) != 354) + { + smtp.closeSession(); + return; + } + + if (!smtp.sendCustomData(F("Subject: Test sending Email\r\n"))) + { + smtp.closeSession(); + return; + } + + if (!smtp.sendCustomData(F("Hello World!\r\n"))) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(F("."), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + // Do not use this command in ESP8266 due to memory leaks in ESP8266 core BearSSL. + // smtp.sendCustomCommand(F("QUIT"), customCommandCallback); + + smtp.closeSession(); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/STARTTLS/STARTTLS.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/STARTTLS/STARTTLS.ino new file mode 100644 index 000000000..64788c799 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Command/STARTTLS/STARTTLS.ino @@ -0,0 +1,268 @@ + + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example showes how to send Email using custom commands. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 // port 465 is not available for Outlook.com + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 // for STARTTLS + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" + "-----END CERTIFICATE-----\n"; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void customCommandCallback(SMTP_Response res) +{ + + // The res.id is the command identifier number that use to identify the source of command. + + // The command identifier number can be set via the last parameter of customConnect and sendCustomCommand functions. + + // If command identifier number was not set in those functions, the res.id received will be auto increased and begins with 0 + + MailClient.printf("> C: Command ID %d\n", res.id); + MailClient.printf("< S: %s\n", res.text.c_str()); + + if (res.statusCode > 0) + { + MailClient.printf("> C: Response finished with status code %d\n\n", res.statusCode); + } +} + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + bool tls = false; + + /* Connect to the server */ + if (smtp.customConnect(&config /* session credentials */, customCommandCallback) != 220) + { + Serial.println("! E: Unable to connect to server"); + return; + } + +init: + + if (smtp.sendCustomCommand(F("EHLO 127.0.0.1"), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + // Only for SMTP port 587 in supported server that accepts STARTTLS + + if (!tls) + { + if (smtp.sendCustomCommand(F("STARTTLS"), customCommandCallback) != 220) + { + smtp.closeSession(); + return; + } + + tls = true; + + // Send greeting again + goto init; + } + + if (smtp.sendCustomCommand(F("AUTH LOGIN"), customCommandCallback) != 334) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(MailClient.toBase64(config.login.email), customCommandCallback) != 334) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(MailClient.toBase64(config.login.password), customCommandCallback) != 235) + { + smtp.closeSession(); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("Successfully logged in.\n"); + else + Serial.println("Connected with no Auth.\n"); + + // Please don't forget to change sender@xxxxxx.com to your email + if (smtp.sendCustomCommand(F("MAIL FROM:"), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + // Please don't forget to change recipient@xxxxx.com with your recipient email + if (smtp.sendCustomCommand(F("RCPT TO:"), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(F("DATA"), customCommandCallback) != 354) + { + smtp.closeSession(); + return; + } + + if (!smtp.sendCustomData(F("Subject: Test sending Email\r\n"))) + { + smtp.closeSession(); + return; + } + + if (!smtp.sendCustomData(F("Hello World!\r\n"))) + { + smtp.closeSession(); + return; + } + + if (smtp.sendCustomCommand(F("."), customCommandCallback) != 250) + { + smtp.closeSession(); + return; + } + + // Do not use this command in ESP8266 due to memory leaks in ESP8266 core BearSSL. + // smtp.sendCustomCommand(F("QUIT"), customCommandCallback); + + smtp.closeSession(); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Ports/Custom_Ports.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Ports/Custom_Ports.ino new file mode 100644 index 000000000..95b1b0330 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Custom_Ports/Custom_Ports.ino @@ -0,0 +1,376 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example showes how to send text Email via the custom port. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT 2525 // non-standard port (TLS) + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" + "-----END CERTIFICATE-----\n"; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /** Set the ports and protocols + * This allows non-standard port to work with this library + * The port that assigned with config.server.port will map with the + * protocol assigned here + */ + + config.ports_functions.list = new port_function[4]; + config.ports_functions.size = 4; + + config.ports_functions.list[0].port = 25; + config.ports_functions.list[0].protocol = esp_mail_protocol_plain_text; + + config.ports_functions.list[1].port = 465; + config.ports_functions.list[1].protocol = esp_mail_protocol_ssl; + + config.ports_functions.list[2].port = 587; + config.ports_functions.list[2].protocol = esp_mail_protocol_tls; + + config.ports_functions.list[3].port = 2525; + config.ports_functions.list[3].protocol = esp_mail_protocol_tls; + + /** In ESP32, timezone environment will not keep after wake up boot from sleep. + * The local time will equal to GMT time. + * + * To sync or set time with NTP server with the valid local time after wake up boot, + * set both gmt and day light offsets to 0 and assign the timezone environment string e.g. + + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 0; + config.time.day_light_offset = 0; + config.time.timezone_env_string = "JST-9"; // for Tokyo + + * The library will get (sync) the time from NTP server without GMT time offset adjustment + * and set the timezone environment variable later. + * + * This timezone environment string will be stored to flash or SD file named "/tz_env.txt" + * which set via config.time.timezone_file. + * + * See the timezone environment string list from + * https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv + * + */ + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); // This witll be used with 'MAIL FROM' command and 'From' header field. + message.sender.email = AUTHOR_EMAIL; // This witll be used with 'From' header field. + message.subject = F("Test sending plain text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); // This will be used with RCPT TO command and 'To' header field. + + String textMsg = "This is simple plain text message"; + message.text.content = textMsg; + + /** If the message to send is a large string, to reduce the memory used from internal copying while sending, + * you can assign string to message.text.blob by cast your string to uint8_t array like this + * + * String myBigString = "..... ......"; + * message.text.blob.data = (uint8_t *)myBigString.c_str(); + * message.text.blob.size = myBigString.length(); + * + * or assign string to message.text.nonCopyContent, like this + * + * message.text.nonCopyContent = myBigString.c_str(); + * + * Only base64 encoding is supported for content transfer encoding in this case. + */ + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + // If this is a reply message + // message.in_reply_to = ""; + // message.references = " "; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + // message.response.reply_to = "someone@somemail.com"; + // message.response.return_path = "someone@somemail.com"; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + // For Root CA certificate verification (ESP8266 and ESP32 only) + // config.certificate.cert_data = rootCACert; + // or + // config.certificate.cert_file = "/path/to/der/file"; + // config.certificate.cert_file_storage_type = esp_mail_file_storage_type_flash; // esp_mail_file_storage_type_sd + // config.certificate.verify = true; + + // The WiFiNINA firmware the Root CA certification can be added via the option in Firmware update tool in Arduino IDE + + /* Connect to server with the session config */ + + // Library will be trying to sync the time with NTP server if time is never sync or set. + // This is 10 seconds blocking process. + // If time reading was timed out, the error "NTP server time reading timed out" will show via debug and callback function. + // You can manually sync time by yourself with NTP library or calling configTime in ESP32 and ESP8266. + // Time can be set manually with provided timestamp to function smtp.setSystemTime. + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP32/Send_Text/Send_Text.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP32/Send_Text/Send_Text.ino new file mode 100644 index 000000000..60a05519e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP32/Send_Text/Send_Text.ino @@ -0,0 +1,287 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email using ESP32 and LAN8720 Ethernet module. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** + * There are many sources for LAN8720 and ESP32 interconnection on the internet which may + * work for your LAN8720 board. + * + * Some methods worked unless no IP is available. + * + * This modification and interconnection provided in this example are mostly worked as + * the 50 MHz clock was created internally in ESP32 which GPIO 17 is set to be output of this clock + * and feeds to the LAN8720 chip XTAL input. + * + * The on-board LAN8720 50 MHz XTAL chip will be disabled by connect its enable pin or pin 1 to GND. + * + * Please see the images in the folder "modified_LAN8720_board_images" for how to modify the LAN8720 board. + * + * The LAN8720 Ethernet modified board and ESP32 board wiring connection. + * + * ESP32 LAN8720 + * + * GPIO17 - EMAC_CLK_OUT_180 nINT/REFCLK - LAN8720 XTAL1/CLKIN 4k7 Pulldown + * GPIO22 - EMAC_TXD1 TX1 + * GPIO19 - EMAC_TXD0 TX0 + * GPIO21 - EMAC_TX_EN TX_EN + * GPIO26 - EMAC_RXD1 RX1 + * GPIO25 - EMAC_RXD0 RX0 + * GPIO27 - EMAC_RX_DV CRS + * GPIO23 - MDC MDC + * GPIO18 - MDIO MDIO + * GND GND + * 3V3 VCC + * + * + * ESP32 Arduino SDK native Ethernet using ETH.h is currently support Ethernet PHY chips + * + * LAN8720, TLK101, RTL8201, DP83848, DM9051, KSZ8041 and KSZ8081. + * + * For ESP32 and other SPI MAC Ethernet modules, the external Client was used, + * see examples/SMTP/External_Client/EthernetClient/EthernetClient.ino + * + */ + +#include + +#ifdef ETH_CLK_MODE +#undef ETH_CLK_MODE +#endif +#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT // RMII clock output from GPIO17 + +// Pin# of the enable signal for the external crystal oscillator (-1 to disable) +#define ETH_POWER_PIN -1 + +// Type of the Ethernet PHY (LAN8720 or TLK110) +#define ETH_TYPE ETH_PHY_LAN8720 + +// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110) +#define ETH_ADDR 1 + +// Pin# of the I²C clock signal for the Ethernet PHY +#define ETH_MDC_PIN 23 + +// Pin# of the I²C IO signal for the Ethernet PHY +#define ETH_MDIO_PIN 18 + +static bool eth_connected = false; + +#define SMTP_HOST "" +#define SMTP_PORT 25 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +SMTPSession smtp; + +void smtpCallback(SMTP_Status status); + +unsigned long sendMillis = 0; + +void WiFiEvent(WiFiEvent_t event) +{ + // Do not run any function here to prevent stack overflow or nested interrupt + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) + + switch (event) + { + case ARDUINO_EVENT_ETH_START: + Serial.println("ETH Started"); + // set eth hostname here + ETH.setHostname("esp32-ethernet"); + break; + case ARDUINO_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case ARDUINO_EVENT_ETH_GOT_IP: + Serial.print("ETH MAC: "); + Serial.print(ETH.macAddress()); + Serial.print(", IPv4: "); + Serial.print(ETH.localIP()); + if (ETH.fullDuplex()) + { + Serial.print(", FULL_DUPLEX"); + } + Serial.print(", "); + Serial.print(ETH.linkSpeed()); + Serial.println("Mbps"); + eth_connected = true; + break; + case ARDUINO_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case ARDUINO_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } + +#else + switch (event) + { + case SYSTEM_EVENT_ETH_START: + Serial.println("ETH Started"); + // set eth hostname here + ETH.setHostname("esp32-ethernet"); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + Serial.println("ETH Connected"); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + Serial.print("ETH MAC: "); + Serial.print(ETH.macAddress()); + Serial.print(", IPv4: "); + Serial.print(ETH.localIP()); + if (ETH.fullDuplex()) + { + Serial.print(", FULL_DUPLEX"); + } + Serial.print(", "); + Serial.print(ETH.linkSpeed()); + Serial.println("Mbps"); + eth_connected = true; + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + Serial.println("ETH Disconnected"); + eth_connected = false; + break; + case SYSTEM_EVENT_ETH_STOP: + Serial.println("ETH Stopped"); + eth_connected = false; + break; + default: + break; + } +#endif +} + +void sendMail() +{ + + smtp.debug(1); + + smtp.callback(smtpCallback); + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + String textMsg = "This is simple plain text message"; + message.text.content = textMsg; + + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); +} + +void setup() +{ + Serial.begin(115200); + Serial.println(); + + WiFi.onEvent(WiFiEvent); + + ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE); +} + +void loop() +{ + if (eth_connected && (millis() - sendMillis > 300000 || sendMillis == 0)) + { + sendMillis = millis(); + sendMail(); + } +} + +void smtpCallback(SMTP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/lib_mail/examples/ESP32_Ethernet_Send_Text/modified_LAN8720_board_images/lan8720_modified_board.png b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP32/Send_Text/modified_LAN8720_board_images/lan8720_modified_board.png similarity index 100% rename from lib/libesp32/lib_mail/examples/ESP32_Ethernet_Send_Text/modified_LAN8720_board_images/lan8720_modified_board.png rename to lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP32/Send_Text/modified_LAN8720_board_images/lan8720_modified_board.png diff --git a/lib/libesp32/lib_mail/examples/ESP32_Ethernet_Send_Text/modified_LAN8720_board_images/lan8720_modified_schematic.png b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP32/Send_Text/modified_LAN8720_board_images/lan8720_modified_schematic.png similarity index 100% rename from lib/libesp32/lib_mail/examples/ESP32_Ethernet_Send_Text/modified_LAN8720_board_images/lan8720_modified_schematic.png rename to lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP32/Send_Text/modified_LAN8720_board_images/lan8720_modified_schematic.png diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP8266/Send_Text/Send_Text.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP8266/Send_Text/Send_Text.ino new file mode 100644 index 000000000..4f677fa88 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Ethernet/ESP8266/Send_Text/Send_Text.ino @@ -0,0 +1,230 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email using ESP8266 and ENC28J60 Ethernet module. + +// This example requires ESP8266 Arduino Core SDK v3.x.x + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** + * + * The ENC28J60 Ethernet module and ESP8266 board, SPI port wiring connection. + * + * ESP8266 (Wemos D1 Mini or NodeMCU) ENC28J60 + * + * GPIO12 (D6) - MISO SO + * GPIO13 (D7) - MOSI SI + * GPIO14 (D5) - SCK SCK + * GPIO16 (D0) - CS CS + * GND GND + * 3V3 VCC + * + */ + +#if defined(ESP8266) +#include +#endif + +#include +// #include +// #include + +/** + * For ENC28J60 ethernet module, uncomment this line in ESP_Mail_FS.h + #define ENABLE_ESP8266_ENC28J60_ETH + + * For W5500 ethernet module, uncomment this line in ESP_Mail_FS.h + #define ENABLE_ESP8266_W5500_ETH + + * For W5100 ethernet module, uncomment this line in ESP_Mail_FS.h + #define ENABLE_ESP8266_W5100_ETH +*/ + +#include + +#define SMTP_HOST "" +#define SMTP_PORT 25 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +SMTPSession smtp; + +void smtpCallback(SMTP_Status status); + +unsigned long sendMillis = 0; + +#ifdef ESP8266_CORE_SDK_V3_X_X + +#define ETH_CS_PIN 16 // D0 +ENC28J60lwIP eth(ETH_CS_PIN); +// Wiznet5100lwIP eth(ETH_CS_PIN); +// Wiznet5500lwIP eth(ETH_CS_PIN); + +#endif + +void sendMail() +{ + + smtp.debug(1); + + smtp.callback(smtpCallback); + + Session_Config config; + + /* Assign the pointer to Ethernet module lwip interface */ +#ifdef ESP8266_CORE_SDK_V3_X_X +#if defined(ENABLE_ESP8266_ENC28J60_ETH) + config.spi_ethernet_module.enc28j60 = ð +#elif defined(ENABLE_ESP8266_W5100_ETH) + config.spi_ethernet_module.w5100 = ð +#elif defined(ENABLE_ESP8266_W5500_ETH) + config.spi_ethernet_module.w5500 = ð +#endif +#endif + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + String textMsg = "This is simple plain text message"; + message.text.content = textMsg; + + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); +} + +void setup() +{ + Serial.begin(115200); + Serial.println(); + +#ifdef ESP8266_CORE_SDK_V3_X_X + + SPI.begin(); + SPI.setClockDivider(SPI_CLOCK_DIV4); // 4 MHz? + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + eth.setDefault(); // use ethernet for default route + if (!eth.begin()) + { + Serial.println("ethernet hardware not found ... sleeping"); + while (1) + { + delay(1000); + } + } + else + { + Serial.print("connecting ethernet"); + while (!eth.connected()) + { + Serial.print("."); + delay(1000); + } + } + Serial.println(); + Serial.print("ethernet IP address: "); + Serial.println(eth.localIP()); + +#else + Serial.println("This example requires ESP8266 Arduino Core SDK v3.x.x, please update."); +#endif +} + +void loop() +{ +#ifdef ESP8266_CORE_SDK_V3_X_X + if (millis() - sendMillis > 300000 || sendMillis == 0) + { + sendMillis = millis(); + sendMail(); + } +#endif +} + +void smtpCallback(SMTP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/EthernetClient/EthernetClient.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/EthernetClient/EthernetClient.ino new file mode 100644 index 000000000..ec9fd07ef --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/EthernetClient/EthernetClient.ino @@ -0,0 +1,224 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +/** + * This example shows how to send Email using EthernetClient. + * + * This example used ESP32 and WIZnet W5500 Ethernet module. + * + * For ESP32 and LAN8720 see examples/SMTP/Ethernet/ESP32/Send_Text.ino + * + * ESP32 Arduino SDK native Ethernet using ETH.h is currently support Ethernet PHY chips + * + * LAN8720, TLK101, RTL8201, DP83848, DM9051, KSZ8041 and KSZ8081. + * + * For ESP8266, the native Ethernet is currently supported ENC28J60, W5100 and W5500. + * + * You do not need to set external Client with native Ethernet support PHY/MAC chips. + * + * + */ + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include + +#include + +#include + +#define SMTP_HOST "smtp.gmail.com" +#define SMTP_PORT 587 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +#define WIZNET_RESET_PIN 26 // Connect W5500 Reset pin to GPIO 26 of ESP32 +#define WIZNET_CS_PIN 5 // Connect W5500 CS pin to GPIO 5 of ESP32 +#define WIZNET_MISO_PIN 19 // Connect W5500 MISO pin to GPIO 19 of ESP32 +#define WIZNET_MOSI_PIN 23 // Connect W5500 MOSI pin to GPIO 23 of ESP32 +#define WIZNET_SCLK_PIN 18 // Connect W5500 SCLK pin to GPIO 18 of ESP32 + +unsigned long sentMillis = 0; + +const int analog_pin = 34; + +uint8_t Eth_MAC[] = {0x02, 0xF0, 0x0D, 0xBE, 0xEF, 0x01}; + +SMTPSession smtp; + +EthernetClient eth_client; + +void smtpCallback(SMTP_Status status); + +void ResetEthernet() +{ + Serial.println("Resetting WIZnet W5500 Ethernet Board... "); + pinMode(WIZNET_RESET_PIN, OUTPUT); + digitalWrite(WIZNET_RESET_PIN, HIGH); + delay(200); + digitalWrite(WIZNET_RESET_PIN, LOW); + delay(50); + digitalWrite(WIZNET_RESET_PIN, HIGH); + delay(200); +} + +void networkConnection() +{ + + Ethernet.init(WIZNET_CS_PIN); + + ResetEthernet(); + + Serial.println("Starting Ethernet connection..."); + Ethernet.begin(Eth_MAC); + + unsigned long to = millis(); + + while (Ethernet.linkStatus() == LinkOFF || millis() - to < 2000) + { + delay(100); + } + + if (Ethernet.linkStatus() == LinkON) + { + Serial.print("Connected with IP "); + Serial.println(Ethernet.localIP()); + } + else + { + Serial.println("Can't connect"); + } +} + +void networkStatusRequestCallback() +{ + smtp.setNetworkStatus(Ethernet.linkStatus() == LinkON); +} + +void sendEmail() +{ + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + config.login.user_domain = F("127.0.0.1"); + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email"); + + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + message.text.content = "This is simple plain text message"; + + smtp.setClient(ð_client); + + smtp.networkConnectionRequestCallback(networkConnection); + + smtp.networkStatusRequestCallback(networkStatusRequestCallback); + + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void setup() +{ + + Serial.begin(115200); + + Serial.println(); + + networkConnection(); + + /* + For internal NTP client + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + MailClient.setUDPClient(&udp_client, 0 /* GMT offset */); + + smtp.debug(1); + + smtp.callback(smtpCallback); +} + +void loop() +{ + if (millis() - sentMillis > 120000 || sentMillis == 0) + { + sentMillis = millis(); + sendEmail(); + } +} + +void smtpCallback(SMTP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/GSMClient/GSMClient.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/GSMClient/GSMClient.ino new file mode 100644 index 000000000..9d1026d4e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/GSMClient/GSMClient.ino @@ -0,0 +1,213 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +// This example used TTGO T-A7670 (ESP32 with SIMCom SIMA7670) and TinyGSMClient. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +// To allow TinyGSM library integration, the following macro should be defined in src/ESP_Mail_FS.h or +// your custom config file src/Custom_ESP_Mail_FS.h. +// #define TINY_GSM_MODEM_SIM7600 + +#define TINY_GSM_MODEM_SIM7600 // SIMA7670 Compatible with SIM7600 AT instructions + +// Set serial for debug console (to the Serial Monitor, default speed 115200) +#define SerialMon Serial + +// Set serial for AT commands (to the module) +// Use Hardware Serial on Mega, Leonardo, Micro +#define SerialAT Serial1 + +// See all AT commands, if wanted +// #define DUMP_AT_COMMANDS + +// Define the serial console for debug prints, if needed +#define TINY_GSM_DEBUG SerialMon + +#define TINY_GSM_USE_GPRS true +#define TINY_GSM_USE_WIFI false + +// set GSM PIN, if any +#define GSM_PIN "" + +// Your GPRS credentials, if any +const char apn[] = "YourAPN"; +const char gprsUser[] = ""; +const char gprsPass[] = ""; + +#define uS_TO_S_FACTOR 1000000ULL // Conversion factor for micro seconds to seconds +#define TIME_TO_SLEEP 600 // Time ESP32 will go to sleep (in seconds) + +#define UART_BAUD 115200 +#define PIN_DTR 25 +#define PIN_TX 26 +#define PIN_RX 27 +#define PWR_PIN 4 +#define BAT_ADC 35 +#define BAT_EN 12 +#define PIN_RI 33 +#define PIN_DTR 25 +#define RESET 5 + +#define SD_MISO 2 +#define SD_MOSI 15 +#define SD_SCLK 14 +#define SD_CS 13 + +#include +#include + +TinyGsm modem(SerialAT); + +TinyGsmClient gsm_client(modem); + +#define SMTP_HOST "" +#define SMTP_PORT esp_mail_smtp_port_587 +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +SMTPSession smtp; + +void smtpCallback(SMTP_Status status); + +void setup() +{ + + SerialMon.begin(115200); + + smtp.debug(1); + + smtp.callback(smtpCallback); + + delay(10); + pinMode(BAT_EN, OUTPUT); + digitalWrite(BAT_EN, HIGH); + + // A7670 Reset + pinMode(RESET, OUTPUT); + digitalWrite(RESET, LOW); + delay(100); + digitalWrite(RESET, HIGH); + delay(3000); + digitalWrite(RESET, LOW); + + pinMode(PWR_PIN, OUTPUT); + digitalWrite(PWR_PIN, LOW); + delay(100); + digitalWrite(PWR_PIN, HIGH); + delay(1000); + digitalWrite(PWR_PIN, LOW); + + DBG("Wait..."); + + delay(3000); + + SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX); + + // Restart takes quite some time + // To skip it, call init() instead of restart() + DBG("Initializing modem..."); + if (!modem.init()) + { + DBG("Failed to restart modem, delaying 10s and retrying"); + return; + } + + /* + 2 Automatic + 13 GSM Only + 14 WCDMA Only + 38 LTE Only + */ + modem.setNetworkMode(38); + if (modem.waitResponse(10000L) != 1) + { + DBG(" setNetworkMode faill"); + } + + String name = modem.getModemName(); + DBG("Modem Name:", name); + + String modemInfo = modem.getModemInfo(); + DBG("Modem Info:", modemInfo); + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + config.login.user_domain = F("127.0.0.1"); + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email using GSM module"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + message.text.content = "This is simple plain text message"; + + smtp.setGSMClient(&gsm_client, &modem, GSM_PIN, apn, gprsUser, gprsPass); + + smtp.connect(&config); + + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); +} + +void loop() +{ +} + +void smtpCallback(SMTP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/WiFiClient/WiFiClient.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/WiFiClient/WiFiClient.ino new file mode 100644 index 000000000..6e80e1101 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/External_Client/WiFiClient/WiFiClient.ino @@ -0,0 +1,187 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email using external WiFiClient. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define SMTP_HOST "" +#define SMTP_PORT esp_mail_smtp_port_587 +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +SMTPSession smtp; + +WiFiClient wifi_client; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void smtpCallback(SMTP_Status status); + +void networkStatusRequestCallback() +{ + smtp.setNetworkStatus(WiFi.status() == WL_CONNECTED); +} + +void networkConnectionRequestCallback() +{ + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); +} + +void setup() +{ + + Serial.begin(115200); + + networkConnectionRequestCallback(); + + MailClient.networkReconnect(true); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + smtp.debug(1); + + smtp.callback(smtpCallback); + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + config.login.user_domain = F("127.0.0.1"); + + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + + smtp.setClient(&wifi_client); + + smtp.networkStatusRequestCallback(networkStatusRequestCallback); + + smtp.networkConnectionRequestCallback(networkConnectionRequestCallback); + + smtp.connect(&config); + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + message.text.content = "This is simple plain text message"; + + if (!MailClient.sendMail(&smtp, &message)) + Serial.println("Error sending Email, " + smtp.errorReason()); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +void smtpCallback(SMTP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Reply_Text/Reply_Text.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Reply_Text/Reply_Text.ino new file mode 100644 index 000000000..76ce8091b --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Reply_Text/Reply_Text.ino @@ -0,0 +1,497 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example showes how to send a reply message when specific email was received. + +// The account 2 will send Hello message to account 1. + +// The account 1 will poll the mailbox for incoming message, when new message received with matched subject +// and sent from account 2, the account 1 will send a reply messsage to account 2. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ +#define IMAP_HOST "" +#define IMAP_PORT 993 + +#define IMAP_AUTHOR_EMAIL "" +#define IMAP_AUTHOR_PASSWORD "" + +#define REPLY_SMTP_AUTHOR_EMAIL "" +#define REPLY_SMTP_AUTHOR_PASSWORD "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define REPLY_SMTP_PORT 587 +#define REPLY_SMTP_HOST "" + +#define HELLO_SMTP_AUTHOR_EMAIL "" +#define HELLO_SMTP_AUTHOR_PASSWORD "" + +#define HELLO_SMTP_PORT 587 +#define HELLO_SMTP_HOST "" + +void setupIMAP(); + +bool setupHelloSMTP(); + +bool setupReplySMTP(); + +void sendHelloMessage(); + +void sendReplyMessage(const char *subject, const char *reply_email, const char *msgID, const char *references); + +/* Print the selected folder update info */ +void printPollingStatus(IMAPSession &imap); + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status); + +/* Callback function to get the Email sending status */ +void helloSMTPCallback(SMTP_Status status); + +void replySMTPCallback(SMTP_Status status); + +/* Declare the global used IMAPSession object for IMAP transport */ +IMAPSession imap; + +/* Declare the global used Session_Config for user defined IMAP session credentials */ +Session_Config imap_config; + +/** Define the IMAP_Data object used for user defined IMAP operating options + * and contains the IMAP operating result + */ +IMAP_Data imap_data; + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession hello_smtp; +SMTPSession reply_smtp; + +/* Declare the global used Session_Config for user defined SMTP session credentials */ +Session_Config hello_smtp_config; +Session_Config reply_smtp_config; + +bool imapSetupOk = false; + +unsigned long helloSendingMillis = 0; + +String sendingSubject = "ESP Mail Hello Test!"; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Setup and connect to IMAP server... "); + + setupIMAP(); + + if (!imapSetupOk) + return; +} + +void loop() +{ + + /* imap.connect and imap.selectFolder or imap.openFolder nedded to be called once prior to listen */ + + // Listen for mailbox changes + if (!imap.listen()) + return; + + // Check the changes + if (imap.folderChanged()) + printPollingStatus(imap); + + // To stop listen, use imap.stopListen(); and to listen again, call imap.listen() + + if (millis() - helloSendingMillis > 5 * 60 * 1000 || helloSendingMillis == 0) + { + helloSendingMillis = millis(); + Serial.print("Sending Hello message... "); + sendHelloMessage(); + } +} + +void setupIMAP() +{ + imap.debug(1); + + /* Set the callback function to get the reading results */ + imap.callback(imapCallback); + + /* Set the imap app config */ + imap_config.server.host_name = IMAP_HOST; + imap_config.server.port = IMAP_PORT; + imap_config.login.email = IMAP_AUTHOR_EMAIL; + imap_config.login.password = IMAP_AUTHOR_PASSWORD; + + /* Connect to the server */ + if (!imap.connect(&imap_config, &imap_data)) + return; + + if (imap.isAuthenticated()) + Serial.println("\nIMAP client, successfully logged in."); + else + Serial.println("\nIMAP client, connected with no Auth."); + + /* Open or select the mailbox folder to read or search the message */ + if (!imap.selectFolder(F("INBOX"))) + return; + + imapSetupOk = true; +} + +bool setupHelloSMTP() +{ + hello_smtp.debug(1); + + /* Set the callback function to get the sending results */ + hello_smtp.callback(helloSMTPCallback); + + /* Set the session config */ + hello_smtp_config.server.host_name = HELLO_SMTP_HOST; + hello_smtp_config.server.port = HELLO_SMTP_PORT; + hello_smtp_config.login.email = HELLO_SMTP_AUTHOR_EMAIL; + hello_smtp_config.login.password = HELLO_SMTP_AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + hello_smtp_config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + hello_smtp_config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + hello_smtp_config.time.gmt_offset = 3; + hello_smtp_config.time.day_light_offset = 0; + + /* Connect to the server */ + if (!hello_smtp.connect(&hello_smtp_config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", hello_smtp.statusCode(), hello_smtp.errorCode(), hello_smtp.errorReason().c_str()); + return false; + } + + if (imap.isAuthenticated()) + Serial.println("\nHello SMTP client, successfully logged in."); + else + Serial.println("\nHello SMTP client, connected with no Auth."); + + return true; +} + +bool setupReplySMTP() +{ + reply_smtp.debug(1); + + /* Set the callback function to get the sending results */ + reply_smtp.callback(replySMTPCallback); + + /* Set the session config */ + reply_smtp_config.server.host_name = REPLY_SMTP_HOST; + reply_smtp_config.server.port = REPLY_SMTP_PORT; + reply_smtp_config.login.email = REPLY_SMTP_AUTHOR_EMAIL; + reply_smtp_config.login.password = REPLY_SMTP_AUTHOR_PASSWORD; + reply_smtp_config.login.user_domain = F("127.0.0.1"); + + /* Connect to the server */ + if (!reply_smtp.connect(&reply_smtp_config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", reply_smtp.statusCode(), reply_smtp.errorCode(), reply_smtp.errorReason().c_str()); + return false; + } + + if (imap.isAuthenticated()) + Serial.println("\nReply SMTP client, successfully logged in."); + else + Serial.println("\nReply SMTP client, connected with no Auth."); + + return true; +} + +void sendHelloMessage() +{ + + if (!setupHelloSMTP()) + return; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = HELLO_SMTP_AUTHOR_EMAIL; + message.subject = sendingSubject.c_str(); + message.addRecipient(F("Me"), IMAP_AUTHOR_EMAIL); + message.response.reply_to = HELLO_SMTP_AUTHOR_EMAIL; // only email address, excluded < and > + message.text.content = F("Hello Me!"); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&hello_smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", hello_smtp.statusCode(), hello_smtp.errorCode(), hello_smtp.errorReason().c_str()); +} + +void sendReplyMessage(const char *subject, const char *reply_email, const char *msgID, const char *references) +{ + + if (!setupReplySMTP()) + return; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = REPLY_SMTP_AUTHOR_EMAIL; + String reSubject = "RE: "; + reSubject += subject; + message.subject = reSubject; + message.addRecipient(F("Me"), reply_email); + + message.in_reply_to = msgID; + + String ref = references; + if (strlen(references) > 0) + ref += " "; + ref += msgID; + + message.references = ref; + message.text.content = F("Yeah!, it works."); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&reply_smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", reply_smtp.statusCode(), reply_smtp.errorCode(), reply_smtp.errorReason().c_str()); +} + +void printPollingStatus(IMAPSession &imap) +{ + /* Declare the selected folder info class to get the info of selected mailbox folder */ + SelectedFolderInfo sFolder = imap.selectedFolder(); + + if (sFolder.pollingStatus().type == imap_polling_status_type_new_message) + { + /* Show the mailbox info */ + MailClient.printf("\nMailbox status changed\n----------------------\nTotal Messages: %d\n", sFolder.msgCount()); + + MailClient.printf("New message %d, has been addedd, reading message...\n", (int)sFolder.pollingStatus().messageNum); + + // we need to stop polling before do anything + imap.stopListen(); + + // Get the UID of new message and fetch + imap_data.fetch.uid = imap.getUID(sFolder.pollingStatus().messageNum); + + // When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status, + // as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag + // to message, see the Set_Flags.ino example. + MailClient.readMail(&imap, false); + } +} + +/* Callback function to get the Email reading status */ +void imapCallback(IMAP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Show the result when reading finished */ + if (status.success()) + { + + /* Get the message list from the message list data */ + IMAP_MSG_List msgList = imap.data(); + + if (strcmp(msgList.msgItems[0].subject, sendingSubject.c_str()) == 0) + { + Serial.print("Sending Reply message... "); + std::string replyEmail = msgList.msgItems[0].reply_to; + + // remove < at the beginning and > at the end. + replyEmail.erase(0, 1); + replyEmail.pop_back(); + + sendReplyMessage(msgList.msgItems[0].subject, replyEmail.c_str(), msgList.msgItems[0].ID, msgList.msgItems[0].references); + } + + /* Clear all stored data in IMAPSession object */ + imap.empty(); + } +} + +/* Callback function to get the Email sending status */ +void helloSMTPCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < hello_smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = hello_smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up + hello_smtp.sendingResult.clear(); + } +} + +void replySMTPCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < reply_smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = reply_smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + reply_smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Access_Token/Send_Access_Token.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Access_Token/Send_Access_Token.ino new file mode 100644 index 000000000..cb0cdb6bf --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Access_Token/Send_Access_Token.ino @@ -0,0 +1,304 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token and send Email. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** For Gmail, to send the Email via port 465 (SSL), less secure app option + * should be enabled in the account settings. https://myaccount.google.com/lesssecureapps?pli=1 + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT 25 + +/* The user Email for OAuth2.0 access token */ +#define AUTHOR_EMAIL "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/** The OAuth2.0 access token + * The generation, exchange and refresh of the access token are not available + * in this library. + * + * To test this using GMail, get the OAuth2.0 access token from this web site + * https://developers.google.com/oauthplayground/ + * + * + * 1. Select the following scope (in Step 1) from Gmail API V1 + * https://mail.google.com/ + * https://mail.google.com/ + * + * 2. Click Authorize APIs button. + * 3. Cick Exchangeauthorization code for tokens. + * 4. From the response, look at access_token from the JSON payload node. + * 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value. + * + * The token will be expired in 3600 seconds (1 Hr). + * The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services. + */ +#define AUTHOR_ACCESS_TOKEN "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.accessToken = AUTHOR_ACCESS_TOKEN; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending Email using Access token"); + message.addRecipient(F("Admin"), RECIPIENT_EMAIL); + + message.text.content = F("This is simple plain text message"); + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Blob/Send_Attachment_Blob.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Blob/Send_Attachment_Blob.ino new file mode 100644 index 000000000..b408c8f81 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Blob/Send_Attachment_Blob.ino @@ -0,0 +1,369 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email with attachments and inline images. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +/* This is for attachment data */ +#include "blob_data.h" + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + + message.subject = F("Test sending Email with attachments and inline images"); + message.addRecipient(F("user1"), RECIPIENT_EMAIL); + + message.html.content = F("This message contains 3 inline images and 1 attachment file.

"); + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = F("utf-8"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + message.text.content = F("This message contains 3 inline images and 1 attachment file.\r\nThe inline images were not shown in the plain text message."); + message.text.charSet = F("utf-8"); + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* The attachment data item */ + SMTP_Attachment att[4]; + int attIndex = 0; + + /** Set the inline image info e.g. + * file name, MIME type, BLOB data, BLOB data size, + * transfer encoding (should be base64 for inline image) + */ + att[attIndex].descr.filename = F("firebase_logo.png"); + att[attIndex].descr.mime = F("image/png"); + att[attIndex].blob.data = firebase_logo_png; + att[attIndex].blob.size = sizeof(firebase_logo_png); + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att[attIndex]); + + /** Set the inline image info e.g. + * file name, MIME type, BLOB data, BLOB data size. + * The default transfer encoding is base64. + */ + attIndex++; + att[attIndex].descr.filename = F("tree.gif"); + att[attIndex].descr.mime = F("image/gif"); + att[attIndex].blob.data = tree_img_gif; + att[attIndex].blob.size = sizeof(tree_img_gif); + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att[attIndex]); + + /** Set the inline image info e.g. + * file name, MIME type, BLOB data, BLOB data size. + * The default transfer encoding is base64. + */ + attIndex++; + att[attIndex].descr.filename = F("bird.gif"); + att[attIndex].descr.mime = F("image/gif"); + att[attIndex].blob.data = bird_img_gif; + att[attIndex].blob.size = sizeof(bird_img_gif); + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att[attIndex]); + + /* Prepare the attachment data (from ram) */ + uint8_t *a = new uint8_t[512]; + int j = 0; + + for (int i = 0; i < 512; i++) + { + a[i] = j; + j++; + if (j > 255) + j = 0; + } + + /** Set the attachment info e.g. + * file name, MIME type, BLOB data, BLOB data size. + * The default transfer encoding is base64. + */ + attIndex++; + att[attIndex].descr.filename = F("test.dat"); + att[attIndex].descr.mime = F("application/octet-stream"); + att[attIndex].blob.data = a; + att[attIndex].blob.size = 512; + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + /* Add attachment to the message */ + message.addAttachment(att[attIndex]); + + /* Connect to the server */ + if (!smtp.connect(&config)) + return; + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/lib_mail/examples/Send_RFC822_Attachment/image.h b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Blob/blob_data.h similarity index 98% rename from lib/libesp32/lib_mail/examples/Send_RFC822_Attachment/image.h rename to lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Blob/blob_data.h index 80ce0a0e7..c853cded3 100644 --- a/lib/libesp32/lib_mail/examples/Send_RFC822_Attachment/image.h +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Blob/blob_data.h @@ -1,1851 +1,1851 @@ -#include - -static const uint8_t firebase_png[] PROGMEM = { - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x58, 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x76, 0x82, - 0x70, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, - 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, - 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, - 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x55, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5E, 0xED, 0xDD, 0x59, - 0x90, 0x1D, 0xF5, 0x81, 0xE7, 0x7B, 0x3F, 0xF4, 0xC3, 0x84, 0x91, 0x40, 0x6E, 0xEF, 0xC6, 0x8B, - 0x30, 0x92, 0x4A, 0x1B, 0x58, 0x98, 0xCD, 0xA0, 0xA5, 0x4A, 0x12, 0x20, 0x6C, 0x9A, 0xB6, 0xBA, - 0x01, 0x63, 0x4F, 0x3F, 0x8C, 0x1E, 0x26, 0xC2, 0xF7, 0xE5, 0xC6, 0x25, 0xE2, 0xDE, 0x97, 0x3B, - 0x7D, 0x67, 0xAC, 0x6E, 0x63, 0x63, 0x83, 0x8D, 0xBC, 0xB1, 0x99, 0xA5, 0x10, 0x08, 0xED, 0x52, - 0x69, 0xAD, 0x92, 0xA0, 0xBB, 0xAB, 0xA7, 0xED, 0x6E, 0x77, 0xB7, 0x81, 0x42, 0x9B, 0x99, 0x89, - 0x89, 0xDB, 0x9A, 0xB9, 0x0E, 0x2F, 0x2C, 0x76, 0x61, 0x16, 0x49, 0x85, 0xA4, 0xFC, 0xDF, 0xFF, - 0x3F, 0x4F, 0xE6, 0xA9, 0x3C, 0x79, 0x7E, 0xE7, 0x9C, 0xCC, 0x3C, 0x99, 0x75, 0xCE, 0xC9, 0xFA, - 0x7E, 0x22, 0x7E, 0xA1, 0x6E, 0x2F, 0x42, 0xC2, 0x94, 0xE2, 0xFF, 0x8D, 0x7F, 0x65, 0x9E, 0xF7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x82, 0x79, 0x6E, 0xCD, 0x80, 0xBF, 0xC3, 0x5F, 0x58, 0x12, 0xFC, - 0x4B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1F, 0x73, 0x78, 0xCD, 0x3A, 0xEF, 0xB9, 0x35, 0x63, 0xE6, - 0xB9, 0x9B, 0x4D, 0x75, 0xCF, 0xAE, 0xF1, 0xE7, 0x3D, 0x7B, 0xD3, 0xA0, 0x0B, 0x92, 0xE0, 0x3F, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x98, 0x91, 0x35, 0xB3, 0xEB, 0xC2, 0x23, 0x12, 0x1F, 0xD1, - 0x79, 0x87, 0xD7, 0x6C, 0x08, 0xFE, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x8E, 0xFB, 0x16, 0x2B, - 0xEF, 0xD9, 0x35, 0xE3, 0x95, 0xE0, 0xB8, 0xD1, 0x98, 0x03, 0x57, 0x19, 0xB3, 0x7B, 0xAE, 0x31, - 0x3B, 0x3E, 0x65, 0xCC, 0xB6, 0x8F, 0x1A, 0xB3, 0xF3, 0xD3, 0xC6, 0x0C, 0x2D, 0x34, 0x66, 0x78, - 0xD9, 0x64, 0x84, 0x3C, 0x7B, 0xD3, 0x60, 0xF0, 0x5F, 0x07, 0x00, 0x00, 0x00, 0x80, 0xE4, 0xAA, - 0x37, 0x1F, 0x2E, 0x3C, 0x76, 0x7C, 0xC2, 0x98, 0xED, 0x1F, 0xAB, 0x84, 0x87, 0xDA, 0x2E, 0x1B, - 0x26, 0x87, 0x6F, 0xA8, 0x84, 0xC8, 0xA1, 0x9B, 0xD6, 0x06, 0x3F, 0x05, 0x00, 0x00, 0x00, 0x00, - 0xB4, 0xE6, 0x9E, 0xF9, 0xF0, 0xE3, 0x63, 0xCF, 0xA2, 0x4A, 0x78, 0x34, 0x8B, 0x8F, 0x70, 0xDB, - 0x3F, 0x6E, 0xCC, 0xC8, 0x0A, 0xF7, 0xAD, 0x58, 0xE3, 0x66, 0xB4, 0x7F, 0x56, 0xF0, 0x53, 0x01, - 0x00, 0x00, 0x00, 0x40, 0x73, 0xDE, 0x73, 0x37, 0x9F, 0x34, 0xFB, 0xAF, 0x48, 0x1E, 0x1F, 0xE1, - 0x76, 0x5E, 0x62, 0xCC, 0xE1, 0xD5, 0x76, 0x37, 0xAE, 0x0F, 0x7E, 0x2A, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xCC, 0x3D, 0x78, 0x6E, 0x0E, 0xAF, 0x4A, 0x1F, 0x1F, 0xFE, 0x3E, 0x62, 0xCC, 0xBE, 0xCF, - 0x18, 0xEF, 0xF0, 0x4D, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x68, 0xCD, 0xFF, 0x8C, 0x8F, 0xBD, - 0x97, 0x67, 0x8B, 0x0F, 0xB7, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x20, 0x19, 0x1B, - 0x20, 0xEB, 0xCD, 0xAE, 0x4F, 0xC7, 0xE2, 0xA2, 0xD5, 0x82, 0xF8, 0x08, 0xB7, 0x67, 0xB1, 0x31, - 0xCF, 0xDE, 0x64, 0xDC, 0x6D, 0x4A, 0xF0, 0xD3, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3D, 0xEF, 0xB9, - 0x9B, 0x07, 0x75, 0x64, 0x34, 0x5A, 0x2C, 0x3E, 0xC2, 0x1D, 0x1A, 0xE0, 0xB5, 0xBC, 0x00, 0x00, - 0x00, 0x00, 0x9A, 0xF3, 0x0E, 0x2E, 0x1B, 0xD5, 0xA1, 0xA1, 0x26, 0xC2, 0x23, 0xDC, 0xD0, 0x02, - 0x6E, 0x41, 0x00, 0x00, 0x00, 0x00, 0x34, 0xE7, 0x1D, 0xB8, 0x76, 0x5C, 0xC7, 0x46, 0x7C, 0x22, - 0x3A, 0xE2, 0x1B, 0x59, 0x6E, 0xBC, 0xC3, 0x37, 0x8E, 0x06, 0x3F, 0x35, 0x00, 0x00, 0x00, 0x00, - 0x4C, 0x72, 0x6F, 0xAE, 0x32, 0xFB, 0x96, 0xD8, 0x78, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x0D, 0xB5, - 0x5D, 0x73, 0x2A, 0xB7, 0x20, 0xCF, 0xAD, 0x19, 0x08, 0xFE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x50, - 0xE1, 0xBF, 0x01, 0x6B, 0x77, 0x9F, 0x8D, 0x07, 0x15, 0x1D, 0xE1, 0x44, 0x68, 0x34, 0xDB, 0xF0, - 0xF5, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xE7, 0x7F, 0x02, 0xFA, 0xAE, 0xB9, 0x36, 0x1C, - 0x54, 0x78, 0xB8, 0x89, 0xC0, 0x68, 0xB5, 0x5D, 0x97, 0x1A, 0xF3, 0xEC, 0x8D, 0xC6, 0x3C, 0xB7, - 0x9A, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x93, 0x6C, 0x80, 0xAC, 0xD7, 0xE1, 0xE1, 0x26, 0xE2, - 0xA2, 0xE5, 0x3E, 0x5C, 0xD9, 0x81, 0xAB, 0x8C, 0xF7, 0xEC, 0x0D, 0x27, 0x83, 0xBF, 0x0C, 0x00, - 0x00, 0x00, 0x00, 0xBC, 0xE7, 0x3D, 0xDE, 0xF0, 0x8A, 0x06, 0x6F, 0xC0, 0x52, 0x71, 0xD1, 0x6A, - 0x41, 0x7C, 0xB8, 0xED, 0xF8, 0x44, 0xE5, 0x16, 0xE4, 0xF0, 0x8D, 0xEB, 0x82, 0xBF, 0x14, 0x00, - 0x00, 0x00, 0x80, 0xE9, 0xCE, 0x3B, 0x70, 0xFD, 0xC9, 0xDC, 0xE3, 0x23, 0x1C, 0xB7, 0x20, 0x00, - 0x00, 0x00, 0x00, 0xA2, 0xCC, 0xFE, 0x2B, 0x6D, 0x2C, 0x14, 0x10, 0x1F, 0x6E, 0xEE, 0x16, 0xE4, - 0xF0, 0x2A, 0x77, 0x0B, 0xB2, 0x3E, 0xF8, 0xCB, 0x01, 0x00, 0x00, 0x00, 0x98, 0xAE, 0x6C, 0x18, - 0x2C, 0x31, 0x7B, 0x2E, 0xB3, 0xB1, 0x50, 0x40, 0x7C, 0x84, 0xDB, 0x77, 0xB9, 0x7B, 0x23, 0xD6, - 0xB8, 0x7B, 0xDD, 0x6F, 0xF0, 0x97, 0x05, 0x00, 0x00, 0x00, 0x30, 0x1D, 0x99, 0x43, 0x37, 0xAD, - 0x9D, 0x7C, 0x03, 0x96, 0x8A, 0x8B, 0x56, 0x13, 0xC1, 0x11, 0xDF, 0xF6, 0x8F, 0x71, 0x0B, 0x02, - 0x00, 0x00, 0x00, 0x20, 0x78, 0x03, 0xD6, 0xF6, 0x8F, 0xDB, 0x50, 0x50, 0x71, 0xD1, 0x6A, 0x22, - 0x36, 0x1A, 0x8D, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB3, 0x37, 0x0D, 0xEA, 0xB8, 0x68, - 0x35, 0x11, 0x19, 0xAD, 0x76, 0xA8, 0xDF, 0x3D, 0x90, 0x3E, 0x18, 0xFC, 0xA5, 0x01, 0x00, 0x00, - 0x00, 0x4C, 0x37, 0xDE, 0x81, 0x6B, 0x46, 0x75, 0x60, 0x34, 0x9B, 0x88, 0x8B, 0x56, 0xDB, 0xFA, - 0x21, 0x63, 0x86, 0xE6, 0x57, 0x5E, 0xCB, 0x3B, 0xB2, 0x66, 0x76, 0xF0, 0x97, 0x07, 0x00, 0x00, - 0x00, 0x30, 0x9D, 0x98, 0x03, 0x57, 0xDB, 0x40, 0x50, 0x91, 0xD1, 0x68, 0x22, 0x2E, 0x5A, 0xCD, - 0xC5, 0x47, 0x38, 0x6E, 0x41, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC9, 0xDD, 0x44, 0x98, 0x7D, 0x9F, - 0xB1, 0x91, 0xA0, 0x42, 0x43, 0x4D, 0xC4, 0x45, 0xAB, 0x45, 0xE3, 0xC3, 0x6D, 0xF7, 0xDC, 0xCA, - 0x2D, 0xC8, 0x73, 0xAB, 0x07, 0x82, 0x5F, 0x06, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC0, 0x3C, 0xB7, - 0x66, 0xC0, 0xEC, 0x9E, 0x67, 0x43, 0x41, 0xC5, 0x46, 0x7C, 0x22, 0x2E, 0x5A, 0x2D, 0x1E, 0x1F, - 0xE1, 0x86, 0xAF, 0x73, 0x0F, 0xA4, 0x8F, 0x06, 0xBF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x81, - 0xF7, 0xEC, 0x4D, 0x77, 0x99, 0x9D, 0x97, 0xD8, 0x58, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x8B, 0x56, - 0x53, 0xE1, 0x11, 0x6E, 0xD7, 0xA7, 0xB9, 0x05, 0x01, 0x00, 0x00, 0x00, 0xA6, 0x1B, 0xEF, 0xF0, - 0x8D, 0x1B, 0x74, 0x70, 0x44, 0x27, 0xE2, 0xA2, 0xD5, 0x54, 0x74, 0xC4, 0xC7, 0x2D, 0x08, 0x00, - 0x00, 0x00, 0x30, 0xBD, 0x78, 0x07, 0xAF, 0x6F, 0xF1, 0x06, 0x2C, 0x11, 0x17, 0xAD, 0xA6, 0x62, - 0x43, 0xCD, 0x7D, 0xF6, 0x88, 0xBB, 0x05, 0x39, 0x7C, 0xE3, 0xBA, 0xE0, 0x97, 0x03, 0x00, 0x00, - 0x00, 0xA0, 0xCC, 0xBC, 0x03, 0xD7, 0x9D, 0xD4, 0xE1, 0xE1, 0x26, 0xE2, 0xA2, 0xD5, 0x54, 0x68, - 0x34, 0xDB, 0xFE, 0x2B, 0xDD, 0x1B, 0xB1, 0x4E, 0x06, 0xBF, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x65, - 0xD6, 0xF8, 0x0D, 0x58, 0x22, 0x2E, 0x5A, 0x4D, 0x05, 0x46, 0xAB, 0xB9, 0x5B, 0x90, 0xC3, 0x37, - 0x70, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x94, 0x9D, 0xFF, 0x06, 0xAC, 0xA1, 0x05, 0x36, 0x1E, 0x3A, - 0x14, 0x1F, 0xFE, 0x3E, 0x68, 0x5C, 0x04, 0x79, 0x87, 0x6E, 0x18, 0x37, 0xA3, 0xFD, 0xB3, 0x82, - 0x5F, 0x1A, 0x00, 0x00, 0x00, 0x80, 0xB2, 0x71, 0xB7, 0x0E, 0x66, 0xD7, 0x1C, 0x1B, 0x10, 0x1D, - 0x8C, 0x0F, 0x37, 0xF7, 0xD7, 0x3D, 0xB4, 0xD2, 0x98, 0xC3, 0xAB, 0xD7, 0x07, 0xBF, 0x34, 0x00, - 0x00, 0x00, 0x00, 0x65, 0x63, 0x03, 0x64, 0xBD, 0xD9, 0x7E, 0x71, 0x25, 0x00, 0x3A, 0x15, 0x1F, - 0xE1, 0xF6, 0x5E, 0xC6, 0x2D, 0x08, 0x00, 0x00, 0x00, 0x50, 0x66, 0xDE, 0xC8, 0xCA, 0xA1, 0xAE, - 0x88, 0x0F, 0xB7, 0xE0, 0x16, 0xC4, 0x3B, 0xBC, 0x7A, 0x43, 0xF0, 0xCB, 0x03, 0x00, 0x00, 0x00, - 0x50, 0x26, 0xDE, 0xC1, 0x6B, 0xC7, 0xBA, 0x22, 0x3E, 0xC2, 0xED, 0xEE, 0xAB, 0x3C, 0x90, 0x3E, - 0xB2, 0x66, 0x76, 0xF0, 0x4B, 0x04, 0x00, 0x00, 0x00, 0x50, 0x16, 0x66, 0xFF, 0x67, 0x75, 0x5C, - 0xB4, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0xD1, 0x11, 0xDF, 0xC8, 0x0A, 0xE3, 0x1D, 0x5A, 0x3D, 0x18, - 0xFC, 0x12, 0x01, 0x00, 0x00, 0x00, 0x94, 0x81, 0xBB, 0x65, 0x30, 0xFB, 0x2E, 0xD7, 0x81, 0xD1, - 0x6C, 0x32, 0x2C, 0x92, 0x4C, 0xC4, 0x86, 0x1A, 0xB7, 0x20, 0x00, 0x00, 0x00, 0x40, 0xF9, 0x98, - 0xE7, 0x56, 0x0F, 0x98, 0x5D, 0x97, 0xEA, 0xC8, 0x68, 0x34, 0x19, 0x16, 0x49, 0x26, 0x42, 0xA3, - 0xD9, 0x0E, 0x7E, 0xCE, 0x78, 0x87, 0x6F, 0x18, 0x0D, 0x7E, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x7A, - 0x9D, 0xFF, 0x06, 0xAC, 0x1D, 0x9F, 0xD0, 0xA1, 0xA1, 0x26, 0xC3, 0x22, 0xC9, 0x44, 0x60, 0xB4, - 0xDA, 0xCE, 0x4B, 0x82, 0x5B, 0x90, 0xD5, 0x03, 0xC1, 0x2F, 0x17, 0x00, 0x00, 0x00, 0x40, 0x2F, - 0xF3, 0x9E, 0xBD, 0x61, 0x50, 0x86, 0x86, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0x71, 0x91, 0x74, 0x07, - 0xAF, 0x35, 0xDE, 0xE1, 0x55, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x65, 0xE0, 0x1D, 0xBC, 0x6E, - 0x54, 0xC6, 0x46, 0x7C, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, 0x6D, 0xF9, 0x80, 0x31, 0x3B, - 0x67, 0xBB, 0x0F, 0x26, 0x34, 0xE6, 0xD0, 0xAA, 0xB5, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, 0x40, - 0xAF, 0xF2, 0x0E, 0x5C, 0x33, 0x2E, 0x83, 0x23, 0x3A, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, - 0x5C, 0x7C, 0x84, 0xDB, 0x77, 0x85, 0xFB, 0x5C, 0x90, 0x93, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, - 0x40, 0x2F, 0x72, 0x9F, 0x36, 0xDE, 0xF2, 0x0D, 0x58, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, - 0x45, 0xE3, 0xC3, 0x6D, 0xDB, 0xC7, 0x2A, 0xB7, 0x20, 0x87, 0x57, 0xAD, 0x0B, 0x7E, 0xE9, 0x00, - 0x00, 0x00, 0x00, 0x7A, 0x8D, 0xFF, 0x06, 0xAC, 0xDD, 0x73, 0xEB, 0xA3, 0x23, 0x9C, 0x0C, 0x8B, - 0x24, 0x13, 0x51, 0x91, 0x74, 0xF1, 0xF8, 0x08, 0xC7, 0x2D, 0x08, 0x00, 0x00, 0x00, 0xD0, 0xDB, - 0xCC, 0xE1, 0x1B, 0xD7, 0x35, 0x7C, 0x05, 0xAF, 0x0C, 0x8B, 0x24, 0x13, 0x51, 0x91, 0x74, 0x2A, - 0x3C, 0xC2, 0x6D, 0xB5, 0xBF, 0xA6, 0x43, 0x03, 0xEE, 0x26, 0x64, 0x7D, 0xF0, 0xCB, 0x07, 0x00, - 0x00, 0x00, 0xD0, 0x4B, 0xFC, 0x57, 0xF0, 0xF6, 0x42, 0x7C, 0x84, 0xDB, 0xB3, 0xD8, 0x7D, 0x3A, - 0xFA, 0xB8, 0xFB, 0xD6, 0xB1, 0xE0, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x57, 0x78, 0xC3, 0xCB, - 0xEB, 0xDF, 0x80, 0x25, 0xC3, 0x22, 0xC9, 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x0D, 0x35, 0x6E, 0x41, - 0x00, 0x00, 0x00, 0x80, 0xDE, 0xE5, 0x1D, 0xBC, 0x76, 0xAC, 0x67, 0xE2, 0x23, 0xDC, 0x9E, 0x45, - 0xC6, 0x3B, 0xB4, 0x6A, 0xDC, 0x8C, 0xF4, 0xCF, 0x0E, 0x7E, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x7A, - 0x81, 0xD9, 0x7F, 0x45, 0x6F, 0xC5, 0x87, 0xBF, 0xF7, 0x1B, 0x33, 0xB2, 0xCC, 0x46, 0xC8, 0xCA, - 0xC1, 0xE0, 0xB7, 0x01, 0x00, 0x00, 0x00, 0xA0, 0xDB, 0x99, 0xC3, 0x37, 0x2E, 0x71, 0xB7, 0x09, - 0x3D, 0x17, 0x1F, 0x6E, 0xEE, 0xCD, 0x5D, 0x87, 0x57, 0xD9, 0x10, 0xE9, 0xCD, 0x5B, 0x10, 0xF7, - 0xEB, 0xB6, 0x1B, 0x08, 0xC6, 0x4D, 0x0E, 0x00, 0x00, 0x00, 0xCA, 0xCF, 0x1C, 0xBA, 0x69, 0xAD, - 0xFF, 0x06, 0x2C, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x5A, 0x10, 0x1F, - 0xE1, 0x7A, 0xEC, 0x16, 0xC4, 0xFF, 0xCC, 0x95, 0x91, 0xFE, 0xF5, 0xDE, 0xA1, 0x81, 0x93, 0xFE, - 0x73, 0x2C, 0x91, 0xF9, 0xFF, 0x9A, 0xFD, 0xF7, 0x78, 0xB8, 0x1E, 0x00, 0x00, 0x00, 0xA5, 0x55, - 0x79, 0x03, 0xD6, 0x47, 0x6D, 0x10, 0xA8, 0xB8, 0x68, 0x35, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, - 0xD5, 0x62, 0xF1, 0xE1, 0xB6, 0xF3, 0x53, 0xC1, 0x2D, 0xC8, 0xEA, 0x81, 0xE0, 0xB7, 0xD4, 0xB5, - 0xCC, 0xA1, 0xFE, 0xB5, 0xDE, 0xC8, 0xC0, 0x78, 0x3C, 0x3C, 0xE2, 0xAB, 0xFC, 0x67, 0xFA, 0xD7, - 0x06, 0xFF, 0x35, 0x00, 0x00, 0x00, 0xA0, 0x3C, 0xBC, 0x67, 0x6F, 0x18, 0xD4, 0x71, 0xD1, 0x6A, - 0x22, 0x2A, 0x92, 0x4E, 0xC6, 0x45, 0xAB, 0x89, 0xF8, 0x08, 0x77, 0xF0, 0x1A, 0xE3, 0x1D, 0x5E, - 0x39, 0x1A, 0xFC, 0x96, 0xBA, 0x92, 0x19, 0xE9, 0x5F, 0x57, 0x8D, 0x8C, 0x91, 0xE5, 0xFE, 0x43, - 0xF4, 0x66, 0xC7, 0xC7, 0x6B, 0xE7, 0xFE, 0x35, 0xF7, 0xEF, 0xF9, 0xFF, 0x99, 0x7E, 0x37, 0x3E, - 0xF1, 0x1D, 0x00, 0x00, 0x00, 0xE5, 0xE2, 0x1D, 0xB8, 0x7A, 0x54, 0x07, 0x46, 0xB3, 0x89, 0xA8, - 0x48, 0x3A, 0x19, 0x17, 0xAD, 0x26, 0xA2, 0x23, 0xBA, 0x2E, 0xBF, 0x05, 0xB1, 0x21, 0x31, 0xBB, - 0x7A, 0xF3, 0x31, 0x34, 0xBF, 0xF2, 0x6B, 0xDE, 0x3C, 0x4B, 0xCF, 0xFD, 0x7B, 0x43, 0x7D, 0x7E, - 0x80, 0x78, 0x23, 0x2B, 0x78, 0xCB, 0x17, 0x00, 0x00, 0x00, 0xCA, 0xC5, 0xEC, 0xBF, 0xD2, 0x86, - 0x81, 0x8A, 0x8C, 0x46, 0x13, 0x51, 0x91, 0x74, 0x32, 0x2E, 0x5A, 0x2D, 0x12, 0x1A, 0xCD, 0xE6, - 0x6E, 0x41, 0x0E, 0xAD, 0x1A, 0x0B, 0x7E, 0x5B, 0x5D, 0xC5, 0xC6, 0xC7, 0x90, 0x1F, 0x1F, 0xBB, - 0x3E, 0xAD, 0xA3, 0xA3, 0x66, 0x17, 0x55, 0xB6, 0xF3, 0x92, 0x4A, 0x84, 0x0C, 0xAF, 0xE8, 0xEA, - 0x9B, 0x1D, 0x00, 0x00, 0x00, 0x20, 0x31, 0xFF, 0x81, 0xE8, 0xBD, 0x97, 0xDB, 0x38, 0x50, 0xA1, - 0xA1, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x9A, 0x08, 0x8D, 0x46, 0x73, 0xCF, 0xB1, 0xB8, - 0x5B, 0x90, 0xC3, 0xAB, 0xBA, 0xEA, 0xDB, 0x96, 0x6C, 0x44, 0x0C, 0xF8, 0xF1, 0xE1, 0xDE, 0xD8, - 0x25, 0x83, 0x23, 0xBA, 0x20, 0x3E, 0x62, 0x11, 0xE2, 0x7E, 0x8E, 0xE0, 0xA7, 0x03, 0x00, 0x00, - 0x00, 0x7A, 0x97, 0x79, 0x6E, 0xF5, 0x80, 0x7F, 0x30, 0x96, 0xB1, 0x11, 0x9F, 0x88, 0x8A, 0xA4, - 0x93, 0x71, 0xD1, 0x6A, 0x22, 0x32, 0x5A, 0x6D, 0xDF, 0x12, 0xE3, 0x1D, 0x5E, 0x75, 0x32, 0xF8, - 0xED, 0x75, 0x05, 0xEF, 0xD0, 0xC0, 0xA8, 0x39, 0x70, 0x55, 0x10, 0x18, 0xCD, 0x16, 0x8B, 0x8F, - 0x70, 0xFB, 0xAF, 0xE4, 0x16, 0x04, 0x00, 0x00, 0x00, 0xE5, 0xE0, 0x3D, 0x7B, 0xC3, 0x5D, 0x66, - 0xC7, 0xA7, 0x6C, 0x24, 0xA8, 0xE0, 0x88, 0x4E, 0x44, 0x45, 0xD2, 0xC9, 0xB8, 0x68, 0x35, 0x11, - 0x17, 0x49, 0x16, 0xDC, 0x82, 0x78, 0x87, 0x56, 0xDD, 0x15, 0xFC, 0x16, 0x3B, 0xAA, 0x7A, 0xFB, - 0xE1, 0x1E, 0x30, 0x97, 0xD1, 0x11, 0x4E, 0x84, 0x47, 0xB8, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, - 0x00, 0x80, 0x72, 0xF0, 0x0E, 0xDF, 0xB8, 0x41, 0x07, 0x47, 0x74, 0x22, 0x2A, 0x92, 0x4E, 0xC6, - 0x45, 0xAB, 0x89, 0xB0, 0x48, 0xB3, 0x3D, 0x0B, 0x8D, 0x37, 0xB2, 0x72, 0xBC, 0x1B, 0x3E, 0x4B, - 0x23, 0xD9, 0xED, 0x87, 0x88, 0x8E, 0xF8, 0xB8, 0x05, 0x01, 0x00, 0x00, 0x40, 0x19, 0x78, 0x07, - 0xAF, 0x6B, 0xF1, 0x06, 0x2C, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, 0xD5, 0x44, 0x50, 0xA4, 0xDA, - 0x1F, 0x57, 0xFE, 0xDA, 0x23, 0x2B, 0xEC, 0x56, 0xAE, 0x0F, 0x7E, 0x9B, 0x1D, 0xE1, 0x3E, 0xC7, - 0xC3, 0xBF, 0xFD, 0x70, 0x7F, 0x1F, 0x65, 0x78, 0xB8, 0x89, 0xD8, 0x50, 0xF3, 0x7F, 0x4F, 0xFD, - 0xC6, 0x1C, 0xE4, 0xB3, 0x41, 0x00, 0x00, 0x00, 0xD0, 0xC3, 0xBC, 0x03, 0x9F, 0x3B, 0x59, 0x1F, - 0x1D, 0xE1, 0x22, 0x31, 0x91, 0x76, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xD9, 0xF8, 0x08, - 0xD7, 0x05, 0xB7, 0x20, 0xFE, 0xA7, 0x9A, 0xBB, 0x07, 0xFC, 0x65, 0x78, 0xB8, 0x89, 0xD0, 0x68, - 0xB6, 0xBD, 0x97, 0xB9, 0x5B, 0x90, 0xAE, 0x7A, 0xBE, 0x05, 0x00, 0x00, 0x00, 0x48, 0xA5, 0xF1, - 0x1B, 0xB0, 0x44, 0x54, 0x24, 0x9D, 0x8C, 0x8B, 0x56, 0x53, 0x41, 0x91, 0x66, 0x91, 0xF8, 0x70, - 0x73, 0xBF, 0x8E, 0xE1, 0xA5, 0xEE, 0x13, 0xC5, 0x37, 0x04, 0xBF, 0xD5, 0x29, 0x65, 0xC2, 0x0F, - 0x1D, 0x74, 0x7F, 0x2F, 0xF3, 0x88, 0x0F, 0x37, 0xF7, 0x7B, 0xF2, 0x9F, 0x05, 0x59, 0xCE, 0x87, - 0x13, 0x02, 0x00, 0x00, 0xA0, 0xF7, 0xF8, 0x6F, 0xC0, 0x72, 0x1F, 0x8A, 0x57, 0xB6, 0xF8, 0x08, - 0xB7, 0x6B, 0x8E, 0x31, 0x87, 0x56, 0xBA, 0x43, 0xFB, 0x94, 0x7F, 0x90, 0x5F, 0xF3, 0xDB, 0x0F, - 0x11, 0x17, 0x49, 0xB7, 0x67, 0xB1, 0xF1, 0x86, 0x97, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x80, 0xDE, - 0x63, 0x0E, 0xDD, 0xB4, 0xD6, 0xFF, 0x60, 0xBC, 0x32, 0xC6, 0x47, 0x38, 0x77, 0x0B, 0x72, 0x68, - 0xE5, 0x60, 0xF0, 0x5B, 0x9E, 0x12, 0xCD, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0xDD, 0x33, 0x17, 0xDA, - 0xDF, 0x93, 0xFD, 0x7B, 0x66, 0x7F, 0x4F, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0xE7, 0x98, 0xC3, - 0x37, 0xAE, 0xF7, 0x5F, 0x5B, 0x5B, 0xD6, 0xF8, 0x70, 0x0B, 0x6F, 0x41, 0x0E, 0xF7, 0x2F, 0x09, - 0x7E, 0xDB, 0x85, 0x72, 0xCF, 0x9C, 0xF8, 0xB7, 0x1F, 0xEE, 0x66, 0x29, 0xEF, 0xF8, 0x08, 0xB7, - 0x7B, 0x9E, 0xF1, 0x46, 0x96, 0x8F, 0x9B, 0xA1, 0xCE, 0xBF, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, - 0xCC, 0x1B, 0x59, 0x39, 0x54, 0xEA, 0xF8, 0x08, 0x77, 0xE0, 0x6A, 0x77, 0x0B, 0x32, 0x25, 0xAF, - 0xB0, 0x35, 0x23, 0xFD, 0xEB, 0xCD, 0xC8, 0x72, 0xFB, 0xD7, 0xB5, 0xBF, 0xC6, 0x22, 0xE2, 0xC3, - 0x6D, 0xF3, 0xFB, 0xC2, 0x5B, 0x90, 0x8E, 0xBE, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, 0xC5, 0xDB, - 0x7F, 0xED, 0x58, 0xE9, 0xE3, 0xC3, 0x6D, 0xC7, 0x27, 0xC3, 0x67, 0x41, 0x0A, 0xFD, 0x20, 0x3F, - 0xFF, 0xF6, 0x63, 0x64, 0x60, 0xBC, 0xFE, 0xF6, 0x43, 0x44, 0x45, 0xD2, 0xC5, 0xE3, 0x23, 0x1C, - 0xB7, 0x20, 0x00, 0x00, 0x00, 0xE8, 0x35, 0x66, 0xDF, 0x12, 0x1D, 0x15, 0x49, 0x27, 0xE3, 0xA2, - 0xD5, 0x54, 0x50, 0xA4, 0x99, 0x08, 0x8C, 0x56, 0x73, 0x37, 0x06, 0x53, 0x70, 0x0B, 0xA2, 0x6F, - 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8F, 0x70, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0x97, 0x98, - 0x91, 0x35, 0xB3, 0xDD, 0xE7, 0x4A, 0xC8, 0xB0, 0x48, 0x32, 0x19, 0x17, 0xAD, 0x16, 0x8F, 0x89, - 0xB4, 0x13, 0x71, 0xD1, 0x6A, 0xEE, 0xA0, 0xEE, 0xB6, 0xED, 0x63, 0x95, 0x5B, 0x90, 0x43, 0xC5, - 0x7C, 0x90, 0x9F, 0xBE, 0xFD, 0x10, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0xE2, 0xE3, 0x16, 0x04, 0x00, - 0x00, 0x00, 0xBD, 0xC2, 0x8C, 0xAC, 0x1E, 0x30, 0x3B, 0x2F, 0xD1, 0x71, 0xD1, 0x6A, 0x32, 0x2E, - 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0x30, 0x3E, 0xC2, 0xED, 0xFD, 0x8C, 0xBB, - 0x05, 0x29, 0xE4, 0x15, 0xB6, 0xEE, 0xF3, 0x46, 0xCC, 0xF0, 0xF5, 0xF6, 0xAF, 0x33, 0x45, 0xF1, - 0x11, 0xEE, 0xE0, 0xE7, 0x6C, 0x84, 0xAC, 0xE8, 0xC8, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x89, - 0x99, 0xC3, 0xAB, 0xD7, 0x9B, 0xED, 0x17, 0xEB, 0xC0, 0x68, 0x36, 0x19, 0x17, 0xAD, 0xA6, 0x82, - 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x5A, 0x3C, 0x3E, 0xDC, 0xB6, 0x7E, 0x38, 0x7C, 0x16, 0x24, 0xD7, - 0x57, 0xD8, 0xDA, 0x9F, 0x6F, 0xB6, 0xFF, 0xDA, 0x5D, 0xF7, 0x4A, 0xE3, 0xA9, 0x8C, 0x0F, 0xB7, - 0x9D, 0xB3, 0xED, 0xEF, 0x67, 0x85, 0xFB, 0x3D, 0x4D, 0xF9, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, - 0x89, 0x79, 0x87, 0x57, 0x6F, 0x90, 0x81, 0xD1, 0x6C, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, - 0x89, 0xB8, 0x68, 0x35, 0x15, 0x1F, 0xE1, 0x82, 0x5B, 0x10, 0xF7, 0x2D, 0x53, 0xC1, 0xDF, 0x8A, - 0xB6, 0x79, 0x87, 0x06, 0x06, 0x27, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8C, 0x24, 0x73, - 0xB7, 0x20, 0xC3, 0x2B, 0xA6, 0xF4, 0xB3, 0x4E, 0x00, 0x00, 0x00, 0x80, 0x54, 0xBC, 0x83, 0x9F, - 0x1B, 0x95, 0x91, 0xD1, 0x68, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0x35, - 0x15, 0x1D, 0xD1, 0xB9, 0x5F, 0x97, 0x7F, 0x63, 0xB0, 0x32, 0x97, 0x87, 0xB7, 0x6B, 0x6F, 0x3F, - 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8B, 0xA4, 0xE3, 0x16, 0x04, 0x00, 0x00, 0x00, 0xDD, 0xCE, 0xDB, - 0x7F, 0xD5, 0xB8, 0x0C, 0x0D, 0xB5, 0xBA, 0xB0, 0x48, 0x32, 0x15, 0x14, 0x69, 0x26, 0xE2, 0xA2, - 0xD5, 0x54, 0x70, 0xA8, 0x0D, 0x2D, 0x30, 0xDE, 0xC8, 0xCA, 0xF1, 0x3C, 0x6E, 0x41, 0xFC, 0xDB, - 0x8F, 0x03, 0xD7, 0xDA, 0x9F, 0x57, 0x44, 0x45, 0xD2, 0xA9, 0xA8, 0x48, 0x3B, 0xF7, 0x96, 0xAF, - 0xE1, 0x65, 0xDC, 0x82, 0x34, 0x60, 0xC6, 0xFE, 0xC3, 0x2C, 0xF3, 0xF2, 0xBF, 0x5F, 0x67, 0x4E, - 0x7C, 0x65, 0x7D, 0x64, 0x6B, 0xDD, 0xBF, 0x1E, 0xFC, 0x47, 0x00, 0x00, 0x00, 0x50, 0x14, 0x77, - 0xF0, 0x4E, 0xFC, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, - 0x0A, 0x8D, 0x46, 0x73, 0xBF, 0xC6, 0x1C, 0x6E, 0x41, 0xDC, 0xA7, 0xAB, 0xFB, 0xB7, 0x1F, 0xEE, - 0x59, 0x1A, 0x15, 0x16, 0x49, 0xA6, 0x62, 0x22, 0xCB, 0xB6, 0x7F, 0xD4, 0xFE, 0x7E, 0x96, 0xDB, - 0x2D, 0x2D, 0xF4, 0xB3, 0x4E, 0x7A, 0x8D, 0x0B, 0x0C, 0xEF, 0xC4, 0x97, 0x07, 0xCD, 0x2F, 0xBE, - 0x62, 0xE4, 0x4E, 0x7C, 0xC9, 0xF8, 0xFF, 0x3E, 0x21, 0x02, 0x00, 0x00, 0x50, 0x1C, 0xFF, 0x0D, - 0x58, 0xBB, 0xE6, 0xE8, 0xE0, 0x88, 0xAE, 0x2E, 0x2C, 0x92, 0x4C, 0x05, 0x45, 0x9A, 0x89, 0xB8, - 0x68, 0x35, 0x15, 0x19, 0xAD, 0xE6, 0xBF, 0xC2, 0x76, 0xE5, 0x78, 0x3B, 0xDF, 0xB6, 0xE4, 0x1D, - 0x1A, 0x18, 0x35, 0xFB, 0xAF, 0xB4, 0x3F, 0x9F, 0x08, 0x8B, 0x24, 0x53, 0x21, 0x91, 0x69, 0x33, - 0x2B, 0xDB, 0x7F, 0x85, 0xF1, 0x86, 0x97, 0x4F, 0xC9, 0x27, 0xBE, 0xF7, 0x02, 0x73, 0xFC, 0xDF, - 0x2F, 0xF1, 0x7E, 0xF1, 0xE5, 0xF1, 0xDA, 0xE0, 0xB8, 0xDD, 0x98, 0xE3, 0x5F, 0xF4, 0xC3, 0x23, - 0xFA, 0xAF, 0xFB, 0xFF, 0x39, 0xFB, 0x9F, 0x0F, 0xFE, 0xAB, 0x00, 0x00, 0x00, 0xC8, 0x93, 0x39, - 0x7C, 0xE3, 0xBA, 0x96, 0xAF, 0xE0, 0x95, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, - 0xAB, 0xA9, 0xB8, 0x48, 0xBA, 0xE1, 0xEB, 0x8D, 0xFB, 0x16, 0xAA, 0xE0, 0x6F, 0x4B, 0x2A, 0x36, - 0x5C, 0x06, 0xEC, 0xB2, 0xDF, 0x7E, 0xC8, 0x90, 0xC8, 0xB2, 0x20, 0x3E, 0xDC, 0xB8, 0x05, 0xA9, - 0xAA, 0x89, 0x0F, 0x17, 0x1D, 0x2F, 0xD9, 0xFF, 0xAD, 0x5E, 0xB0, 0xB1, 0xF8, 0xFC, 0x92, 0xC9, - 0xBD, 0x70, 0xB5, 0xFD, 0xD7, 0x57, 0x55, 0xFE, 0x7D, 0x22, 0x04, 0x00, 0x00, 0xA0, 0x38, 0xFE, - 0x2B, 0x78, 0x55, 0x74, 0x84, 0x93, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, - 0xA9, 0xA8, 0x48, 0xBC, 0x59, 0x95, 0x07, 0xC7, 0xDD, 0xB7, 0x50, 0x65, 0xB8, 0x05, 0xF1, 0x86, - 0x57, 0x64, 0xBF, 0xFD, 0x90, 0x21, 0x91, 0x65, 0x91, 0xF8, 0x08, 0xC7, 0x2D, 0x48, 0x6D, 0x7C, - 0x1C, 0xB9, 0xB1, 0x36, 0x3A, 0xD4, 0x5C, 0x98, 0x1C, 0xFD, 0x42, 0x25, 0x42, 0x4E, 0x7C, 0x85, - 0x1B, 0x24, 0x00, 0x00, 0x80, 0xBC, 0x79, 0x07, 0x97, 0x35, 0x7E, 0x03, 0x96, 0x8C, 0x8B, 0x56, - 0x53, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0x85, 0x1F, 0x16, 0x68, 0xE7, - 0x6E, 0x41, 0x46, 0x06, 0x86, 0x82, 0xBF, 0x35, 0x89, 0xB4, 0x75, 0xFB, 0x21, 0x43, 0x22, 0xCB, - 0x44, 0x7C, 0xB8, 0x6D, 0xFD, 0xD0, 0xB4, 0xBE, 0x05, 0xA9, 0x89, 0x0F, 0x77, 0xEB, 0xA1, 0x82, - 0xA3, 0xD1, 0x5C, 0xAC, 0xF8, 0x37, 0x26, 0x5F, 0x29, 0xE4, 0xD3, 0xF2, 0x01, 0x00, 0x00, 0xA6, - 0x2D, 0x6F, 0xFF, 0x35, 0x63, 0xC4, 0x47, 0xB0, 0xED, 0x1F, 0xB7, 0x87, 0x75, 0xFF, 0x16, 0x24, - 0xF1, 0x81, 0xDD, 0x1B, 0x59, 0x31, 0xE6, 0x3F, 0xC4, 0xAF, 0x02, 0xA3, 0xD9, 0x64, 0x48, 0x64, - 0x99, 0x08, 0x8F, 0xE8, 0xF6, 0x2C, 0xB2, 0x51, 0xB5, 0x7C, 0x2C, 0xF8, 0xE5, 0x4E, 0x1B, 0x6D, - 0xC5, 0x47, 0xB8, 0x63, 0x7F, 0xE2, 0x3F, 0x94, 0x1E, 0xFC, 0x94, 0x00, 0x00, 0x00, 0xC8, 0x83, - 0xD9, 0xF7, 0x19, 0xE2, 0xC3, 0xED, 0x99, 0x60, 0xFB, 0xAF, 0x32, 0xDE, 0xF0, 0x40, 0xA2, 0x6F, - 0xBD, 0xB1, 0xA1, 0xB2, 0xCE, 0xBF, 0xFD, 0x70, 0x7F, 0xCF, 0x54, 0x64, 0x34, 0x9A, 0x0C, 0x89, - 0x2C, 0x13, 0xC1, 0x11, 0x9F, 0xFB, 0x7B, 0xEB, 0xDF, 0x82, 0x2C, 0xCF, 0xF5, 0x13, 0xDF, 0xBB, - 0x59, 0x2E, 0xF1, 0xE1, 0xF6, 0xC2, 0xD5, 0xEE, 0xDB, 0xB0, 0x4E, 0x06, 0x3F, 0x2D, 0x00, 0x00, - 0x00, 0xDA, 0x65, 0x0E, 0xDF, 0xB8, 0xC4, 0x0C, 0x2D, 0x9C, 0xBE, 0xF1, 0x11, 0x46, 0x47, 0xF0, - 0x7F, 0x7B, 0x6E, 0xDB, 0x3F, 0xEE, 0xBE, 0x0D, 0x2B, 0xD1, 0x2D, 0x88, 0x37, 0xBC, 0xE2, 0x64, - 0xEA, 0xDB, 0x0F, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, 0xD1, 0xDC, 0x2D, 0xC8, 0xF0, 0xB2, 0x69, - 0x71, 0x90, 0xCE, 0x2D, 0x3E, 0xC2, 0x1D, 0xBB, 0xC5, 0x04, 0x3F, 0x35, 0x00, 0x00, 0x00, 0xDA, - 0x65, 0x0E, 0xAD, 0x5A, 0x5B, 0xF3, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, - 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0xAB, 0x8F, 0x0F, 0x3F, 0x3C, 0xC2, 0x6D, 0xB2, 0xDB, 0x7B, - 0x85, 0x39, 0x3F, 0x3C, 0xD0, 0xF4, 0xC0, 0x9E, 0xE9, 0xF6, 0x43, 0x86, 0x44, 0x96, 0x89, 0xC8, - 0x68, 0x36, 0xF7, 0xF7, 0x79, 0x1A, 0xDC, 0x82, 0xE4, 0x1E, 0x1F, 0xCF, 0x7F, 0xC6, 0x98, 0x23, - 0x37, 0x18, 0xF3, 0xF2, 0x9D, 0x7C, 0x9E, 0x0A, 0x00, 0x00, 0x40, 0x1E, 0xFC, 0x37, 0x60, 0x6D, - 0xFB, 0xC8, 0xF4, 0x8D, 0x8F, 0x68, 0x78, 0xB8, 0xB9, 0xF8, 0x70, 0xDB, 0xFC, 0x21, 0xF7, 0x6D, - 0x58, 0xEE, 0x16, 0xA4, 0xE1, 0x81, 0xDD, 0xBF, 0xFD, 0xD8, 0xB3, 0xD0, 0xFE, 0x7C, 0x22, 0x34, - 0xD4, 0x64, 0x48, 0x64, 0x99, 0x08, 0x8C, 0x24, 0x1B, 0x9A, 0x5F, 0xEA, 0x5B, 0x90, 0x42, 0xE2, - 0xC3, 0x6D, 0xEC, 0x3A, 0x17, 0x20, 0xD3, 0xE6, 0xDB, 0xD7, 0x00, 0x00, 0x00, 0x0A, 0xE5, 0x1D, - 0x5A, 0x3D, 0x38, 0xED, 0xE2, 0x23, 0x12, 0x20, 0xD5, 0xE8, 0x88, 0xC4, 0xC7, 0xF9, 0x70, 0x43, - 0x97, 0x9B, 0x73, 0x07, 0xF5, 0x2D, 0xC8, 0xF9, 0x91, 0xFE, 0xF5, 0x66, 0x78, 0x99, 0xFD, 0xB9, - 0xDC, 0xAF, 0x49, 0xC4, 0x46, 0x7C, 0x32, 0x24, 0xB2, 0x4C, 0x84, 0x45, 0xD2, 0xB9, 0xDF, 0xF7, - 0xF0, 0xF5, 0xEE, 0x16, 0xA4, 0xAD, 0x4F, 0x7C, 0xEF, 0x46, 0x85, 0xC5, 0x87, 0xDB, 0x0B, 0x57, - 0x19, 0x73, 0xE2, 0xCE, 0xD2, 0xFD, 0x3D, 0x03, 0x00, 0x00, 0xE8, 0x08, 0x6F, 0xDF, 0x55, 0xA3, - 0x3A, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xC5, 0xC2, 0x22, 0xC9, 0x64, 0x54, 0x24, 0x5D, 0x24, - 0x3E, 0x82, 0xD5, 0xDC, 0x78, 0x84, 0xD1, 0xF1, 0x74, 0x64, 0x9B, 0x3F, 0x64, 0xCE, 0x1F, 0x5C, - 0x6E, 0xCE, 0x0D, 0xF7, 0xDF, 0x15, 0xFC, 0xED, 0xF2, 0x99, 0xA1, 0xFE, 0x59, 0xE7, 0x47, 0x56, - 0x8C, 0x9B, 0xDD, 0x7D, 0xF6, 0x60, 0x2F, 0x62, 0x23, 0x3E, 0x19, 0x12, 0x59, 0x26, 0xA2, 0x22, - 0xED, 0x76, 0xCF, 0x35, 0xDE, 0xC8, 0xB2, 0x71, 0xF7, 0x7B, 0x08, 0x7E, 0x3B, 0x3D, 0xAF, 0xD0, - 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x9F, 0x07, 0x02, 0x00, 0x00, 0x90, 0x07, 0xB3, 0xEF, 0x0A, - 0x7B, 0xB8, 0x57, 0x81, 0xD1, 0x6C, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, 0x48, - 0xBA, 0x48, 0x78, 0x44, 0x6F, 0x3E, 0xE2, 0xB7, 0x1E, 0x7E, 0x78, 0xBC, 0xCF, 0x9C, 0x7B, 0x6A, - 0x72, 0xE7, 0x77, 0xCE, 0x77, 0xB7, 0x20, 0x35, 0x07, 0xF6, 0xF3, 0x07, 0xFB, 0xD7, 0x7B, 0xC3, - 0xCB, 0x8C, 0xE7, 0x6E, 0x3F, 0x5A, 0x05, 0x88, 0x0C, 0x89, 0x2C, 0x13, 0x31, 0x91, 0x76, 0x9B, - 0x66, 0xD8, 0x1F, 0xED, 0xAF, 0xA9, 0x44, 0xB7, 0x20, 0x53, 0x11, 0x1F, 0x6E, 0xDE, 0xD1, 0x5B, - 0xA6, 0xDD, 0x6B, 0x8C, 0x01, 0x00, 0x00, 0x72, 0x67, 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x8B, 0xED, - 0x01, 0x5F, 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x58, 0x24, 0x99, 0x8C, 0x8A, 0xA4, - 0x8B, 0xC4, 0x47, 0x83, 0x00, 0x09, 0xE3, 0xE3, 0x5C, 0x24, 0x3E, 0xCE, 0x6E, 0x0C, 0xF6, 0xD4, - 0xFB, 0xCD, 0xF9, 0x03, 0xCB, 0x8D, 0x8B, 0x0E, 0xFF, 0xEF, 0x99, 0x0D, 0x91, 0x73, 0xC3, 0x2B, - 0xC6, 0xBD, 0x5D, 0x7D, 0xF6, 0xBF, 0x7F, 0x91, 0x3F, 0xFF, 0x50, 0xAF, 0x42, 0x44, 0x86, 0x44, - 0x96, 0x89, 0x98, 0x48, 0x3B, 0x17, 0x1F, 0xE1, 0x4A, 0x72, 0x0B, 0x32, 0x55, 0xF1, 0xE1, 0xEF, - 0xE8, 0xE7, 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xBB, 0xCC, 0xC8, 0xEA, 0x01, 0xB3, 0xEB, 0x52, - 0x7B, 0xC8, 0x57, 0xA1, 0xA1, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, - 0x4B, 0x1F, 0x1F, 0xD5, 0xF0, 0x78, 0xD2, 0x6D, 0x96, 0xBF, 0x73, 0x3B, 0xE6, 0x9B, 0xB3, 0x07, - 0x2A, 0xB7, 0x20, 0x2E, 0x44, 0xCE, 0x1F, 0x5C, 0x66, 0xFF, 0xFB, 0x7F, 0xDC, 0x3C, 0x40, 0x64, - 0x48, 0x64, 0x99, 0x88, 0x89, 0xB4, 0x8B, 0xC6, 0x87, 0x9B, 0xFB, 0xB5, 0x1E, 0xBC, 0xB6, 0xA7, - 0x6F, 0x41, 0xA6, 0x34, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0xEC, 0x5F, 0x33, 0xF8, 0xCB, 0x03, 0x00, - 0x00, 0x20, 0x0B, 0xEF, 0xD0, 0xAA, 0xBB, 0xCC, 0xF6, 0x4F, 0xD8, 0x83, 0xBE, 0x8A, 0x8D, 0xF8, - 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, 0x74, 0xB1, 0xF8, 0x08, 0x02, 0x24, - 0x49, 0x7C, 0xBC, 0x6B, 0xE3, 0xE3, 0xDD, 0xC1, 0x59, 0x93, 0xDB, 0xF8, 0x7E, 0x73, 0x6E, 0xEF, - 0xF5, 0xE6, 0xDC, 0x81, 0x81, 0x51, 0xF7, 0xED, 0x58, 0xE7, 0xB7, 0x5F, 0x62, 0xFF, 0xBB, 0x36, - 0x3E, 0xDC, 0x54, 0x84, 0xC8, 0x90, 0xC8, 0x32, 0x11, 0x13, 0x69, 0x17, 0x8F, 0x8F, 0x70, 0x3B, - 0x3E, 0xE9, 0x02, 0xC4, 0xBD, 0xE5, 0x6B, 0x76, 0xF0, 0x8F, 0x43, 0xCF, 0x98, 0xF2, 0xF8, 0x70, - 0x1B, 0x5B, 0x66, 0xCC, 0x89, 0xAF, 0xAC, 0x0D, 0x7E, 0x09, 0x00, 0x00, 0x00, 0xC8, 0xC2, 0x3B, - 0xBC, 0x7A, 0x83, 0x8E, 0x8D, 0xF8, 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, - 0x74, 0x3A, 0x3E, 0xEA, 0x02, 0xC4, 0x86, 0x47, 0xF8, 0xCC, 0x47, 0x3C, 0x3E, 0x26, 0xDC, 0x9E, - 0xA8, 0xCC, 0xFD, 0xFF, 0x67, 0xB7, 0x7C, 0xDA, 0x4C, 0x3C, 0xD3, 0x6F, 0xCE, 0x0D, 0xD9, 0x10, - 0x79, 0xCA, 0xFD, 0x77, 0x2F, 0xD2, 0x11, 0xB2, 0x49, 0x85, 0x44, 0x96, 0x89, 0x98, 0x48, 0x3B, - 0x15, 0x1E, 0xD1, 0x1D, 0xBC, 0xD6, 0xBD, 0x96, 0x77, 0x30, 0xF8, 0xC7, 0xA1, 0x27, 0x74, 0x24, - 0x3E, 0xDC, 0x5E, 0xBC, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0xB4, 0xCB, 0x3B, 0x78, 0x4D, 0x82, - 0x37, 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0xE1, 0x11, - 0x2E, 0x1E, 0x1F, 0xE1, 0xED, 0x47, 0xE4, 0x99, 0x0F, 0x17, 0x1F, 0xD1, 0xF0, 0x98, 0x78, 0x3C, - 0x98, 0xFB, 0xBF, 0x1F, 0x9B, 0x65, 0x4E, 0x3F, 0x72, 0x9D, 0x39, 0xF3, 0xF0, 0x25, 0x7E, 0x80, - 0x9C, 0xF3, 0x1F, 0x58, 0x8F, 0x05, 0x88, 0x8B, 0x8F, 0x5C, 0x02, 0x44, 0xC4, 0x44, 0xDA, 0xA9, - 0xE0, 0x88, 0xAF, 0xC7, 0x6E, 0x41, 0x3A, 0x16, 0x1F, 0xC1, 0xBC, 0x5F, 0xDC, 0x39, 0x14, 0xFC, - 0x52, 0x00, 0x00, 0x00, 0x90, 0x85, 0xB7, 0xFF, 0xEA, 0x93, 0x3A, 0x3A, 0xC2, 0xA9, 0xA0, 0x48, - 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x78, 0xB8, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, - 0xDE, 0x7E, 0xD4, 0x7E, 0xEB, 0x55, 0x34, 0x3E, 0xCE, 0xD8, 0xE8, 0x38, 0xF3, 0xF8, 0xFB, 0x82, - 0x55, 0x22, 0xE4, 0xF4, 0xFD, 0x17, 0x99, 0x53, 0xF7, 0x5E, 0x6C, 0x4E, 0xDD, 0x7D, 0x91, 0x39, - 0x6B, 0xFF, 0x33, 0x75, 0xB7, 0x20, 0x36, 0x3C, 0xDC, 0xDA, 0x0F, 0x10, 0x11, 0x13, 0x69, 0xA7, - 0x62, 0xA3, 0xD1, 0x7A, 0xE4, 0x16, 0xA4, 0xD3, 0xF1, 0xE1, 0xE6, 0x1D, 0xFB, 0x53, 0xDE, 0x84, - 0x05, 0x00, 0x00, 0xD0, 0x8E, 0xE6, 0x6F, 0xC0, 0x52, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, - 0x46, 0x45, 0xD2, 0xC5, 0xA2, 0x23, 0xBA, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDC, 0x7E, 0xD4, 0x7C, - 0xDB, 0x55, 0x18, 0x1F, 0x8F, 0xD9, 0xF0, 0xB0, 0x3B, 0x1D, 0xFC, 0x78, 0xE6, 0x91, 0xF7, 0xF9, - 0xE1, 0x11, 0xEE, 0xF4, 0x7D, 0x36, 0x42, 0x36, 0x4E, 0x46, 0x88, 0xF7, 0x74, 0x25, 0x3E, 0xAA, - 0x01, 0x92, 0x39, 0x42, 0x44, 0x4C, 0xA4, 0x9D, 0x8A, 0x8C, 0x66, 0xDB, 0x7E, 0x71, 0xD7, 0xDF, - 0x82, 0x74, 0x43, 0x7C, 0xF8, 0x3B, 0x76, 0x0B, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xC8, 0xCA, 0x7F, - 0x03, 0xD6, 0xEE, 0x79, 0xF6, 0xE0, 0x5F, 0xFE, 0xF8, 0x70, 0x3F, 0x36, 0xBF, 0xFD, 0xB0, 0xF1, - 0xE1, 0x02, 0x24, 0x88, 0x0F, 0x17, 0x1E, 0xA7, 0x1F, 0x9D, 0xDC, 0xA9, 0x7B, 0x67, 0xD5, 0x04, - 0x88, 0xDB, 0xBB, 0x3F, 0x0E, 0x02, 0xE4, 0xA9, 0x0B, 0xED, 0xCF, 0x67, 0xE3, 0x23, 0x1E, 0x21, - 0x32, 0x30, 0x9A, 0x4D, 0xC4, 0x44, 0xDA, 0xA9, 0xC0, 0x48, 0xB2, 0x7D, 0x57, 0x18, 0x6F, 0x78, - 0x79, 0x57, 0x7E, 0xD0, 0x5E, 0xD7, 0xC4, 0x87, 0x9B, 0x7B, 0x13, 0xD6, 0xCB, 0x77, 0xF6, 0xDC, - 0x43, 0xFB, 0x00, 0x00, 0x00, 0x5D, 0xC1, 0x1C, 0x5A, 0xB5, 0xD6, 0xEC, 0x9C, 0x6D, 0x0F, 0xFF, - 0x25, 0x8E, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDD, 0x7E, 0xB8, 0xD7, 0xEC, 0x46, 0x6F, - 0x3F, 0xE2, 0xF1, 0x71, 0xFA, 0x81, 0xDA, 0xDB, 0x8F, 0x70, 0xEE, 0x16, 0xE4, 0xDC, 0x93, 0x76, - 0x1B, 0x2F, 0xF2, 0x23, 0xA4, 0x26, 0x40, 0x5C, 0x50, 0xA4, 0x8A, 0x10, 0x11, 0x13, 0x69, 0xA7, - 0xC2, 0x22, 0xE9, 0xB6, 0x7D, 0x24, 0xB8, 0x05, 0x59, 0x3A, 0x10, 0xFC, 0xE3, 0xD1, 0x15, 0xBA, - 0x2A, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0xB3, 0xAB, 0xFE, 0x1E, 0x01, 0x00, 0x00, 0xF4, - 0x0C, 0x73, 0x78, 0xF5, 0x7A, 0xB3, 0xF5, 0xC3, 0x36, 0x00, 0x4A, 0x1C, 0x1F, 0xC1, 0xD4, 0xED, - 0xC7, 0x59, 0x3F, 0x40, 0x6C, 0x7C, 0xB8, 0xDB, 0x8F, 0xC8, 0xB7, 0x5E, 0x55, 0xC3, 0xE3, 0xC7, - 0x95, 0xA9, 0xDB, 0x0F, 0x7F, 0x5F, 0xBF, 0xD0, 0xBC, 0xFB, 0x48, 0x25, 0x40, 0xCE, 0xB5, 0x75, - 0x0B, 0x22, 0x62, 0x22, 0xED, 0x54, 0x54, 0xA4, 0x9D, 0xBB, 0x05, 0x39, 0xB8, 0xAC, 0x6B, 0x6E, - 0x41, 0xBA, 0x2E, 0x3E, 0xDC, 0x78, 0x13, 0x16, 0x00, 0x00, 0x40, 0x76, 0xDE, 0xC8, 0x8A, 0xA1, - 0xD2, 0xC7, 0x47, 0xC3, 0xDB, 0x8F, 0x59, 0xD5, 0xF8, 0xA8, 0xDE, 0x7E, 0x84, 0xF1, 0x11, 0x84, - 0x87, 0x1F, 0x1F, 0x3F, 0xD2, 0xB7, 0x1F, 0x2E, 0x3E, 0xDC, 0x4E, 0x7F, 0xEB, 0x42, 0x73, 0xB6, - 0xAD, 0x5B, 0x10, 0x11, 0x13, 0x69, 0xA7, 0x62, 0x22, 0xCB, 0xB6, 0xD9, 0x18, 0x1D, 0x5E, 0xD6, - 0x15, 0xB7, 0x20, 0x5D, 0x19, 0x1F, 0xC1, 0xBC, 0x13, 0x5F, 0xEE, 0xA9, 0xD7, 0x16, 0x03, 0x00, - 0x00, 0x74, 0x0D, 0x6F, 0xDF, 0x55, 0x63, 0x65, 0xBF, 0xF9, 0x70, 0xAB, 0xBF, 0xFD, 0x88, 0x04, - 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x70, 0x44, 0x02, 0xE4, 0x94, 0x7B, 0xE8, 0xDC, 0xED, 0xDB, 0xE2, - 0xF6, 0x23, 0x88, 0x8F, 0x70, 0x13, 0x0F, 0x64, 0xBD, 0x05, 0x11, 0x31, 0x91, 0x76, 0x2A, 0x24, - 0x32, 0xED, 0x82, 0xCA, 0xF6, 0x5C, 0xD6, 0xF1, 0x5B, 0x90, 0x6E, 0x8E, 0x0F, 0x37, 0xEF, 0xF8, - 0x9F, 0x75, 0xE5, 0xB3, 0x32, 0x00, 0x00, 0x00, 0x5D, 0xCF, 0xEC, 0xBD, 0xDC, 0x86, 0x40, 0x89, - 0xE3, 0x23, 0xC1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xC1, 0xB7, 0x5E, 0x9D, 0x0A, 0x03, 0xE4, 0x07, - 0xAD, 0xE3, 0xC3, 0xED, 0xF4, 0x3D, 0x2D, 0x6E, 0x41, 0xE4, 0x44, 0x4C, 0xA4, 0x9D, 0x0C, 0x89, - 0x2C, 0x0B, 0xE2, 0xC3, 0xCD, 0xFD, 0xFD, 0xF5, 0x6F, 0x41, 0x96, 0xAF, 0x0B, 0xFE, 0x31, 0x99, - 0x52, 0xDD, 0x1E, 0x1F, 0xFE, 0x8E, 0xFF, 0x29, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x48, 0xCB, 0xBD, - 0x72, 0xD5, 0xEC, 0x59, 0x64, 0x63, 0x40, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0xBA, 0xA0, - 0x48, 0x33, 0x11, 0x1A, 0x8D, 0x16, 0x0F, 0x90, 0xE0, 0xF6, 0xE3, 0x6C, 0x92, 0xDB, 0x8F, 0x87, - 0xED, 0xEE, 0x69, 0x1D, 0x1F, 0xE1, 0xC2, 0x5B, 0x90, 0x64, 0x6F, 0xC4, 0x12, 0x31, 0x91, 0x76, - 0x32, 0x24, 0xB2, 0x2C, 0x12, 0x1F, 0xE1, 0x86, 0x16, 0x1A, 0xEF, 0xE0, 0xD2, 0x93, 0xC1, 0x3F, - 0x2A, 0x53, 0xA6, 0x27, 0xE2, 0xC3, 0xED, 0xC8, 0x6A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0x90, 0x96, - 0xFF, 0x0A, 0xDE, 0x9D, 0x9F, 0xB2, 0x41, 0xA0, 0xA2, 0x22, 0xE9, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, - 0x8A, 0xA4, 0x13, 0x91, 0xA1, 0x66, 0x83, 0xA3, 0x1A, 0x1F, 0x36, 0x3C, 0x12, 0xDF, 0x7E, 0x44, - 0xBF, 0xF5, 0xEA, 0xFB, 0xB1, 0xDB, 0x0F, 0x11, 0x1D, 0xD1, 0x25, 0xBF, 0x05, 0x11, 0x31, 0x91, - 0x76, 0x32, 0x24, 0xB2, 0x4C, 0xC4, 0x87, 0x9B, 0xFB, 0x7B, 0x3D, 0xC5, 0xB7, 0x20, 0x3D, 0x13, - 0x1F, 0x3F, 0xBF, 0xDC, 0x98, 0xB1, 0x15, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x20, 0x2D, 0x73, 0x78, - 0xE5, 0x7A, 0xB3, 0xED, 0xA3, 0x36, 0x0A, 0x54, 0x58, 0x24, 0x99, 0x88, 0x8B, 0x56, 0xAB, 0x0B, - 0x8A, 0x34, 0x8B, 0x45, 0x46, 0xB3, 0x45, 0x03, 0xC4, 0xAE, 0x12, 0x1F, 0x36, 0x0E, 0xC2, 0x00, - 0x69, 0xF4, 0xDA, 0xDD, 0x46, 0xB7, 0x1F, 0x22, 0x38, 0xD4, 0x26, 0x7E, 0x50, 0x09, 0x90, 0x9A, - 0x67, 0x41, 0x82, 0x10, 0xA9, 0xDC, 0x82, 0x88, 0x98, 0x48, 0x3B, 0x19, 0x12, 0x59, 0x26, 0xC2, - 0x23, 0xBA, 0x29, 0xBC, 0x05, 0xE9, 0xA9, 0xF8, 0x70, 0x7B, 0xF1, 0x3A, 0x63, 0x7F, 0xBD, 0x77, - 0x05, 0xBF, 0x7C, 0x00, 0x00, 0x00, 0x24, 0xE1, 0x1D, 0x5E, 0xB9, 0x41, 0x87, 0x45, 0x92, 0x89, - 0xB8, 0x68, 0x35, 0x19, 0x15, 0x49, 0x17, 0x0B, 0x8C, 0x66, 0x8B, 0xC5, 0x47, 0xE5, 0xF6, 0x23, - 0x12, 0x1F, 0xCD, 0x6E, 0x3F, 0xC2, 0x00, 0x89, 0xDE, 0x7E, 0x88, 0xD0, 0x68, 0xB8, 0x6F, 0x5C, - 0x68, 0xCE, 0x3E, 0xD1, 0xE0, 0x16, 0x64, 0x93, 0x88, 0x89, 0xB4, 0x93, 0x21, 0x91, 0x65, 0x22, - 0x38, 0xE2, 0x73, 0x7F, 0xDF, 0x0F, 0x5E, 0x57, 0xF8, 0x2D, 0x48, 0xCF, 0xC5, 0x47, 0x30, 0xEF, - 0xC4, 0x9D, 0x1B, 0x82, 0xDF, 0x02, 0x00, 0x00, 0x00, 0x92, 0xF0, 0x0E, 0x5E, 0x3D, 0xAA, 0xE3, - 0xA2, 0xD5, 0x44, 0x5C, 0xB4, 0x5A, 0x5D, 0x50, 0xA4, 0x59, 0x2C, 0x30, 0x9A, 0xAD, 0x41, 0x7C, - 0xF8, 0xB7, 0x1F, 0x2E, 0x3E, 0xD4, 0xED, 0x47, 0x10, 0x1F, 0xD5, 0xDB, 0x8F, 0x87, 0xEC, 0xBE, - 0x91, 0x21, 0x3E, 0x82, 0x85, 0xB7, 0x20, 0xE7, 0x9F, 0x72, 0x7F, 0xDD, 0x20, 0x42, 0x9E, 0x9E, - 0x69, 0x7F, 0x2D, 0x2E, 0x20, 0x82, 0xA9, 0xB8, 0x68, 0x35, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, - 0xD1, 0x76, 0xCD, 0x31, 0xDE, 0xF0, 0xD2, 0x71, 0x33, 0xD4, 0x3F, 0x2B, 0xF8, 0xC7, 0x26, 0x57, - 0xBD, 0x1A, 0x1F, 0x7E, 0x80, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x74, 0xBC, 0xFD, 0x9F, 0x1D, - 0xD7, 0x81, 0xD1, 0x6C, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xC5, 0x02, 0xA3, 0xD5, 0xEA, - 0x02, 0x24, 0x88, 0x8F, 0xF8, 0xED, 0x47, 0x10, 0x1F, 0xF2, 0xD9, 0x8F, 0xFB, 0x83, 0xDB, 0x0F, - 0x11, 0x17, 0x89, 0x16, 0xBB, 0x05, 0x39, 0x1F, 0xC4, 0x47, 0x5B, 0x01, 0x22, 0x43, 0x22, 0xCB, - 0x44, 0x64, 0x34, 0x9B, 0x7B, 0x66, 0xC5, 0xDD, 0x82, 0x1C, 0x5C, 0x9A, 0xFB, 0x07, 0xEF, 0xF5, - 0x72, 0x7C, 0xB8, 0x79, 0xC7, 0xFE, 0x64, 0x3C, 0xF8, 0xAD, 0x00, 0x00, 0x00, 0xA0, 0x15, 0x33, - 0xDA, 0x3F, 0x2B, 0xFD, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x8B, 0xC5, 0x45, - 0x92, 0xC5, 0xE3, 0x23, 0x7A, 0xFB, 0x11, 0xC4, 0x47, 0xCD, 0x9B, 0xAF, 0x1A, 0xDD, 0x7E, 0xA8, - 0xB0, 0x48, 0xB1, 0x33, 0xDF, 0xBB, 0x70, 0xF2, 0x59, 0x90, 0xA7, 0x6C, 0x7C, 0xB4, 0x13, 0x21, - 0x32, 0x24, 0xB2, 0x4C, 0x04, 0x46, 0x92, 0x15, 0x70, 0x0B, 0xD2, 0xEB, 0xF1, 0xE1, 0xEF, 0xC8, - 0x4D, 0xC6, 0x8C, 0xFD, 0x87, 0x42, 0x6E, 0x86, 0x00, 0x00, 0x00, 0x4A, 0xC7, 0x7F, 0x03, 0xD6, - 0xAE, 0x4F, 0xDB, 0x48, 0x50, 0xA1, 0xA1, 0x26, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, - 0x8B, 0x56, 0xB3, 0xD1, 0x31, 0x19, 0x20, 0x17, 0x55, 0x02, 0x24, 0xB8, 0xFD, 0xA8, 0xBE, 0x76, - 0xB7, 0x7A, 0xFB, 0xF1, 0xBE, 0xC6, 0xB7, 0x1F, 0x22, 0x28, 0xB2, 0xEC, 0xEC, 0x63, 0x2E, 0x42, - 0x2A, 0x01, 0xE2, 0xDF, 0x82, 0x64, 0x89, 0x10, 0x19, 0x12, 0x59, 0x26, 0xC2, 0x22, 0xE9, 0x72, - 0xBE, 0x05, 0x29, 0x45, 0x7C, 0xB8, 0xBD, 0x34, 0xC0, 0x9B, 0xB0, 0x00, 0x00, 0x00, 0x92, 0x32, - 0x87, 0x57, 0xAD, 0x4B, 0xFE, 0x0A, 0x5E, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x61, - 0x91, 0x74, 0xF1, 0xF8, 0xC8, 0x74, 0xFB, 0xA1, 0x63, 0x22, 0xFD, 0x66, 0x9A, 0x33, 0xF7, 0xCF, - 0x34, 0x67, 0x9F, 0x9C, 0x8C, 0x90, 0xD4, 0x01, 0x22, 0x43, 0x22, 0xCB, 0x44, 0x54, 0xA4, 0xDD, - 0xCE, 0xD9, 0xC6, 0x1B, 0xBE, 0xBE, 0xED, 0x5B, 0x90, 0xD2, 0xC4, 0x87, 0x1B, 0x6F, 0xC2, 0x02, - 0x00, 0x00, 0x48, 0xCE, 0xB8, 0x57, 0xF0, 0xCA, 0xD8, 0x88, 0x4F, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, - 0x48, 0x3A, 0x11, 0x16, 0x49, 0xE6, 0x6E, 0x3F, 0xEC, 0x8F, 0x7E, 0x7C, 0xC4, 0x6E, 0x3F, 0xEA, - 0x9F, 0xFD, 0x68, 0x70, 0xFB, 0x71, 0x5F, 0xFB, 0xDF, 0x7A, 0x55, 0xD9, 0xCC, 0xEA, 0xDE, 0x0D, - 0x6E, 0x41, 0xCE, 0x35, 0xBA, 0x05, 0x51, 0xE1, 0xE1, 0x26, 0x43, 0x22, 0xCB, 0x44, 0x4C, 0x64, - 0xDA, 0x7B, 0x8D, 0x39, 0x70, 0xB5, 0x7B, 0x2D, 0xEF, 0x60, 0xF0, 0x8F, 0x50, 0x6A, 0xA5, 0x8A, - 0x0F, 0xB7, 0xE7, 0xAF, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x49, 0x79, 0x07, 0xAF, 0x4B, 0xF0, - 0x06, 0x2C, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x51, 0x91, 0x66, 0xE1, 0xCD, 0x47, - 0x83, 0xDB, 0x8F, 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0x78, 0x30, 0xAF, 0x6F, 0xBD, 0x9A, 0x8C, 0x0F, - 0xB7, 0x4C, 0xB7, 0x20, 0x32, 0x24, 0xB2, 0x4C, 0x85, 0x44, 0x96, 0xD9, 0xF8, 0x70, 0xDB, 0xFE, - 0x71, 0xF7, 0x6D, 0x58, 0xC6, 0x8C, 0x5C, 0x9B, 0xFA, 0x13, 0xC0, 0x4B, 0x17, 0x1F, 0xC1, 0xBC, - 0x13, 0x77, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x24, 0xBC, 0x7D, 0x57, 0x8E, 0xE9, 0xE8, 0x08, - 0x27, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, 0x8A, 0xA4, 0xF3, 0x6F, 0x3F, 0x82, 0xF8, - 0x88, 0xDD, 0x7E, 0xA8, 0x67, 0x3F, 0xEA, 0x3F, 0x74, 0xD0, 0xC6, 0x47, 0x2E, 0xB7, 0x1F, 0xB5, - 0xF1, 0x11, 0xEE, 0xDD, 0x47, 0x5A, 0x3C, 0x0B, 0xD2, 0x0B, 0xF1, 0xF1, 0x74, 0xB0, 0xFD, 0xE9, - 0x6F, 0x41, 0xCA, 0x1A, 0x1F, 0x6E, 0xDE, 0xB1, 0x5B, 0xA6, 0xE4, 0x83, 0x1A, 0x01, 0x00, 0x00, - 0x7A, 0x9E, 0xD9, 0x7B, 0x99, 0x8D, 0x06, 0x15, 0x1E, 0x6E, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, - 0xD2, 0xC5, 0x82, 0x22, 0xED, 0xC2, 0xF0, 0x68, 0x70, 0xFB, 0x51, 0xF7, 0xEC, 0x47, 0x10, 0x20, - 0x95, 0xDB, 0x0F, 0x1B, 0x1F, 0xB9, 0xDC, 0x7E, 0xE8, 0xF8, 0x70, 0x3B, 0x7D, 0xEF, 0x4C, 0x73, - 0xAE, 0xD1, 0x2D, 0x88, 0x1F, 0x1D, 0x3D, 0x12, 0x1F, 0xF6, 0xFF, 0xF6, 0xB6, 0x7F, 0xDC, 0x05, - 0x48, 0xE2, 0x5B, 0x90, 0x32, 0xC7, 0x87, 0xBF, 0x23, 0x37, 0x99, 0xE0, 0xB7, 0x0A, 0x00, 0x00, - 0x80, 0x46, 0xCC, 0xE1, 0xFE, 0x25, 0x66, 0x68, 0xBE, 0x0D, 0x87, 0x72, 0xC4, 0x47, 0xCB, 0xDB, - 0x0F, 0x11, 0x1F, 0x95, 0xDB, 0x0F, 0x1B, 0x1E, 0xB9, 0xDC, 0x7E, 0xE8, 0xF0, 0x88, 0x2E, 0xBC, - 0x05, 0x69, 0xF8, 0x2C, 0x88, 0x0C, 0x89, 0x2C, 0x53, 0x21, 0x91, 0x65, 0x22, 0x3E, 0xEC, 0x8F, - 0xFE, 0xF6, 0x7C, 0xC6, 0x9C, 0x3F, 0x70, 0xFD, 0x50, 0xF0, 0x8F, 0x53, 0x43, 0xA5, 0x8F, 0x0F, - 0x37, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x9A, 0xFF, 0x0A, 0x5E, 0xF9, 0x06, 0x2C, 0x11, 0x17, - 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x50, 0xA4, 0x9A, 0x8D, 0x8F, 0x30, 0x3C, 0xC2, 0xF8, 0x48, - 0x7A, 0xFB, 0xF1, 0x63, 0x1B, 0x1E, 0x2E, 0x40, 0x7E, 0xD8, 0xEE, 0xED, 0x87, 0x0E, 0x8E, 0xF8, - 0xDC, 0x2D, 0x48, 0xE3, 0x67, 0x41, 0x54, 0x48, 0x64, 0x99, 0x0A, 0x89, 0x2C, 0x6B, 0x12, 0x1F, - 0x4F, 0xBD, 0xD7, 0x9C, 0xDF, 0xF2, 0x21, 0x73, 0x7E, 0xFF, 0x32, 0x73, 0x76, 0xFF, 0xD2, 0x86, - 0x07, 0xEF, 0x69, 0x11, 0x1F, 0x6E, 0x2F, 0x5E, 0xE7, 0x02, 0x64, 0x5D, 0xF0, 0xDB, 0x06, 0x00, - 0x00, 0x80, 0xE2, 0xBF, 0x01, 0x6B, 0xEB, 0x87, 0x6C, 0x40, 0xF4, 0x7E, 0x7C, 0x64, 0xB9, 0xFD, - 0xA8, 0xC6, 0x87, 0xBB, 0xFD, 0xF8, 0x56, 0x3B, 0xB7, 0x1F, 0x3A, 0x36, 0x1A, 0x6D, 0xE2, 0x21, - 0x75, 0x0B, 0x32, 0xC3, 0x9F, 0x0E, 0x8A, 0x34, 0x53, 0x21, 0x91, 0x65, 0x2D, 0xE2, 0xC3, 0x6D, - 0xE3, 0x05, 0xE6, 0xFC, 0xEE, 0x25, 0xE6, 0xDC, 0xDE, 0x65, 0xF2, 0x01, 0xEC, 0x69, 0x13, 0x1F, - 0x6E, 0xCF, 0x5F, 0x69, 0xCC, 0x89, 0x3B, 0x73, 0xFF, 0x94, 0x78, 0x00, 0x00, 0x80, 0x52, 0xF1, - 0x0E, 0xAD, 0x1C, 0xEC, 0xF9, 0xF8, 0xC8, 0x78, 0xFB, 0x71, 0xEA, 0x51, 0x1B, 0x1D, 0xB9, 0xDC, - 0x7E, 0xE8, 0xC8, 0x68, 0xB6, 0xD3, 0xF7, 0xC4, 0x6F, 0x41, 0x2A, 0xF1, 0xD1, 0x7E, 0x80, 0xA8, - 0x90, 0xC8, 0xB2, 0x64, 0xF1, 0x71, 0xEE, 0x49, 0xBB, 0x4D, 0x1F, 0x76, 0x01, 0x62, 0xCE, 0x0E, - 0xD5, 0xDE, 0x82, 0x4C, 0xAB, 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x6F, 0xC2, 0x02, 0x00, 0x00, - 0x68, 0xC6, 0xDB, 0x77, 0x45, 0xE4, 0x15, 0xBC, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xA9, - 0xA0, 0x48, 0xB3, 0x20, 0x3E, 0x82, 0xA5, 0xBB, 0xFD, 0x88, 0xC4, 0x47, 0x5B, 0xB7, 0x1F, 0x3A, - 0x30, 0x92, 0x6C, 0xE2, 0x81, 0xE8, 0x2D, 0x88, 0x8D, 0x8F, 0xB6, 0x23, 0x44, 0x85, 0x44, 0x96, - 0x25, 0x8F, 0x8F, 0xB3, 0x83, 0x76, 0x4F, 0x5C, 0x60, 0xDE, 0xDD, 0xB1, 0xC4, 0x4C, 0xEC, 0x5E, - 0x5E, 0x3D, 0x7C, 0x4F, 0xC7, 0xF8, 0x70, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x2D, 0x98, 0x7D, - 0xF6, 0x70, 0xD7, 0xEB, 0xF1, 0x91, 0xE6, 0xF6, 0x23, 0x8C, 0x8F, 0x5C, 0x6E, 0x3F, 0x74, 0x58, - 0x24, 0x5D, 0xE5, 0x16, 0x64, 0xA6, 0x8D, 0x10, 0x1B, 0x20, 0x4F, 0xB5, 0x1B, 0x20, 0x2A, 0x24, - 0xB2, 0x2C, 0x43, 0x7C, 0x3C, 0x7E, 0x81, 0x39, 0x33, 0xF8, 0x41, 0x17, 0x20, 0xE6, 0xF4, 0x8E, - 0xA5, 0x03, 0xD3, 0x35, 0x3E, 0xFC, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x00, 0x34, 0x62, - 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x0B, 0x75, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, - 0x66, 0x91, 0xF8, 0x08, 0xA6, 0x6E, 0x3F, 0xAA, 0x01, 0x52, 0x73, 0xFB, 0x31, 0xAB, 0xFE, 0xF6, - 0xE3, 0x9B, 0x2A, 0x2E, 0x5A, 0x4D, 0x47, 0x45, 0x9A, 0xBD, 0xF3, 0xD7, 0x33, 0xCC, 0x99, 0x1F, - 0x4E, 0x06, 0x48, 0xF6, 0x5B, 0x10, 0x15, 0x12, 0x59, 0x96, 0x31, 0x3E, 0x1E, 0x9D, 0x61, 0x4E, - 0xFF, 0xD8, 0xEE, 0x99, 0x45, 0x66, 0xE2, 0xC0, 0xAA, 0x93, 0xD3, 0x36, 0x3E, 0xDC, 0x8E, 0xAC, - 0x32, 0xE6, 0xF8, 0x1D, 0x4B, 0x82, 0x2F, 0x31, 0x00, 0x00, 0x00, 0x44, 0x99, 0x91, 0xFE, 0x01, - 0xB3, 0xF3, 0x12, 0x1D, 0x18, 0xCD, 0x26, 0xA3, 0x22, 0xE9, 0x54, 0x50, 0xA4, 0x59, 0x2C, 0x3E, - 0x12, 0xDC, 0x7E, 0x4C, 0xB8, 0x00, 0x79, 0xDC, 0xDD, 0x7E, 0xC4, 0xE2, 0xC3, 0xED, 0x7B, 0x59, - 0xBE, 0xF5, 0x4A, 0x07, 0x45, 0x9A, 0xB9, 0xF8, 0xF0, 0x77, 0xF7, 0x0C, 0x7B, 0x90, 0x6F, 0xE7, - 0x16, 0x44, 0x85, 0x44, 0x96, 0xB5, 0x17, 0x1F, 0xA7, 0x1E, 0x76, 0x01, 0x32, 0xDB, 0x98, 0x63, - 0x77, 0x9A, 0x69, 0x1B, 0x1F, 0x3F, 0xBF, 0xCC, 0x98, 0x17, 0x3F, 0x67, 0xCC, 0x89, 0x2F, 0xAD, - 0x0D, 0xBE, 0xC4, 0x00, 0x00, 0x00, 0x10, 0xE5, 0x1D, 0x5A, 0x75, 0x97, 0xD9, 0x7E, 0xB1, 0x8E, - 0x8C, 0x46, 0x93, 0x51, 0x91, 0x74, 0x2A, 0x28, 0xD2, 0x2C, 0x16, 0x1F, 0x2A, 0x40, 0x1A, 0x3E, - 0xFB, 0x61, 0xE3, 0x23, 0x97, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0x56, 0x8D, 0x8F, 0x60, 0x67, 0xBE, - 0x5F, 0x09, 0x90, 0x73, 0xD1, 0x5B, 0x90, 0x20, 0x44, 0x74, 0x74, 0x84, 0x53, 0x21, 0x91, 0x65, - 0x39, 0xC4, 0xC7, 0xD3, 0x1F, 0x33, 0xDE, 0xD1, 0xDB, 0xA7, 0x77, 0x7C, 0xB8, 0x3D, 0xFF, 0x59, - 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x88, 0x19, 0x59, 0xB9, 0x5E, 0x46, 0x46, 0xA3, 0xC9, 0xA8, - 0x48, 0x3A, 0x15, 0x14, 0x69, 0x56, 0x1F, 0x1E, 0xD5, 0xF8, 0xB0, 0xE1, 0x31, 0x79, 0xFB, 0x11, - 0xF9, 0xD6, 0xAB, 0xEA, 0xED, 0xC7, 0x45, 0x95, 0xDB, 0x0F, 0xBB, 0xF6, 0x6E, 0x3F, 0x74, 0x50, - 0xA4, 0x59, 0x3C, 0x3E, 0xFC, 0x65, 0xBA, 0x05, 0x51, 0x21, 0x91, 0x65, 0xC4, 0x47, 0xFB, 0x0B, - 0xE2, 0x23, 0x98, 0xF7, 0x8B, 0x3B, 0x5B, 0x7E, 0x30, 0x23, 0x00, 0x00, 0xC0, 0xB4, 0xE4, 0x1D, - 0xB8, 0x7A, 0x54, 0x86, 0x86, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, 0x66, 0xB1, 0xF8, 0x88, - 0x07, 0x88, 0x5D, 0xF5, 0x5B, 0xAF, 0xC2, 0x00, 0xA9, 0x3E, 0x78, 0x6E, 0xE3, 0xC3, 0x06, 0x48, - 0xFB, 0xB7, 0x1F, 0x3A, 0x28, 0xD2, 0x4C, 0xC6, 0x47, 0xB0, 0xF0, 0x16, 0xC4, 0xBD, 0x92, 0xB7, - 0xF5, 0x2D, 0x88, 0x0A, 0x89, 0x2C, 0x23, 0x3E, 0xDA, 0x5F, 0x6D, 0x7C, 0xF8, 0x01, 0x72, 0xF4, - 0xD6, 0xB1, 0xE0, 0x4B, 0x0C, 0x00, 0x00, 0x00, 0x51, 0xDE, 0xFE, 0x2B, 0x4F, 0xCA, 0xD8, 0x88, - 0x4F, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x78, 0x88, 0xF8, 0x08, 0x6F, 0x3F, 0x6A, - 0x1E, 0x3C, 0xF7, 0x6F, 0x3F, 0x2E, 0x9A, 0xBC, 0xFD, 0x08, 0xE3, 0x23, 0x0C, 0x90, 0xFB, 0xD3, - 0xDC, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x1D, 0x35, 0x73, 0xB7, 0x20, 0x8F, 0x4D, 0xDE, 0x82, - 0xF8, 0x11, 0x62, 0x63, 0xA3, 0x3E, 0x40, 0x54, 0x48, 0x64, 0x19, 0xF1, 0xD1, 0xFE, 0xEA, 0xE3, - 0xC3, 0xDF, 0xB1, 0x2F, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x00, 0x25, 0xD1, 0x1B, 0xB0, 0x64, 0x54, - 0x24, 0x9D, 0x0A, 0x8A, 0x34, 0x8B, 0x85, 0x47, 0x93, 0xF8, 0xA8, 0x3E, 0x78, 0x5E, 0xBD, 0xFD, - 0xB0, 0xF1, 0x11, 0xDE, 0x7E, 0xC4, 0xE3, 0xE3, 0x21, 0xBB, 0xBB, 0x55, 0x68, 0xA8, 0xE9, 0xA0, - 0x48, 0x33, 0x19, 0x1C, 0x62, 0xA7, 0xBF, 0x3B, 0x23, 0x78, 0x16, 0xA4, 0xC1, 0xB7, 0x62, 0x3D, - 0xAD, 0x42, 0x22, 0xCB, 0x88, 0x8F, 0xF6, 0x27, 0xC2, 0x23, 0x1C, 0x6F, 0xC2, 0x02, 0x00, 0x00, - 0xA8, 0xE7, 0xBF, 0x01, 0x6B, 0xD7, 0x1C, 0x1D, 0x1D, 0xE1, 0x64, 0x54, 0x24, 0x9D, 0x0A, 0x8A, - 0x34, 0x8B, 0x85, 0x47, 0x38, 0x15, 0x20, 0xF1, 0xD7, 0xEE, 0x3E, 0x39, 0x19, 0x1F, 0xF2, 0xCD, - 0x57, 0x89, 0x6F, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0A, 0x8D, 0x66, 0x7B, 0x37, 0x7E, 0x0B, 0x12, - 0x46, 0x88, 0x8B, 0x8F, 0x70, 0x32, 0x2A, 0x92, 0x8E, 0xF8, 0x68, 0x7F, 0x22, 0x3A, 0xA2, 0x7B, - 0xF1, 0x7A, 0x63, 0x5E, 0xBE, 0xB3, 0xE6, 0x53, 0xE1, 0x01, 0x00, 0x00, 0xA6, 0x3D, 0x73, 0xA8, - 0x7F, 0xAD, 0xD9, 0xF1, 0x49, 0x1D, 0x1E, 0x6E, 0x32, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, 0xC5, - 0xA2, 0x23, 0xBA, 0x78, 0x7C, 0x44, 0x6F, 0x3F, 0x82, 0xF8, 0x98, 0xBC, 0xFD, 0x10, 0xDF, 0x7A, - 0x95, 0xF8, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xA9, 0xC0, 0x68, 0x35, 0x77, 0x0B, 0x52, 0xF7, 0xE1, - 0x84, 0x36, 0x3A, 0xF2, 0x09, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xE0, 0x88, 0xEF, 0x85, 0xAB, 0x79, - 0x13, 0x16, 0x00, 0x00, 0x40, 0x9C, 0xFF, 0x06, 0xAC, 0xAD, 0x1F, 0xEC, 0xB9, 0xF8, 0x68, 0x74, - 0xFB, 0xE1, 0xE2, 0xE3, 0x6C, 0x2C, 0x3E, 0xB2, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x17, - 0x49, 0xF7, 0xEE, 0x8F, 0x2B, 0x01, 0xE2, 0xBF, 0x96, 0xF7, 0x29, 0x1B, 0x1F, 0x6E, 0xD1, 0x08, - 0x91, 0x71, 0xD1, 0x6A, 0xC4, 0x47, 0xFB, 0x13, 0xB1, 0xD1, 0x60, 0xDE, 0x89, 0x2F, 0x0D, 0x06, - 0x5F, 0x6A, 0x00, 0x00, 0x00, 0x70, 0xBC, 0xE1, 0xE5, 0x43, 0x3D, 0x15, 0x1F, 0x6E, 0xF1, 0xF8, - 0x88, 0xDE, 0x7E, 0xB8, 0xF8, 0x68, 0x75, 0xFB, 0xF1, 0xA0, 0x9D, 0x0C, 0x8E, 0xE8, 0x74, 0x50, - 0xA4, 0x99, 0x8A, 0x8A, 0x34, 0x3B, 0xFD, 0xED, 0xE0, 0x16, 0xE4, 0x49, 0x1B, 0x20, 0x36, 0x0A, - 0xEA, 0x02, 0x24, 0x75, 0x84, 0x10, 0x1F, 0xED, 0x4F, 0x87, 0x46, 0xA3, 0x79, 0x47, 0x6F, 0x1D, - 0x0D, 0xBE, 0xD4, 0x00, 0x00, 0x00, 0xE0, 0x78, 0x7B, 0xAF, 0xA8, 0x7F, 0x05, 0xAF, 0x8C, 0x8A, - 0xA4, 0x53, 0x41, 0x91, 0x66, 0x22, 0x38, 0xA2, 0xB3, 0xD1, 0xE1, 0x7E, 0xAC, 0xBB, 0xFD, 0xB0, - 0xF1, 0x71, 0x6E, 0xE3, 0x45, 0xC9, 0x6E, 0x3F, 0xEE, 0x6B, 0x75, 0xFB, 0xA1, 0x83, 0x22, 0xCD, - 0x54, 0x50, 0x64, 0xD9, 0xBB, 0xF6, 0xD0, 0x1F, 0x06, 0x48, 0x7B, 0xB7, 0x20, 0xC4, 0x47, 0xFB, - 0xD3, 0x91, 0xD1, 0x74, 0xC7, 0x6E, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x51, 0x66, 0xEF, 0xE2, - 0xDE, 0x89, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x08, 0x03, 0x24, 0x88, 0x8F, 0x78, 0x80, 0xD4, - 0xC5, 0x47, 0xCB, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0xA6, 0x42, 0x22, 0xDB, 0x2E, 0x30, 0xA7, 0xBF, - 0x6D, 0xA3, 0x60, 0x70, 0x32, 0x42, 0x6A, 0x02, 0xC4, 0x85, 0x45, 0xA2, 0x08, 0x21, 0x3E, 0xDA, - 0x9F, 0x88, 0x8B, 0x24, 0x73, 0x6F, 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x1B, 0x00, 0x00, - 0xC0, 0xF4, 0x66, 0x46, 0xFA, 0x67, 0xD7, 0xBC, 0x82, 0x57, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, - 0x33, 0x11, 0x1B, 0xF1, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, 0xDF, 0x7E, 0xD8, 0xF0, 0x10, 0xB7, 0x1F, - 0xF2, 0x43, 0x07, 0x9B, 0xDE, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x76, 0x41, 0x75, - 0xE1, 0x2D, 0xC8, 0xB9, 0x4C, 0xB7, 0x20, 0xC4, 0x47, 0xFB, 0x13, 0x61, 0x91, 0x74, 0x63, 0xCB, - 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xC8, 0x7F, 0x05, 0x6F, 0xF8, 0x06, 0x2C, 0x19, 0x15, 0x49, - 0xA7, 0x82, 0x22, 0xCD, 0x62, 0xA1, 0xD1, 0x68, 0x61, 0x78, 0x84, 0xF1, 0xE1, 0xF6, 0xD4, 0x85, - 0x35, 0xDF, 0x7A, 0x15, 0x0F, 0x90, 0x53, 0x2E, 0x40, 0xC2, 0xDB, 0x8F, 0x1F, 0xD9, 0xC9, 0xF0, - 0x70, 0xD3, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x6C, 0x32, 0x3E, 0xDC, 0x4E, 0x7D, 0xD3, 0xC5, - 0x41, 0x96, 0x5B, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xA8, 0x48, 0xB3, 0x17, 0x3F, 0xC7, 0x9B, 0xB0, - 0x00, 0x00, 0x00, 0x42, 0xFE, 0x1B, 0xB0, 0xB6, 0x7D, 0xC4, 0x1E, 0xEE, 0x55, 0x54, 0x24, 0x9D, - 0x0A, 0x8A, 0x34, 0x13, 0xA1, 0xA1, 0x66, 0xA3, 0xC3, 0xFD, 0x58, 0x7B, 0xFB, 0x61, 0xE3, 0x23, - 0xCD, 0xED, 0xC7, 0xB7, 0x1A, 0xDD, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x56, 0x1B, - 0x1F, 0xE1, 0x26, 0x7E, 0x94, 0xF6, 0x16, 0x84, 0xF8, 0x68, 0x7F, 0x22, 0x28, 0x32, 0x8C, 0x37, - 0x61, 0x01, 0x00, 0x00, 0x04, 0xBC, 0x91, 0x81, 0x0D, 0x3A, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, - 0xC5, 0x22, 0xA3, 0xD9, 0xC2, 0xF0, 0x88, 0xC4, 0x47, 0xA2, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x68, - 0xD7, 0xA3, 0xF1, 0xE1, 0xD6, 0xF2, 0x16, 0x84, 0xF8, 0xC8, 0x79, 0x3A, 0x26, 0xB2, 0xCC, 0x3B, - 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0x38, 0xDE, 0x81, 0xAB, 0x47, 0x75, 0x58, 0x24, 0x99, - 0x0A, 0x8A, 0x34, 0x13, 0x91, 0xD1, 0x62, 0xD5, 0x00, 0x09, 0xE3, 0xA3, 0xED, 0xDB, 0x0F, 0x1D, - 0x14, 0x69, 0xA6, 0x43, 0x22, 0xCB, 0x74, 0x78, 0x44, 0x17, 0xDE, 0x82, 0xB8, 0x78, 0x68, 0x7C, - 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x12, 0x59, 0xE7, 0x1D, 0xBB, 0x65, 0x3C, 0xF8, 0x92, 0x03, - 0x00, 0x00, 0x98, 0xDE, 0xBC, 0x7D, 0x57, 0x8C, 0xEB, 0xB8, 0x68, 0x35, 0x15, 0x14, 0x69, 0xA6, - 0x03, 0xA3, 0xE1, 0x6A, 0x6E, 0x3F, 0x6C, 0x7C, 0x34, 0xBB, 0xFD, 0x08, 0xE3, 0xA3, 0xE5, 0xED, - 0x87, 0x0E, 0x8A, 0x34, 0xD3, 0x21, 0x91, 0x65, 0x3A, 0x38, 0xE2, 0xF3, 0x6F, 0x41, 0x1E, 0x6F, - 0x76, 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x11, 0x6D, 0xCD, 0xBD, 0x09, 0x6B, 0xEC, 0x8B, 0xB3, - 0x82, 0x2F, 0x3B, 0x00, 0x00, 0x80, 0xE9, 0xCB, 0x0C, 0x2D, 0xB0, 0x07, 0x7C, 0x15, 0x18, 0xCD, - 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x60, 0x24, 0x58, 0x18, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xB9, 0x1F, - 0xC9, 0x6E, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0E, 0x89, 0x2C, 0xD3, 0xB1, 0xD1, 0x68, 0x67, 0xBE, - 0x2F, 0x9E, 0x05, 0xF1, 0x43, 0x24, 0x12, 0x1E, 0x6E, 0xC4, 0x47, 0x86, 0x89, 0x78, 0xC8, 0x63, - 0x63, 0xCB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x80, 0xFF, 0x06, 0xAC, 0x9D, 0xB3, 0xED, 0xE1, 0x5E, - 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0x33, 0x1D, 0x17, 0x4D, 0x17, 0xB9, 0xF9, 0xF0, 0xE3, 0x43, - 0xDC, 0x7E, 0x4C, 0xB8, 0x3D, 0x1E, 0xB9, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xE5, 0x89, 0x0F, - 0x7F, 0x77, 0xAB, 0x5B, 0x90, 0x4A, 0x68, 0x18, 0x1B, 0x19, 0xC4, 0x47, 0xD6, 0x89, 0x70, 0xC8, - 0x65, 0x8B, 0x8D, 0x79, 0xF1, 0x5A, 0xE3, 0xFD, 0xE2, 0x4B, 0x77, 0x05, 0x5F, 0x7A, 0x00, 0x00, - 0x00, 0xD3, 0x93, 0x0D, 0x90, 0x75, 0x66, 0xC7, 0x27, 0xEC, 0x21, 0x5F, 0x85, 0x86, 0x9A, 0x0A, - 0x8A, 0x34, 0x13, 0x71, 0x91, 0x64, 0x61, 0x7C, 0xC4, 0x6E, 0x3F, 0x12, 0x3F, 0xFB, 0xF1, 0xCD, - 0x12, 0xC5, 0x47, 0xB0, 0x33, 0xDF, 0x8B, 0x3E, 0x0B, 0x52, 0x89, 0x8C, 0x70, 0x2E, 0x40, 0xC2, - 0xF0, 0x20, 0x3E, 0x92, 0x4E, 0x85, 0x43, 0x1E, 0xB3, 0xF1, 0xE1, 0x66, 0x7F, 0xED, 0xDE, 0x89, - 0x3B, 0x36, 0x04, 0x5F, 0x7A, 0x00, 0x00, 0x00, 0xD3, 0x93, 0xFF, 0x0A, 0x5E, 0x19, 0x1A, 0x6A, - 0x2A, 0x28, 0xD2, 0x4C, 0x84, 0x45, 0xAB, 0xD9, 0xF0, 0xA8, 0xC6, 0x87, 0x0D, 0x8F, 0xC9, 0xDB, - 0x8F, 0xD8, 0xB7, 0x5E, 0x45, 0x6F, 0x3F, 0xEC, 0x1A, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, - 0x12, 0x59, 0xA6, 0xC3, 0x22, 0xF1, 0xAA, 0xB7, 0x20, 0x36, 0x40, 0x36, 0xBA, 0xC0, 0x08, 0x82, - 0x23, 0x12, 0x1E, 0xC4, 0x47, 0xD2, 0xA9, 0x70, 0xC8, 0x63, 0x41, 0x7C, 0x04, 0xF3, 0x4E, 0xFC, - 0x39, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x9B, 0x77, 0xF0, 0xBA, 0x84, 0x6F, 0xC0, 0x52, 0x41, - 0x91, 0x66, 0xB1, 0xB0, 0x48, 0x3A, 0x17, 0x20, 0xE1, 0xCD, 0x87, 0x5D, 0xF5, 0x5B, 0xAF, 0xE4, - 0xB3, 0x1F, 0x17, 0xB5, 0xB8, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x04, 0x45, - 0x86, 0x9D, 0xFE, 0xCE, 0x7B, 0xFD, 0xB0, 0x08, 0x23, 0xA4, 0x1A, 0x1C, 0x2E, 0x3E, 0x82, 0x28, - 0x21, 0x3E, 0x5A, 0x4D, 0x85, 0x43, 0x1E, 0xAB, 0x8D, 0x0F, 0x3F, 0x40, 0x8E, 0x7D, 0x81, 0x37, - 0x61, 0x01, 0x00, 0x80, 0xE9, 0xCD, 0xDB, 0xFB, 0xD9, 0x31, 0x1D, 0x1C, 0xD1, 0xA9, 0xA0, 0x48, - 0xB3, 0x58, 0x54, 0x24, 0x5D, 0x2C, 0x3E, 0xC2, 0xDB, 0x8F, 0xBA, 0xF8, 0x88, 0xDE, 0x7E, 0x84, - 0xF1, 0x11, 0x06, 0xC8, 0x86, 0xF0, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xE9, 0x90, 0xC8, 0x32, 0x1D, - 0x13, 0xA9, 0xF7, 0x57, 0xEF, 0xF5, 0xF7, 0xEE, 0xA3, 0x93, 0x01, 0x12, 0x9F, 0x1F, 0x27, 0x2E, - 0x3C, 0x88, 0x8F, 0x06, 0x53, 0xE1, 0x90, 0xC7, 0xEA, 0xE3, 0xC3, 0xDF, 0x91, 0x1B, 0x4C, 0xF0, - 0xA5, 0x07, 0x00, 0x00, 0x30, 0x3D, 0x99, 0x3D, 0xF6, 0x50, 0x24, 0xA3, 0x23, 0x9C, 0x0A, 0x8A, - 0x34, 0x8B, 0x45, 0x45, 0xD2, 0x35, 0x88, 0x8F, 0xEA, 0x83, 0xE7, 0xEA, 0xF6, 0x23, 0x1E, 0x1F, - 0x0F, 0xD9, 0xDD, 0x5D, 0xEE, 0xF8, 0x70, 0x73, 0xB7, 0x20, 0x7E, 0x60, 0xD8, 0x9D, 0x7B, 0xD2, - 0x86, 0x87, 0xDD, 0xB9, 0x68, 0x7C, 0xD8, 0xF0, 0x38, 0x6B, 0xC3, 0x83, 0xF8, 0x88, 0x4F, 0x85, - 0x43, 0x1E, 0x8B, 0x45, 0x47, 0x74, 0x2F, 0xAD, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xFA, 0x32, - 0x87, 0xFB, 0x97, 0x98, 0xDD, 0xF3, 0xEC, 0x81, 0x5F, 0x85, 0x87, 0x9B, 0x0A, 0x8A, 0x34, 0x8B, - 0x45, 0x45, 0x9A, 0xD9, 0xE8, 0xA8, 0x0B, 0x90, 0x26, 0xDF, 0x7A, 0x25, 0xDF, 0x7C, 0x75, 0xBF, - 0xBB, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x45, 0xE2, 0x23, - 0x9C, 0xBB, 0x05, 0xF1, 0x43, 0x63, 0xD0, 0xC6, 0x88, 0x0D, 0x90, 0xB3, 0xB1, 0x6F, 0xB9, 0x7A, - 0xF7, 0x31, 0xE2, 0xA3, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x88, 0x8E, 0xE8, 0x5E, 0xBC, 0xD6, 0x06, - 0xC8, 0x1D, 0xEB, 0x82, 0x2F, 0x41, 0x00, 0x00, 0x80, 0xE9, 0xC5, 0x7F, 0x05, 0x6F, 0xC3, 0x37, - 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x15, 0x49, 0xF7, 0x8C, 0x88, 0x8F, 0xE8, 0xED, 0x87, 0x8B, - 0x8F, 0x9A, 0x00, 0x11, 0xDF, 0x7A, 0xE5, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, - 0x26, 0x42, 0x22, 0xCB, 0x44, 0x7C, 0xBC, 0xBD, 0xFE, 0xBD, 0xE6, 0xD4, 0x3D, 0x36, 0x42, 0x5C, - 0x68, 0xB8, 0xE0, 0x70, 0x21, 0x12, 0xFC, 0xE8, 0xFE, 0xB5, 0x09, 0x17, 0x1F, 0x36, 0x3C, 0x4E, - 0x3F, 0x42, 0x7C, 0x54, 0xA6, 0xC2, 0x21, 0x8F, 0x89, 0xE0, 0x88, 0xCF, 0xFD, 0xBE, 0x4E, 0xDC, - 0xB1, 0x3E, 0xF8, 0x12, 0x04, 0x00, 0x00, 0x98, 0x5E, 0xFC, 0x37, 0x60, 0x6D, 0xF9, 0x80, 0x3D, - 0xF4, 0x77, 0x5F, 0x7C, 0x34, 0xBA, 0xFD, 0x50, 0xAF, 0xDD, 0xD5, 0xB7, 0x1F, 0xED, 0x7F, 0xEB, - 0x95, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0x0D, 0xE2, 0x23, 0xDC, 0x99, 0x07, 0x6D, 0x6C, - 0x3C, 0x3E, 0xA3, 0x12, 0x22, 0x41, 0x78, 0x4C, 0x3C, 0x7A, 0x81, 0x7F, 0xEB, 0x41, 0x7C, 0x84, - 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x6C, 0x34, 0x98, 0x77, 0xE2, 0x0E, 0xDE, 0x84, 0x05, 0x00, 0x00, - 0xA6, 0x27, 0xEF, 0xD0, 0xCA, 0xC1, 0xAE, 0x8B, 0x8F, 0x5C, 0x6E, 0x3F, 0x2E, 0x6A, 0xFB, 0xF6, - 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0xD6, 0xD7, 0xEC, 0xBF, 0xF6, - 0x4D, 0x17, 0x1D, 0x33, 0xFC, 0x9D, 0xB1, 0xE1, 0xE1, 0xE6, 0x7F, 0xCB, 0x55, 0x18, 0x1F, 0x4F, - 0x11, 0x1F, 0xC5, 0x4C, 0x87, 0x46, 0xA3, 0x79, 0xC7, 0xBE, 0x70, 0x32, 0xF8, 0x12, 0x04, 0x00, - 0x00, 0x98, 0x5E, 0xBC, 0xBD, 0x57, 0xC4, 0x5E, 0xC1, 0xAB, 0x82, 0x22, 0xCD, 0x44, 0x54, 0x24, - 0x5D, 0x24, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0xA3, 0xFE, 0xD9, 0x0F, 0x75, 0xFB, 0x61, 0xE3, 0xE3, - 0xBE, 0xF6, 0x6E, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x4B, 0x10, 0x1F, 0x6F, 0x7D, - 0xED, 0x02, 0xF3, 0xD6, 0x7F, 0xB9, 0xC0, 0x9C, 0xFA, 0xA1, 0x0D, 0x0D, 0x77, 0xE3, 0xF1, 0x63, - 0x1B, 0x1F, 0x41, 0x78, 0xBC, 0xF3, 0x90, 0xFD, 0x91, 0xF8, 0x28, 0x68, 0x3A, 0x32, 0x9A, 0xEE, - 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x4C, 0x4F, 0x66, 0xAF, 0x3D, 0xF0, 0x75, 0x53, 0x7C, - 0x04, 0x01, 0xD2, 0xEC, 0xF6, 0x23, 0x1E, 0x20, 0x75, 0xF1, 0xF1, 0x60, 0x7B, 0x0F, 0x9E, 0xEB, - 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x96, 0x22, 0x3E, 0xDE, 0xFC, 0xCF, 0xF6, 0xC7, 0xBB, 0x6D, - 0x84, 0x04, 0xD1, 0xE1, 0xEF, 0x41, 0xE2, 0x43, 0x87, 0x43, 0x1E, 0x13, 0x71, 0x91, 0x64, 0x47, - 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xFD, 0x98, 0xD1, 0xFE, 0x59, 0x66, 0x68, 0x81, 0x0D, - 0x80, 0xEE, 0x8A, 0x0F, 0xF7, 0xA3, 0xBA, 0xFD, 0x50, 0xCF, 0x7E, 0xD4, 0x7E, 0xE8, 0xA0, 0x0D, - 0x8F, 0x87, 0xDB, 0xBB, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x2C, 0x65, 0x7C, 0xB8, - 0xFD, 0xE1, 0xFF, 0xB1, 0xFF, 0xFF, 0x77, 0x66, 0x98, 0xB7, 0x1F, 0x98, 0x69, 0x67, 0xE3, 0x63, - 0x23, 0xF1, 0x51, 0xCC, 0x44, 0x58, 0x24, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x2F, 0xAD, 0x0D, 0xBE, - 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0xFF, 0x0D, 0x58, 0x3B, 0x67, 0xDB, 0x08, 0x50, 0x41, 0x91, - 0x66, 0x22, 0x2A, 0x92, 0x2E, 0x1A, 0x1F, 0x41, 0x80, 0x34, 0xBB, 0xFD, 0x70, 0xF1, 0x11, 0x0F, - 0x90, 0x6A, 0x7C, 0xB4, 0x79, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, 0x64, 0x59, 0xC6, 0xF8, - 0x78, 0xE3, 0x2F, 0x67, 0x98, 0xF1, 0xFF, 0x3C, 0xC3, 0xBC, 0xF5, 0x23, 0xFB, 0x7B, 0x7A, 0x92, - 0xF8, 0x28, 0x66, 0x22, 0x2A, 0xD2, 0xEC, 0xF9, 0x2B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x7E, - 0xBC, 0x43, 0xAB, 0xEE, 0x32, 0xDB, 0x3E, 0x6A, 0x43, 0x40, 0x45, 0x45, 0xD2, 0x89, 0xA8, 0x48, - 0x3A, 0x11, 0x1F, 0xEE, 0xC7, 0xD4, 0xB7, 0x1F, 0x61, 0x7C, 0xB8, 0xDB, 0x8F, 0x7B, 0xB3, 0xDD, - 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x4E, 0x7C, 0xFC, 0xA7, 0x19, 0xE6, 0xF7, - 0xFF, 0xF7, 0x0C, 0xF3, 0xE6, 0x03, 0xC4, 0x47, 0x31, 0x13, 0x41, 0x91, 0x61, 0xDE, 0x2F, 0xEE, - 0x18, 0x0A, 0xBE, 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0x33, 0xD2, 0xBF, 0x5E, 0x47, 0x45, 0xD2, - 0x89, 0xA8, 0x48, 0xBA, 0x78, 0x7C, 0xB8, 0x85, 0xE1, 0x11, 0xC6, 0x47, 0xAB, 0xDB, 0x0F, 0xFF, - 0x5B, 0xAF, 0x82, 0xF8, 0x70, 0xFB, 0xA1, 0x9D, 0x88, 0x8B, 0x56, 0xD3, 0x21, 0x91, 0x65, 0x22, - 0x24, 0xB2, 0x2C, 0x87, 0xF8, 0x78, 0xE3, 0xDB, 0x36, 0x3E, 0x5E, 0x22, 0x3E, 0xF2, 0x9F, 0x8E, - 0x89, 0x2C, 0xF3, 0x8E, 0xDE, 0x3C, 0x16, 0x7C, 0x29, 0x02, 0x00, 0x00, 0x4C, 0x0F, 0xDE, 0x81, - 0xAB, 0x46, 0x75, 0x58, 0x24, 0x99, 0x88, 0x8A, 0xA4, 0x6B, 0x10, 0x1F, 0xEE, 0xC7, 0x54, 0xB7, - 0x1F, 0xD1, 0xF8, 0x70, 0xB7, 0x1F, 0xDF, 0x4A, 0x7F, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, - 0x64, 0x19, 0xF1, 0x91, 0xC3, 0x54, 0x38, 0xE4, 0x31, 0x1D, 0x12, 0x99, 0xC7, 0x9B, 0xB0, 0x00, - 0x00, 0xC0, 0x74, 0xE3, 0xED, 0xFF, 0xEC, 0x49, 0x1D, 0x17, 0xAD, 0x26, 0xA2, 0x22, 0xE9, 0xE2, - 0xE1, 0x11, 0x2E, 0x0C, 0x8F, 0x30, 0x3E, 0x9A, 0xDD, 0x7E, 0x3C, 0x76, 0x91, 0x39, 0xFD, 0xA8, - 0x0D, 0x8E, 0x36, 0x6F, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, - 0x0A, 0x87, 0x3C, 0x26, 0x02, 0xA2, 0xDD, 0xB9, 0x37, 0x61, 0x1D, 0xBF, 0x63, 0x49, 0xF0, 0xE5, - 0x08, 0x00, 0x00, 0x50, 0x7E, 0x66, 0x68, 0xBE, 0x8D, 0x02, 0x15, 0x18, 0xCD, 0x26, 0xA2, 0x22, - 0xE9, 0x54, 0x78, 0x44, 0x96, 0xE8, 0xF6, 0x23, 0x88, 0x8F, 0x76, 0x6F, 0x3F, 0x74, 0x48, 0x64, - 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0x26, 0xE2, 0x21, 0x8F, 0xBD, - 0x78, 0x1D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x87, 0xFF, 0x06, 0xAC, 0x5D, 0x9F, 0xB6, 0x61, - 0xA0, 0x22, 0xA3, 0xD1, 0x44, 0x54, 0x24, 0x9D, 0x08, 0x8E, 0xEA, 0x92, 0xDE, 0x7E, 0x3C, 0x6E, - 0x03, 0x24, 0x8C, 0x8F, 0x68, 0x80, 0xFC, 0x80, 0xF8, 0x20, 0x3E, 0x54, 0x38, 0xE4, 0x31, 0x11, - 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x3E, 0xCC, 0xA1, 0xFE, 0xB5, - 0x66, 0xC7, 0xC7, 0x6D, 0x1C, 0xA8, 0xD0, 0x50, 0x13, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0x62, 0x53, - 0xB7, 0x1F, 0xD1, 0x00, 0xF1, 0xE3, 0xA3, 0xD1, 0xED, 0xC7, 0x37, 0x75, 0x68, 0xA8, 0xE9, 0x90, - 0xC8, 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x44, 0x43, 0xCE, - 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xDA, 0xF0, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0x36, 0x10, 0x54, - 0x6C, 0xC4, 0x27, 0xA2, 0x22, 0xE9, 0x44, 0x6C, 0xD4, 0x2C, 0xC1, 0xED, 0x87, 0xFB, 0xD6, 0xAB, - 0x89, 0xC7, 0x2E, 0x9C, 0xBC, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xC9, 0x6F, 0x3F, 0x74, 0x48, - 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0xA6, 0x83, 0x21, 0xEF, - 0x79, 0x47, 0xFF, 0x64, 0x34, 0xF8, 0x92, 0x04, 0x00, 0x00, 0x28, 0x37, 0x6F, 0x78, 0xE9, 0x90, - 0x8E, 0x8D, 0xF8, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8E, 0xF8, 0xE2, 0x01, 0xA2, 0x9E, 0xFD, 0x78, - 0xDC, 0xC6, 0x47, 0x9B, 0xB7, 0x1F, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x11, 0x1F, 0x39, - 0x4C, 0x85, 0x43, 0x1E, 0xD3, 0xB1, 0x50, 0xC8, 0x8E, 0x7D, 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, - 0xE9, 0xC1, 0xDB, 0xBB, 0x24, 0xC1, 0x2B, 0x78, 0x45, 0x54, 0x24, 0x9D, 0x8A, 0x8D, 0xE8, 0x6C, - 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, 0x47, 0xEC, 0x5B, 0xAF, 0x9E, 0xB8, 0x70, 0xF2, - 0xF6, 0xC3, 0x2E, 0xCB, 0xED, 0x87, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, - 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x24, 0x14, 0xB6, 0x45, 0x95, 0x37, 0x61, 0xBD, 0x7C, 0xE7, 0xEC, - 0xE0, 0xCB, 0x12, 0x00, 0x00, 0xA0, 0xBC, 0xCC, 0x1E, 0x7B, 0xF8, 0x91, 0xD1, 0x11, 0x4E, 0x44, - 0x45, 0xD2, 0xA9, 0xE0, 0x88, 0x2F, 0x1A, 0x20, 0x76, 0xD5, 0x6F, 0xBD, 0x8A, 0x06, 0x88, 0x8B, - 0x0F, 0xFF, 0xF6, 0xE3, 0xC2, 0xFA, 0xDB, 0x8F, 0x87, 0xEC, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, - 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xB3, - 0x5F, 0x7F, 0x6E, 0x2F, 0x7E, 0xCE, 0x05, 0xC8, 0x40, 0xF0, 0x65, 0x09, 0x00, 0x00, 0x50, 0x4E, - 0x66, 0xA4, 0x7F, 0x76, 0xF3, 0x57, 0xF0, 0x8A, 0xA8, 0x48, 0x3A, 0x15, 0x1B, 0xF1, 0xC5, 0xE2, - 0x23, 0xBC, 0xFD, 0xA8, 0x7D, 0xF0, 0xDC, 0xC6, 0x47, 0xF4, 0xF6, 0x23, 0xFE, 0xAD, 0x57, 0xF7, - 0xB7, 0xBE, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, - 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x16, 0xC4, 0x87, 0x1F, 0x20, 0xD7, 0xF0, 0x26, 0x2C, 0x00, 0x00, - 0x50, 0x7E, 0xFE, 0x2B, 0x78, 0x1B, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, 0xA9, 0xD8, 0x88, 0xAF, - 0x41, 0x7C, 0x54, 0x1F, 0x3C, 0x77, 0xB3, 0xF1, 0x51, 0x73, 0xFB, 0x11, 0x7F, 0xF0, 0xDC, 0xDD, - 0x7E, 0xDC, 0xAD, 0xA3, 0x23, 0x9C, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, - 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0xB5, 0x48, 0x7C, 0x04, 0xF3, 0x4E, 0x7C, 0x69, 0x30, - 0xF8, 0xD2, 0x04, 0x00, 0x00, 0x28, 0x27, 0xFF, 0x0D, 0x58, 0x5B, 0x3F, 0x64, 0xA3, 0x61, 0x8A, - 0xE3, 0xC3, 0x4D, 0x05, 0x48, 0xCD, 0xB7, 0x5E, 0xD9, 0xF8, 0x70, 0xB7, 0x1F, 0x41, 0x7C, 0x64, - 0xB9, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, 0xF2, - 0x98, 0x8A, 0x84, 0xA2, 0x56, 0x1F, 0x1F, 0x6E, 0xDE, 0xF1, 0x3F, 0xE5, 0x4D, 0x58, 0x00, 0x00, - 0xA0, 0xDC, 0xBC, 0x91, 0x81, 0x0D, 0x1D, 0x89, 0x0F, 0xB7, 0x78, 0x7C, 0x54, 0x6F, 0x3F, 0x2E, - 0xAC, 0xC6, 0xC7, 0xE4, 0xED, 0x47, 0x2C, 0x3E, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, - 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xF1, 0xE1, - 0xEF, 0xD8, 0x2D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x94, 0x9B, 0x77, 0xE0, 0xAA, 0xD8, 0x1B, 0xB0, - 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x8C, 0x46, 0xB3, 0xD1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0x44, 0x02, - 0x24, 0x8C, 0x0F, 0xF9, 0xB9, 0x1F, 0xDF, 0x69, 0x7C, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, - 0x64, 0x59, 0x34, 0x3A, 0x88, 0x8F, 0x8C, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x11, - 0x1D, 0xD1, 0xB9, 0x37, 0x61, 0x8D, 0x7D, 0x71, 0x56, 0xF0, 0xE5, 0x09, 0x00, 0x00, 0x50, 0x3E, - 0xDE, 0xBE, 0x25, 0xE3, 0x53, 0x1E, 0x1F, 0x6E, 0xF1, 0xF8, 0x48, 0x7B, 0xFB, 0xF1, 0xA0, 0x9D, - 0x08, 0x0F, 0x37, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x52, 0xC4, 0x47, 0x18, 0x20, 0x2E, - 0x3E, 0xFE, 0x40, 0x7C, 0x44, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x38, 0xE2, - 0x1B, 0x5B, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB9, 0x4D, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, - 0xA9, 0xC0, 0x68, 0x36, 0x1B, 0x1D, 0xEE, 0x47, 0x75, 0xFB, 0x11, 0x0D, 0x90, 0xA6, 0xB7, 0x1F, - 0xF7, 0xE9, 0xDB, 0x0F, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x22, 0xF1, 0x11, 0xAE, 0x3E, - 0x3E, 0xEC, 0x5C, 0x78, 0x84, 0xB7, 0x1F, 0xC4, 0x47, 0x6C, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, - 0xA2, 0x26, 0x62, 0x43, 0xED, 0xC5, 0x6B, 0x8C, 0xF7, 0x8B, 0x2F, 0xDD, 0x15, 0x7C, 0x79, 0x02, - 0x00, 0x00, 0x94, 0x8B, 0xFF, 0x06, 0xAC, 0x9D, 0x9F, 0xD2, 0x51, 0x91, 0x74, 0xF1, 0xB8, 0x48, - 0xB2, 0x30, 0x3C, 0xC2, 0xF8, 0xF0, 0x03, 0x64, 0x66, 0x35, 0x3E, 0x6A, 0xDF, 0x7C, 0x95, 0xFC, - 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0x76, 0x24, 0x3E, 0xE2, - 0x37, 0x1F, 0x6F, 0x04, 0xF1, 0xF1, 0x07, 0xE2, 0xA3, 0xA0, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x34, - 0x9A, 0xCC, 0x3B, 0x71, 0xC7, 0x86, 0xE0, 0x4B, 0x14, 0x00, 0x00, 0xA0, 0x5C, 0x6C, 0x80, 0xAC, - 0x33, 0xDB, 0x2F, 0xD6, 0x61, 0x91, 0x64, 0x2A, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0xF6, - 0xF6, 0xC3, 0xC6, 0x47, 0x83, 0x67, 0x3F, 0xEA, 0x3E, 0x74, 0xD0, 0xBD, 0xF9, 0x4A, 0xDC, 0x7E, - 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x22, 0x3E, 0xA2, 0x37, 0x1F, 0x61, 0x7C, 0x84, - 0x37, 0x1F, 0xC4, 0x47, 0x38, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x91, 0xD1, 0x6C, - 0xDE, 0x89, 0x3F, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x9C, 0xFC, 0x57, 0xF0, 0xAA, 0xB0, 0x48, - 0xB2, 0x78, 0x58, 0x24, 0x5D, 0x18, 0x1E, 0x61, 0x7C, 0x3C, 0x3D, 0xB3, 0xE6, 0xF6, 0xA3, 0xEE, - 0xD9, 0x0F, 0x1B, 0x20, 0xA7, 0xA2, 0x01, 0xF2, 0x23, 0xBB, 0x1E, 0x8C, 0x0F, 0xB7, 0xBA, 0x00, - 0x69, 0x10, 0x1F, 0xE3, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0xC0, - 0x68, 0x35, 0xEF, 0xD8, 0x17, 0xC6, 0x83, 0x2F, 0x51, 0x00, 0x00, 0x80, 0x72, 0xF1, 0x0E, 0x5C, - 0x33, 0x2A, 0xE3, 0xA2, 0xD5, 0x54, 0x58, 0x24, 0x99, 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, - 0xF1, 0x11, 0xBD, 0xFD, 0x88, 0xC5, 0x47, 0xDD, 0xED, 0xC7, 0xB7, 0x6A, 0x6F, 0x3F, 0x74, 0x48, - 0x64, 0x99, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x56, 0x17, 0x1F, 0xEA, 0x8D, 0x57, 0xC4, 0x47, - 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x71, 0x91, 0x68, 0x47, 0x56, 0xF3, 0x26, - 0x2C, 0x00, 0x00, 0x50, 0x4E, 0xDE, 0xDE, 0x25, 0x63, 0x32, 0x30, 0x9A, 0x2D, 0x1E, 0x15, 0x69, - 0x16, 0x86, 0x47, 0x18, 0x1F, 0x69, 0x6F, 0x3F, 0x7E, 0x68, 0x57, 0xB6, 0xF8, 0x70, 0x37, 0x1F, - 0x2E, 0x3E, 0xDC, 0x43, 0xE7, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, - 0xA8, 0x48, 0xB3, 0x97, 0x56, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x4E, 0x66, 0xCF, 0x42, 0x1D, - 0x19, 0x8D, 0xA6, 0xA2, 0x22, 0xE5, 0x2A, 0x01, 0x32, 0xB3, 0xED, 0xDB, 0x0F, 0x1D, 0x12, 0x59, - 0x26, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0xB5, 0x8C, 0x8F, 0xBF, 0x9C, 0xFC, 0xAC, 0x8F, 0x3F, - 0xDC, 0x4B, 0x7C, 0x14, 0x33, 0x15, 0x09, 0x45, 0x4D, 0x04, 0x45, 0xDA, 0xBD, 0x78, 0x8D, 0x0D, - 0x90, 0x3B, 0xD6, 0x05, 0x5F, 0xA6, 0x00, 0x00, 0x00, 0xE5, 0x60, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, - 0xE6, 0xE8, 0xD0, 0x50, 0x13, 0x31, 0x91, 0x6A, 0xD5, 0xDB, 0x8F, 0x20, 0x3E, 0x9A, 0xDD, 0x7E, - 0x84, 0xF1, 0xD1, 0xE0, 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, - 0x0D, 0xE3, 0x23, 0x08, 0x90, 0xE8, 0x07, 0x0D, 0x12, 0x1F, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, - 0xA2, 0x26, 0x62, 0x22, 0xCB, 0x9E, 0xB7, 0x7F, 0x3F, 0x4E, 0xDC, 0xB1, 0x3E, 0xF8, 0x52, 0x05, - 0x00, 0x00, 0x28, 0x07, 0xFF, 0x15, 0xBC, 0x49, 0xDF, 0x80, 0xA5, 0x82, 0x22, 0xC3, 0xFC, 0xF8, - 0x88, 0xDD, 0x7E, 0x54, 0x03, 0xA4, 0xD5, 0xED, 0xC7, 0x3D, 0xBD, 0x1B, 0x1F, 0x95, 0xD7, 0xED, - 0x12, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x24, 0xDA, 0x18, 0x6F, - 0xC2, 0x02, 0x00, 0x00, 0xA5, 0xE3, 0xBF, 0x01, 0x6B, 0xEB, 0x07, 0x75, 0x70, 0x44, 0x27, 0x42, - 0x22, 0xF5, 0xC2, 0x9B, 0x8F, 0x26, 0xB7, 0x1F, 0x13, 0x2E, 0x40, 0x1E, 0x8B, 0xDC, 0x7E, 0x84, - 0xF1, 0xE1, 0xF6, 0xBD, 0xCA, 0xB7, 0x5E, 0xE9, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x26, 0xC2, - 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x11, 0xD1, 0xCE, - 0xBC, 0x63, 0x5F, 0x38, 0x19, 0x7C, 0xA9, 0x02, 0x00, 0x00, 0x94, 0x83, 0x37, 0xBC, 0x62, 0x50, - 0x06, 0x47, 0x74, 0x2A, 0x26, 0xB2, 0x2C, 0x8C, 0x8F, 0xD8, 0xED, 0x47, 0xE2, 0x67, 0x3F, 0xBE, - 0xC9, 0xB7, 0x5D, 0x25, 0x9B, 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, - 0x2A, 0x12, 0x8A, 0x9A, 0x0E, 0x88, 0xB6, 0x77, 0x64, 0xB5, 0x09, 0xBE, 0x54, 0x01, 0x00, 0x00, - 0xCA, 0xC1, 0xDB, 0x7B, 0x79, 0xF3, 0x57, 0xF0, 0xAA, 0x90, 0x48, 0xBB, 0x4D, 0x6E, 0x93, 0xE1, - 0x31, 0x79, 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xFC, 0xF6, 0x43, 0x87, 0x44, - 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0x0D, 0xE3, 0xC3, 0x3D, 0x70, 0x1E, 0x8B, 0x8F, - 0xF1, 0xFF, 0x32, 0xCB, 0x9C, 0xFF, 0xD7, 0x5B, 0x83, 0xF8, 0x58, 0x65, 0x0F, 0xFA, 0x2A, 0x28, - 0xD2, 0x4C, 0x84, 0x43, 0x1E, 0x93, 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, - 0x4D, 0x84, 0x43, 0x5E, 0x3B, 0xB2, 0x92, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF1, 0xF6, 0x2C, - 0x1A, 0x97, 0xE1, 0xE1, 0xA6, 0x62, 0x22, 0xCB, 0x6C, 0x78, 0x44, 0x6F, 0x3F, 0xAA, 0xDF, 0x7A, - 0x15, 0x06, 0x48, 0xCD, 0x6B, 0x77, 0x2F, 0x94, 0xB7, 0x1F, 0xEF, 0x7C, 0x23, 0xAF, 0xDB, 0x0F, - 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x2D, 0x6D, 0x7C, 0x9C, 0xFB, 0xE9, 0x17, 0x2A, 0xF1, 0x71, - 0xD4, 0xFE, 0x28, 0x83, 0x22, 0xCD, 0x44, 0x38, 0xE4, 0x31, 0x19, 0x0E, 0x79, 0x4C, 0x85, 0x43, - 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x44, 0x34, 0xE4, 0x39, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xCA, 0xC4, - 0x0C, 0xF5, 0xCF, 0x32, 0x43, 0x7D, 0x53, 0x1A, 0x1F, 0xE1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xCD, - 0x9E, 0xFD, 0x70, 0xF1, 0x71, 0x7F, 0x5E, 0xB7, 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, - 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x82, 0x21, 0xEF, 0xB9, 0xFF, - 0x6D, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0x0B, 0xFF, 0x0D, 0x58, 0x3B, 0x3E, 0x39, 0xE5, 0xF1, - 0x51, 0x7D, 0xF0, 0x5C, 0xDD, 0x7E, 0xC4, 0x1E, 0x3C, 0x7F, 0xE7, 0x41, 0x1B, 0x1F, 0x5F, 0x57, - 0x31, 0x91, 0x76, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, - 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x62, 0xA1, 0xA0, 0x79, 0x27, 0xEE, 0xE0, 0x4D, 0x58, 0x00, 0x00, - 0xA0, 0x1C, 0xBC, 0xE1, 0xFE, 0xBB, 0xCC, 0xB6, 0x8F, 0x14, 0x13, 0x1F, 0xCF, 0x54, 0xE2, 0xA3, - 0x2E, 0x40, 0xE2, 0xAF, 0xDD, 0x75, 0xB7, 0x1F, 0x41, 0x7C, 0xC4, 0x6F, 0x3F, 0xDE, 0x79, 0xD8, - 0xC6, 0xC7, 0x77, 0xF3, 0xF8, 0xD6, 0x2B, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, - 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xA1, 0x50, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, - 0x82, 0x2F, 0x59, 0x00, 0x00, 0x80, 0xDE, 0xE6, 0xBF, 0x82, 0xB7, 0xA8, 0xF8, 0x08, 0x02, 0xA4, - 0xE1, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0x8A, 0xC7, 0x47, 0x2E, 0xB7, 0x1F, 0x22, 0x24, - 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0xA6, - 0x23, 0xA1, 0xD0, 0x1D, 0xB9, 0x91, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF0, 0x0E, 0x5C, 0x33, - 0xF9, 0x06, 0x2C, 0x19, 0x12, 0x59, 0x36, 0x19, 0x1F, 0x8D, 0x6E, 0x3F, 0xAA, 0xAF, 0xDD, 0xAD, - 0xDE, 0x7E, 0x5C, 0x14, 0xBB, 0xFD, 0xB0, 0xE1, 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, - 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x38, 0x98, - 0x8A, 0xBD, 0x34, 0x60, 0xCC, 0xF1, 0x3B, 0x96, 0x04, 0x5F, 0xB6, 0x00, 0x00, 0x00, 0xBD, 0xCB, - 0xDB, 0x77, 0xC5, 0xC9, 0x42, 0xE2, 0xA3, 0xAD, 0xDB, 0x8F, 0x20, 0x3E, 0x1E, 0x68, 0xF7, 0xF6, - 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, - 0x50, 0xD4, 0x44, 0x18, 0x4C, 0xD5, 0xDC, 0x9B, 0xB0, 0x4E, 0x7C, 0x69, 0x6D, 0xF0, 0x65, 0x0B, - 0x00, 0x00, 0xD0, 0xBB, 0xCC, 0xEE, 0xBE, 0x48, 0x3C, 0xB4, 0xBB, 0xDA, 0xF8, 0x70, 0x3F, 0xAA, - 0xDB, 0x8F, 0xFA, 0x67, 0x3F, 0xA2, 0xB7, 0x1F, 0x41, 0x7C, 0xB8, 0xDD, 0xDB, 0xCE, 0xED, 0x87, - 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, - 0xA8, 0x89, 0x28, 0x98, 0xCA, 0xBD, 0x70, 0x25, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xCF, 0x1C, - 0xE8, 0x5F, 0x62, 0x76, 0xCE, 0x0E, 0xE2, 0xA1, 0xDD, 0x45, 0xE2, 0x23, 0x08, 0x90, 0x66, 0xB7, - 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xE1, 0x6E, 0x3F, 0x64, 0x58, 0x24, 0x99, 0x08, 0x89, 0x2C, - 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x20, - 0xE8, 0xC0, 0xBC, 0xE3, 0xB7, 0x0F, 0x05, 0x5F, 0xBA, 0x00, 0x00, 0x00, 0xBD, 0xC9, 0x1C, 0x5C, - 0xB6, 0xD6, 0x6C, 0xFF, 0x58, 0x10, 0x10, 0xED, 0xAC, 0x3E, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0x43, - 0x3D, 0xFB, 0x51, 0xF9, 0xD0, 0xC1, 0x0B, 0x27, 0x03, 0xE4, 0x21, 0xBB, 0xCC, 0xB7, 0x1F, 0x22, - 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, - 0xA6, 0x63, 0xA0, 0x13, 0xF3, 0x8E, 0xDE, 0xC2, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x33, 0x23, - 0xCB, 0xD7, 0x9B, 0xCD, 0xEF, 0xB3, 0xB1, 0xA0, 0xA2, 0x22, 0xE9, 0x62, 0xF1, 0xE1, 0x16, 0x86, - 0x47, 0x18, 0x1F, 0xB1, 0xDB, 0x8F, 0xBA, 0x67, 0x3F, 0x1E, 0xB5, 0xF1, 0xE1, 0x02, 0xA4, 0xED, - 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, - 0x45, 0x42, 0x51, 0xD3, 0x21, 0xD0, 0xB1, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, - 0xE6, 0x1D, 0xB8, 0x7E, 0xA8, 0x36, 0x26, 0xD2, 0x4E, 0xC7, 0x87, 0xFB, 0xB1, 0xE9, 0xED, 0x47, - 0x2C, 0x3E, 0xEA, 0x6E, 0x3F, 0xEE, 0xC9, 0x72, 0xFB, 0x21, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, - 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x00, 0x3A, 0x3D, 0xF7, - 0x26, 0xAC, 0x97, 0xEF, 0x9C, 0x1D, 0x7C, 0xF9, 0x02, 0x00, 0x00, 0xF4, 0x1E, 0x6F, 0xEF, 0x65, - 0xA3, 0xF5, 0x51, 0x91, 0x74, 0xB1, 0xF0, 0x08, 0x17, 0x86, 0x47, 0x18, 0x1F, 0x4D, 0x6F, 0x3F, - 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x4E, 0x06, 0x46, 0xB3, 0x89, 0x90, 0xC8, - 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, - 0xFC, 0x77, 0xC3, 0x5E, 0xFC, 0x9C, 0x31, 0xC7, 0x6E, 0x1B, 0x08, 0xBE, 0x7C, 0x01, 0x00, 0x00, - 0x7A, 0x8F, 0xD9, 0x63, 0x0F, 0x5B, 0x32, 0x2E, 0x5A, 0x4D, 0x84, 0x47, 0x64, 0xC9, 0x6E, 0x3F, - 0x2A, 0xF1, 0xD1, 0xFE, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, - 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xFE, 0xDD, 0x32, 0xDE, 0x84, 0x05, 0x00, - 0x00, 0x7A, 0x99, 0x19, 0xE9, 0x9F, 0x6D, 0x76, 0xCF, 0xB3, 0xC1, 0xA0, 0x02, 0xA3, 0xD9, 0x74, - 0x74, 0xF8, 0x4B, 0x7C, 0xFB, 0x31, 0xD3, 0x9C, 0x09, 0xE3, 0xA3, 0xAD, 0xDB, 0x0F, 0x11, 0x12, - 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, - 0x87, 0xFE, 0x2E, 0x9B, 0x77, 0xE2, 0xF6, 0xC1, 0xE0, 0x4B, 0x18, 0x00, 0x00, 0xA0, 0xB7, 0xD8, - 0x00, 0x19, 0x48, 0xFF, 0x06, 0x2C, 0x11, 0x1D, 0xB1, 0xA9, 0xDB, 0x8F, 0x6A, 0x80, 0x84, 0xF1, - 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, - 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7F, 0xB7, 0xCD, 0x3B, 0xFA, 0x85, 0xD1, 0xE0, 0x4B, - 0x18, 0x00, 0x00, 0xA0, 0xB7, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0x3E, 0x60, 0xA3, 0x41, 0x85, - 0x86, 0x9A, 0x0E, 0x8E, 0xEA, 0x12, 0xDC, 0x7E, 0x4C, 0x3C, 0x31, 0xD3, 0x4C, 0x3C, 0x16, 0xB9, - 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0xFB, 0xC4, 0x47, 0x65, 0x22, 0x1C, 0xF2, 0x98, 0x0C, 0x87, 0x3C, - 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0xB0, 0xDF, 0x95, 0x3B, 0x76, 0x0B, 0x6F, - 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xC9, 0x1B, 0x59, 0xB1, 0xA1, 0x3E, 0x32, 0x1A, 0x4D, 0x04, 0x47, - 0x7C, 0xF1, 0x00, 0xA9, 0x7B, 0xF6, 0xC3, 0xC6, 0x47, 0xB3, 0xDB, 0x8F, 0x6F, 0xA8, 0xD0, 0x50, - 0x13, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, - 0x14, 0x35, 0x71, 0xC8, 0xEF, 0xE6, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xAB, 0xBC, 0x7D, 0x57, - 0x24, 0x7C, 0x03, 0x96, 0x88, 0x8D, 0xE8, 0x6C, 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, - 0x47, 0xE4, 0x5B, 0xAF, 0x06, 0x6D, 0x7C, 0x44, 0x6F, 0x3F, 0xEC, 0x6A, 0x6E, 0x3F, 0x36, 0x24, - 0xBD, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, - 0x54, 0x24, 0x14, 0x35, 0x71, 0xC0, 0xEF, 0xF6, 0x8D, 0x2D, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0xA0, - 0x37, 0x79, 0x7B, 0x2F, 0x1B, 0xAF, 0x8F, 0x8D, 0xF8, 0x62, 0xB1, 0xA1, 0x16, 0x0D, 0x10, 0xBB, - 0xEA, 0xB7, 0x5E, 0x85, 0x01, 0x62, 0xE3, 0x63, 0xF2, 0xF6, 0x63, 0x66, 0x1B, 0xB7, 0x1F, 0x22, - 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, - 0x26, 0x0E, 0xF7, 0xBD, 0xB0, 0x17, 0xAF, 0x31, 0xDE, 0x2F, 0x6E, 0xBF, 0x2B, 0xF8, 0x32, 0x06, - 0x00, 0x00, 0xE8, 0x1D, 0xAD, 0xDF, 0x80, 0x15, 0x0B, 0x0D, 0xB5, 0x58, 0x7C, 0x84, 0xB7, 0x1F, - 0x93, 0x0F, 0x9E, 0xDB, 0xF8, 0x88, 0xDF, 0x7E, 0x84, 0xF1, 0x11, 0x06, 0x48, 0xA2, 0xDB, 0x0F, - 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, - 0x51, 0x13, 0x07, 0xFB, 0x1E, 0x9A, 0x77, 0xFC, 0x8E, 0x0D, 0xC1, 0x97, 0x31, 0x00, 0x00, 0x40, - 0x6F, 0xF0, 0xDF, 0x80, 0xB5, 0x73, 0xB6, 0x8D, 0x08, 0x15, 0x1E, 0x6E, 0xB1, 0xD0, 0x50, 0x6B, - 0x10, 0x1F, 0xD5, 0x07, 0xCF, 0x37, 0xCE, 0xAC, 0xBF, 0xFD, 0x08, 0xE2, 0xA3, 0x7A, 0xFB, 0xF1, - 0xA0, 0xDD, 0xD7, 0x55, 0x70, 0x44, 0x27, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, - 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0x50, 0xDF, 0x4B, 0xF3, 0x8E, 0xDE, 0xCA, - 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x31, 0x23, 0xCB, 0xD7, 0x35, 0x7E, 0x05, 0x6F, 0x2C, 0x34, - 0x1A, 0x4D, 0x05, 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x41, 0x7C, 0xC8, 0x37, - 0x5F, 0x7D, 0xB7, 0xD5, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, - 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7D, 0xAF, 0xCD, 0x3B, 0xFA, 0xF9, 0xF1, - 0xE0, 0x4B, 0x19, 0x00, 0x00, 0xA0, 0x37, 0xD8, 0x00, 0x59, 0x5F, 0x1F, 0x1E, 0x29, 0xE2, 0xC3, - 0x2D, 0x1E, 0x1F, 0xD5, 0xDB, 0x8F, 0xC9, 0xF8, 0xA8, 0x79, 0xF3, 0x55, 0xEA, 0xDB, 0x0F, 0x11, - 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, - 0xD3, 0x87, 0xF9, 0x9E, 0x9C, 0x7B, 0x13, 0xD6, 0xD8, 0x17, 0x67, 0x05, 0x5F, 0xCE, 0x00, 0x00, - 0x00, 0xDD, 0xCF, 0x3B, 0x70, 0xD5, 0x50, 0xBB, 0xF1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0xD4, 0xDD, - 0x7E, 0x5C, 0x98, 0xE1, 0xF6, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, - 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBE, 0x97, 0x37, 0xB6, 0x9C, 0x37, 0x61, - 0x01, 0x00, 0x80, 0xDE, 0xE2, 0xED, 0xBD, 0x7C, 0x2C, 0x73, 0x7C, 0xB8, 0xC5, 0xE3, 0xC3, 0x0F, - 0x90, 0x19, 0x39, 0xDD, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, - 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xC0, 0xF7, 0xFA, 0x78, 0x13, 0x16, 0x00, 0x00, - 0xE8, 0x35, 0x66, 0x68, 0x81, 0x0D, 0x89, 0xEC, 0xF1, 0xE1, 0x7E, 0xAC, 0xBD, 0xFD, 0xB0, 0xF1, - 0x11, 0xFB, 0xF6, 0xAB, 0xA6, 0xB7, 0x1F, 0xF7, 0x35, 0xBA, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, - 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x78, 0x2F, - 0xC3, 0x9E, 0xBF, 0x9C, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, 0x61, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, - 0x2E, 0xB5, 0x11, 0x91, 0x21, 0x3E, 0xDC, 0xC2, 0xF0, 0x08, 0xE3, 0xE3, 0xE9, 0x19, 0x35, 0xB7, - 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xF1, 0x80, 0x1D, 0xF1, 0x91, 0xCF, 0x64, 0x38, 0xE4, 0x31, - 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x07, 0xF7, 0x12, 0xCD, 0x3B, 0xFE, 0x67, 0xBC, - 0x09, 0x0B, 0x00, 0x00, 0xF4, 0x06, 0xFF, 0x15, 0xBC, 0xFE, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, - 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, 0xF1, 0xD1, 0xE0, 0xD9, 0x0F, 0xF9, 0xA1, 0x83, 0xF7, - 0xAA, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, - 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x87, 0xF6, 0x32, 0xCD, 0x3B, 0xFA, 0xF9, 0x93, 0xC1, 0x97, 0x34, - 0x00, 0x00, 0x40, 0x77, 0xF3, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0xF5, 0x71, 0x91, 0x64, 0x61, 0x78, - 0x84, 0xF1, 0x11, 0xBB, 0xFD, 0xA8, 0x7B, 0xF6, 0xC3, 0x06, 0xC8, 0x29, 0x17, 0x20, 0x4D, 0x6F, - 0x3F, 0x44, 0x48, 0x64, 0x99, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, - 0x09, 0x45, 0x4D, 0x1F, 0xD8, 0x4B, 0xB7, 0x23, 0xAB, 0x4C, 0xF0, 0x25, 0x0D, 0x00, 0x00, 0xD0, - 0xDD, 0xBC, 0xE1, 0x65, 0x83, 0x32, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0x12, 0x20, 0x33, - 0xF4, 0xED, 0x47, 0x2C, 0x3E, 0x5A, 0xDF, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, - 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA8, 0x97, 0x75, 0x63, 0xCB, - 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0D, 0xDE, 0xDE, 0xCB, 0x46, 0xEB, 0xE2, 0x22, 0xC9, 0xAA, - 0xB7, 0x1F, 0x41, 0x7C, 0x24, 0xBD, 0xFD, 0x08, 0x03, 0xE4, 0x07, 0x76, 0xC4, 0x47, 0x7B, 0x93, - 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0xBA, 0x7F, - 0x5D, 0x68, 0xCC, 0x0B, 0x57, 0x1B, 0x73, 0xFC, 0x8E, 0x75, 0xC1, 0x97, 0x35, 0x00, 0x00, 0x40, - 0xF7, 0xF2, 0xF6, 0x2C, 0x18, 0x97, 0x81, 0xD1, 0x6C, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0x59, 0x6F, - 0x3F, 0xEE, 0x89, 0xDE, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, - 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2E, 0x3E, 0xDC, 0x7E, 0x6E, - 0xFF, 0x99, 0x38, 0x71, 0xDB, 0xFA, 0xE0, 0xCB, 0x1A, 0x00, 0x00, 0xA0, 0x3B, 0x99, 0xA1, 0xFE, - 0x59, 0x66, 0xF7, 0xDC, 0xFA, 0xC0, 0x68, 0xB5, 0xF0, 0xE6, 0x23, 0x97, 0xDB, 0x0F, 0x11, 0x12, - 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, - 0x87, 0xF4, 0xB2, 0x2E, 0x8C, 0x8F, 0x60, 0xDE, 0x89, 0xDB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, - 0x6E, 0x66, 0x64, 0xE9, 0x80, 0xD9, 0xF1, 0x71, 0x1D, 0x19, 0xCD, 0x16, 0xC6, 0x47, 0xDB, 0xB7, - 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, - 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x5D, 0x2C, 0x3E, 0xFC, 0x00, 0x39, 0x7A, 0x33, 0x6F, 0xC2, - 0x02, 0x00, 0x00, 0xDD, 0xCD, 0x1B, 0x5E, 0x7E, 0x97, 0xD9, 0xFA, 0x21, 0x1D, 0x19, 0x8D, 0x16, - 0x8F, 0x8F, 0x66, 0xB7, 0x1F, 0x61, 0x7C, 0xC8, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, - 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, - 0xC4, 0x87, 0xBF, 0x23, 0x37, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xDD, 0xFC, 0x57, 0xF0, 0xAA, - 0xC8, 0x68, 0x34, 0x1B, 0x1D, 0x8D, 0x6E, 0x3F, 0xAA, 0x01, 0xD2, 0xEA, 0xF6, 0xE3, 0x1B, 0xC4, - 0x47, 0xA6, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, - 0x65, 0x9D, 0x0A, 0x8F, 0x70, 0x2F, 0xF5, 0xBB, 0x07, 0xD1, 0x97, 0x04, 0x5F, 0xDE, 0x00, 0x00, - 0x00, 0xDD, 0xC7, 0x3B, 0x70, 0x75, 0xF2, 0x37, 0x60, 0x45, 0xE3, 0xC3, 0x86, 0x47, 0xA3, 0xDB, - 0x8F, 0x09, 0x17, 0x20, 0x8F, 0x45, 0x6E, 0x3F, 0xC2, 0xF8, 0x70, 0xDB, 0xE0, 0xBE, 0xF5, 0x4A, - 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, - 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xD1, 0x11, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x3F, 0x5F, 0x1B, - 0x7C, 0x79, 0x03, 0x00, 0x00, 0x74, 0x1F, 0x6F, 0xDF, 0xE5, 0x27, 0x65, 0x6C, 0xC4, 0x17, 0xC4, - 0x47, 0xA3, 0xDB, 0x8F, 0xC4, 0xCF, 0x7E, 0x7C, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, - 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xC1, - 0x11, 0x1F, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xDD, 0x2E, 0xD1, 0x1B, 0xB0, 0xE2, 0xF1, 0x51, 0x73, - 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xED, 0xED, 0x47, 0x4E, 0xDF, 0x7A, 0x25, - 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, - 0xB2, 0x4E, 0xC5, 0x46, 0x83, 0x79, 0xC7, 0x6F, 0x1F, 0x0A, 0xBE, 0xBC, 0x01, 0x00, 0x00, 0xBA, - 0x8B, 0x39, 0x70, 0xFD, 0x12, 0xB3, 0xF3, 0x53, 0x3A, 0x3A, 0xC2, 0x45, 0xE2, 0xA3, 0x1A, 0x20, - 0x76, 0xD5, 0x6F, 0xBD, 0x0A, 0x03, 0xA4, 0xE6, 0xB5, 0xBB, 0x33, 0xC5, 0xED, 0xC7, 0xCC, 0x7C, - 0x6E, 0x3F, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, - 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0xC8, 0x68, 0x36, 0xEF, 0xC8, 0x9A, 0xB1, 0xE0, 0x4B, 0x1C, 0x00, - 0x00, 0xA0, 0xBB, 0x98, 0x83, 0xCB, 0xD6, 0x9A, 0xED, 0x1F, 0xD5, 0xE1, 0xE1, 0x16, 0x09, 0x8F, - 0x68, 0x7C, 0x84, 0xB7, 0x1F, 0x35, 0x0F, 0x9E, 0x37, 0x7A, 0xF6, 0xC3, 0x0F, 0x10, 0x1B, 0x1F, - 0xDF, 0xCD, 0xE1, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, - 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x08, 0x8C, 0x96, 0x3B, 0xBA, 0x86, 0x37, 0x61, 0x01, - 0x00, 0x80, 0xEE, 0xE4, 0xBF, 0x01, 0x6B, 0xF3, 0xAC, 0x4C, 0xF1, 0x51, 0x7D, 0xF0, 0x5C, 0xDD, - 0x7E, 0x04, 0xF1, 0x51, 0xB9, 0xFD, 0xB0, 0xF1, 0xF1, 0xA0, 0xDD, 0xD7, 0x45, 0x50, 0xA4, 0x99, - 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, - 0xCB, 0x3A, 0x15, 0x17, 0x49, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB7, 0xF2, 0x0E, 0x7C, 0x6E, - 0x28, 0x49, 0x7C, 0xD4, 0x05, 0x48, 0xFC, 0xB5, 0xBB, 0xEE, 0xF6, 0x23, 0x88, 0x8F, 0xDA, 0x37, - 0x5F, 0xD9, 0xF0, 0xC8, 0xE3, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, - 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x0A, 0x8B, 0xA4, 0x7B, 0xE1, 0x5A, 0x63, - 0x8E, 0xDD, 0x36, 0x10, 0x7C, 0x99, 0x03, 0x00, 0x00, 0x74, 0x0F, 0x6F, 0xEF, 0x65, 0xF5, 0xAF, - 0xE0, 0x8D, 0x44, 0x87, 0x8C, 0x8F, 0xE8, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0xAA, 0xDE, - 0x7E, 0x04, 0xF1, 0xD1, 0xEE, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, - 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x15, 0x69, 0xF6, 0xFC, 0x67, 0x79, - 0x13, 0x16, 0x00, 0x00, 0xE8, 0x4E, 0x66, 0x8F, 0x3D, 0xEC, 0xB4, 0x88, 0x0F, 0x37, 0x75, 0xFB, - 0x51, 0x7D, 0xED, 0x6E, 0xF5, 0xF6, 0xE3, 0xC2, 0xC8, 0xED, 0x47, 0x10, 0x1F, 0xED, 0xDE, 0x7E, - 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x62, 0x07, - 0xF4, 0x32, 0x4F, 0x05, 0x45, 0x86, 0x79, 0x27, 0x6E, 0x1B, 0x0C, 0xBE, 0xCC, 0x01, 0x00, 0x00, - 0xBA, 0x83, 0x19, 0xE9, 0x9F, 0x5D, 0xF3, 0x0A, 0xDE, 0x48, 0x70, 0x44, 0x97, 0xFE, 0xF6, 0x63, - 0xE6, 0x64, 0x80, 0x3C, 0x60, 0xA7, 0xC2, 0x22, 0xC9, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, - 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0x90, 0xC8, 0x3A, 0xEF, - 0xC8, 0xE7, 0x47, 0x83, 0x2F, 0x75, 0x00, 0x00, 0x80, 0xEE, 0x60, 0x46, 0x96, 0x0E, 0x54, 0xDF, - 0x80, 0x15, 0x09, 0x8E, 0xF8, 0xD4, 0xED, 0x47, 0xFD, 0xB3, 0x1F, 0xE1, 0xED, 0x47, 0x24, 0x3E, - 0xDC, 0xEE, 0xCD, 0x78, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, - 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x44, 0x44, 0x5B, 0xE3, 0x4D, 0x58, 0x00, 0x00, - 0xA0, 0xDB, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0xDE, 0x2F, 0xA3, 0x23, 0x5C, 0xB3, 0xDB, 0x8F, - 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0xC8, 0x7A, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, - 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x05, 0x44, 0xBB, 0x73, 0x6F, - 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x3B, 0x00, 0x00, 0x40, 0xE7, 0x79, 0x23, 0xCB, 0x36, - 0xA8, 0xE8, 0x88, 0x4E, 0xDD, 0x7E, 0xD4, 0x3F, 0xFB, 0xE1, 0x3E, 0x74, 0xD0, 0xBD, 0x7A, 0x37, - 0x12, 0x20, 0xEE, 0x43, 0x07, 0xB3, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, - 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xF1, 0x90, 0xC7, 0x5E, 0xBC, - 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, 0xEE, 0xE2, 0xED, 0xBD, 0x62, 0x54, 0x45, 0x47, 0xB8, 0x66, - 0xB7, 0x1F, 0xD5, 0x67, 0x3F, 0xFC, 0xD7, 0xEE, 0x06, 0xF1, 0xE1, 0xD6, 0xCE, 0xED, 0x87, 0x08, - 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, - 0x3A, 0x15, 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x2E, 0xDE, 0xDE, - 0xC5, 0xE3, 0x2A, 0x3C, 0xC2, 0x35, 0xBD, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC5, 0x87, 0xBA, 0xFD, - 0xB8, 0x27, 0xE5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, - 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x0D, 0x39, 0xCF, 0x3B, 0xB6, 0x96, 0x37, 0x61, - 0x01, 0x00, 0x80, 0xEE, 0xE1, 0xBF, 0x01, 0x2B, 0x12, 0x1C, 0xD1, 0xB5, 0xBC, 0xFD, 0xB0, 0xF1, - 0x31, 0xF1, 0xD8, 0x8C, 0xDA, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x60, 0xA7, 0x22, 0xA3, 0xD1, 0x44, - 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, - 0xD6, 0x89, 0x58, 0x28, 0x62, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0E, 0xFE, - 0x1B, 0xB0, 0x76, 0x7C, 0x52, 0xC6, 0x87, 0x5B, 0xCB, 0xDB, 0x8F, 0x30, 0x3E, 0xDA, 0xBD, 0xFD, - 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, - 0x7A, 0x59, 0x27, 0x42, 0xA1, 0xA8, 0x79, 0x47, 0x6F, 0x1E, 0x0F, 0xBE, 0xE4, 0x01, 0x00, 0x00, - 0x3A, 0xCB, 0x8C, 0x2C, 0x5F, 0x67, 0xB6, 0x7D, 0xA4, 0x75, 0x7C, 0xC8, 0xDB, 0x8F, 0x19, 0xF9, - 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, - 0xC4, 0x21, 0xBD, 0xAC, 0x13, 0x91, 0x50, 0xE8, 0xDC, 0x9B, 0xB0, 0xC6, 0xBE, 0x38, 0x2B, 0xF8, - 0xB2, 0x07, 0x00, 0x00, 0xE8, 0x1C, 0x1B, 0x20, 0xEB, 0x55, 0x7C, 0xB8, 0xA9, 0xDB, 0x0F, 0x3F, - 0x40, 0x44, 0x7C, 0x64, 0xBE, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, - 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA1, 0xE8, 0xF1, 0x26, 0x2C, 0x00, - 0x00, 0xD0, 0x2D, 0xBC, 0x03, 0x57, 0x0D, 0x35, 0x8C, 0x0F, 0x1B, 0x1E, 0xF2, 0xF6, 0xE3, 0x09, - 0x1B, 0x1F, 0x2E, 0x40, 0x1E, 0x8D, 0xDC, 0x7E, 0x84, 0xF1, 0xE1, 0xB6, 0x81, 0xF8, 0xA8, 0x9B, - 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xA9, - 0x38, 0x98, 0x8A, 0xBD, 0x70, 0xB5, 0xF1, 0x7E, 0x71, 0xFB, 0x5D, 0xC1, 0x97, 0x3D, 0x00, 0x00, - 0x40, 0xE7, 0x78, 0x7B, 0x2F, 0x1B, 0x6B, 0x18, 0x20, 0x6E, 0x91, 0xDB, 0x0F, 0x17, 0x1F, 0x67, - 0x07, 0x67, 0xD4, 0xDE, 0x7E, 0xA8, 0x67, 0x3F, 0xBE, 0x21, 0x62, 0x23, 0x3E, 0x11, 0x1E, 0x6E, - 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2A, - 0x0C, 0xA6, 0x70, 0xDE, 0xF1, 0xDB, 0x36, 0x04, 0x5F, 0xF6, 0x00, 0x00, 0x00, 0x9D, 0x63, 0x86, - 0xE6, 0xEB, 0xF8, 0xA8, 0xB9, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC6, 0x47, 0x1E, 0xB7, 0x1F, 0x22, - 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, - 0xEB, 0x44, 0x10, 0x4C, 0xF5, 0xBC, 0xE3, 0x7F, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x67, 0x99, - 0x91, 0xFE, 0xD9, 0x66, 0xE7, 0x25, 0x3A, 0x40, 0xEC, 0xA2, 0xDF, 0x7A, 0x75, 0xEE, 0xC9, 0x19, - 0xE6, 0xAC, 0x8D, 0x8F, 0xC9, 0xDB, 0x8F, 0x19, 0xFA, 0xD9, 0x8F, 0x56, 0xB7, 0x1F, 0x22, 0x3C, - 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, - 0x44, 0x0C, 0x74, 0x62, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x74, 0x9C, 0xFF, 0x0A, 0xDE, 0xD8, 0x1B, - 0xB0, 0x6A, 0xBE, 0xF5, 0xCA, 0xEE, 0x9C, 0x0B, 0x10, 0x17, 0x1F, 0xF1, 0xDB, 0x8F, 0x68, 0x7C, - 0x84, 0x01, 0x72, 0x7F, 0x8B, 0xDB, 0x0F, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, - 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x22, 0x04, 0x3A, 0xB6, 0x97, 0x56, 0x99, - 0xE0, 0x4B, 0x1F, 0x00, 0x00, 0xA0, 0x33, 0xFC, 0x37, 0x60, 0x6D, 0xFE, 0xE3, 0x86, 0xF1, 0x51, - 0xB9, 0xFD, 0xB0, 0xF1, 0xD1, 0xE0, 0xF6, 0xC3, 0xC5, 0x47, 0xF5, 0xF6, 0xE3, 0x41, 0xBB, 0xAF, - 0x8B, 0xE8, 0x08, 0x27, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, - 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x45, 0x40, 0x27, 0x37, 0xB6, 0x8C, 0x37, 0x61, 0x01, 0x00, - 0x80, 0xCE, 0xF2, 0x86, 0x97, 0x0D, 0x36, 0xBC, 0xFD, 0x08, 0xE2, 0xA3, 0xE6, 0xF6, 0x23, 0x88, - 0x8F, 0x9A, 0xDB, 0x8F, 0xF0, 0xD9, 0x8F, 0xEF, 0x36, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, - 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA0, - 0xD3, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0xF2, 0x07, 0x00, 0x00, 0x98, 0x7A, - 0xDE, 0xDE, 0xCB, 0x46, 0x1B, 0xDE, 0x7E, 0x6C, 0xBC, 0xA0, 0x26, 0x3E, 0xEA, 0x3E, 0x74, 0x30, - 0xE9, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, - 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x75, 0xF8, 0xEF, 0xF8, 0x16, 0xD8, 0x5F, 0x9B, 0xFD, 0xDF, 0xE1, - 0xC4, 0x6D, 0xEB, 0x83, 0x2F, 0x7F, 0x00, 0x00, 0x80, 0xA9, 0xE7, 0xED, 0x9E, 0x3F, 0xAE, 0x6F, - 0x3F, 0x6C, 0x7C, 0x84, 0xDF, 0x7A, 0x55, 0x73, 0xFB, 0x31, 0x33, 0xDD, 0xED, 0x87, 0x08, 0x0F, - 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0xB1, 0x78, 0x20, 0x14, 0x39, 0x71, 0x48, 0x2F, 0xEB, - 0xE4, 0xE1, 0xBF, 0xD3, 0xB3, 0xF1, 0x11, 0xCC, 0x3B, 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x80, - 0xCE, 0x30, 0x43, 0xFD, 0xB3, 0xCC, 0xEE, 0xB9, 0x32, 0x3E, 0x72, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, - 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, - 0x0F, 0xFF, 0x9D, 0xDE, 0x64, 0x7C, 0xF8, 0x01, 0x72, 0xF4, 0xE6, 0x93, 0xC1, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x53, 0xCB, 0x7F, 0x03, 0xD6, 0xF6, 0x8B, 0x6B, 0x03, 0x24, 0x8C, 0x0F, 0xF9, 0xEC, - 0x47, 0x83, 0xDB, 0x8F, 0x7B, 0xC5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, - 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x6A, 0xE3, - 0xC3, 0xDF, 0x91, 0x1B, 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0C, 0x33, 0xB2, 0x7C, 0x9D, 0xD9, - 0xFA, 0xC1, 0xC8, 0xED, 0x87, 0x8D, 0x8F, 0xD8, 0xED, 0x47, 0xED, 0x9B, 0xAF, 0x44, 0x7C, 0x3C, - 0x60, 0x47, 0x7C, 0x14, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, - 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x11, 0x1F, 0x6E, 0x2F, 0xF5, 0xF3, 0x26, 0x2C, 0x00, 0x00, 0xD0, - 0x19, 0xE6, 0xE0, 0xF2, 0xF5, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xEC, 0xC7, - 0xE9, 0x78, 0x80, 0xB8, 0x0F, 0x1D, 0x8C, 0xDF, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, - 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, - 0x84, 0x47, 0x38, 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x00, 0x00, 0x00, 0x60, - 0xEA, 0x78, 0xFB, 0xAE, 0x1E, 0xAD, 0x89, 0x8F, 0x24, 0xCF, 0x7E, 0xB8, 0x35, 0xBA, 0xFD, 0x10, - 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, - 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x88, 0x8E, 0xE8, 0xDC, 0x3F, 0x67, 0xBC, 0x09, 0x0B, 0x00, - 0x00, 0x74, 0x82, 0xB7, 0xF7, 0xF2, 0x93, 0x7E, 0x7C, 0x34, 0xBA, 0xFD, 0x88, 0xC6, 0x87, 0xBA, - 0xFD, 0xF8, 0x76, 0xE4, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, - 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x38, 0xC4, 0xBC, - 0xE3, 0xB7, 0x0F, 0x05, 0x7F, 0x0C, 0x00, 0x00, 0x00, 0x4C, 0x1D, 0x6F, 0xE7, 0x9C, 0xF4, 0xB7, - 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x8E, 0xF8, 0xC8, 0x71, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, - 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x36, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, - 0x82, 0x3F, 0x06, 0x00, 0x00, 0x00, 0xA6, 0x86, 0x39, 0x70, 0xFD, 0x12, 0x6F, 0xFB, 0x27, 0xB2, - 0xDF, 0x7E, 0xDC, 0x13, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, - 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x87, 0x46, 0xC3, - 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xD5, 0xCC, 0xC1, 0x65, 0x6B, 0xBD, 0xAD, 0x1F, 0x6E, 0xEF, - 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, - 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x30, 0x5A, 0xCD, 0xBD, 0x09, 0xEB, 0xF8, - 0x1D, 0x4B, 0x82, 0x3F, 0x0E, 0x00, 0x00, 0x00, 0x8A, 0x77, 0xFE, 0xE0, 0xD2, 0xF5, 0xDE, 0xA6, - 0x0B, 0x33, 0xDE, 0x7E, 0x10, 0x1F, 0xF9, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, - 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC4, 0x45, 0x92, 0xBD, 0x70, 0x0D, 0x6F, 0xC2, - 0x02, 0x00, 0x00, 0x53, 0xEB, 0xFC, 0xFE, 0x6B, 0x06, 0xB3, 0xDD, 0x7E, 0xCC, 0x90, 0xE1, 0xE1, - 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, - 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x8B, 0xA4, 0x7B, 0xFE, 0x0A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xA6, - 0xD6, 0xF9, 0xDD, 0x8B, 0x47, 0xA3, 0xB7, 0x1F, 0xD5, 0x00, 0x89, 0xC5, 0x47, 0xDD, 0xED, 0xC7, - 0xDD, 0xC4, 0x47, 0xFB, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, - 0xE4, 0xE1, 0xBF, 0xD3, 0x13, 0x51, 0x91, 0x72, 0xDE, 0xB1, 0xB5, 0xBC, 0x09, 0x0B, 0x00, 0x00, - 0x4C, 0x1D, 0x6F, 0xF7, 0x42, 0x79, 0xFB, 0x31, 0xE1, 0x02, 0xE4, 0xD1, 0xC8, 0xED, 0x47, 0x18, - 0x1F, 0x6E, 0xF7, 0xEB, 0x6F, 0xBD, 0x22, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, - 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x07, 0x45, 0xDA, 0x79, 0x47, 0x3E, - 0x3F, 0x1A, 0xFC, 0x71, 0x00, 0x00, 0x00, 0x50, 0x2C, 0x33, 0xD2, 0x3F, 0xDB, 0xDB, 0x31, 0x27, - 0xDD, 0xB3, 0x1F, 0x0F, 0xCE, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, - 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x98, 0xC8, 0xB4, 0xA3, - 0x6B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x1A, 0x66, 0xFF, 0xD2, 0x81, 0xF3, 0x5B, 0x3E, 0x6C, - 0x03, 0x24, 0xF2, 0xAD, 0x57, 0xCD, 0x6E, 0x3F, 0x1E, 0xB2, 0xF1, 0x21, 0x6E, 0x3F, 0x88, 0x8F, - 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, - 0xD3, 0x13, 0x11, 0xD1, 0xCE, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0x73, 0x76, 0xF0, 0xC7, 0x02, 0x00, - 0x00, 0x40, 0x71, 0xCE, 0xED, 0x5F, 0x7A, 0xD7, 0xF9, 0x4D, 0xEF, 0x9B, 0x7C, 0xF6, 0xA3, 0xE6, - 0xC1, 0xF3, 0x19, 0xB5, 0xCF, 0x7E, 0xB8, 0xF8, 0x78, 0xA0, 0xFE, 0xF6, 0x83, 0xF8, 0x48, 0x33, - 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, - 0x11, 0x10, 0xED, 0xCE, 0xBD, 0x09, 0xEB, 0xD8, 0x6D, 0x03, 0xC1, 0x1F, 0x0B, 0x00, 0x00, 0x00, - 0xC5, 0x39, 0x7F, 0x60, 0xD9, 0x86, 0x9A, 0x07, 0xCF, 0xA3, 0xB7, 0x1F, 0xD1, 0xF8, 0x78, 0xD8, - 0x86, 0x87, 0x0B, 0x90, 0xEF, 0xD4, 0xDE, 0x7E, 0x10, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, - 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x21, 0x8F, 0xF1, - 0x26, 0x2C, 0x00, 0x00, 0x30, 0x55, 0xCE, 0xEF, 0x5E, 0x32, 0xEA, 0xC7, 0x47, 0x83, 0xDB, 0x0F, - 0x17, 0x1F, 0xA7, 0xC2, 0xF8, 0x70, 0xB7, 0x1F, 0x7F, 0x4D, 0x7C, 0x64, 0x9B, 0x0A, 0x87, 0x3C, - 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x87, 0x1C, - 0xE7, 0x9D, 0xB8, 0x6D, 0x30, 0xF8, 0x63, 0x01, 0x00, 0x00, 0xA0, 0x38, 0xE7, 0x76, 0x2E, 0x3A, - 0x59, 0x73, 0xFB, 0x11, 0xC4, 0x47, 0xF5, 0xD9, 0x8F, 0x30, 0x3E, 0x62, 0xB7, 0x1F, 0xC4, 0x47, - 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, - 0xE9, 0xE9, 0x68, 0xC8, 0x73, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0xDE, 0xF9, - 0xED, 0x73, 0xAA, 0xF1, 0x51, 0xF7, 0xA1, 0x83, 0x8F, 0xCC, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, - 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, - 0xE9, 0x60, 0xC8, 0x7D, 0x47, 0x3F, 0xCF, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB1, 0xCE, 0xEE, 0x5F, - 0x3A, 0x70, 0x6E, 0xCB, 0x27, 0x63, 0xB7, 0x1F, 0x33, 0x2B, 0xCF, 0x7E, 0x44, 0xE3, 0xC3, 0xED, - 0xDE, 0xCA, 0xED, 0x07, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, - 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x14, 0x8A, 0x9A, 0x7B, 0x13, 0xD6, 0xD8, 0x17, - 0x67, 0x05, 0x7F, 0x3C, 0x00, 0x00, 0x00, 0xE4, 0xEF, 0xDC, 0xDE, 0xE5, 0xEB, 0xCE, 0x6D, 0xFA, - 0x48, 0xEC, 0xF6, 0x63, 0x46, 0x35, 0x3E, 0xAA, 0x01, 0xF2, 0x23, 0x3B, 0xE2, 0x23, 0xE5, 0x54, - 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x44, - 0x24, 0x14, 0xB9, 0x17, 0xAF, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x58, 0xE7, 0xF7, 0x2E, 0x5F, - 0x5F, 0xF7, 0xEC, 0xC7, 0x8F, 0x27, 0x03, 0xA4, 0x7A, 0xFB, 0xF1, 0xED, 0x0B, 0x88, 0x8F, 0x54, - 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, - 0x13, 0x81, 0x50, 0xF4, 0x5E, 0xB8, 0xCA, 0x78, 0xBF, 0xB8, 0xFD, 0xAE, 0xE0, 0x8F, 0x07, 0x00, - 0x00, 0x80, 0xFC, 0x9D, 0xDB, 0x7D, 0xD5, 0x50, 0xCD, 0x9B, 0xAF, 0xC2, 0xF8, 0x88, 0x06, 0xC8, - 0x8F, 0x66, 0x10, 0x1F, 0xA9, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, - 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x60, 0x8A, 0xE6, 0x1D, 0xBF, 0x6D, 0x43, 0xF0, 0xC7, - 0x03, 0x00, 0x00, 0x40, 0xFE, 0xCE, 0xED, 0xB8, 0x6C, 0x6C, 0xF2, 0xF6, 0xE3, 0x02, 0x79, 0xFB, - 0xF1, 0x76, 0xE4, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, - 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x06, 0x53, 0x35, 0xDE, 0x84, 0x05, 0x00, - 0x00, 0x0A, 0x75, 0x76, 0xDB, 0xFC, 0xE0, 0xF6, 0xC3, 0xC6, 0x87, 0x78, 0xF6, 0xE3, 0xED, 0x1F, - 0x4C, 0xDE, 0x7E, 0x10, 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, - 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0xA3, 0x60, 0x2A, 0xE7, 0x1D, 0xBD, 0x79, 0x3C, 0xF8, - 0xE3, 0x01, 0x00, 0x00, 0x20, 0x5F, 0x66, 0xA8, 0x7F, 0xF6, 0xD9, 0xCD, 0x97, 0x04, 0xF1, 0x51, - 0x7B, 0xFB, 0x71, 0x2A, 0xBC, 0xFD, 0xF8, 0x66, 0xE5, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, - 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x04, - 0x53, 0xBE, 0x97, 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x8C, 0xB3, 0x43, 0x4B, 0x07, 0xDE, - 0xDD, 0xF8, 0xE1, 0x6A, 0x80, 0x9C, 0xB6, 0x01, 0x52, 0xF3, 0xEC, 0xC7, 0xF7, 0x2B, 0xB7, 0x1F, - 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, - 0xF0, 0xDF, 0xE9, 0x89, 0x10, 0xE8, 0xD4, 0xC6, 0x96, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x0C, - 0x1B, 0x20, 0xEB, 0x27, 0x06, 0xDF, 0x57, 0x73, 0xFB, 0x11, 0x7D, 0xFE, 0xC3, 0xDD, 0x7E, 0x10, - 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, - 0x7F, 0xA7, 0x27, 0x22, 0xA0, 0x93, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0x63, - 0x02, 0x00, 0x00, 0x20, 0x3F, 0xEF, 0xEE, 0x59, 0x3A, 0xE8, 0xDF, 0x7E, 0x88, 0xF8, 0x70, 0xB7, - 0x1F, 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, - 0xF2, 0xF0, 0xDF, 0xE9, 0x89, 0x00, 0xE8, 0xF4, 0xDC, 0x3F, 0x17, 0x27, 0x6E, 0x5B, 0x1F, 0xFC, - 0x31, 0x01, 0x00, 0x00, 0x90, 0x9F, 0x89, 0x6D, 0x8B, 0x47, 0xEB, 0xDE, 0x7C, 0x15, 0xDE, 0x7E, - 0xDC, 0x4D, 0x7C, 0x34, 0x9F, 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xE9, 0x65, - 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xE2, 0xF0, 0xDF, 0x25, 0xF3, 0x8E, 0xAF, 0xE5, 0x4D, 0x58, 0x00, - 0x00, 0x20, 0x7F, 0x13, 0x5B, 0xFA, 0xC6, 0xE5, 0xC3, 0xE7, 0xF7, 0xBB, 0x6F, 0xBD, 0x22, 0x3E, - 0x1A, 0x4F, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, - 0x4E, 0x4F, 0x1F, 0xFC, 0xBB, 0x65, 0xDE, 0xD1, 0x9B, 0x4F, 0x06, 0x7F, 0x4C, 0x00, 0x00, 0x00, - 0xE4, 0xC3, 0x0C, 0xF5, 0xCF, 0x7A, 0xF7, 0x99, 0x39, 0x95, 0xF8, 0xB0, 0x8B, 0x3E, 0x7C, 0xFE, - 0xD6, 0x5F, 0x11, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, - 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFD, 0x5D, 0xB5, 0x97, 0x56, 0x9A, 0xE0, 0x8F, 0x0A, - 0x00, 0x00, 0x80, 0x7C, 0xB8, 0x37, 0x60, 0x4D, 0x6C, 0xFC, 0x98, 0x0D, 0x90, 0x0B, 0xCC, 0xE9, - 0x47, 0xEC, 0xDC, 0xED, 0x87, 0x0B, 0x90, 0xFB, 0x6D, 0x80, 0x10, 0x1F, 0x0D, 0xA6, 0xC2, 0x21, - 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xFB, - 0xDD, 0x38, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x7C, 0xDD, 0xC4, 0x13, 0x1F, - 0x30, 0xA7, 0xFD, 0x00, 0x09, 0xBE, 0xFD, 0xEA, 0xE1, 0x99, 0xFE, 0xED, 0x07, 0xF1, 0xA1, 0xA6, - 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, - 0x0E, 0xFA, 0xDD, 0x3A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x74, 0x7D, 0x78, - 0xFB, 0x71, 0xCA, 0xCD, 0xDD, 0x7E, 0x7C, 0x67, 0x06, 0xF1, 0x21, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, - 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF9, 0xDD, 0x3C, - 0xF7, 0xCF, 0x3D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x79, 0x9A, 0xD8, 0x79, 0xD5, 0x68, 0xF5, 0xDB, - 0xAF, 0xDC, 0x0D, 0x88, 0x7B, 0xF6, 0xE3, 0x6B, 0xC4, 0x47, 0xFD, 0x54, 0x38, 0xE4, 0x31, 0x15, - 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, 0x01, 0xBF, 0x07, 0xC6, - 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xAE, 0x26, 0xB6, 0x5D, 0x76, 0xB2, 0x7A, 0x03, 0xF2, 0xF0, 0x0C, - 0xF3, 0xF6, 0x7D, 0xC1, 0xED, 0x87, 0x8D, 0x8F, 0x3F, 0x10, 0x1F, 0xC1, 0x54, 0x38, 0xE4, 0x31, - 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0xE1, 0xBE, 0x17, - 0xE6, 0x1D, 0x59, 0x33, 0x16, 0xFC, 0x71, 0x01, 0x00, 0x00, 0xD0, 0xBE, 0x09, 0xFF, 0x0D, 0x58, - 0x93, 0xB7, 0x1F, 0x6F, 0x7E, 0x6D, 0xF2, 0xE6, 0xE3, 0x0D, 0xE2, 0xC3, 0x4E, 0x85, 0x43, 0x1E, - 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xEC, 0x7B, - 0x66, 0x47, 0x6E, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x20, 0x1F, 0x13, 0x43, 0xD7, 0x2F, 0x99, 0x78, - 0xFA, 0x13, 0xE6, 0xCC, 0xA3, 0x95, 0xCF, 0xFF, 0x70, 0xB7, 0x1F, 0x95, 0xF8, 0xB8, 0xC0, 0xBF, - 0xF9, 0x78, 0x83, 0xF8, 0x28, 0x68, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, - 0xDF, 0xE9, 0x89, 0x03, 0x7D, 0xAF, 0xED, 0xA5, 0x7E, 0xF7, 0x20, 0xFA, 0x92, 0xE0, 0x8F, 0x0D, - 0x00, 0x00, 0x80, 0xEC, 0xCE, 0x0C, 0x2D, 0x5B, 0x3B, 0xF1, 0xE4, 0x87, 0x2B, 0x9F, 0x01, 0xF2, - 0x60, 0xE5, 0xB5, 0xBB, 0xD5, 0xDB, 0x8F, 0xAF, 0xD9, 0xF8, 0xF8, 0x47, 0xE2, 0x23, 0xFF, 0xA9, - 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF3, 0xBD, 0x38, - 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x03, 0x00, 0x00, 0x20, 0x3B, 0xF7, 0x06, - 0xAC, 0x89, 0xC7, 0x2F, 0xF2, 0x03, 0xE4, 0xED, 0x6F, 0x55, 0x9E, 0xFB, 0x20, 0x3E, 0xDC, 0x54, - 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, - 0x41, 0xBE, 0x57, 0xE7, 0xBE, 0x26, 0x78, 0x13, 0x16, 0x00, 0x00, 0xC8, 0xC3, 0xD9, 0x5D, 0xD7, - 0x0C, 0x4E, 0x3C, 0x36, 0xC3, 0x9C, 0x71, 0xCF, 0x7E, 0x04, 0x6F, 0xBD, 0xFA, 0xC3, 0x7A, 0xE2, - 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, - 0xF1, 0x3D, 0xBB, 0xF9, 0xFE, 0xBC, 0xE3, 0xB7, 0x0D, 0x05, 0x7F, 0x6C, 0x00, 0x00, 0x00, 0x64, - 0xF7, 0xEE, 0xB6, 0xC5, 0xA3, 0x13, 0x8F, 0xCF, 0x30, 0xEF, 0x7C, 0xBB, 0x72, 0xFB, 0xF1, 0xE6, - 0x5F, 0x5D, 0x44, 0x7C, 0x14, 0x32, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, - 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x57, 0x89, 0x0F, 0x3F, 0x40, 0x8E, 0xDC, 0xCC, 0x9B, 0xB0, - 0x00, 0x00, 0x40, 0xFB, 0xCE, 0x6D, 0x5F, 0x60, 0x26, 0x1E, 0xB9, 0xC0, 0xBC, 0xE5, 0x5E, 0xBB, - 0xFB, 0xD7, 0xC4, 0x47, 0x31, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, - 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0xE1, 0xEF, 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, - 0x00, 0xB4, 0xC7, 0x0C, 0x5D, 0x3B, 0xFB, 0xDC, 0xB6, 0x4B, 0xCD, 0x3B, 0xDF, 0xB4, 0x01, 0xF2, - 0x75, 0xE2, 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, - 0xA7, 0x0E, 0xF1, 0xBD, 0xBA, 0x58, 0x7C, 0xB8, 0xBD, 0xB4, 0xC2, 0x98, 0x97, 0xBF, 0x38, 0x3B, - 0xF8, 0xE3, 0x03, 0x00, 0x00, 0x20, 0xBD, 0xB3, 0xFB, 0x97, 0x0E, 0xBC, 0xFB, 0xD8, 0x87, 0xCC, - 0xDB, 0x77, 0x5F, 0x64, 0xCE, 0x13, 0x1F, 0x05, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, - 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x89, 0xF8, 0x70, 0x7B, 0xE1, 0x6A, 0x63, - 0x8E, 0xDD, 0x36, 0x10, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDE, 0x99, 0x5D, 0x9F, 0xBB, 0xEB, - 0xD4, 0x86, 0x0F, 0x98, 0xF3, 0xFF, 0x44, 0x7C, 0xE4, 0x3F, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, - 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x27, 0xC2, 0x23, 0x98, 0xF7, 0xAF, - 0x4B, 0xCC, 0xE9, 0x9F, 0xDD, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x76, 0xAF, 0x3D, 0x70, 0xED, - 0x86, 0xF1, 0xDD, 0xAB, 0xCD, 0xD9, 0x17, 0xBF, 0x44, 0x7C, 0xE4, 0x3A, 0x15, 0x09, 0x45, 0x4D, - 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0xA7, 0xC3, 0xC3, 0xED, - 0xD4, 0xB3, 0xF3, 0xCC, 0xEF, 0x77, 0xCC, 0x31, 0xBF, 0xDB, 0x77, 0xD3, 0x60, 0xF0, 0xC7, 0x07, - 0x00, 0x00, 0x40, 0x7A, 0xAF, 0xEF, 0xB9, 0x75, 0xF8, 0xF7, 0x07, 0x6F, 0x35, 0xBF, 0xDF, 0xB7, - 0xD2, 0xBC, 0x79, 0xE0, 0x32, 0x73, 0xFE, 0x9F, 0x55, 0x54, 0x24, 0x9D, 0x08, 0x87, 0x3C, 0x26, - 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, - 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0x4E, 0x87, 0xC7, 0x99, 0xBF, 0xEB, 0x33, 0xE3, 0xBB, - 0xE6, 0x9A, 0xDF, 0x6D, 0xB3, 0xF1, 0xE1, 0xB6, 0x67, 0x39, 0xAF, 0xE2, 0x05, 0x00, 0x00, 0xD9, - 0xFD, 0xF3, 0xFF, 0xFE, 0x17, 0x17, 0xFE, 0x76, 0xFB, 0xEA, 0xFB, 0x7E, 0xB7, 0x6D, 0xF1, 0x5B, - 0xBF, 0xDF, 0xB9, 0xD8, 0xB8, 0xBD, 0x7D, 0xE8, 0x72, 0xFF, 0x5B, 0x2D, 0x74, 0x64, 0x34, 0x9A, - 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, - 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0xAE, 0x3E, 0x3C, 0xCE, 0xFE, - 0x43, 0x9F, 0x79, 0x73, 0xEF, 0x64, 0x78, 0xBC, 0xBE, 0x75, 0xCE, 0xF8, 0xEF, 0xB6, 0x5D, 0xBA, - 0x7E, 0xB4, 0xFF, 0x3D, 0x7F, 0x14, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDD, 0x7F, 0xBF, 0xFB, - 0x33, 0x17, 0xBF, 0xB6, 0x79, 0xF1, 0x96, 0x30, 0x42, 0xC6, 0x77, 0x2F, 0x36, 0xA7, 0xFF, 0xC6, - 0x1E, 0xD4, 0x65, 0x6C, 0xC4, 0x27, 0xC2, 0x21, 0x8F, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, - 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, 0xDF, - 0xAB, 0xAB, 0x0D, 0x8F, 0xF3, 0xFF, 0x34, 0xDF, 0xBC, 0xB5, 0x3F, 0x72, 0xE3, 0x61, 0xF7, 0xEA, - 0x33, 0x73, 0x7E, 0x34, 0x3E, 0xF4, 0xA9, 0x59, 0xC1, 0x1F, 0x17, 0x00, 0x00, 0x00, 0xF9, 0xF9, - 0xEF, 0xDF, 0x5D, 0xF2, 0x99, 0xD7, 0xB6, 0x2C, 0xFA, 0x59, 0x18, 0x22, 0x6F, 0xEC, 0xB9, 0xCC, - 0x4C, 0xFC, 0xBD, 0x0B, 0x02, 0x15, 0x1E, 0x6E, 0xB1, 0x68, 0xC8, 0x6B, 0x32, 0x1C, 0xF2, 0x98, - 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, - 0x3A, 0xC4, 0xF7, 0xEA, 0x26, 0xC3, 0xC3, 0xFB, 0xE7, 0xF9, 0xE6, 0x9D, 0x91, 0x79, 0x35, 0xE1, - 0xF1, 0xDA, 0xE6, 0x4B, 0xF7, 0x8F, 0x6F, 0xE9, 0xE3, 0xB5, 0xBB, 0x00, 0x00, 0xA0, 0x78, 0xFF, - 0xEB, 0xA1, 0xCB, 0xBE, 0xF8, 0xBB, 0x6D, 0x8B, 0x7E, 0x19, 0x86, 0x88, 0x7B, 0x3E, 0xE4, 0xEC, - 0x4F, 0x5D, 0x1C, 0x10, 0x1F, 0xF5, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, - 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0x51, 0x7D, 0xC0, 0x3C, 0x08, 0x8F, 0xD7, - 0xB7, 0x5E, 0x3A, 0xF6, 0xDA, 0x96, 0x4B, 0x79, 0xDD, 0x2E, 0x00, 0x00, 0x98, 0x5A, 0xA3, 0xFD, - 0xFD, 0x7F, 0xF4, 0xAB, 0x27, 0x2E, 0xFB, 0x3F, 0xA2, 0xCF, 0x87, 0xBC, 0x35, 0xEC, 0x1E, 0x54, - 0x17, 0xD1, 0x90, 0xD7, 0x64, 0x38, 0xE4, 0x31, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, - 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x55, 0xC2, 0x23, 0xFE, - 0x80, 0xB9, 0x8D, 0x8E, 0x5F, 0xBE, 0xBE, 0x7D, 0xEE, 0xBA, 0xE0, 0x8F, 0x00, 0x00, 0x00, 0x80, - 0xCE, 0xF8, 0xD5, 0x23, 0x57, 0x7E, 0xE0, 0x37, 0x4F, 0x2E, 0xDE, 0x30, 0x19, 0x22, 0x8B, 0xCC, - 0xE9, 0xBF, 0xB9, 0xCC, 0x78, 0xFF, 0x2A, 0x02, 0xA2, 0x9D, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, - 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, - 0xDF, 0xAB, 0x6B, 0xFC, 0x80, 0x39, 0xCF, 0x79, 0x00, 0x00, 0x80, 0xAE, 0x72, 0xF2, 0x91, 0xC5, - 0xF3, 0x5F, 0x7D, 0x66, 0xF1, 0x0E, 0x17, 0x20, 0x6E, 0xE3, 0xBB, 0x17, 0x99, 0x33, 0x7F, 0x67, - 0x0F, 0xE2, 0x2A, 0x26, 0xD2, 0x4E, 0x86, 0x43, 0x1E, 0x8B, 0x47, 0x43, 0x5E, 0x53, 0x91, 0x50, - 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x73, 0xEA, 0x01, - 0xF3, 0xDF, 0x6D, 0xBD, 0x74, 0xF0, 0xBF, 0x7D, 0x67, 0xDE, 0x07, 0x82, 0x2F, 0x73, 0x00, 0x00, - 0x80, 0xEE, 0xF3, 0xAB, 0x8D, 0x8B, 0xD6, 0xBC, 0xFA, 0xCC, 0xC2, 0x9F, 0x87, 0x21, 0xF2, 0xC6, - 0x9E, 0xC5, 0xE6, 0xDD, 0x7F, 0xB0, 0x87, 0x7D, 0x15, 0x16, 0x49, 0x26, 0xC3, 0x21, 0x8F, 0xA9, - 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, - 0x83, 0x7C, 0xAF, 0xCD, 0xFB, 0xE7, 0x05, 0x75, 0x0F, 0x98, 0xDB, 0x8D, 0xFE, 0x7F, 0x8F, 0x5E, - 0x3A, 0x27, 0xF8, 0xB2, 0x06, 0x00, 0x00, 0xE8, 0x6E, 0xFE, 0xF3, 0x21, 0x83, 0x8B, 0xFF, 0xE2, - 0x77, 0xDB, 0x16, 0xFE, 0x32, 0x0C, 0x91, 0x37, 0x0F, 0x2C, 0x36, 0x67, 0x7F, 0x6A, 0x0F, 0xFE, - 0x2A, 0x32, 0x1A, 0x4D, 0x86, 0x43, 0x1E, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, - 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x87, 0xF9, 0x5E, 0xDB, 0xE9, 0xBF, 0xE9, 0xAB, - 0x79, 0xC0, 0xFC, 0xB5, 0x67, 0xE6, 0x1C, 0xE3, 0x01, 0x73, 0x00, 0x00, 0xD0, 0xB3, 0x6C, 0x88, - 0xFC, 0xBB, 0x57, 0x37, 0x2F, 0xBA, 0xE7, 0x77, 0xDB, 0x16, 0xBD, 0x15, 0x86, 0xC8, 0xDB, 0x87, - 0x12, 0x3E, 0xA8, 0x2E, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, - 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xC3, 0x7C, 0x2F, 0x6D, 0xE2, 0xEF, 0xE7, 0xF3, - 0x80, 0x39, 0x00, 0x00, 0x28, 0xAF, 0x93, 0xF7, 0x2E, 0xFC, 0xC8, 0x2B, 0x9B, 0x16, 0x3F, 0x1A, - 0x46, 0x88, 0x7B, 0x3E, 0xA4, 0xE9, 0x83, 0xEA, 0x32, 0x1C, 0xF2, 0x98, 0x0A, 0x87, 0x3C, 0xA6, - 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x3E, 0xD0, 0xF7, 0xCA, - 0xCE, 0xFE, 0xC3, 0x7C, 0xF3, 0xE6, 0x5E, 0xF7, 0xED, 0x56, 0x95, 0xF8, 0xE0, 0x01, 0x73, 0x00, - 0x00, 0x50, 0x6A, 0xFF, 0xE3, 0xFE, 0xCF, 0x2C, 0x7A, 0x75, 0xF3, 0xA2, 0xE7, 0xA2, 0x21, 0x32, - 0xF1, 0xF7, 0x36, 0x0C, 0x88, 0x8F, 0x84, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, - 0x7D, 0xA8, 0xEF, 0x85, 0x9D, 0xFF, 0xA7, 0x05, 0xE6, 0xED, 0x83, 0x7D, 0x41, 0x78, 0x04, 0x37, - 0x1F, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0xA6, 0x8B, 0x5F, 0x3E, 0xB6, 0xF8, 0x96, 0xD7, 0xB7, 0x2E, - 0x7C, 0x39, 0x0C, 0x11, 0xF7, 0xA0, 0xBA, 0xFF, 0x7C, 0x88, 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, - 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xF6, - 0xDD, 0x3E, 0xF7, 0x80, 0xF9, 0xA9, 0x67, 0xA3, 0xE1, 0xE1, 0xC7, 0x07, 0x0F, 0x98, 0x03, 0x00, - 0x80, 0xE9, 0xC7, 0x3D, 0xA8, 0xFE, 0xDB, 0xA7, 0x17, 0x7F, 0xF5, 0xF5, 0xAD, 0x8B, 0x7E, 0xE3, - 0x22, 0xE4, 0x77, 0x3B, 0x16, 0x9A, 0x37, 0xF7, 0x2F, 0x32, 0xE7, 0xFE, 0xD1, 0x1D, 0xEC, 0x55, - 0x44, 0x64, 0x5D, 0x3C, 0x1A, 0xF2, 0x9A, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, - 0xFC, 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xED, 0xAB, 0x3C, 0x60, 0x3E, 0x19, 0x1E, 0xAF, 0x3D, 0x33, - 0x97, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x7E, 0xF5, 0xC8, 0xBC, 0x0F, 0xFC, 0xE6, 0xE9, 0x85, 0xF7, - 0xBD, 0xBE, 0x75, 0xC1, 0x5B, 0x2E, 0x42, 0xDC, 0xDE, 0x1E, 0x59, 0x6C, 0xBC, 0x7F, 0x51, 0x31, - 0x91, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, - 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xCD, 0xAB, 0x3C, 0x60, 0x1E, 0x3E, 0xE7, 0x61, 0xC3, 0x63, 0xCB, - 0x5C, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x88, 0x1B, 0xFB, 0x4F, 0x9F, 0xB9, 0xF8, 0x95, 0xCD, 0x0B, - 0xB7, 0x84, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCD, 0xA9, 0xE7, 0xDA, 0x09, 0x11, 0x15, 0x0E, 0x79, - 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC0, 0xEF, - 0xD6, 0xD5, 0x3E, 0x60, 0x3E, 0xD7, 0xBC, 0xBE, 0x75, 0xEE, 0xB8, 0xFD, 0x91, 0x07, 0xCC, 0x01, - 0x00, 0x00, 0x9A, 0xF9, 0x9F, 0x0F, 0x2D, 0x5A, 0xFA, 0xEA, 0xE6, 0x85, 0x3F, 0x0B, 0x43, 0x64, - 0x7C, 0x68, 0x91, 0x39, 0x33, 0xEA, 0x0E, 0xFE, 0x2A, 0x32, 0x1A, 0x2D, 0x1E, 0x0D, 0x79, 0x4D, - 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC8, 0xEF, 0xC6, - 0xD5, 0x3F, 0x60, 0x6E, 0xB7, 0x75, 0x0E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA4, 0xF1, 0xBF, 0x1E, - 0x5A, 0xF0, 0xC5, 0xD7, 0xB6, 0x2E, 0xF8, 0x65, 0x18, 0x22, 0x6F, 0xEC, 0x5D, 0x64, 0xCE, 0xFE, - 0xC4, 0x45, 0x80, 0x0A, 0x8E, 0xE8, 0xE2, 0xD1, 0x90, 0xD7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, - 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x07, 0xFD, 0x6E, 0x9B, 0x7E, 0xC0, 0x7C, 0x2E, 0x0F, - 0x98, 0x03, 0x00, 0x00, 0x64, 0xE5, 0x1E, 0x54, 0xFF, 0xF5, 0xC6, 0x45, 0x7F, 0x19, 0x7D, 0x3E, - 0xC4, 0x3D, 0xA8, 0x7E, 0xFE, 0x67, 0x2A, 0x3C, 0xDC, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, - 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0x61, 0xBF, 0xDB, 0xC6, 0x03, 0xE6, - 0x00, 0x00, 0x00, 0x05, 0x72, 0x0F, 0xAA, 0xFF, 0xFA, 0xC9, 0x85, 0x1B, 0xC2, 0x08, 0x71, 0x7B, - 0xE7, 0x70, 0xFC, 0xF9, 0x10, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, - 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xD8, 0xEF, 0xA6, 0xF1, 0x80, 0x39, 0x00, 0x00, 0xC0, 0x14, - 0x3A, 0xF9, 0xC8, 0xE2, 0xF9, 0xBF, 0xDD, 0xB4, 0x60, 0x47, 0x18, 0x21, 0xE1, 0x83, 0xEA, 0x3A, - 0x1C, 0xF2, 0x58, 0x3C, 0x10, 0x8A, 0x9C, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, - 0x03, 0x7F, 0xB7, 0x8C, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x3A, 0xE8, 0x57, 0x1B, 0x17, 0xAD, 0x79, - 0x65, 0xD3, 0x82, 0x9F, 0x57, 0x42, 0x64, 0x81, 0x19, 0x1F, 0x5A, 0x68, 0xCE, 0x8C, 0xBA, 0x43, - 0xBC, 0x8A, 0x88, 0xAC, 0x8B, 0x07, 0x42, 0x91, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, - 0x3D, 0x7D, 0xE8, 0xEF, 0x86, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x40, 0x97, 0xA8, 0x7C, 0x90, 0xE1, - 0xC2, 0xAF, 0xBE, 0xB6, 0x75, 0xFE, 0x2F, 0x5D, 0x84, 0xB8, 0xBD, 0xB9, 0x7F, 0xA1, 0x39, 0xFB, - 0x13, 0x77, 0xA0, 0x57, 0x41, 0x91, 0x66, 0xF1, 0x40, 0x28, 0x72, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, - 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFE, 0x9D, 0x5E, 0xA3, 0x07, 0xCC, 0x4F, 0x7E, 0xE7, 0x53, 0xF3, - 0x83, 0x2F, 0x01, 0x00, 0x00, 0x00, 0x74, 0xC2, 0x60, 0xFF, 0xA7, 0xFE, 0xDD, 0xAB, 0x9B, 0x16, - 0xDC, 0xF3, 0xFA, 0xD6, 0xF9, 0x6F, 0x85, 0x21, 0xF2, 0xF6, 0x88, 0x7B, 0x50, 0x5D, 0x85, 0x45, - 0x92, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFF, - 0x9D, 0x9E, 0x7A, 0xC0, 0xFC, 0xB7, 0x1B, 0xE7, 0xDE, 0x10, 0xFC, 0x23, 0x0F, 0x00, 0x00, 0x80, - 0x6E, 0xF0, 0xFF, 0x7E, 0x63, 0xF1, 0x87, 0x7F, 0xF3, 0xD4, 0x82, 0x47, 0xC3, 0x08, 0x71, 0x3B, - 0xF5, 0xDC, 0x22, 0xE3, 0xFD, 0x8B, 0x8A, 0x8C, 0x46, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, - 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xFE, 0x3B, 0xB9, 0xF8, 0x03, 0xE6, 0xEE, 0x39, 0x8F, - 0x57, 0x9F, 0xBE, 0xF4, 0x3F, 0x06, 0xFF, 0x88, 0x03, 0x00, 0x00, 0xA0, 0x1B, 0xFD, 0x8F, 0xFB, - 0x17, 0x2C, 0x7A, 0x75, 0xF3, 0x82, 0x9F, 0x85, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCC, 0xE9, 0xBF, - 0x75, 0x07, 0x61, 0x15, 0x1C, 0xD1, 0xA9, 0x48, 0x28, 0x6A, 0xB1, 0x03, 0x7A, 0x99, 0x27, 0x0F, - 0xFF, 0x9D, 0x9E, 0x0E, 0x80, 0x4E, 0xAD, 0xEE, 0x01, 0xF3, 0xCD, 0x73, 0xDE, 0xB2, 0x3F, 0xF2, - 0x80, 0x39, 0x00, 0x00, 0x40, 0x2F, 0xF9, 0xE5, 0xC3, 0xF3, 0x6F, 0x79, 0x75, 0xCB, 0x82, 0x97, - 0xC3, 0x10, 0x71, 0x0F, 0xAA, 0x4F, 0xFC, 0x57, 0x77, 0xF8, 0x27, 0x3E, 0xA6, 0x6C, 0xF2, 0xF0, - 0xDF, 0xE9, 0xE9, 0x08, 0xE8, 0xC4, 0x1A, 0x3D, 0x60, 0x3E, 0xBE, 0xA5, 0x6F, 0x76, 0xF0, 0x8F, - 0x31, 0x00, 0x00, 0x00, 0x7A, 0x49, 0xF8, 0xA0, 0x7A, 0xF4, 0xF9, 0x10, 0xF7, 0xA0, 0xFA, 0xB9, - 0x7F, 0x74, 0x21, 0x40, 0x7C, 0x14, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x74, 0x08, 0x4C, 0xF5, 0x1A, - 0x3D, 0x60, 0xFE, 0xEB, 0xC7, 0x3E, 0x7D, 0x55, 0xF0, 0x8F, 0x2E, 0x00, 0x00, 0x00, 0x7A, 0x99, - 0xFB, 0x20, 0xC3, 0xDF, 0x6C, 0x9C, 0x7F, 0x5F, 0xED, 0x83, 0xEA, 0x0B, 0xCD, 0xF9, 0x9F, 0xA9, - 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x63, 0x60, 0xAA, 0x17, - 0x7F, 0xC0, 0xFC, 0xF5, 0x6D, 0x73, 0x4E, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x40, 0x49, 0xFD, 0xDB, - 0x83, 0x7D, 0x7D, 0xAF, 0x6C, 0x5E, 0xB0, 0xA5, 0x12, 0x21, 0xF3, 0xCD, 0xEF, 0x77, 0xCD, 0x37, - 0xA7, 0x9E, 0x5B, 0x68, 0xBC, 0x7F, 0x51, 0xC1, 0x90, 0xE7, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, - 0xFF, 0x4E, 0x4F, 0xC7, 0xC0, 0x54, 0x8E, 0x07, 0xCC, 0x01, 0x00, 0x00, 0xA6, 0xB1, 0xFF, 0xF9, - 0xD0, 0xBC, 0xA5, 0xAF, 0x6E, 0xEE, 0xFB, 0x99, 0x8B, 0x90, 0x30, 0x44, 0xCE, 0x8C, 0xBA, 0x03, - 0xB4, 0x8A, 0x87, 0x76, 0x17, 0x3B, 0xA0, 0x97, 0x79, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x20, 0x98, - 0xAA, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xAA, 0x7E, 0xF5, 0x58, 0xDF, 0x5F, 0x54, 0x3E, 0xC8, - 0xB0, 0x12, 0x22, 0xE3, 0x43, 0xF6, 0xC0, 0xF8, 0x13, 0x77, 0x98, 0x56, 0x21, 0x91, 0x65, 0xB1, - 0x03, 0x7A, 0x99, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x82, 0xA9, 0x18, 0x0F, 0x98, 0x03, 0x00, - 0x00, 0x40, 0x72, 0x0F, 0xAA, 0xFF, 0x7A, 0x63, 0xDF, 0x5F, 0xBE, 0xBE, 0xB5, 0xEF, 0xAD, 0x30, - 0x44, 0xDE, 0xDC, 0x6F, 0x0F, 0x90, 0x6D, 0x3F, 0x1F, 0x22, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, - 0x77, 0x7A, 0x3A, 0x0C, 0x8A, 0x1E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x20, 0x11, 0xFF, 0x41, 0xF5, - 0xA7, 0xFA, 0x1E, 0x0D, 0x23, 0xC4, 0xCD, 0x3D, 0xA8, 0x9E, 0xED, 0xF9, 0x10, 0x71, 0x48, 0x2F, - 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x71, 0x50, 0xF4, 0xCE, 0xFC, 0xDD, 0x7C, 0x1E, 0x30, 0x07, - 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x41, 0xF5, 0x57, 0x9F, 0x99, 0x3F, 0x12, 0x46, 0x48, 0xFA, 0x07, - 0xD5, 0xC5, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x41, 0x91, 0x73, 0xCF, 0x79, - 0xF0, 0x80, 0x39, 0x00, 0x00, 0x00, 0xDA, 0xF2, 0xAB, 0x27, 0xFA, 0xD6, 0x44, 0x1F, 0x54, 0x77, - 0xCF, 0x87, 0xB4, 0x7E, 0x50, 0x3D, 0x76, 0x40, 0x2F, 0xF3, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x81, - 0x50, 0xD4, 0xCE, 0xFD, 0x94, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x90, 0xA3, 0xCA, 0x07, 0x19, 0xF6, - 0x7D, 0x35, 0xFA, 0xA0, 0xBA, 0x7B, 0x3E, 0x44, 0x3F, 0xA8, 0x1E, 0x3B, 0xA0, 0x97, 0x79, 0xF2, - 0xF0, 0xDF, 0xE9, 0xE9, 0x48, 0x28, 0x62, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x42, 0xB9, 0xE7, - 0x43, 0x5E, 0xDD, 0xD4, 0x77, 0x4F, 0xF4, 0x41, 0xF5, 0xB7, 0x0E, 0x46, 0x1F, 0x54, 0x17, 0x87, - 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0A, 0x79, 0x2F, 0x7C, 0xC0, 0x3C, 0xFA, 0x9C, - 0x87, 0x1D, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA0, 0x18, 0x47, 0xBF, 0xB1, 0xF8, 0xC3, 0xAF, 0x6C, - 0xEE, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0x3B, 0x87, 0xEC, 0xC1, 0xF4, 0x5F, 0xC4, 0x41, 0xBD, 0x8C, - 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x42, 0xDE, 0x53, 0x0F, 0x98, 0xFF, 0xFA, 0xE1, 0x4B, 0x6F, - 0x0E, 0xFE, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0x3F, 0xA8, 0xEE, 0x9E, 0x0F, 0xD9, 0xDE, - 0x67, 0xDC, 0x7E, 0xBF, 0xB3, 0xCF, 0x9C, 0x7A, 0xCE, 0x1E, 0x54, 0xD5, 0xA1, 0xBD, 0x2C, 0x93, - 0x87, 0xFF, 0x4E, 0xAF, 0x3E, 0x14, 0xF2, 0x9E, 0x7A, 0xC0, 0xFC, 0xD7, 0x83, 0x73, 0xFE, 0xB7, - 0xE0, 0x1F, 0x05, 0x00, 0x00, 0x00, 0x60, 0xEA, 0xFC, 0xF2, 0xE1, 0xB9, 0xB7, 0xBC, 0xB6, 0xB5, - 0xEF, 0x97, 0x61, 0x88, 0x8C, 0xEF, 0x9E, 0x6F, 0x26, 0xFE, 0xAB, 0x3D, 0x18, 0xAB, 0x03, 0x7C, - 0x2F, 0x4F, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0C, 0x79, 0x4D, 0x3D, 0x60, 0xFE, 0xDA, 0xA6, 0x39, - 0x77, 0xF3, 0x80, 0x39, 0x00, 0x00, 0x00, 0x3A, 0xCA, 0x7F, 0x50, 0xFD, 0xC9, 0xBE, 0xAF, 0xBE, - 0xBE, 0x65, 0xDE, 0x5B, 0x61, 0x88, 0xBC, 0xB9, 0x6F, 0xBE, 0x39, 0xFB, 0x13, 0x7B, 0x48, 0x56, - 0x87, 0xF9, 0x5E, 0x9B, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x1A, 0xF2, 0x98, 0x7A, 0xC0, 0xFC, 0xD5, - 0xCD, 0x73, 0x37, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xBA, 0x8A, 0x7B, 0x50, 0xFD, 0xB7, 0x9B, - 0xFA, 0xEE, 0x09, 0x23, 0xC4, 0xED, 0xED, 0x61, 0xF7, 0xA0, 0xBA, 0x38, 0xD4, 0xF7, 0xCA, 0xE4, - 0xE1, 0xBF, 0xD3, 0xD3, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0xC9, 0x3D, - 0x1F, 0xF2, 0xCA, 0xA6, 0xBE, 0x2D, 0xD1, 0x10, 0x71, 0xCF, 0x87, 0xF4, 0xDC, 0x83, 0xEA, 0xF2, - 0xF0, 0xDF, 0xE9, 0xE9, 0x78, 0x68, 0x77, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x9E, 0x57, 0xF9, - 0x20, 0xC3, 0x79, 0x35, 0x0F, 0xAA, 0x9F, 0xFE, 0x5B, 0x7B, 0xE0, 0x55, 0x87, 0xFD, 0x6E, 0x9B, - 0x3C, 0xFC, 0x77, 0x7A, 0xF5, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xA5, 0xF3, - 0xAB, 0xC7, 0xFA, 0xFE, 0x22, 0xFE, 0xA0, 0x7A, 0x57, 0x3F, 0x1F, 0x22, 0x0F, 0xFF, 0x9D, 0x9E, - 0x0E, 0x88, 0xAC, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0x94, 0x9A, 0x7B, 0x50, 0xFD, 0xB5, 0x2D, - 0xF3, 0xBE, 0x1E, 0x7F, 0x50, 0xFD, 0xDC, 0x3F, 0xDA, 0xC3, 0xB5, 0x8A, 0x80, 0x4E, 0x4D, 0x1E, - 0xFE, 0x3B, 0x3D, 0x1D, 0x11, 0x59, 0xC6, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x98, 0x56, 0xDC, 0x83, - 0xEA, 0xBF, 0x79, 0xAA, 0xEF, 0xC7, 0x61, 0x84, 0xB8, 0x75, 0xCD, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, - 0xE9, 0xE9, 0x90, 0x48, 0xBB, 0x46, 0x0F, 0x98, 0xBF, 0xB6, 0xE5, 0xD2, 0x81, 0xE0, 0x7F, 0x1A, - 0x00, 0x00, 0x00, 0xA0, 0xBC, 0xFC, 0x0F, 0x32, 0xDC, 0xD4, 0x37, 0x12, 0x46, 0x48, 0xF8, 0x41, - 0x86, 0x1D, 0x7B, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x13, 0x69, 0xA7, 0x1E, 0x30, 0x7F, - 0xE5, 0xC9, 0x39, 0xB7, 0x07, 0xFF, 0x53, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x87, 0x7B, 0x50, 0xFD, - 0xB5, 0x2D, 0xF3, 0x8E, 0x85, 0x21, 0xE2, 0x9E, 0x0F, 0x39, 0x33, 0x6A, 0x0F, 0xDF, 0x2A, 0x12, - 0x8A, 0x9A, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x26, 0xD2, 0x4C, 0x3D, 0x60, 0xFE, 0xCA, 0xA6, 0xB9, - 0xFF, 0x57, 0xF0, 0xB7, 0x1E, 0x00, 0x00, 0x00, 0x98, 0x9E, 0xC2, 0x0F, 0x32, 0x8C, 0x3E, 0xA8, - 0xFE, 0xC6, 0x9E, 0x29, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x14, 0x49, 0x17, 0x7F, - 0xC0, 0xDC, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x98, 0xF0, 0x83, 0x0C, 0xE3, 0x0F, 0xAA, - 0x17, 0xF6, 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2A, 0x92, 0x8C, 0x07, 0xCC, 0x01, 0x00, - 0x00, 0x80, 0x0C, 0x5E, 0x79, 0x72, 0xCE, 0xA5, 0xF1, 0x0F, 0x32, 0x74, 0x0F, 0xAA, 0xE7, 0xFA, - 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2C, 0x5A, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, - 0x1C, 0xFC, 0x7A, 0x63, 0xDF, 0x55, 0xAF, 0x6E, 0x9E, 0xF7, 0x4F, 0x61, 0x84, 0x84, 0x0F, 0xAA, - 0xCB, 0xA0, 0x48, 0x33, 0x79, 0xF8, 0xEF, 0xF4, 0xEA, 0xC3, 0x22, 0xC9, 0x78, 0xC0, 0x1C, 0x00, - 0x00, 0x00, 0xC8, 0xD9, 0x2F, 0x1F, 0x9E, 0x7B, 0x4B, 0xFC, 0x83, 0x0C, 0x33, 0x3F, 0xA8, 0x2E, - 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x8B, 0x66, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, 0x40, 0xFE, - 0x07, 0x19, 0x6E, 0xEE, 0xFB, 0x3F, 0xE3, 0xCF, 0x87, 0xA4, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, - 0x3D, 0x1D, 0x18, 0x8D, 0xA6, 0x1E, 0x30, 0xFF, 0xED, 0xC6, 0x4B, 0xBF, 0xC5, 0x03, 0xE6, 0x00, - 0x00, 0x00, 0x40, 0x01, 0xC2, 0x07, 0xD5, 0xC3, 0x08, 0x71, 0x7B, 0xEB, 0x40, 0x82, 0x07, 0xD5, - 0xE5, 0xE1, 0xBF, 0xD3, 0xD3, 0x91, 0xA1, 0xE6, 0x9E, 0xF3, 0x88, 0x3F, 0x60, 0xFE, 0xCA, 0x53, - 0x73, 0xB6, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x00, 0x30, 0x05, 0xDC, 0x07, 0x19, 0xBE, 0xBE, 0x75, - 0xDE, 0xFE, 0x68, 0x88, 0xBC, 0x73, 0xA8, 0xC1, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xD0, - 0x88, 0x4F, 0x3D, 0x60, 0xFE, 0xDA, 0xE6, 0x39, 0x3F, 0xE1, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, - 0x03, 0xDC, 0x07, 0x19, 0xC6, 0x1F, 0x54, 0x3F, 0xFD, 0xB7, 0xF6, 0xF0, 0x5E, 0x82, 0xF8, 0x70, - 0x0F, 0x98, 0xD7, 0x3C, 0xE7, 0xC1, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x40, 0x77, 0x88, 0x7F, 0x90, - 0xE1, 0xF8, 0xEE, 0x3E, 0x33, 0xF1, 0xF7, 0xEE, 0x20, 0xAF, 0x02, 0xA0, 0x93, 0xAB, 0x0F, 0x8D, - 0xF8, 0xDC, 0x03, 0xE6, 0x6F, 0x0C, 0xD5, 0x3F, 0x60, 0x3E, 0xDA, 0xFF, 0x9E, 0x3F, 0x0A, 0x7E, - 0xBB, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xCD, 0x7F, 0x50, 0x7D, 0xCB, 0xBC, 0xAF, 0x57, 0x1E, 0x54, - 0xB7, 0x07, 0x78, 0xBB, 0x37, 0xF7, 0xF5, 0xD9, 0x03, 0xBD, 0x3B, 0xD8, 0xAB, 0x18, 0x98, 0xEA, - 0xD5, 0xC7, 0x46, 0x74, 0xEE, 0x83, 0x04, 0x79, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xE8, 0x31, 0xEE, - 0x41, 0xF5, 0x57, 0x36, 0xCD, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0xDB, 0xC3, 0xF3, 0xED, 0x01, 0x5F, - 0x45, 0xC1, 0x54, 0x4D, 0x47, 0x87, 0x1B, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x00, 0x25, 0xF0, 0x6F, - 0x1B, 0xFA, 0xFA, 0x5E, 0xDB, 0x32, 0xF7, 0x27, 0x61, 0x84, 0xFC, 0x7E, 0xE7, 0x3C, 0x73, 0xEA, - 0xD9, 0xF9, 0xF6, 0xC0, 0xAF, 0x02, 0xA1, 0xC8, 0x35, 0x0E, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, - 0x00, 0x4A, 0xE6, 0x57, 0x4F, 0x5C, 0xBA, 0xC6, 0x86, 0xC8, 0xB1, 0x68, 0x88, 0x9C, 0xF9, 0x3B, - 0x17, 0x01, 0x2A, 0x16, 0xF2, 0x5E, 0x7D, 0x78, 0xB8, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0x50, - 0x62, 0xEE, 0x01, 0xEE, 0xDF, 0x3E, 0x39, 0xF7, 0xAB, 0xAF, 0x6F, 0x9B, 0x37, 0x1E, 0x86, 0x88, - 0x7B, 0x50, 0xBD, 0xD8, 0xE7, 0x43, 0xEA, 0xC3, 0x83, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x69, - 0xA4, 0xF2, 0x41, 0x86, 0x73, 0xEF, 0x79, 0x7D, 0xCB, 0xDC, 0x9A, 0x07, 0xD5, 0xCF, 0xFD, 0x34, - 0xEF, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, 0xA6, 0xB1, 0x57, 0x9E, 0x9C, - 0x73, 0xA9, 0x7A, 0x50, 0x3D, 0x9F, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, - 0xE0, 0x7B, 0x6D, 0x47, 0xDF, 0x40, 0xE5, 0x83, 0x0C, 0x27, 0x43, 0xE4, 0x8D, 0x3D, 0x7D, 0xFE, - 0x33, 0x22, 0xD9, 0xDE, 0x9A, 0x55, 0x79, 0xB8, 0xDC, 0x3D, 0xE3, 0x11, 0xBF, 0xF1, 0xE0, 0x01, - 0x73, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x57, 0x9E, 0x99, 0x73, 0xDB, 0xEB, 0xDB, 0xE7, 0x9E, 0x8C, - 0x86, 0x48, 0x18, 0x23, 0xEF, 0x1C, 0x9A, 0x6F, 0x4E, 0xFF, 0xCD, 0x7C, 0xFF, 0x79, 0x91, 0xF8, - 0x0D, 0x89, 0xFB, 0xFF, 0xDD, 0xBF, 0xEE, 0xFE, 0xFD, 0x77, 0x0E, 0xF5, 0xD5, 0x3C, 0xDF, 0x11, - 0xCE, 0x3D, 0x60, 0x6E, 0x7F, 0xEE, 0x75, 0xC1, 0x5F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xDC, - 0x1B, 0xB3, 0x5E, 0x79, 0x66, 0xEE, 0x70, 0x3C, 0x44, 0x5A, 0x2E, 0x16, 0x1D, 0x95, 0xCD, 0x19, - 0xFA, 0xF5, 0xA3, 0x97, 0xDE, 0x1C, 0xFC, 0xD4, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xB9, 0x87, 0xD5, - 0x7F, 0xB3, 0x71, 0xDE, 0x9D, 0xAF, 0x3E, 0x3D, 0xEF, 0xA1, 0x57, 0x37, 0xCF, 0x7D, 0x59, 0x46, - 0x47, 0xB8, 0x20, 0x38, 0x5E, 0xDB, 0x3C, 0xF7, 0xD8, 0xAB, 0xCF, 0xCC, 0x7D, 0xDA, 0xDD, 0x76, - 0xFC, 0xB7, 0xEF, 0xCC, 0xFB, 0x40, 0xF0, 0x53, 0x01, 0x00, 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x35, - 0xB9, 0xFE, 0x07, 0x1B, 0xEE, 0xE8, 0x1B, 0x88, 0xEF, 0xDF, 0x36, 0xCC, 0xEE, 0x0B, 0xFE, 0x63, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xD0, 0x15, 0xDE, 0xF3, 0x9E, 0xFF, 0x1F, 0x5B, 0xE2, 0x94, 0x1D, 0x86, - 0x86, 0x23, 0x09, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; - -static const uint8_t tree_gif[] PROGMEM = { - - 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x28, 0x00, 0x3C, 0x00, 0x83, 0x0B, 0x00, 0x00, 0xFF, 0xFF, - 0x00, 0x21, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x94, 0x00, 0x00, 0xB5, 0x00, 0x00, - 0xDE, 0x00, 0x00, 0xFF, 0x00, 0x6B, 0x00, 0x00, 0xFF, 0x33, 0x33, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x00, 0xCC, 0x00, 0x00, 0x21, 0xFF, 0x0B, - 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0xA0, 0x0F, 0x00, - 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, - 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, - 0x8C, 0xCA, 0xE8, 0x85, 0xE8, 0xA5, 0xAC, 0x67, 0xEA, 0x8A, 0xE5, 0x2B, 0x2F, 0xE3, 0x31, 0xCE, - 0xAF, 0x41, 0x1C, 0xB8, 0x1B, 0x24, 0x80, 0x04, 0xAF, 0x87, 0x02, 0x26, 0x88, 0xA1, 0x07, 0x60, - 0xB9, 0x44, 0x82, 0x04, 0x02, 0x80, 0x61, 0x30, 0x70, 0x6E, 0x0C, 0x86, 0x03, 0x60, 0x20, 0xB0, - 0x6A, 0xA8, 0xD3, 0x03, 0x21, 0xEC, 0xAD, 0x18, 0x12, 0xE8, 0xF4, 0xB1, 0x4C, 0x51, 0xA0, 0x07, - 0xEA, 0x07, 0x5B, 0xF2, 0x70, 0x13, 0x76, 0xD4, 0xA8, 0xBC, 0xBC, 0xEA, 0x1F, 0x06, 0x77, 0x51, - 0x73, 0x50, 0x0A, 0x80, 0x7F, 0x04, 0x4C, 0x4D, 0x65, 0x06, 0x0A, 0x3B, 0x3B, 0x62, 0x5A, 0x53, - 0x65, 0x05, 0x02, 0x04, 0x68, 0x0C, 0x6A, 0x00, 0x5D, 0x5E, 0x0F, 0x0F, 0x6A, 0x98, 0x6A, 0x09, - 0x7B, 0x56, 0x9D, 0x09, 0x0C, 0xA7, 0xA7, 0x7F, 0x06, 0x9D, 0xA3, 0x44, 0x02, 0x01, 0x03, 0x90, - 0x0C, 0x87, 0x03, 0x06, 0x02, 0x05, 0x56, 0x06, 0x01, 0x02, 0x53, 0xB1, 0xB3, 0x04, 0x79, 0xAF, - 0x55, 0x48, 0x51, 0xB0, 0x87, 0xC0, 0x7F, 0x07, 0x95, 0x05, 0x85, 0x44, 0xB6, 0x00, 0x05, 0x53, - 0x96, 0x6A, 0x60, 0x02, 0x0A, 0x48, 0x89, 0x00, 0x07, 0xA1, 0x69, 0x7D, 0x2B, 0x3D, 0x9D, 0x41, - 0xA1, 0x04, 0xA0, 0xDD, 0x9D, 0x38, 0x02, 0xE1, 0x6A, 0x07, 0x62, 0x0C, 0x77, 0xE6, 0xAD, 0x2F, - 0x05, 0x01, 0xB6, 0x90, 0x07, 0xA8, 0xA7, 0x54, 0xB5, 0xBC, 0x06, 0x33, 0x50, 0x53, 0x3A, 0x00, - 0x39, 0x62, 0x10, 0x6B, 0xDF, 0xBE, 0x19, 0x03, 0x18, 0x40, 0xA9, 0x15, 0x4B, 0xCC, 0x0E, 0x77, - 0x3B, 0x04, 0xC4, 0x02, 0x38, 0x43, 0x21, 0x96, 0x2C, 0xD3, 0xD6, 0x81, 0x01, 0x26, 0x2A, 0xFB, - 0xDE, 0x07, 0x7C, 0x0A, 0xB7, 0x71, 0x1B, 0x79, 0xEE, 0xC5, 0x83, 0x72, 0xDD, 0x84, 0xBC, 0x4B, - 0x13, 0xA4, 0x13, 0x15, 0x17, 0xAB, 0x18, 0x78, 0x4A, 0x43, 0x40, 0x81, 0x43, 0x76, 0x8E, 0xB6, - 0x04, 0x7C, 0x19, 0x02, 0x98, 0xC4, 0x86, 0x35, 0xBD, 0xE1, 0x1C, 0x90, 0x4D, 0x62, 0xBF, 0x14, - 0xFC, 0x7E, 0x02, 0x1A, 0x60, 0xD3, 0xD1, 0x9D, 0x3B, 0x3A, 0x09, 0xFC, 0x44, 0xB1, 0xD0, 0x96, - 0x8E, 0x43, 0x8D, 0x9E, 0xDA, 0xDB, 0x22, 0x11, 0x8A, 0x42, 0x10, 0x5C, 0x00, 0x1A, 0x2D, 0x38, - 0xF2, 0x0E, 0xA0, 0x4A, 0x03, 0x4E, 0xA2, 0xF0, 0xF4, 0x80, 0x17, 0x95, 0x8C, 0x23, 0xD1, 0xD8, - 0x12, 0x00, 0x92, 0x03, 0xAB, 0x99, 0x23, 0x71, 0x3E, 0x8D, 0xEB, 0x6E, 0x18, 0x07, 0x66, 0x23, - 0x05, 0x3E, 0x72, 0xE4, 0x06, 0x0D, 0x81, 0x02, 0xE4, 0x36, 0x5D, 0xD9, 0xA5, 0xC0, 0xAD, 0x59, - 0xA2, 0x86, 0x6E, 0xD6, 0xC4, 0x73, 0xEB, 0x15, 0xA5, 0xC5, 0xDE, 0x14, 0xF4, 0x62, 0x07, 0xC0, - 0xE9, 0x9D, 0xCC, 0x58, 0x02, 0x14, 0xA0, 0x84, 0x45, 0x83, 0x68, 0x7A, 0x8D, 0x81, 0x66, 0xC3, - 0xE9, 0xD0, 0xA6, 0x3E, 0x03, 0xF3, 0x80, 0x7D, 0x90, 0xD8, 0x58, 0xA2, 0x59, 0x2D, 0x90, 0x68, - 0xD6, 0x64, 0x17, 0x76, 0x5A, 0x23, 0xBF, 0x13, 0x58, 0x89, 0x7A, 0xC3, 0xF0, 0x8F, 0xB6, 0xB8, - 0x4B, 0xD3, 0x74, 0x52, 0x50, 0x92, 0xC2, 0x03, 0xD1, 0x78, 0xD7, 0x89, 0x4C, 0x23, 0x26, 0x6E, - 0x82, 0xCC, 0x15, 0x5E, 0x05, 0x08, 0x30, 0x06, 0x8A, 0x75, 0x64, 0xFA, 0x42, 0xF1, 0x12, 0xAD, - 0x60, 0xDE, 0x51, 0x0A, 0x94, 0xBA, 0x5E, 0x2C, 0x8C, 0x86, 0xDD, 0x3D, 0xDE, 0x8F, 0x0A, 0x70, - 0x51, 0x5F, 0xFE, 0xF2, 0x84, 0xD1, 0xD0, 0xA6, 0x68, 0xB7, 0x96, 0x62, 0x14, 0x0C, 0xC1, 0xB7, - 0x90, 0x68, 0x72, 0xD1, 0x7C, 0xD9, 0x3D, 0xA3, 0x94, 0x35, 0xDE, 0x54, 0x06, 0x92, 0x51, 0x50, - 0x68, 0xC2, 0xC5, 0x44, 0xB7, 0x30, 0x70, 0xDE, 0x6A, 0x49, 0x69, 0x86, 0xC5, 0x2D, 0xA3, 0x29, - 0x04, 0x05, 0x2F, 0xD9, 0xC4, 0x02, 0x0C, 0x6C, 0x0C, 0x48, 0xB0, 0x94, 0x01, 0xDA, 0x3C, 0xF2, - 0x56, 0x21, 0xFA, 0xE8, 0xA3, 0xA1, 0x55, 0x12, 0xE9, 0xF4, 0x56, 0x42, 0xF8, 0x50, 0x00, 0x40, - 0x08, 0x08, 0xD4, 0x88, 0x80, 0x05, 0x33, 0x66, 0x10, 0xA2, 0x0C, 0xDC, 0xA0, 0xB0, 0xA3, 0x0B, - 0x71, 0xCD, 0xB1, 0x80, 0x75, 0x69, 0x20, 0x41, 0xE4, 0x91, 0x6B, 0x64, 0x10, 0x01, 0x00, 0x21, - 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, 0x00, - 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, 0x8C, - 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0x31, 0x1C, 0x34, - 0x1B, 0x24, 0x4C, 0x82, 0xE7, 0x28, 0x5E, 0x02, 0x78, 0x7A, 0x30, 0x8E, 0x47, 0x62, 0x48, 0x20, - 0x60, 0xD8, 0x06, 0x4A, 0x8E, 0xC1, 0x70, 0x60, 0x0C, 0x04, 0xD1, 0xCD, 0x60, 0x60, 0x3B, 0x10, - 0xBA, 0x59, 0x8B, 0x21, 0x41, 0x2E, 0x0F, 0xC3, 0x16, 0xF2, 0xC0, 0xAC, 0x40, 0x4F, 0x1E, 0x80, - 0x04, 0x81, 0x70, 0xD8, 0x0A, 0x14, 0x0F, 0xF7, 0x42, 0x00, 0xA0, 0xD6, 0x09, 0x0A, 0x81, 0x81, - 0x68, 0x00, 0x85, 0x85, 0x7F, 0x07, 0x07, 0x0A, 0x06, 0x7A, 0x06, 0x00, 0x74, 0x74, 0x5E, 0x8A, - 0x36, 0x68, 0x05, 0x7C, 0x66, 0x3D, 0x64, 0x58, 0x61, 0x0F, 0x0F, 0x66, 0x64, 0x99, 0x64, 0x79, - 0x9C, 0x9E, 0xA0, 0x48, 0x4E, 0x9D, 0xA3, 0x4A, 0x02, 0x01, 0x37, 0x90, 0x55, 0x04, 0x5C, 0x02, - 0x05, 0x59, 0x06, 0x01, 0x02, 0x4F, 0x89, 0x55, 0x76, 0xAC, 0x50, 0xAB, 0x0A, 0xAD, 0x7F, 0xB1, - 0x75, 0x07, 0x02, 0x04, 0x05, 0x00, 0xBE, 0x39, 0x06, 0x77, 0x05, 0x36, 0x04, 0x9F, 0x5B, 0xCC, - 0x00, 0x4A, 0x82, 0x81, 0x07, 0x9F, 0x65, 0x86, 0x85, 0x40, 0x9D, 0x0A, 0x9F, 0x0C, 0xD0, 0x9F, - 0x00, 0x9D, 0x39, 0x02, 0xDE, 0x66, 0xB0, 0x73, 0xE2, 0x09, 0xE4, 0xAA, 0x2F, 0x05, 0x01, 0xCC, - 0x5E, 0xA7, 0x56, 0x75, 0xD2, 0xB8, 0x8C, 0x2F, 0x4C, 0x36, 0x06, 0xB1, 0x73, 0xE1, 0x88, 0xC9, - 0x92, 0x45, 0x43, 0x96, 0x00, 0x2E, 0x37, 0xE8, 0x79, 0x99, 0x53, 0xEC, 0x86, 0x0D, 0x06, 0x05, - 0xF3, 0x51, 0x61, 0x57, 0xE6, 0x9E, 0xBF, 0x35, 0x0C, 0xDE, 0x81, 0xE8, 0x64, 0x10, 0xFB, 0x5B, - 0xB6, 0x6C, 0xF5, 0x56, 0x94, 0x22, 0x13, 0xA7, 0xE2, 0x9C, 0x04, 0xDF, 0xCA, 0x74, 0xB2, 0xB2, - 0xC2, 0x40, 0x2A, 0x92, 0x72, 0x20, 0x45, 0x52, 0xE0, 0x45, 0x1A, 0x01, 0x2B, 0xCA, 0x3E, 0xC4, - 0x3A, 0x38, 0x60, 0xDB, 0x23, 0x86, 0xD6, 0x14, 0x0C, 0x20, 0xC0, 0x84, 0xCB, 0x8A, 0x7C, 0x3C, - 0x1F, 0x25, 0x94, 0xA9, 0x80, 0x21, 0x17, 0xA2, 0x5B, 0x4E, 0x34, 0x91, 0xE5, 0x2F, 0x99, 0x4C, - 0xA0, 0x89, 0xEC, 0x5C, 0xC1, 0xB5, 0x89, 0xC3, 0x15, 0x2B, 0xCC, 0x10, 0xD6, 0xF9, 0x38, 0x67, - 0xA8, 0xB1, 0x01, 0xE5, 0x40, 0xD4, 0x7B, 0x42, 0xF1, 0x63, 0x02, 0x66, 0x02, 0x12, 0xA4, 0xFA, - 0x90, 0x2A, 0x54, 0xB6, 0x44, 0xEB, 0xDA, 0x96, 0x19, 0x9A, 0x53, 0x43, 0x01, 0xBB, 0x64, 0x84, - 0xAE, 0xC3, 0xBB, 0xB0, 0xCC, 0x31, 0x40, 0x5D, 0x35, 0xD8, 0x62, 0x82, 0x6B, 0x68, 0xAC, 0xA6, - 0x43, 0xF1, 0xD2, 0x01, 0x20, 0xE9, 0x8A, 0x25, 0x05, 0x96, 0x36, 0xD8, 0x8A, 0xD7, 0xD8, 0x46, - 0xD0, 0x85, 0xEB, 0x7E, 0x72, 0x31, 0x10, 0x54, 0x9F, 0x85, 0x00, 0xF1, 0xA6, 0x1C, 0x94, 0x2C, - 0x34, 0xB2, 0x17, 0x9F, 0x5B, 0xB8, 0x14, 0x80, 0xFC, 0x41, 0x28, 0x63, 0xC7, 0x03, 0x9A, 0x4A, - 0x32, 0x9C, 0x2C, 0x2B, 0x2E, 0x40, 0x72, 0x63, 0x59, 0x48, 0x85, 0x47, 0x8D, 0xD8, 0xC8, 0xD9, - 0xE2, 0xF0, 0x55, 0x99, 0x4A, 0xE3, 0x82, 0x07, 0x41, 0x3F, 0x25, 0x92, 0xAE, 0xD7, 0x4C, 0x3C, - 0xE7, 0xAC, 0x02, 0x04, 0x58, 0xC4, 0xC4, 0xAD, 0x9C, 0x1B, 0xB1, 0x3F, 0xE1, 0x42, 0x3D, 0x4B, - 0x9E, 0x85, 0xCB, 0x57, 0xA6, 0x30, 0x4B, 0x97, 0x88, 0x26, 0xA2, 0x03, 0x7F, 0x8B, 0x72, 0x2D, - 0x90, 0x79, 0x02, 0xFD, 0x59, 0x36, 0xB2, 0xF3, 0x41, 0x2A, 0x65, 0xAD, 0x75, 0x64, 0x3A, 0x0C, - 0x48, 0xB4, 0x15, 0x35, 0x13, 0xE0, 0xC2, 0xC0, 0x2D, 0xB1, 0x15, 0x95, 0x0C, 0x13, 0x97, 0x59, - 0x73, 0x90, 0x01, 0xF5, 0xAC, 0x36, 0x8D, 0x79, 0x12, 0x40, 0xB8, 0x45, 0x22, 0xB8, 0xF8, 0xC4, - 0x0C, 0x7D, 0xB3, 0x31, 0x96, 0xCF, 0x00, 0x01, 0x76, 0x41, 0x80, 0x4F, 0x0B, 0x80, 0x78, 0x4A, - 0x24, 0x5B, 0x8C, 0x18, 0xDB, 0x8A, 0x0A, 0xF0, 0xC3, 0x15, 0x88, 0x08, 0xF1, 0xC5, 0xC7, 0x3C, - 0x13, 0x40, 0x94, 0x01, 0x81, 0x13, 0x20, 0xA0, 0x23, 0x02, 0x27, 0xE0, 0x58, 0x63, 0x08, 0xD9, - 0xE8, 0x41, 0x81, 0x5B, 0x42, 0x7A, 0x57, 0x86, 0x12, 0x46, 0x26, 0x79, 0x46, 0x06, 0x11, 0x00, - 0x00, 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x3C, 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, - 0xE4, 0x8C, 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0xA1, - 0x1C, 0x34, 0x1B, 0x24, 0x4A, 0x82, 0xE7, 0x27, 0x85, 0x50, 0x08, 0x0C, 0x3D, 0x12, 0xBC, 0xC4, - 0xA3, 0x18, 0x12, 0x08, 0x14, 0x86, 0xC1, 0x80, 0xC9, 0x31, 0x18, 0x0E, 0x84, 0x81, 0x80, 0xBA, - 0x91, 0x46, 0xB1, 0x51, 0x06, 0xD7, 0x62, 0x40, 0x9A, 0x91, 0xE2, 0x71, 0xA5, 0x37, 0x40, 0x33, - 0xDE, 0xE9, 0xF1, 0xE3, 0xA1, 0x20, 0x10, 0x0E, 0x52, 0x01, 0x63, 0xA9, 0x5E, 0x0C, 0x85, 0x03, - 0x76, 0x7A, 0x7D, 0x0B, 0x4E, 0x03, 0x75, 0x78, 0x77, 0x78, 0x06, 0x84, 0x51, 0x37, 0x8A, 0x77, - 0x02, 0x51, 0x6A, 0x05, 0x02, 0x04, 0x67, 0x67, 0x5B, 0x72, 0x47, 0x98, 0x98, 0x7C, 0x5C, 0x73, - 0x66, 0x58, 0x07, 0x8B, 0x0F, 0x00, 0x9F, 0x45, 0x02, 0x01, 0x03, 0xA3, 0x0C, 0x89, 0x03, 0x06, - 0x02, 0x00, 0x5C, 0x06, 0x01, 0x92, 0x52, 0x07, 0xAE, 0x59, 0x03, 0x00, 0xBD, 0xBD, 0x4C, 0x02, - 0x05, 0xAB, 0xB9, 0x70, 0x0C, 0xAC, 0x96, 0x00, 0x52, 0x45, 0x36, 0xC1, 0x51, 0x97, 0x0C, 0x66, - 0x5E, 0x00, 0x8C, 0x4C, 0x0A, 0x05, 0x5F, 0x68, 0x98, 0x4E, 0x56, 0x40, 0x7F, 0x3D, 0x67, 0x97, - 0x9D, 0x73, 0x39, 0x02, 0x74, 0x9C, 0x48, 0xA4, 0x76, 0x76, 0x66, 0x73, 0xA8, 0x2C, 0x05, 0x50, - 0x02, 0xA3, 0xA3, 0x59, 0x78, 0x5E, 0x92, 0xD4, 0x2C, 0xDB, 0xB0, 0x59, 0x76, 0x07, 0x00, 0x78, - 0x16, 0x09, 0x80, 0xF5, 0xE4, 0x05, 0xC1, 0x81, 0x5F, 0xB0, 0x10, 0x00, 0xA0, 0xEE, 0xC0, 0xC0, - 0x03, 0x8E, 0x68, 0x68, 0xB1, 0x72, 0xE5, 0x92, 0xAF, 0x5E, 0xF6, 0x0C, 0x10, 0xF0, 0x86, 0x62, - 0xFB, 0xCE, 0xC1, 0x03, 0x98, 0x00, 0x74, 0x42, 0x42, 0xE7, 0xC5, 0xB9, 0x4E, 0xFF, 0xC2, 0x9D, - 0x99, 0xA3, 0x60, 0x0A, 0x0A, 0x03, 0xED, 0xC0, 0xDD, 0xF1, 0x47, 0xCF, 0xCB, 0x2E, 0x97, 0x20, - 0x92, 0x0D, 0x64, 0x85, 0xA5, 0x65, 0x43, 0x2C, 0x3C, 0x19, 0x10, 0x30, 0x94, 0x2F, 0x27, 0xBE, - 0x9D, 0x87, 0x78, 0xCE, 0x54, 0x47, 0xC0, 0x98, 0xC6, 0x9D, 0x39, 0x2F, 0xC6, 0xB2, 0xF1, 0x87, - 0x29, 0x96, 0x62, 0xC6, 0xB6, 0x69, 0xE2, 0xC0, 0x2B, 0x4A, 0x2C, 0x58, 0x49, 0x47, 0xDA, 0x11, - 0x6A, 0x69, 0xC0, 0xB8, 0x10, 0x22, 0x1F, 0xDC, 0x0A, 0xF4, 0x6D, 0x64, 0x02, 0x06, 0xB1, 0x04, - 0x28, 0x39, 0xBB, 0xA1, 0xDD, 0x49, 0x4C, 0xE9, 0xD4, 0xB9, 0x4D, 0x0A, 0xA2, 0x40, 0x81, 0x91, - 0x81, 0x68, 0x2E, 0x35, 0x43, 0xA0, 0xC0, 0x50, 0x05, 0x1F, 0x6A, 0x39, 0xB9, 0x65, 0x47, 0x4A, - 0xBF, 0xBC, 0xF4, 0xF0, 0x04, 0xE3, 0x98, 0xA1, 0x96, 0x02, 0x5B, 0x5E, 0x71, 0xA5, 0x53, 0xA8, - 0x4E, 0x68, 0x16, 0x2B, 0x01, 0xFC, 0x42, 0x29, 0x4A, 0x21, 0xF4, 0xE8, 0x87, 0x0A, 0xA5, 0x04, - 0xDA, 0xDC, 0x94, 0x95, 0x6A, 0x03, 0xC2, 0x5A, 0x6E, 0xF0, 0x66, 0xC8, 0x0E, 0xC0, 0x99, 0x20, - 0xDF, 0x16, 0x93, 0xAC, 0x91, 0x64, 0x16, 0x0B, 0xED, 0x14, 0x70, 0xF2, 0xC2, 0x6B, 0x75, 0x27, - 0x68, 0x81, 0xDA, 0x90, 0xB4, 0x0B, 0xDC, 0x74, 0xC8, 0x8B, 0x67, 0xB0, 0xBC, 0x75, 0x2B, 0xCC, - 0x5D, 0xA1, 0x00, 0xD8, 0x09, 0xC4, 0x3D, 0x23, 0x92, 0xB0, 0x6B, 0x29, 0xDA, 0x6A, 0x55, 0x12, - 0x46, 0x7A, 0x41, 0xA5, 0x81, 0xF8, 0x62, 0x25, 0xE8, 0x4E, 0x2A, 0x60, 0x22, 0x52, 0x05, 0xB4, - 0xB4, 0x94, 0x14, 0xAC, 0x12, 0x05, 0xBF, 0xCD, 0xB4, 0x60, 0xA7, 0x6F, 0x66, 0x65, 0xE7, 0x57, - 0xC7, 0xA3, 0xC8, 0x67, 0x85, 0x16, 0x5B, 0x49, 0xF0, 0x84, 0x2A, 0x48, 0x19, 0x92, 0x47, 0x30, - 0x4E, 0x00, 0x60, 0xC9, 0x57, 0x71, 0x79, 0x03, 0x51, 0x30, 0xD3, 0x4C, 0xA0, 0xC0, 0x4E, 0xA4, - 0x1C, 0x45, 0x51, 0x2C, 0x7E, 0x39, 0xB8, 0x18, 0x3E, 0x04, 0xB5, 0x04, 0x14, 0x6C, 0xB3, 0xF8, - 0xF1, 0xC7, 0x3C, 0x00, 0xAA, 0xC6, 0xCB, 0x45, 0xFC, 0x21, 0xD5, 0x52, 0x72, 0x17, 0x95, 0x88, - 0xD8, 0x09, 0x08, 0x00, 0x80, 0x00, 0x02, 0x28, 0x94, 0x28, 0xC1, 0x8C, 0x20, 0x20, 0xD1, 0x5D, - 0x02, 0x27, 0xE8, 0x88, 0x82, 0x5B, 0x84, 0x2C, 0xE0, 0xD6, 0x19, 0x4C, 0x1C, 0xA9, 0xA4, 0x19, - 0x1B, 0x44, 0x00, 0x00, 0x21, 0xFE, 0x19, 0x42, 0x6F, 0x79, 0x27, 0x73, 0x20, 0x48, 0x61, 0x70, - 0x70, 0x79, 0x20, 0x48, 0x6F, 0x6C, 0x69, 0x64, 0x61, 0x79, 0x73, 0x20, 0x50, 0x61, 0x67, 0x65, - 0x00, 0x3B - -}; - -static const uint8_t bird_gif[] PROGMEM = { - 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x74, 0x00, 0x4E, 0x00, 0xCC, 0x13, 0x00, 0xFF, 0xFF, 0xFF, - 0xEF, 0xFF, 0xFF, 0xBD, 0xE7, 0xE7, 0xD6, 0xEF, 0xEF, 0x63, 0x63, 0x63, 0xAD, 0xAD, 0xAD, 0xCE, - 0xCE, 0xCE, 0xD6, 0xDE, 0xDE, 0x4A, 0x4A, 0x4A, 0x7B, 0x84, 0x84, 0x94, 0x9C, 0x9C, 0xE7, 0xE7, - 0xE7, 0x84, 0x94, 0x94, 0xB5, 0xC6, 0xC6, 0x73, 0x7B, 0x7B, 0x31, 0x31, 0x31, 0xF7, 0xF7, 0xF7, - 0x18, 0x10, 0x10, 0xCE, 0x63, 0x39, 0x6B, 0x39, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xFF, 0x0B, - 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00, - 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x4B, - 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0xAE, 0xEC, 0x68, 0x2C, - 0x6D, 0x2C, 0xCF, 0x74, 0x6D, 0x03, 0x46, 0x84, 0x40, 0x77, 0xEF, 0xFF, 0x40, 0x51, 0x42, 0x41, - 0x0C, 0x1A, 0x8F, 0x48, 0x13, 0xC1, 0xD0, 0x20, 0x00, 0x0E, 0x8E, 0x42, 0x72, 0x4A, 0xAD, 0x21, - 0x0E, 0xCD, 0x05, 0xE1, 0x80, 0xA8, 0x7A, 0xBF, 0x29, 0xC2, 0xA0, 0x91, 0x28, 0x34, 0x02, 0x5D, - 0xB0, 0x5A, 0xFD, 0x08, 0x34, 0x14, 0x84, 0x00, 0x7A, 0x4D, 0xF7, 0x22, 0xDC, 0x89, 0xB8, 0xC1, - 0xB9, 0x80, 0xD5, 0xFF, 0x40, 0x0B, 0x77, 0x0C, 0x0F, 0x05, 0x01, 0x0C, 0x0A, 0x0B, 0x0F, 0x08, - 0x06, 0x80, 0x8E, 0x37, 0x7B, 0x01, 0x09, 0x11, 0x03, 0x68, 0x5C, 0x4C, 0x0A, 0x8F, 0x9A, 0x33, - 0x06, 0x09, 0x01, 0x0E, 0x71, 0x68, 0x88, 0x92, 0x07, 0x9B, 0xA6, 0x2C, 0x0A, 0x86, 0x07, 0x95, - 0x05, 0x04, 0xA1, 0x5D, 0x8D, 0xA7, 0xB2, 0x26, 0x09, 0x06, 0x72, 0x72, 0x0E, 0x94, 0x01, 0xA9, - 0x04, 0x08, 0x52, 0xB3, 0xC0, 0x00, 0x09, 0x95, 0xB7, 0x0D, 0x86, 0x01, 0x04, 0x0A, 0xC3, 0x09, - 0x34, 0x43, 0xC1, 0x54, 0x0E, 0xB7, 0xD2, 0x87, 0xAE, 0xBB, 0x99, 0x32, 0x7B, 0x0E, 0xCF, 0x49, - 0x0B, 0xD1, 0xD3, 0x72, 0x0C, 0xDE, 0x57, 0x33, 0xBE, 0xCC, 0xDB, 0x47, 0x05, 0x0C, 0xDF, 0xD3, - 0x05, 0xD7, 0x31, 0x0C, 0xE1, 0xA5, 0xE7, 0x46, 0xBE, 0xEB, 0xD2, 0x04, 0x05, 0xBF, 0x2C, 0x5C, - 0x4D, 0xF3, 0x46, 0x0B, 0x11, 0x56, 0xD9, 0x3B, 0x14, 0x01, 0x14, 0x0F, 0x16, 0x04, 0x1A, 0x30, - 0x28, 0x00, 0x81, 0xA1, 0x3F, 0x1F, 0xAD, 0x02, 0x10, 0x5B, 0x87, 0x6F, 0x0E, 0x8B, 0x02, 0x0E, - 0x04, 0x5C, 0x41, 0x10, 0xF0, 0x61, 0x8F, 0x25, 0x03, 0x26, 0xDA, 0x43, 0xC4, 0x42, 0x8B, 0x00, - 0x05, 0x0E, 0x7C, 0xFF, 0xED, 0xF0, 0x68, 0x83, 0x8B, 0x44, 0x91, 0xDF, 0x06, 0xAC, 0x54, 0x01, - 0x21, 0xA1, 0x80, 0x07, 0x0F, 0x1A, 0x38, 0x70, 0xC7, 0x72, 0x46, 0xC2, 0x97, 0x03, 0x3F, 0xC5, - 0x52, 0xE1, 0x80, 0x81, 0x00, 0x01, 0x19, 0x1B, 0x3C, 0x38, 0xD8, 0x53, 0xC6, 0x81, 0x38, 0x21, - 0x61, 0x4A, 0xEB, 0xB7, 0x42, 0x01, 0x82, 0xA3, 0x58, 0x7D, 0xC9, 0x6B, 0x1A, 0x63, 0x0B, 0xD0, - 0x81, 0x11, 0x08, 0x74, 0x44, 0x61, 0xE0, 0x01, 0xD6, 0xA3, 0x05, 0x16, 0x2D, 0xE5, 0xDA, 0xC2, - 0x80, 0xB7, 0x90, 0x41, 0xCB, 0xA4, 0x39, 0xC1, 0xEF, 0x2C, 0x56, 0xAA, 0x6C, 0x57, 0x38, 0xA8, - 0x14, 0x35, 0xA8, 0x35, 0x14, 0x10, 0x10, 0x34, 0xB0, 0x9B, 0xD5, 0x4F, 0xDE, 0x14, 0x06, 0x8E, - 0xF5, 0x1D, 0xC8, 0x25, 0x85, 0x83, 0xC1, 0x84, 0x05, 0x20, 0x32, 0x30, 0xF4, 0x30, 0x2D, 0x39, - 0x8B, 0x07, 0x32, 0x42, 0xA1, 0x00, 0x72, 0xE4, 0x45, 0x08, 0x7C, 0x59, 0x36, 0x91, 0x18, 0x73, - 0xE6, 0x6F, 0x79, 0x38, 0x2B, 0x88, 0x7C, 0x54, 0xE7, 0xE0, 0x2D, 0xA3, 0x4B, 0x78, 0x7A, 0x79, - 0x7A, 0x1A, 0xCE, 0x04, 0x4C, 0x85, 0xAC, 0x66, 0x7D, 0x96, 0x80, 0xB9, 0xD8, 0x22, 0x4A, 0x4B, - 0x14, 0x00, 0x97, 0xF1, 0xD3, 0x12, 0x3B, 0x79, 0x9F, 0x45, 0xC0, 0x13, 0xB8, 0xB7, 0xE1, 0xC5, - 0x19, 0x33, 0xEB, 0x53, 0xD3, 0xA8, 0x72, 0x01, 0x0D, 0x44, 0x97, 0x5C, 0x90, 0x7B, 0x9B, 0x01, - 0x05, 0xA6, 0x89, 0xFB, 0x3D, 0x54, 0x20, 0x81, 0xDA, 0x8C, 0xD7, 0x91, 0x16, 0x22, 0x91, 0xF8, - 0x80, 0x9F, 0x86, 0x08, 0x1E, 0xF4, 0xF2, 0xD5, 0x7D, 0x96, 0x18, 0xCC, 0x47, 0xA3, 0xDB, 0x7B, - 0xCA, 0x60, 0x40, 0xCA, 0xF4, 0x58, 0x81, 0xE2, 0x42, 0x04, 0x11, 0x4C, 0x80, 0x53, 0x7C, 0x3F, - 0xC9, 0xB1, 0xC7, 0xFF, 0x7A, 0xC1, 0x18, 0xA0, 0x0E, 0x7E, 0xC4, 0x49, 0xA5, 0x99, 0x67, 0xD7, - 0xA5, 0xB4, 0x15, 0x04, 0x93, 0x48, 0xA0, 0xA1, 0x81, 0x7C, 0x49, 0xB3, 0xC7, 0x38, 0xF6, 0x11, - 0x13, 0x52, 0x7E, 0x12, 0xAE, 0x63, 0xC0, 0x55, 0x00, 0x82, 0x62, 0xD8, 0x08, 0x0B, 0x24, 0xA0, - 0xA1, 0x86, 0x57, 0x3C, 0xF0, 0xE0, 0x2D, 0x05, 0x68, 0x67, 0x4A, 0x27, 0xB7, 0x0C, 0x80, 0x95, - 0x7E, 0x41, 0x11, 0x80, 0x5E, 0x85, 0xBF, 0x9D, 0xD0, 0xC0, 0x04, 0x2F, 0x2E, 0x62, 0xCB, 0x34, - 0x03, 0xE4, 0xB1, 0xA2, 0x23, 0x5E, 0x41, 0xC8, 0x63, 0x50, 0x0E, 0x9A, 0x75, 0x5D, 0x68, 0x5B, - 0x9D, 0xA0, 0x45, 0x04, 0x38, 0x2D, 0x72, 0xCC, 0x34, 0x7B, 0x24, 0xF2, 0x88, 0x5B, 0x39, 0xEA, - 0x18, 0xE1, 0x78, 0xD2, 0x58, 0x05, 0x20, 0x6C, 0x2B, 0xD4, 0x78, 0x64, 0x89, 0x6E, 0xB8, 0xF2, - 0xC2, 0x1F, 0x4D, 0xBE, 0x44, 0x22, 0x99, 0x72, 0xE4, 0x01, 0x60, 0x19, 0x31, 0x68, 0xB1, 0xC4, - 0x78, 0x50, 0xF4, 0xE2, 0x9B, 0x43, 0x5E, 0x80, 0x99, 0xE3, 0x8E, 0x6C, 0x4E, 0xE3, 0x63, 0x7A, - 0xD9, 0x55, 0xD6, 0x82, 0x4E, 0x04, 0x30, 0xD0, 0xC0, 0x01, 0x7C, 0x2A, 0xE4, 0xA3, 0xA2, 0x47, - 0xDC, 0x37, 0xE8, 0x9C, 0xE3, 0xC9, 0x64, 0x9D, 0x72, 0x70, 0x54, 0x29, 0x03, 0x04, 0xDF, 0xE5, - 0xE1, 0x4A, 0x19, 0x06, 0xB0, 0xD9, 0xC4, 0x66, 0x48, 0x7C, 0x27, 0xCD, 0x88, 0x98, 0x92, 0x89, - 0xE2, 0x75, 0x69, 0x2D, 0x69, 0xC3, 0x02, 0x07, 0xA4, 0x03, 0x8A, 0x2B, 0x8E, 0xC2, 0x04, 0x05, - 0x03, 0x48, 0x3C, 0x17, 0x5E, 0xAB, 0x7E, 0x61, 0x04, 0x20, 0x03, 0x33, 0x21, 0x01, 0xC1, 0x02, - 0xDF, 0x81, 0x52, 0x8B, 0x34, 0xAD, 0xC8, 0x6A, 0x43, 0x3E, 0x48, 0x9E, 0xF5, 0x24, 0x45, 0xAF, - 0xF2, 0x96, 0x9D, 0xFF, 0x03, 0xF5, 0x51, 0xD1, 0xA2, 0x03, 0x90, 0xCA, 0xF1, 0x94, 0x3E, 0x37, - 0x68, 0x81, 0xA4, 0x98, 0xC0, 0x9A, 0xF8, 0xC0, 0x8F, 0xCA, 0x39, 0xA0, 0xCD, 0x1F, 0x0B, 0x10, - 0x21, 0x0D, 0x03, 0xB8, 0x7D, 0x74, 0x64, 0x98, 0xD2, 0x16, 0x8A, 0x0C, 0xBA, 0xCA, 0x29, 0xF5, - 0x48, 0x8B, 0x53, 0xA1, 0x19, 0x03, 0xA8, 0x18, 0x85, 0xB2, 0x2A, 0xB9, 0x63, 0x06, 0x45, 0x06, - 0x80, 0x48, 0x05, 0xC9, 0x6E, 0x9C, 0x4F, 0xE1, 0xA3, 0xC2, 0x77, 0xF0, 0x16, 0x95, 0x4B, 0xB7, - 0xF4, 0x12, 0xEA, 0x57, 0x59, 0x14, 0xB2, 0x46, 0x08, 0xB8, 0x8E, 0x08, 0x72, 0x06, 0xB3, 0x3E, - 0xA6, 0xF2, 0x28, 0x46, 0x8B, 0x2C, 0xEB, 0xED, 0x03, 0xF3, 0x56, 0x5C, 0xF0, 0x40, 0xE6, 0xED, - 0xA6, 0x9C, 0x7C, 0xD9, 0x02, 0xA2, 0x48, 0xCA, 0x98, 0x25, 0xD6, 0xCE, 0x4E, 0x14, 0x2B, 0x18, - 0xE7, 0xC0, 0xE5, 0xAE, 0x93, 0x00, 0xC2, 0x45, 0x01, 0xB3, 0xC0, 0x8C, 0x74, 0xFA, 0xF7, 0x80, - 0x84, 0xAC, 0xAE, 0x6C, 0xCF, 0x00, 0x04, 0xA4, 0x47, 0x2C, 0x02, 0xCE, 0x6A, 0xF2, 0x06, 0x9D, - 0x98, 0xE5, 0x3C, 0xB0, 0x98, 0xB5, 0x4D, 0xD3, 0x40, 0x04, 0x05, 0x28, 0x57, 0x40, 0x04, 0x0A, - 0x50, 0x2A, 0x4B, 0x02, 0x1F, 0x53, 0xBD, 0x74, 0x54, 0x59, 0xBF, 0x1B, 0x5A, 0x41, 0xAC, 0x65, - 0xA7, 0xF0, 0x33, 0x0C, 0x58, 0x6D, 0xB6, 0x69, 0x68, 0x4F, 0x2B, 0x87, 0x55, 0xB7, 0x38, 0x50, - 0xC8, 0x5D, 0x7E, 0x8A, 0x1D, 0x0C, 0x04, 0x8F, 0xCD, 0x1D, 0x94, 0xDD, 0x4F, 0xA1, 0xEC, 0xA1, - 0x7C, 0xAD, 0x8D, 0xC5, 0x52, 0x4D, 0xBE, 0x0A, 0x3E, 0x9E, 0x55, 0x32, 0xDA, 0xA3, 0x37, 0x03, - 0xBD, 0x44, 0x3D, 0x8F, 0x55, 0x34, 0x3B, 0x6E, 0x4F, 0x03, 0x99, 0x73, 0x89, 0x93, 0xE5, 0xFE, - 0x74, 0x13, 0xB7, 0xCB, 0xE6, 0xA4, 0x4B, 0x63, 0x90, 0x65, 0xED, 0x16, 0x25, 0x77, 0xE9, 0x54, - 0x67, 0x11, 0xDB, 0x89, 0x44, 0xB3, 0x6E, 0xF6, 0x89, 0x7E, 0x37, 0x05, 0x47, 0xE7, 0xB2, 0xFB, - 0xF5, 0x2D, 0x70, 0xDD, 0x80, 0x37, 0xDE, 0x0A, 0x8E, 0xFB, 0x06, 0x1C, 0x00, 0x4D, 0xE0, 0x1E, - 0x80, 0x0C, 0x73, 0xFB, 0x47, 0x00, 0xE8, 0x2C, 0x89, 0x6E, 0xCF, 0x0C, 0x66, 0x87, 0x64, 0x55, - 0x73, 0x87, 0xB5, 0xD2, 0x39, 0xF2, 0x54, 0xA3, 0xAD, 0x24, 0xEF, 0x09, 0xC4, 0x2E, 0x47, 0x0C, - 0x83, 0x4F, 0x44, 0x6E, 0x25, 0xA9, 0x0C, 0x8F, 0x43, 0xE0, 0xD3, 0xB4, 0x30, 0x50, 0x54, 0xF9, - 0x41, 0x57, 0xC9, 0x63, 0xE6, 0x03, 0x00, 0xC1, 0xED, 0xE9, 0xAB, 0x60, 0x4F, 0x62, 0x94, 0x41, - 0x2A, 0xFE, 0x01, 0x56, 0x11, 0x10, 0xB3, 0x65, 0x4F, 0x11, 0xCC, 0x37, 0x4A, 0x10, 0x2C, 0x8E, - 0x3C, 0x80, 0x40, 0x3A, 0x30, 0x20, 0x02, 0x96, 0x10, 0x3F, 0x13, 0x64, 0xA7, 0x1E, 0x17, 0x53, - 0x90, 0x02, 0x28, 0x87, 0x00, 0xB2, 0xC1, 0xE0, 0x29, 0x08, 0x24, 0x50, 0xC9, 0xFE, 0x37, 0x3C, - 0x28, 0x30, 0x67, 0x75, 0x01, 0x9C, 0x20, 0x4E, 0x0A, 0xE0, 0xAC, 0xAF, 0x21, 0x90, 0x3E, 0x0D, - 0x4C, 0x41, 0xBB, 0x42, 0x13, 0x05, 0x63, 0xA4, 0x64, 0x81, 0x43, 0x28, 0x40, 0xED, 0x44, 0x00, - 0x01, 0x2C, 0x78, 0x29, 0x85, 0x2C, 0x38, 0x56, 0x62, 0x1A, 0xC0, 0x1D, 0x35, 0x84, 0x00, 0x00, - 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, - 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, - 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, - 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, - 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, - 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, - 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, - 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, - 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, - 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, - 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, - 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, - 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, - 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, - 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, - 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, - 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, - 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, - 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, - 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, - 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, - 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, - 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, - 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, - 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, - 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, - 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, - 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, - 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, - 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, - 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, - 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, - 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, - 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, - 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, - 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, - 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, - 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, - 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, - 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, - 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, - 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, - 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, - 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, - 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, - 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, - 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, - 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, - 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, - 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, - 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, - 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, - 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, - 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, - 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, - 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, - 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, - 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, - 0x0D, 0x21, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, - 0x00, 0x6A, 0x00, 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, - 0xAE, 0x6C, 0xEB, 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, - 0x0A, 0xC7, 0x03, 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, - 0xA4, 0x10, 0xA8, 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, - 0x9E, 0x18, 0x02, 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, - 0xD4, 0x81, 0x01, 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, - 0x0D, 0x08, 0x05, 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, - 0x04, 0x06, 0x10, 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, - 0x93, 0x09, 0x0C, 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, - 0x0C, 0x39, 0x9A, 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, - 0xAB, 0x5B, 0x4A, 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, - 0x0D, 0x0D, 0x07, 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, - 0x0E, 0x7B, 0x04, 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, - 0x92, 0x0C, 0x0E, 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, - 0x5B, 0x03, 0x0E, 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, - 0x98, 0xBE, 0x73, 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, - 0xB0, 0x6A, 0xA3, 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, - 0xBC, 0xA5, 0x0C, 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, - 0x04, 0x32, 0x53, 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, - 0x67, 0x8E, 0xA2, 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, - 0x33, 0xA0, 0x2B, 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, - 0x0E, 0x10, 0xC0, 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, - 0x0A, 0x08, 0xF8, 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, - 0x1D, 0x8A, 0x47, 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, - 0x22, 0x22, 0x82, 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, - 0x6B, 0x50, 0xE0, 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, - 0xA3, 0x2D, 0x60, 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, - 0x94, 0x14, 0x7F, 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, - 0x05, 0x30, 0x4A, 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, - 0x53, 0x20, 0xC1, 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, - 0x10, 0x03, 0x80, 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, - 0x26, 0x0F, 0x28, 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, - 0xC6, 0x0A, 0x02, 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, - 0xA0, 0xC0, 0x28, 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, - 0x42, 0x01, 0x5A, 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, - 0x88, 0x33, 0x14, 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, - 0x6A, 0xC4, 0x80, 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, - 0x28, 0xC2, 0xE2, 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, - 0x21, 0xA4, 0x0C, 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, - 0x4A, 0x93, 0x29, 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, - 0x94, 0x0C, 0x38, 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, - 0x56, 0x74, 0x54, 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, - 0x99, 0x83, 0x8A, 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, - 0x10, 0x02, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, - 0x6A, 0x00, 0x2E, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x00, 0x40, 0x62, 0xB9, 0x28, 0x08, 0x41, 0x28, - 0x4B, 0xE9, 0xBE, 0x70, 0x2C, 0xCF, 0x74, 0x6D, 0xDF, 0xE5, 0xF1, 0x3C, 0x69, 0x52, 0x24, 0x0F, - 0x82, 0xE1, 0x60, 0x00, 0x26, 0x5A, 0xB8, 0xA4, 0x72, 0xC9, 0x94, 0xE9, 0x22, 0x12, 0xC9, 0x64, - 0xF2, 0x18, 0x04, 0xAE, 0xD7, 0x01, 0xB0, 0xD0, 0xEC, 0x7A, 0xBF, 0x31, 0x48, 0x61, 0x12, 0x95, - 0x32, 0x02, 0x8E, 0x06, 0x36, 0x70, 0x50, 0x21, 0xC1, 0xF0, 0x78, 0x72, 0x91, 0x20, 0x4B, 0x55, - 0x85, 0xF5, 0xB5, 0x81, 0xE0, 0xCA, 0xFF, 0x80, 0x32, 0x0D, 0x0F, 0x53, 0x11, 0x11, 0x04, 0x07, - 0x7A, 0x57, 0x0E, 0x04, 0x6F, 0x81, 0x8F, 0x7F, 0x0B, 0x2A, 0x06, 0x94, 0x6A, 0x8A, 0x01, 0x06, - 0x04, 0x05, 0x07, 0x0B, 0x0B, 0x44, 0x94, 0xA0, 0x43, 0x24, 0x90, 0xA4, 0x37, 0x05, 0x04, 0x96, - 0x97, 0x58, 0x45, 0x09, 0x0A, 0x0C, 0x0C, 0x0A, 0x05, 0x0D, 0xB3, 0x05, 0x0A, 0x09, 0x0C, 0x05, - 0x06, 0xA3, 0x4D, 0x9F, 0xA0, 0x0B, 0xBB, 0xA5, 0x33, 0x6D, 0x08, 0x0C, 0x89, 0xAA, 0xC7, 0x8A, - 0x07, 0xAE, 0x3E, 0xC0, 0x32, 0x10, 0x07, 0x3F, 0x2A, 0x0E, 0x8C, 0x2A, 0x08, 0xD6, 0x29, 0x0E, - 0xB9, 0xCD, 0xC1, 0x22, 0x10, 0x45, 0xD2, 0xB8, 0x07, 0x56, 0x97, 0x22, 0xC8, 0x01, 0x0D, 0x0C, - 0x3E, 0x9C, 0x25, 0xCF, 0xA7, 0x04, 0xD9, 0xE2, 0xC8, 0x03, 0xD0, 0x09, 0x04, 0xD6, 0x09, 0xBA, - 0xDC, 0x30, 0x10, 0x0B, 0x06, 0xB6, 0x2A, 0x04, 0x12, 0xDC, 0x52, 0x40, 0x90, 0x60, 0x81, 0x5C, - 0x07, 0x20, 0xA8, 0x1A, 0xD0, 0x20, 0x01, 0x35, 0x07, 0x3C, 0x1C, 0x18, 0x30, 0x87, 0xCC, 0x00, - 0x03, 0x02, 0x0F, 0x12, 0x34, 0xD8, 0xA6, 0xCF, 0x44, 0xA7, 0x8F, 0x9D, 0x0E, 0x88, 0xAC, 0x75, - 0x6B, 0x22, 0xC5, 0x4B, 0x44, 0x4E, 0xFF, 0x26, 0x63, 0x80, 0x20, 0xE3, 0x81, 0x8E, 0x5D, 0x0E, - 0xA4, 0x33, 0xA6, 0x92, 0x8D, 0x03, 0x04, 0x35, 0x2F, 0x35, 0xC0, 0x98, 0xE0, 0x25, 0x4C, 0x26, - 0x07, 0x7C, 0xE4, 0xBC, 0x82, 0x40, 0xE1, 0x50, 0x3D, 0xCA, 0x52, 0x38, 0xFA, 0x89, 0xE3, 0x47, - 0xCE, 0x1F, 0x00, 0x8E, 0xAA, 0x02, 0xC2, 0x80, 0xE9, 0x92, 0x86, 0x2A, 0x0D, 0x3C, 0xA0, 0x29, - 0x55, 0xD1, 0x00, 0x8C, 0x06, 0xAC, 0x26, 0x31, 0x80, 0xC0, 0x24, 0x32, 0x04, 0x09, 0xBA, 0x9A, - 0x1B, 0x94, 0x80, 0xA3, 0x58, 0x18, 0x5A, 0xCF, 0x1C, 0x13, 0x78, 0x69, 0x9C, 0xDA, 0x2C, 0x04, - 0x22, 0x34, 0x78, 0x6B, 0x03, 0x82, 0x02, 0x44, 0x97, 0x5E, 0xD5, 0x1D, 0x60, 0xF7, 0xEE, 0xB9, - 0x07, 0x61, 0xF9, 0xD6, 0x58, 0xC0, 0x20, 0xDB, 0x1A, 0x82, 0x0B, 0x09, 0x17, 0xBE, 0xFB, 0x55, - 0x81, 0xE2, 0x1B, 0x99, 0x10, 0x39, 0xF6, 0x2A, 0x99, 0xB0, 0x61, 0x3D, 0x0E, 0x2F, 0xDF, 0x18, - 0x94, 0x87, 0xF3, 0x00, 0x01, 0x02, 0x24, 0x7F, 0x7E, 0x8C, 0x60, 0xA9, 0x68, 0x17, 0x6D, 0xCC, - 0x62, 0x91, 0x8C, 0x1A, 0x75, 0xE7, 0x2B, 0x30, 0xBA, 0xF2, 0xF1, 0xF9, 0xDA, 0x45, 0x26, 0xAE, - 0x59, 0x4E, 0xD7, 0x4E, 0xED, 0x19, 0xF7, 0x8C, 0xA3, 0x5A, 0xF7, 0xF6, 0x16, 0xF1, 0xC3, 0x68, - 0x70, 0xE1, 0xC3, 0x8B, 0xAF, 0xA1, 0x31, 0xF4, 0xB4, 0xD2, 0xD7, 0x10, 0x60, 0xE9, 0x21, 0x3C, - 0x3C, 0xFA, 0x64, 0xE3, 0x32, 0x6A, 0xD2, 0x56, 0xF0, 0xC0, 0x0F, 0x5F, 0x3A, 0xA9, 0x02, 0x70, - 0xEF, 0x4E, 0x5C, 0x3A, 0x68, 0xD7, 0xE5, 0x54, 0x72, 0xB7, 0xF2, 0xD5, 0xBC, 0xD5, 0xA0, 0x34, - 0xD7, 0xDB, 0x6E, 0xAF, 0x5A, 0x95, 0x03, 0xDE, 0x2F, 0x98, 0x73, 0xDB, 0x70, 0x01, 0xC4, 0xF2, - 0x96, 0x45, 0xB3, 0x41, 0x67, 0x5B, 0xFF, 0x7F, 0xE6, 0x00, 0x20, 0x51, 0x0C, 0xF2, 0xD0, 0x47, - 0x9C, 0x7A, 0xEA, 0x91, 0x07, 0x20, 0x4C, 0x05, 0xC8, 0xA5, 0x9E, 0x70, 0xA7, 0x31, 0x78, 0x92, - 0x24, 0x89, 0xB9, 0x70, 0x4C, 0x26, 0x41, 0x04, 0xA4, 0x40, 0x03, 0x19, 0x32, 0x72, 0xC8, 0x85, - 0x1D, 0xB9, 0x92, 0x20, 0x7F, 0xEE, 0x9D, 0x94, 0xE1, 0x49, 0x0C, 0xDD, 0x84, 0x16, 0x79, 0x11, - 0xF4, 0x11, 0x0B, 0x42, 0x62, 0x41, 0x70, 0xCB, 0x73, 0x1E, 0x0E, 0xE5, 0x20, 0x70, 0x7B, 0x10, - 0x40, 0x58, 0x5E, 0xC4, 0xE4, 0x23, 0x42, 0x02, 0x86, 0x34, 0xA2, 0x98, 0x24, 0x0A, 0x00, 0x19, - 0x63, 0x4E, 0xFD, 0x10, 0x43, 0x93, 0x32, 0x79, 0xF1, 0x90, 0x42, 0x88, 0x2E, 0x2C, 0xF0, 0x80, - 0x21, 0x0F, 0x30, 0x00, 0x5F, 0x30, 0x62, 0xF4, 0xB1, 0x61, 0x90, 0x47, 0x39, 0x18, 0xCB, 0x3F, - 0xEF, 0xF8, 0x60, 0xC0, 0x2F, 0x36, 0x3C, 0xB1, 0x22, 0x53, 0x99, 0x20, 0x90, 0x08, 0x9A, 0x5D, - 0x79, 0xD9, 0x80, 0x00, 0x29, 0xB4, 0xD6, 0x04, 0x59, 0x2C, 0xFC, 0x24, 0x13, 0x2A, 0x78, 0x76, - 0xF5, 0x95, 0x03, 0x0C, 0xA0, 0xA6, 0xA3, 0x17, 0x6E, 0x3D, 0xB2, 0xC0, 0x0F, 0x0A, 0x10, 0xB9, - 0xDA, 0x39, 0x08, 0x08, 0x90, 0x86, 0x00, 0x4E, 0x2E, 0x17, 0x86, 0x3B, 0xA5, 0x4D, 0xAA, 0x87, - 0x42, 0xAF, 0x0C, 0xE2, 0x00, 0xA6, 0x63, 0x8A, 0xF6, 0xA8, 0x0A, 0x91, 0x06, 0xF0, 0x4B, 0x9E, - 0xCE, 0x29, 0xF2, 0x17, 0x4B, 0x96, 0x16, 0x50, 0xA9, 0x9F, 0x9A, 0x02, 0x50, 0x00, 0x23, 0x81, - 0x9E, 0x1A, 0x41, 0x94, 0x47, 0x31, 0x10, 0xE6, 0x01, 0xD3, 0x98, 0xA5, 0x10, 0x2A, 0x2D, 0xF1, - 0x21, 0x46, 0x40, 0xB5, 0xDA, 0x8A, 0xD8, 0x02, 0x0D, 0x21, 0x9A, 0x80, 0x99, 0x98, 0xE0, 0x63, - 0xCE, 0x10, 0x01, 0xC8, 0x7A, 0xC2, 0x79, 0x11, 0x50, 0x65, 0x26, 0x2B, 0x9F, 0x64, 0xF9, 0xD1, - 0xE8, 0x93, 0x29, 0x32, 0x30, 0x84, 0x03, 0x0A, 0x28, 0x04, 0x2C, 0x46, 0x0B, 0x5C, 0x91, 0xAE, - 0x22, 0x64, 0x21, 0xB0, 0x13, 0x30, 0x99, 0xDC, 0xB4, 0xD3, 0xB3, 0xE9, 0x00, 0x50, 0x6A, 0xB2, - 0x00, 0xB4, 0xD1, 0x42, 0x50, 0x42, 0x00, 0xF6, 0x55, 0x51, 0xAA, 0x6A, 0x82, 0x09, 0x22, 0x08, - 0x38, 0xB0, 0x4D, 0xB7, 0x88, 0x2C, 0x60, 0x0D, 0x8B, 0xF8, 0xBE, 0x90, 0x89, 0x02, 0x0E, 0xE0, - 0x03, 0x81, 0xC0, 0x99, 0xDC, 0xAA, 0x2A, 0x44, 0xB3, 0xF8, 0xE9, 0x16, 0x04, 0x08, 0xD8, 0xC2, - 0x1C, 0x97, 0x0D, 0xCB, 0xE0, 0xC9, 0x28, 0x3A, 0x28, 0xF3, 0x5F, 0x6B, 0xBF, 0xD9, 0x72, 0xC4, - 0x62, 0x1D, 0x7F, 0x1B, 0x72, 0x0D, 0xCA, 0xBC, 0xD4, 0x86, 0x2D, 0x3E, 0xB9, 0xBC, 0x5C, 0x08, - 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, 0x6A, 0x00, - 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, 0xAE, 0x6C, 0xEB, - 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, 0x0A, 0xC7, 0x03, - 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, 0xA4, 0x10, 0xA8, - 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, 0x9E, 0x18, 0x02, - 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, 0xD4, 0x81, 0x01, - 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, 0x0D, 0x08, 0x05, - 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, 0x04, 0x06, 0x10, - 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, 0x93, 0x09, 0x0C, - 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, 0x0C, 0x39, 0x9A, - 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, 0xAB, 0x5B, 0x4A, - 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, 0x0D, 0x0D, 0x07, - 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, 0x0E, 0x7B, 0x04, - 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, 0x92, 0x0C, 0x0E, - 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, 0x5B, 0x03, 0x0E, - 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, 0x98, 0xBE, 0x73, - 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, 0xB0, 0x6A, 0xA3, - 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, 0xBC, 0xA5, 0x0C, - 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, 0x04, 0x32, 0x53, - 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, 0x67, 0x8E, 0xA2, - 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, 0x33, 0xA0, 0x2B, - 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, 0x0E, 0x10, 0xC0, - 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, 0x0A, 0x08, 0xF8, - 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, 0x1D, 0x8A, 0x47, - 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, 0x22, 0x22, 0x82, - 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, 0x6B, 0x50, 0xE0, - 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, 0xA3, 0x2D, 0x60, - 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, 0x94, 0x14, 0x7F, - 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, 0x05, 0x30, 0x4A, - 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, 0x53, 0x20, 0xC1, - 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, 0x10, 0x03, 0x80, - 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, 0x26, 0x0F, 0x28, - 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, 0xC6, 0x0A, 0x02, - 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, 0xA0, 0xC0, 0x28, - 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, 0x42, 0x01, 0x5A, - 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, 0x88, 0x33, 0x14, - 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, 0x6A, 0xC4, 0x80, - 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, 0x28, 0xC2, 0xE2, - 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, 0x21, 0xA4, 0x0C, - 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, 0x4A, 0x93, 0x29, - 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, 0x94, 0x0C, 0x38, - 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, 0x56, 0x74, 0x54, - 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, 0x99, 0x83, 0x8A, - 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, 0x10, 0x02, 0x00, - 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, - 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, - 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, - 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, - 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, - 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, - 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, - 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, - 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, - 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, - 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, - 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, - 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, - 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, - 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, - 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, - 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, - 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, - 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, - 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, - 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, - 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, - 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, - 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, - 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, - 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, - 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, - 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, - 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, - 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, - 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, - 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, - 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, - 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, - 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, - 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, - 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, - 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, - 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, - 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, - 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, - 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, - 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, - 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, - 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, - 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, - 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, - 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, - 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, - 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, - 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, - 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, - 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, - 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, - 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, - 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, - 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, - 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, - 0x0D, 0x21, 0x00, 0x00, 0x3B}; +#include + +static const uint8_t firebase_logo_png[] PROGMEM = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x58, 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x76, 0x82, + 0x70, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, + 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, + 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, + 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x55, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5E, 0xED, 0xDD, 0x59, + 0x90, 0x1D, 0xF5, 0x81, 0xE7, 0x7B, 0x3F, 0xF4, 0xC3, 0x84, 0x91, 0x40, 0x6E, 0xEF, 0xC6, 0x8B, + 0x30, 0x92, 0x4A, 0x1B, 0x58, 0x98, 0xCD, 0xA0, 0xA5, 0x4A, 0x12, 0x20, 0x6C, 0x9A, 0xB6, 0xBA, + 0x01, 0x63, 0x4F, 0x3F, 0x8C, 0x1E, 0x26, 0xC2, 0xF7, 0xE5, 0xC6, 0x25, 0xE2, 0xDE, 0x97, 0x3B, + 0x7D, 0x67, 0xAC, 0x6E, 0x63, 0x63, 0x83, 0x8D, 0xBC, 0xB1, 0x99, 0xA5, 0x10, 0x08, 0xED, 0x52, + 0x69, 0xAD, 0x92, 0xA0, 0xBB, 0xAB, 0xA7, 0xED, 0x6E, 0x77, 0xB7, 0x81, 0x42, 0x9B, 0x99, 0x89, + 0x89, 0xDB, 0x9A, 0xB9, 0x0E, 0x2F, 0x2C, 0x76, 0x61, 0x16, 0x49, 0x85, 0xA4, 0xFC, 0xDF, 0xFF, + 0x3F, 0x4F, 0xE6, 0xA9, 0x3C, 0x79, 0x7E, 0xE7, 0x9C, 0xCC, 0x3C, 0x99, 0x75, 0xCE, 0xC9, 0xFA, + 0x7E, 0x22, 0x7E, 0xA1, 0x6E, 0x2F, 0x42, 0xC2, 0x94, 0xE2, 0xFF, 0x8D, 0x7F, 0x65, 0x9E, 0xF7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x82, 0x79, 0x6E, 0xCD, 0x80, 0xBF, 0xC3, 0x5F, 0x58, 0x12, 0xFC, + 0x4B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1F, 0x73, 0x78, 0xCD, 0x3A, 0xEF, 0xB9, 0x35, 0x63, 0xE6, + 0xB9, 0x9B, 0x4D, 0x75, 0xCF, 0xAE, 0xF1, 0xE7, 0x3D, 0x7B, 0xD3, 0xA0, 0x0B, 0x92, 0xE0, 0x3F, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x98, 0x91, 0x35, 0xB3, 0xEB, 0xC2, 0x23, 0x12, 0x1F, 0xD1, + 0x79, 0x87, 0xD7, 0x6C, 0x08, 0xFE, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x8E, 0xFB, 0x16, 0x2B, + 0xEF, 0xD9, 0x35, 0xE3, 0x95, 0xE0, 0xB8, 0xD1, 0x98, 0x03, 0x57, 0x19, 0xB3, 0x7B, 0xAE, 0x31, + 0x3B, 0x3E, 0x65, 0xCC, 0xB6, 0x8F, 0x1A, 0xB3, 0xF3, 0xD3, 0xC6, 0x0C, 0x2D, 0x34, 0x66, 0x78, + 0xD9, 0x64, 0x84, 0x3C, 0x7B, 0xD3, 0x60, 0xF0, 0x5F, 0x07, 0x00, 0x00, 0x00, 0x80, 0xE4, 0xAA, + 0x37, 0x1F, 0x2E, 0x3C, 0x76, 0x7C, 0xC2, 0x98, 0xED, 0x1F, 0xAB, 0x84, 0x87, 0xDA, 0x2E, 0x1B, + 0x26, 0x87, 0x6F, 0xA8, 0x84, 0xC8, 0xA1, 0x9B, 0xD6, 0x06, 0x3F, 0x05, 0x00, 0x00, 0x00, 0x00, + 0xB4, 0xE6, 0x9E, 0xF9, 0xF0, 0xE3, 0x63, 0xCF, 0xA2, 0x4A, 0x78, 0x34, 0x8B, 0x8F, 0x70, 0xDB, + 0x3F, 0x6E, 0xCC, 0xC8, 0x0A, 0xF7, 0xAD, 0x58, 0xE3, 0x66, 0xB4, 0x7F, 0x56, 0xF0, 0x53, 0x01, + 0x00, 0x00, 0x00, 0x40, 0x73, 0xDE, 0x73, 0x37, 0x9F, 0x34, 0xFB, 0xAF, 0x48, 0x1E, 0x1F, 0xE1, + 0x76, 0x5E, 0x62, 0xCC, 0xE1, 0xD5, 0x76, 0x37, 0xAE, 0x0F, 0x7E, 0x2A, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xCC, 0x3D, 0x78, 0x6E, 0x0E, 0xAF, 0x4A, 0x1F, 0x1F, 0xFE, 0x3E, 0x62, 0xCC, 0xBE, 0xCF, + 0x18, 0xEF, 0xF0, 0x4D, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x68, 0xCD, 0xFF, 0x8C, 0x8F, 0xBD, + 0x97, 0x67, 0x8B, 0x0F, 0xB7, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x20, 0x19, 0x1B, + 0x20, 0xEB, 0xCD, 0xAE, 0x4F, 0xC7, 0xE2, 0xA2, 0xD5, 0x82, 0xF8, 0x08, 0xB7, 0x67, 0xB1, 0x31, + 0xCF, 0xDE, 0x64, 0xDC, 0x6D, 0x4A, 0xF0, 0xD3, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3D, 0xEF, 0xB9, + 0x9B, 0x07, 0x75, 0x64, 0x34, 0x5A, 0x2C, 0x3E, 0xC2, 0x1D, 0x1A, 0xE0, 0xB5, 0xBC, 0x00, 0x00, + 0x00, 0x00, 0x9A, 0xF3, 0x0E, 0x2E, 0x1B, 0xD5, 0xA1, 0xA1, 0x26, 0xC2, 0x23, 0xDC, 0xD0, 0x02, + 0x6E, 0x41, 0x00, 0x00, 0x00, 0x00, 0x34, 0xE7, 0x1D, 0xB8, 0x76, 0x5C, 0xC7, 0x46, 0x7C, 0x22, + 0x3A, 0xE2, 0x1B, 0x59, 0x6E, 0xBC, 0xC3, 0x37, 0x8E, 0x06, 0x3F, 0x35, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0x72, 0x6F, 0xAE, 0x32, 0xFB, 0x96, 0xD8, 0x78, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x0D, 0xB5, + 0x5D, 0x73, 0x2A, 0xB7, 0x20, 0xCF, 0xAD, 0x19, 0x08, 0xFE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x50, + 0xE1, 0xBF, 0x01, 0x6B, 0x77, 0x9F, 0x8D, 0x07, 0x15, 0x1D, 0xE1, 0x44, 0x68, 0x34, 0xDB, 0xF0, + 0xF5, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xE7, 0x7F, 0x02, 0xFA, 0xAE, 0xB9, 0x36, 0x1C, + 0x54, 0x78, 0xB8, 0x89, 0xC0, 0x68, 0xB5, 0x5D, 0x97, 0x1A, 0xF3, 0xEC, 0x8D, 0xC6, 0x3C, 0xB7, + 0x9A, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x93, 0x6C, 0x80, 0xAC, 0xD7, 0xE1, 0xE1, 0x26, 0xE2, + 0xA2, 0xE5, 0x3E, 0x5C, 0xD9, 0x81, 0xAB, 0x8C, 0xF7, 0xEC, 0x0D, 0x27, 0x83, 0xBF, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0xBC, 0xE7, 0x3D, 0xDE, 0xF0, 0x8A, 0x06, 0x6F, 0xC0, 0x52, 0x71, 0xD1, 0x6A, + 0x41, 0x7C, 0xB8, 0xED, 0xF8, 0x44, 0xE5, 0x16, 0xE4, 0xF0, 0x8D, 0xEB, 0x82, 0xBF, 0x14, 0x00, + 0x00, 0x00, 0x80, 0xE9, 0xCE, 0x3B, 0x70, 0xFD, 0xC9, 0xDC, 0xE3, 0x23, 0x1C, 0xB7, 0x20, 0x00, + 0x00, 0x00, 0x00, 0xA2, 0xCC, 0xFE, 0x2B, 0x6D, 0x2C, 0x14, 0x10, 0x1F, 0x6E, 0xEE, 0x16, 0xE4, + 0xF0, 0x2A, 0x77, 0x0B, 0xB2, 0x3E, 0xF8, 0xCB, 0x01, 0x00, 0x00, 0x00, 0x98, 0xAE, 0x6C, 0x18, + 0x2C, 0x31, 0x7B, 0x2E, 0xB3, 0xB1, 0x50, 0x40, 0x7C, 0x84, 0xDB, 0x77, 0xB9, 0x7B, 0x23, 0xD6, + 0xB8, 0x7B, 0xDD, 0x6F, 0xF0, 0x97, 0x05, 0x00, 0x00, 0x00, 0x30, 0x1D, 0x99, 0x43, 0x37, 0xAD, + 0x9D, 0x7C, 0x03, 0x96, 0x8A, 0x8B, 0x56, 0x13, 0xC1, 0x11, 0xDF, 0xF6, 0x8F, 0x71, 0x0B, 0x02, + 0x00, 0x00, 0x00, 0x20, 0x78, 0x03, 0xD6, 0xF6, 0x8F, 0xDB, 0x50, 0x50, 0x71, 0xD1, 0x6A, 0x22, + 0x36, 0x1A, 0x8D, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB3, 0x37, 0x0D, 0xEA, 0xB8, 0x68, + 0x35, 0x11, 0x19, 0xAD, 0x76, 0xA8, 0xDF, 0x3D, 0x90, 0x3E, 0x18, 0xFC, 0xA5, 0x01, 0x00, 0x00, + 0x00, 0x4C, 0x37, 0xDE, 0x81, 0x6B, 0x46, 0x75, 0x60, 0x34, 0x9B, 0x88, 0x8B, 0x56, 0xDB, 0xFA, + 0x21, 0x63, 0x86, 0xE6, 0x57, 0x5E, 0xCB, 0x3B, 0xB2, 0x66, 0x76, 0xF0, 0x97, 0x07, 0x00, 0x00, + 0x00, 0x30, 0x9D, 0x98, 0x03, 0x57, 0xDB, 0x40, 0x50, 0x91, 0xD1, 0x68, 0x22, 0x2E, 0x5A, 0xCD, + 0xC5, 0x47, 0x38, 0x6E, 0x41, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC9, 0xDD, 0x44, 0x98, 0x7D, 0x9F, + 0xB1, 0x91, 0xA0, 0x42, 0x43, 0x4D, 0xC4, 0x45, 0xAB, 0x45, 0xE3, 0xC3, 0x6D, 0xF7, 0xDC, 0xCA, + 0x2D, 0xC8, 0x73, 0xAB, 0x07, 0x82, 0x5F, 0x06, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC0, 0x3C, 0xB7, + 0x66, 0xC0, 0xEC, 0x9E, 0x67, 0x43, 0x41, 0xC5, 0x46, 0x7C, 0x22, 0x2E, 0x5A, 0x2D, 0x1E, 0x1F, + 0xE1, 0x86, 0xAF, 0x73, 0x0F, 0xA4, 0x8F, 0x06, 0xBF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x81, + 0xF7, 0xEC, 0x4D, 0x77, 0x99, 0x9D, 0x97, 0xD8, 0x58, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x8B, 0x56, + 0x53, 0xE1, 0x11, 0x6E, 0xD7, 0xA7, 0xB9, 0x05, 0x01, 0x00, 0x00, 0x00, 0xA6, 0x1B, 0xEF, 0xF0, + 0x8D, 0x1B, 0x74, 0x70, 0x44, 0x27, 0xE2, 0xA2, 0xD5, 0x54, 0x74, 0xC4, 0xC7, 0x2D, 0x08, 0x00, + 0x00, 0x00, 0x30, 0xBD, 0x78, 0x07, 0xAF, 0x6F, 0xF1, 0x06, 0x2C, 0x11, 0x17, 0xAD, 0xA6, 0x62, + 0x43, 0xCD, 0x7D, 0xF6, 0x88, 0xBB, 0x05, 0x39, 0x7C, 0xE3, 0xBA, 0xE0, 0x97, 0x03, 0x00, 0x00, + 0x00, 0xA0, 0xCC, 0xBC, 0x03, 0xD7, 0x9D, 0xD4, 0xE1, 0xE1, 0x26, 0xE2, 0xA2, 0xD5, 0x54, 0x68, + 0x34, 0xDB, 0xFE, 0x2B, 0xDD, 0x1B, 0xB1, 0x4E, 0x06, 0xBF, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x65, + 0xD6, 0xF8, 0x0D, 0x58, 0x22, 0x2E, 0x5A, 0x4D, 0x05, 0x46, 0xAB, 0xB9, 0x5B, 0x90, 0xC3, 0x37, + 0x70, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x94, 0x9D, 0xFF, 0x06, 0xAC, 0xA1, 0x05, 0x36, 0x1E, 0x3A, + 0x14, 0x1F, 0xFE, 0x3E, 0x68, 0x5C, 0x04, 0x79, 0x87, 0x6E, 0x18, 0x37, 0xA3, 0xFD, 0xB3, 0x82, + 0x5F, 0x1A, 0x00, 0x00, 0x00, 0x80, 0xB2, 0x71, 0xB7, 0x0E, 0x66, 0xD7, 0x1C, 0x1B, 0x10, 0x1D, + 0x8C, 0x0F, 0x37, 0xF7, 0xD7, 0x3D, 0xB4, 0xD2, 0x98, 0xC3, 0xAB, 0xD7, 0x07, 0xBF, 0x34, 0x00, + 0x00, 0x00, 0x00, 0x65, 0x63, 0x03, 0x64, 0xBD, 0xD9, 0x7E, 0x71, 0x25, 0x00, 0x3A, 0x15, 0x1F, + 0xE1, 0xF6, 0x5E, 0xC6, 0x2D, 0x08, 0x00, 0x00, 0x00, 0x50, 0x66, 0xDE, 0xC8, 0xCA, 0xA1, 0xAE, + 0x88, 0x0F, 0xB7, 0xE0, 0x16, 0xC4, 0x3B, 0xBC, 0x7A, 0x43, 0xF0, 0xCB, 0x03, 0x00, 0x00, 0x00, + 0x50, 0x26, 0xDE, 0xC1, 0x6B, 0xC7, 0xBA, 0x22, 0x3E, 0xC2, 0xED, 0xEE, 0xAB, 0x3C, 0x90, 0x3E, + 0xB2, 0x66, 0x76, 0xF0, 0x4B, 0x04, 0x00, 0x00, 0x00, 0x50, 0x16, 0x66, 0xFF, 0x67, 0x75, 0x5C, + 0xB4, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0xD1, 0x11, 0xDF, 0xC8, 0x0A, 0xE3, 0x1D, 0x5A, 0x3D, 0x18, + 0xFC, 0x12, 0x01, 0x00, 0x00, 0x00, 0x94, 0x81, 0xBB, 0x65, 0x30, 0xFB, 0x2E, 0xD7, 0x81, 0xD1, + 0x6C, 0x32, 0x2C, 0x92, 0x4C, 0xC4, 0x86, 0x1A, 0xB7, 0x20, 0x00, 0x00, 0x00, 0x40, 0xF9, 0x98, + 0xE7, 0x56, 0x0F, 0x98, 0x5D, 0x97, 0xEA, 0xC8, 0x68, 0x34, 0x19, 0x16, 0x49, 0x26, 0x42, 0xA3, + 0xD9, 0x0E, 0x7E, 0xCE, 0x78, 0x87, 0x6F, 0x18, 0x0D, 0x7E, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x7A, + 0x9D, 0xFF, 0x06, 0xAC, 0x1D, 0x9F, 0xD0, 0xA1, 0xA1, 0x26, 0xC3, 0x22, 0xC9, 0x44, 0x60, 0xB4, + 0xDA, 0xCE, 0x4B, 0x82, 0x5B, 0x90, 0xD5, 0x03, 0xC1, 0x2F, 0x17, 0x00, 0x00, 0x00, 0x40, 0x2F, + 0xF3, 0x9E, 0xBD, 0x61, 0x50, 0x86, 0x86, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0x71, 0x91, 0x74, 0x07, + 0xAF, 0x35, 0xDE, 0xE1, 0x55, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x65, 0xE0, 0x1D, 0xBC, 0x6E, + 0x54, 0xC6, 0x46, 0x7C, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, 0x6D, 0xF9, 0x80, 0x31, 0x3B, + 0x67, 0xBB, 0x0F, 0x26, 0x34, 0xE6, 0xD0, 0xAA, 0xB5, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, 0x40, + 0xAF, 0xF2, 0x0E, 0x5C, 0x33, 0x2E, 0x83, 0x23, 0x3A, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, + 0x5C, 0x7C, 0x84, 0xDB, 0x77, 0x85, 0xFB, 0x5C, 0x90, 0x93, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, + 0x40, 0x2F, 0x72, 0x9F, 0x36, 0xDE, 0xF2, 0x0D, 0x58, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, + 0x45, 0xE3, 0xC3, 0x6D, 0xDB, 0xC7, 0x2A, 0xB7, 0x20, 0x87, 0x57, 0xAD, 0x0B, 0x7E, 0xE9, 0x00, + 0x00, 0x00, 0x00, 0x7A, 0x8D, 0xFF, 0x06, 0xAC, 0xDD, 0x73, 0xEB, 0xA3, 0x23, 0x9C, 0x0C, 0x8B, + 0x24, 0x13, 0x51, 0x91, 0x74, 0xF1, 0xF8, 0x08, 0xC7, 0x2D, 0x08, 0x00, 0x00, 0x00, 0xD0, 0xDB, + 0xCC, 0xE1, 0x1B, 0xD7, 0x35, 0x7C, 0x05, 0xAF, 0x0C, 0x8B, 0x24, 0x13, 0x51, 0x91, 0x74, 0x2A, + 0x3C, 0xC2, 0x6D, 0xB5, 0xBF, 0xA6, 0x43, 0x03, 0xEE, 0x26, 0x64, 0x7D, 0xF0, 0xCB, 0x07, 0x00, + 0x00, 0x00, 0xD0, 0x4B, 0xFC, 0x57, 0xF0, 0xF6, 0x42, 0x7C, 0x84, 0xDB, 0xB3, 0xD8, 0x7D, 0x3A, + 0xFA, 0xB8, 0xFB, 0xD6, 0xB1, 0xE0, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x57, 0x78, 0xC3, 0xCB, + 0xEB, 0xDF, 0x80, 0x25, 0xC3, 0x22, 0xC9, 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x0D, 0x35, 0x6E, 0x41, + 0x00, 0x00, 0x00, 0x80, 0xDE, 0xE5, 0x1D, 0xBC, 0x76, 0xAC, 0x67, 0xE2, 0x23, 0xDC, 0x9E, 0x45, + 0xC6, 0x3B, 0xB4, 0x6A, 0xDC, 0x8C, 0xF4, 0xCF, 0x0E, 0x7E, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x7A, + 0x81, 0xD9, 0x7F, 0x45, 0x6F, 0xC5, 0x87, 0xBF, 0xF7, 0x1B, 0x33, 0xB2, 0xCC, 0x46, 0xC8, 0xCA, + 0xC1, 0xE0, 0xB7, 0x01, 0x00, 0x00, 0x00, 0xA0, 0xDB, 0x99, 0xC3, 0x37, 0x2E, 0x71, 0xB7, 0x09, + 0x3D, 0x17, 0x1F, 0x6E, 0xEE, 0xCD, 0x5D, 0x87, 0x57, 0xD9, 0x10, 0xE9, 0xCD, 0x5B, 0x10, 0xF7, + 0xEB, 0xB6, 0x1B, 0x08, 0xC6, 0x4D, 0x0E, 0x00, 0x00, 0x00, 0xCA, 0xCF, 0x1C, 0xBA, 0x69, 0xAD, + 0xFF, 0x06, 0x2C, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x5A, 0x10, 0x1F, + 0xE1, 0x7A, 0xEC, 0x16, 0xC4, 0xFF, 0xCC, 0x95, 0x91, 0xFE, 0xF5, 0xDE, 0xA1, 0x81, 0x93, 0xFE, + 0x73, 0x2C, 0x91, 0xF9, 0xFF, 0x9A, 0xFD, 0xF7, 0x78, 0xB8, 0x1E, 0x00, 0x00, 0x00, 0xA5, 0x55, + 0x79, 0x03, 0xD6, 0x47, 0x6D, 0x10, 0xA8, 0xB8, 0x68, 0x35, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, + 0xD5, 0x62, 0xF1, 0xE1, 0xB6, 0xF3, 0x53, 0xC1, 0x2D, 0xC8, 0xEA, 0x81, 0xE0, 0xB7, 0xD4, 0xB5, + 0xCC, 0xA1, 0xFE, 0xB5, 0xDE, 0xC8, 0xC0, 0x78, 0x3C, 0x3C, 0xE2, 0xAB, 0xFC, 0x67, 0xFA, 0xD7, + 0x06, 0xFF, 0x35, 0x00, 0x00, 0x00, 0xA0, 0x3C, 0xBC, 0x67, 0x6F, 0x18, 0xD4, 0x71, 0xD1, 0x6A, + 0x22, 0x2A, 0x92, 0x4E, 0xC6, 0x45, 0xAB, 0x89, 0xF8, 0x08, 0x77, 0xF0, 0x1A, 0xE3, 0x1D, 0x5E, + 0x39, 0x1A, 0xFC, 0x96, 0xBA, 0x92, 0x19, 0xE9, 0x5F, 0x57, 0x8D, 0x8C, 0x91, 0xE5, 0xFE, 0x43, + 0xF4, 0x66, 0xC7, 0xC7, 0x6B, 0xE7, 0xFE, 0x35, 0xF7, 0xEF, 0xF9, 0xFF, 0x99, 0x7E, 0x37, 0x3E, + 0xF1, 0x1D, 0x00, 0x00, 0x00, 0xE5, 0xE2, 0x1D, 0xB8, 0x7A, 0x54, 0x07, 0x46, 0xB3, 0x89, 0xA8, + 0x48, 0x3A, 0x19, 0x17, 0xAD, 0x26, 0xA2, 0x23, 0xBA, 0x2E, 0xBF, 0x05, 0xB1, 0x21, 0x31, 0xBB, + 0x7A, 0xF3, 0x31, 0x34, 0xBF, 0xF2, 0x6B, 0xDE, 0x3C, 0x4B, 0xCF, 0xFD, 0x7B, 0x43, 0x7D, 0x7E, + 0x80, 0x78, 0x23, 0x2B, 0x78, 0xCB, 0x17, 0x00, 0x00, 0x00, 0xCA, 0xC5, 0xEC, 0xBF, 0xD2, 0x86, + 0x81, 0x8A, 0x8C, 0x46, 0x13, 0x51, 0x91, 0x74, 0x32, 0x2E, 0x5A, 0x2D, 0x12, 0x1A, 0xCD, 0xE6, + 0x6E, 0x41, 0x0E, 0xAD, 0x1A, 0x0B, 0x7E, 0x5B, 0x5D, 0xC5, 0xC6, 0xC7, 0x90, 0x1F, 0x1F, 0xBB, + 0x3E, 0xAD, 0xA3, 0xA3, 0x66, 0x17, 0x55, 0xB6, 0xF3, 0x92, 0x4A, 0x84, 0x0C, 0xAF, 0xE8, 0xEA, + 0x9B, 0x1D, 0x00, 0x00, 0x00, 0x20, 0x31, 0xFF, 0x81, 0xE8, 0xBD, 0x97, 0xDB, 0x38, 0x50, 0xA1, + 0xA1, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x9A, 0x08, 0x8D, 0x46, 0x73, 0xCF, 0xB1, 0xB8, + 0x5B, 0x90, 0xC3, 0xAB, 0xBA, 0xEA, 0xDB, 0x96, 0x6C, 0x44, 0x0C, 0xF8, 0xF1, 0xE1, 0xDE, 0xD8, + 0x25, 0x83, 0x23, 0xBA, 0x20, 0x3E, 0x62, 0x11, 0xE2, 0x7E, 0x8E, 0xE0, 0xA7, 0x03, 0x00, 0x00, + 0x00, 0x7A, 0x97, 0x79, 0x6E, 0xF5, 0x80, 0x7F, 0x30, 0x96, 0xB1, 0x11, 0x9F, 0x88, 0x8A, 0xA4, + 0x93, 0x71, 0xD1, 0x6A, 0x22, 0x32, 0x5A, 0x6D, 0xDF, 0x12, 0xE3, 0x1D, 0x5E, 0x75, 0x32, 0xF8, + 0xED, 0x75, 0x05, 0xEF, 0xD0, 0xC0, 0xA8, 0x39, 0x70, 0x55, 0x10, 0x18, 0xCD, 0x16, 0x8B, 0x8F, + 0x70, 0xFB, 0xAF, 0xE4, 0x16, 0x04, 0x00, 0x00, 0x00, 0xE5, 0xE0, 0x3D, 0x7B, 0xC3, 0x5D, 0x66, + 0xC7, 0xA7, 0x6C, 0x24, 0xA8, 0xE0, 0x88, 0x4E, 0x44, 0x45, 0xD2, 0xC9, 0xB8, 0x68, 0x35, 0x11, + 0x17, 0x49, 0x16, 0xDC, 0x82, 0x78, 0x87, 0x56, 0xDD, 0x15, 0xFC, 0x16, 0x3B, 0xAA, 0x7A, 0xFB, + 0xE1, 0x1E, 0x30, 0x97, 0xD1, 0x11, 0x4E, 0x84, 0x47, 0xB8, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, + 0x00, 0x80, 0x72, 0xF0, 0x0E, 0xDF, 0xB8, 0x41, 0x07, 0x47, 0x74, 0x22, 0x2A, 0x92, 0x4E, 0xC6, + 0x45, 0xAB, 0x89, 0xB0, 0x48, 0xB3, 0x3D, 0x0B, 0x8D, 0x37, 0xB2, 0x72, 0xBC, 0x1B, 0x3E, 0x4B, + 0x23, 0xD9, 0xED, 0x87, 0x88, 0x8E, 0xF8, 0xB8, 0x05, 0x01, 0x00, 0x00, 0x40, 0x19, 0x78, 0x07, + 0xAF, 0x6B, 0xF1, 0x06, 0x2C, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, 0xD5, 0x44, 0x50, 0xA4, 0xDA, + 0x1F, 0x57, 0xFE, 0xDA, 0x23, 0x2B, 0xEC, 0x56, 0xAE, 0x0F, 0x7E, 0x9B, 0x1D, 0xE1, 0x3E, 0xC7, + 0xC3, 0xBF, 0xFD, 0x70, 0x7F, 0x1F, 0x65, 0x78, 0xB8, 0x89, 0xD8, 0x50, 0xF3, 0x7F, 0x4F, 0xFD, + 0xC6, 0x1C, 0xE4, 0xB3, 0x41, 0x00, 0x00, 0x00, 0xD0, 0xC3, 0xBC, 0x03, 0x9F, 0x3B, 0x59, 0x1F, + 0x1D, 0xE1, 0x22, 0x31, 0x91, 0x76, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xD9, 0xF8, 0x08, + 0xD7, 0x05, 0xB7, 0x20, 0xFE, 0xA7, 0x9A, 0xBB, 0x07, 0xFC, 0x65, 0x78, 0xB8, 0x89, 0xD0, 0x68, + 0xB6, 0xBD, 0x97, 0xB9, 0x5B, 0x90, 0xAE, 0x7A, 0xBE, 0x05, 0x00, 0x00, 0x00, 0x48, 0xA5, 0xF1, + 0x1B, 0xB0, 0x44, 0x54, 0x24, 0x9D, 0x8C, 0x8B, 0x56, 0x53, 0x41, 0x91, 0x66, 0x91, 0xF8, 0x70, + 0x73, 0xBF, 0x8E, 0xE1, 0xA5, 0xEE, 0x13, 0xC5, 0x37, 0x04, 0xBF, 0xD5, 0x29, 0x65, 0xC2, 0x0F, + 0x1D, 0x74, 0x7F, 0x2F, 0xF3, 0x88, 0x0F, 0x37, 0xF7, 0x7B, 0xF2, 0x9F, 0x05, 0x59, 0xCE, 0x87, + 0x13, 0x02, 0x00, 0x00, 0xA0, 0xF7, 0xF8, 0x6F, 0xC0, 0x72, 0x1F, 0x8A, 0x57, 0xB6, 0xF8, 0x08, + 0xB7, 0x6B, 0x8E, 0x31, 0x87, 0x56, 0xBA, 0x43, 0xFB, 0x94, 0x7F, 0x90, 0x5F, 0xF3, 0xDB, 0x0F, + 0x11, 0x17, 0x49, 0xB7, 0x67, 0xB1, 0xF1, 0x86, 0x97, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x80, 0xDE, + 0x63, 0x0E, 0xDD, 0xB4, 0xD6, 0xFF, 0x60, 0xBC, 0x32, 0xC6, 0x47, 0x38, 0x77, 0x0B, 0x72, 0x68, + 0xE5, 0x60, 0xF0, 0x5B, 0x9E, 0x12, 0xCD, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0xDD, 0x33, 0x17, 0xDA, + 0xDF, 0x93, 0xFD, 0x7B, 0x66, 0x7F, 0x4F, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0xE7, 0x98, 0xC3, + 0x37, 0xAE, 0xF7, 0x5F, 0x5B, 0x5B, 0xD6, 0xF8, 0x70, 0x0B, 0x6F, 0x41, 0x0E, 0xF7, 0x2F, 0x09, + 0x7E, 0xDB, 0x85, 0x72, 0xCF, 0x9C, 0xF8, 0xB7, 0x1F, 0xEE, 0x66, 0x29, 0xEF, 0xF8, 0x08, 0xB7, + 0x7B, 0x9E, 0xF1, 0x46, 0x96, 0x8F, 0x9B, 0xA1, 0xCE, 0xBF, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, + 0xCC, 0x1B, 0x59, 0x39, 0x54, 0xEA, 0xF8, 0x08, 0x77, 0xE0, 0x6A, 0x77, 0x0B, 0x32, 0x25, 0xAF, + 0xB0, 0x35, 0x23, 0xFD, 0xEB, 0xCD, 0xC8, 0x72, 0xFB, 0xD7, 0xB5, 0xBF, 0xC6, 0x22, 0xE2, 0xC3, + 0x6D, 0xF3, 0xFB, 0xC2, 0x5B, 0x90, 0x8E, 0xBE, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, 0xC5, 0xDB, + 0x7F, 0xED, 0x58, 0xE9, 0xE3, 0xC3, 0x6D, 0xC7, 0x27, 0xC3, 0x67, 0x41, 0x0A, 0xFD, 0x20, 0x3F, + 0xFF, 0xF6, 0x63, 0x64, 0x60, 0xBC, 0xFE, 0xF6, 0x43, 0x44, 0x45, 0xD2, 0xC5, 0xE3, 0x23, 0x1C, + 0xB7, 0x20, 0x00, 0x00, 0x00, 0xE8, 0x35, 0x66, 0xDF, 0x12, 0x1D, 0x15, 0x49, 0x27, 0xE3, 0xA2, + 0xD5, 0x54, 0x50, 0xA4, 0x99, 0x08, 0x8C, 0x56, 0x73, 0x37, 0x06, 0x53, 0x70, 0x0B, 0xA2, 0x6F, + 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8F, 0x70, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0x97, 0x98, + 0x91, 0x35, 0xB3, 0xDD, 0xE7, 0x4A, 0xC8, 0xB0, 0x48, 0x32, 0x19, 0x17, 0xAD, 0x16, 0x8F, 0x89, + 0xB4, 0x13, 0x71, 0xD1, 0x6A, 0xEE, 0xA0, 0xEE, 0xB6, 0xED, 0x63, 0x95, 0x5B, 0x90, 0x43, 0xC5, + 0x7C, 0x90, 0x9F, 0xBE, 0xFD, 0x10, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0xE2, 0xE3, 0x16, 0x04, 0x00, + 0x00, 0x00, 0xBD, 0xC2, 0x8C, 0xAC, 0x1E, 0x30, 0x3B, 0x2F, 0xD1, 0x71, 0xD1, 0x6A, 0x32, 0x2E, + 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0x30, 0x3E, 0xC2, 0xED, 0xFD, 0x8C, 0xBB, + 0x05, 0x29, 0xE4, 0x15, 0xB6, 0xEE, 0xF3, 0x46, 0xCC, 0xF0, 0xF5, 0xF6, 0xAF, 0x33, 0x45, 0xF1, + 0x11, 0xEE, 0xE0, 0xE7, 0x6C, 0x84, 0xAC, 0xE8, 0xC8, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x89, + 0x99, 0xC3, 0xAB, 0xD7, 0x9B, 0xED, 0x17, 0xEB, 0xC0, 0x68, 0x36, 0x19, 0x17, 0xAD, 0xA6, 0x82, + 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x5A, 0x3C, 0x3E, 0xDC, 0xB6, 0x7E, 0x38, 0x7C, 0x16, 0x24, 0xD7, + 0x57, 0xD8, 0xDA, 0x9F, 0x6F, 0xB6, 0xFF, 0xDA, 0x5D, 0xF7, 0x4A, 0xE3, 0xA9, 0x8C, 0x0F, 0xB7, + 0x9D, 0xB3, 0xED, 0xEF, 0x67, 0x85, 0xFB, 0x3D, 0x4D, 0xF9, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x79, 0x87, 0x57, 0x6F, 0x90, 0x81, 0xD1, 0x6C, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, + 0x89, 0xB8, 0x68, 0x35, 0x15, 0x1F, 0xE1, 0x82, 0x5B, 0x10, 0xF7, 0x2D, 0x53, 0xC1, 0xDF, 0x8A, + 0xB6, 0x79, 0x87, 0x06, 0x06, 0x27, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8C, 0x24, 0x73, + 0xB7, 0x20, 0xC3, 0x2B, 0xA6, 0xF4, 0xB3, 0x4E, 0x00, 0x00, 0x00, 0x80, 0x54, 0xBC, 0x83, 0x9F, + 0x1B, 0x95, 0x91, 0xD1, 0x68, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0x35, + 0x15, 0x1D, 0xD1, 0xB9, 0x5F, 0x97, 0x7F, 0x63, 0xB0, 0x32, 0x97, 0x87, 0xB7, 0x6B, 0x6F, 0x3F, + 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8B, 0xA4, 0xE3, 0x16, 0x04, 0x00, 0x00, 0x00, 0xDD, 0xCE, 0xDB, + 0x7F, 0xD5, 0xB8, 0x0C, 0x0D, 0xB5, 0xBA, 0xB0, 0x48, 0x32, 0x15, 0x14, 0x69, 0x26, 0xE2, 0xA2, + 0xD5, 0x54, 0x70, 0xA8, 0x0D, 0x2D, 0x30, 0xDE, 0xC8, 0xCA, 0xF1, 0x3C, 0x6E, 0x41, 0xFC, 0xDB, + 0x8F, 0x03, 0xD7, 0xDA, 0x9F, 0x57, 0x44, 0x45, 0xD2, 0xA9, 0xA8, 0x48, 0x3B, 0xF7, 0x96, 0xAF, + 0xE1, 0x65, 0xDC, 0x82, 0x34, 0x60, 0xC6, 0xFE, 0xC3, 0x2C, 0xF3, 0xF2, 0xBF, 0x5F, 0x67, 0x4E, + 0x7C, 0x65, 0x7D, 0x64, 0x6B, 0xDD, 0xBF, 0x1E, 0xFC, 0x47, 0x00, 0x00, 0x00, 0x50, 0x14, 0x77, + 0xF0, 0x4E, 0xFC, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, + 0x0A, 0x8D, 0x46, 0x73, 0xBF, 0xC6, 0x1C, 0x6E, 0x41, 0xDC, 0xA7, 0xAB, 0xFB, 0xB7, 0x1F, 0xEE, + 0x59, 0x1A, 0x15, 0x16, 0x49, 0xA6, 0x62, 0x22, 0xCB, 0xB6, 0x7F, 0xD4, 0xFE, 0x7E, 0x96, 0xDB, + 0x2D, 0x2D, 0xF4, 0xB3, 0x4E, 0x7A, 0x8D, 0x0B, 0x0C, 0xEF, 0xC4, 0x97, 0x07, 0xCD, 0x2F, 0xBE, + 0x62, 0xE4, 0x4E, 0x7C, 0xC9, 0xF8, 0xFF, 0x3E, 0x21, 0x02, 0x00, 0x00, 0x50, 0x1C, 0xFF, 0x0D, + 0x58, 0xBB, 0xE6, 0xE8, 0xE0, 0x88, 0xAE, 0x2E, 0x2C, 0x92, 0x4C, 0x05, 0x45, 0x9A, 0x89, 0xB8, + 0x68, 0x35, 0x15, 0x19, 0xAD, 0xE6, 0xBF, 0xC2, 0x76, 0xE5, 0x78, 0x3B, 0xDF, 0xB6, 0xE4, 0x1D, + 0x1A, 0x18, 0x35, 0xFB, 0xAF, 0xB4, 0x3F, 0x9F, 0x08, 0x8B, 0x24, 0x53, 0x21, 0x91, 0x69, 0x33, + 0x2B, 0xDB, 0x7F, 0x85, 0xF1, 0x86, 0x97, 0x4F, 0xC9, 0x27, 0xBE, 0xF7, 0x02, 0x73, 0xFC, 0xDF, + 0x2F, 0xF1, 0x7E, 0xF1, 0xE5, 0xF1, 0xDA, 0xE0, 0xB8, 0xDD, 0x98, 0xE3, 0x5F, 0xF4, 0xC3, 0x23, + 0xFA, 0xAF, 0xFB, 0xFF, 0x39, 0xFB, 0x9F, 0x0F, 0xFE, 0xAB, 0x00, 0x00, 0x00, 0xC8, 0x93, 0x39, + 0x7C, 0xE3, 0xBA, 0x96, 0xAF, 0xE0, 0x95, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, + 0xAB, 0xA9, 0xB8, 0x48, 0xBA, 0xE1, 0xEB, 0x8D, 0xFB, 0x16, 0xAA, 0xE0, 0x6F, 0x4B, 0x2A, 0x36, + 0x5C, 0x06, 0xEC, 0xB2, 0xDF, 0x7E, 0xC8, 0x90, 0xC8, 0xB2, 0x20, 0x3E, 0xDC, 0xB8, 0x05, 0xA9, + 0xAA, 0x89, 0x0F, 0x17, 0x1D, 0x2F, 0xD9, 0xFF, 0xAD, 0x5E, 0xB0, 0xB1, 0xF8, 0xFC, 0x92, 0xC9, + 0xBD, 0x70, 0xB5, 0xFD, 0xD7, 0x57, 0x55, 0xFE, 0x7D, 0x22, 0x04, 0x00, 0x00, 0xA0, 0x38, 0xFE, + 0x2B, 0x78, 0x55, 0x74, 0x84, 0x93, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, + 0xA9, 0xA8, 0x48, 0xBC, 0x59, 0x95, 0x07, 0xC7, 0xDD, 0xB7, 0x50, 0x65, 0xB8, 0x05, 0xF1, 0x86, + 0x57, 0x64, 0xBF, 0xFD, 0x90, 0x21, 0x91, 0x65, 0x91, 0xF8, 0x08, 0xC7, 0x2D, 0x48, 0x6D, 0x7C, + 0x1C, 0xB9, 0xB1, 0x36, 0x3A, 0xD4, 0x5C, 0x98, 0x1C, 0xFD, 0x42, 0x25, 0x42, 0x4E, 0x7C, 0x85, + 0x1B, 0x24, 0x00, 0x00, 0x80, 0xBC, 0x79, 0x07, 0x97, 0x35, 0x7E, 0x03, 0x96, 0x8C, 0x8B, 0x56, + 0x53, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0x85, 0x1F, 0x16, 0x68, 0xE7, + 0x6E, 0x41, 0x46, 0x06, 0x86, 0x82, 0xBF, 0x35, 0x89, 0xB4, 0x75, 0xFB, 0x21, 0x43, 0x22, 0xCB, + 0x44, 0x7C, 0xB8, 0x6D, 0xFD, 0xD0, 0xB4, 0xBE, 0x05, 0xA9, 0x89, 0x0F, 0x77, 0xEB, 0xA1, 0x82, + 0xA3, 0xD1, 0x5C, 0xAC, 0xF8, 0x37, 0x26, 0x5F, 0x29, 0xE4, 0xD3, 0xF2, 0x01, 0x00, 0x00, 0xA6, + 0x2D, 0x6F, 0xFF, 0x35, 0x63, 0xC4, 0x47, 0xB0, 0xED, 0x1F, 0xB7, 0x87, 0x75, 0xFF, 0x16, 0x24, + 0xF1, 0x81, 0xDD, 0x1B, 0x59, 0x31, 0xE6, 0x3F, 0xC4, 0xAF, 0x02, 0xA3, 0xD9, 0x64, 0x48, 0x64, + 0x99, 0x08, 0x8F, 0xE8, 0xF6, 0x2C, 0xB2, 0x51, 0xB5, 0x7C, 0x2C, 0xF8, 0xE5, 0x4E, 0x1B, 0x6D, + 0xC5, 0x47, 0xB8, 0x63, 0x7F, 0xE2, 0x3F, 0x94, 0x1E, 0xFC, 0x94, 0x00, 0x00, 0x00, 0xC8, 0x83, + 0xD9, 0xF7, 0x19, 0xE2, 0xC3, 0xED, 0x99, 0x60, 0xFB, 0xAF, 0x32, 0xDE, 0xF0, 0x40, 0xA2, 0x6F, + 0xBD, 0xB1, 0xA1, 0xB2, 0xCE, 0xBF, 0xFD, 0x70, 0x7F, 0xCF, 0x54, 0x64, 0x34, 0x9A, 0x0C, 0x89, + 0x2C, 0x13, 0xC1, 0x11, 0x9F, 0xFB, 0x7B, 0xEB, 0xDF, 0x82, 0x2C, 0xCF, 0xF5, 0x13, 0xDF, 0xBB, + 0x59, 0x2E, 0xF1, 0xE1, 0xF6, 0xC2, 0xD5, 0xEE, 0xDB, 0xB0, 0x4E, 0x06, 0x3F, 0x2D, 0x00, 0x00, + 0x00, 0xDA, 0x65, 0x0E, 0xDF, 0xB8, 0xC4, 0x0C, 0x2D, 0x9C, 0xBE, 0xF1, 0x11, 0x46, 0x47, 0xF0, + 0x7F, 0x7B, 0x6E, 0xDB, 0x3F, 0xEE, 0xBE, 0x0D, 0x2B, 0xD1, 0x2D, 0x88, 0x37, 0xBC, 0xE2, 0x64, + 0xEA, 0xDB, 0x0F, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, 0xD1, 0xDC, 0x2D, 0xC8, 0xF0, 0xB2, 0x69, + 0x71, 0x90, 0xCE, 0x2D, 0x3E, 0xC2, 0x1D, 0xBB, 0xC5, 0x04, 0x3F, 0x35, 0x00, 0x00, 0x00, 0xDA, + 0x65, 0x0E, 0xAD, 0x5A, 0x5B, 0xF3, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, + 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0xAB, 0x8F, 0x0F, 0x3F, 0x3C, 0xC2, 0x6D, 0xB2, 0xDB, 0x7B, + 0x85, 0x39, 0x3F, 0x3C, 0xD0, 0xF4, 0xC0, 0x9E, 0xE9, 0xF6, 0x43, 0x86, 0x44, 0x96, 0x89, 0xC8, + 0x68, 0x36, 0xF7, 0xF7, 0x79, 0x1A, 0xDC, 0x82, 0xE4, 0x1E, 0x1F, 0xCF, 0x7F, 0xC6, 0x98, 0x23, + 0x37, 0x18, 0xF3, 0xF2, 0x9D, 0x7C, 0x9E, 0x0A, 0x00, 0x00, 0x40, 0x1E, 0xFC, 0x37, 0x60, 0x6D, + 0xFB, 0xC8, 0xF4, 0x8D, 0x8F, 0x68, 0x78, 0xB8, 0xB9, 0xF8, 0x70, 0xDB, 0xFC, 0x21, 0xF7, 0x6D, + 0x58, 0xEE, 0x16, 0xA4, 0xE1, 0x81, 0xDD, 0xBF, 0xFD, 0xD8, 0xB3, 0xD0, 0xFE, 0x7C, 0x22, 0x34, + 0xD4, 0x64, 0x48, 0x64, 0x99, 0x08, 0x8C, 0x24, 0x1B, 0x9A, 0x5F, 0xEA, 0x5B, 0x90, 0x42, 0xE2, + 0xC3, 0x6D, 0xEC, 0x3A, 0x17, 0x20, 0xD3, 0xE6, 0xDB, 0xD7, 0x00, 0x00, 0x00, 0x0A, 0xE5, 0x1D, + 0x5A, 0x3D, 0x38, 0xED, 0xE2, 0x23, 0x12, 0x20, 0xD5, 0xE8, 0x88, 0xC4, 0xC7, 0xF9, 0x70, 0x43, + 0x97, 0x9B, 0x73, 0x07, 0xF5, 0x2D, 0xC8, 0xF9, 0x91, 0xFE, 0xF5, 0x66, 0x78, 0x99, 0xFD, 0xB9, + 0xDC, 0xAF, 0x49, 0xC4, 0x46, 0x7C, 0x32, 0x24, 0xB2, 0x4C, 0x84, 0x45, 0xD2, 0xB9, 0xDF, 0xF7, + 0xF0, 0xF5, 0xEE, 0x16, 0xA4, 0xAD, 0x4F, 0x7C, 0xEF, 0x46, 0x85, 0xC5, 0x87, 0xDB, 0x0B, 0x57, + 0x19, 0x73, 0xE2, 0xCE, 0xD2, 0xFD, 0x3D, 0x03, 0x00, 0x00, 0xE8, 0x08, 0x6F, 0xDF, 0x55, 0xA3, + 0x3A, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xC5, 0xC2, 0x22, 0xC9, 0x64, 0x54, 0x24, 0x5D, 0x24, + 0x3E, 0x82, 0xD5, 0xDC, 0x78, 0x84, 0xD1, 0xF1, 0x74, 0x64, 0x9B, 0x3F, 0x64, 0xCE, 0x1F, 0x5C, + 0x6E, 0xCE, 0x0D, 0xF7, 0xDF, 0x15, 0xFC, 0xED, 0xF2, 0x99, 0xA1, 0xFE, 0x59, 0xE7, 0x47, 0x56, + 0x8C, 0x9B, 0xDD, 0x7D, 0xF6, 0x60, 0x2F, 0x62, 0x23, 0x3E, 0x19, 0x12, 0x59, 0x26, 0xA2, 0x22, + 0xED, 0x76, 0xCF, 0x35, 0xDE, 0xC8, 0xB2, 0x71, 0xF7, 0x7B, 0x08, 0x7E, 0x3B, 0x3D, 0xAF, 0xD0, + 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x9F, 0x07, 0x02, 0x00, 0x00, 0x90, 0x07, 0xB3, 0xEF, 0x0A, + 0x7B, 0xB8, 0x57, 0x81, 0xD1, 0x6C, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, 0x48, + 0xBA, 0x48, 0x78, 0x44, 0x6F, 0x3E, 0xE2, 0xB7, 0x1E, 0x7E, 0x78, 0xBC, 0xCF, 0x9C, 0x7B, 0x6A, + 0x72, 0xE7, 0x77, 0xCE, 0x77, 0xB7, 0x20, 0x35, 0x07, 0xF6, 0xF3, 0x07, 0xFB, 0xD7, 0x7B, 0xC3, + 0xCB, 0x8C, 0xE7, 0x6E, 0x3F, 0x5A, 0x05, 0x88, 0x0C, 0x89, 0x2C, 0x13, 0x31, 0x91, 0x76, 0x9B, + 0x66, 0xD8, 0x1F, 0xED, 0xAF, 0xA9, 0x44, 0xB7, 0x20, 0x53, 0x11, 0x1F, 0x6E, 0xDE, 0xD1, 0x5B, + 0xA6, 0xDD, 0x6B, 0x8C, 0x01, 0x00, 0x00, 0x72, 0x67, 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x8B, 0xED, + 0x01, 0x5F, 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x58, 0x24, 0x99, 0x8C, 0x8A, 0xA4, + 0x8B, 0xC4, 0x47, 0x83, 0x00, 0x09, 0xE3, 0xE3, 0x5C, 0x24, 0x3E, 0xCE, 0x6E, 0x0C, 0xF6, 0xD4, + 0xFB, 0xCD, 0xF9, 0x03, 0xCB, 0x8D, 0x8B, 0x0E, 0xFF, 0xEF, 0x99, 0x0D, 0x91, 0x73, 0xC3, 0x2B, + 0xC6, 0xBD, 0x5D, 0x7D, 0xF6, 0xBF, 0x7F, 0x91, 0x3F, 0xFF, 0x50, 0xAF, 0x42, 0x44, 0x86, 0x44, + 0x96, 0x89, 0x98, 0x48, 0x3B, 0x17, 0x1F, 0xE1, 0x4A, 0x72, 0x0B, 0x32, 0x55, 0xF1, 0xE1, 0xEF, + 0xE8, 0xE7, 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xBB, 0xCC, 0xC8, 0xEA, 0x01, 0xB3, 0xEB, 0x52, + 0x7B, 0xC8, 0x57, 0xA1, 0xA1, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, + 0x4B, 0x1F, 0x1F, 0xD5, 0xF0, 0x78, 0xD2, 0x6D, 0x96, 0xBF, 0x73, 0x3B, 0xE6, 0x9B, 0xB3, 0x07, + 0x2A, 0xB7, 0x20, 0x2E, 0x44, 0xCE, 0x1F, 0x5C, 0x66, 0xFF, 0xFB, 0x7F, 0xDC, 0x3C, 0x40, 0x64, + 0x48, 0x64, 0x99, 0x88, 0x89, 0xB4, 0x8B, 0xC6, 0x87, 0x9B, 0xFB, 0xB5, 0x1E, 0xBC, 0xB6, 0xA7, + 0x6F, 0x41, 0xA6, 0x34, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0xEC, 0x5F, 0x33, 0xF8, 0xCB, 0x03, 0x00, + 0x00, 0x20, 0x0B, 0xEF, 0xD0, 0xAA, 0xBB, 0xCC, 0xF6, 0x4F, 0xD8, 0x83, 0xBE, 0x8A, 0x8D, 0xF8, + 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, 0x74, 0xB1, 0xF8, 0x08, 0x02, 0x24, + 0x49, 0x7C, 0xBC, 0x6B, 0xE3, 0xE3, 0xDD, 0xC1, 0x59, 0x93, 0xDB, 0xF8, 0x7E, 0x73, 0x6E, 0xEF, + 0xF5, 0xE6, 0xDC, 0x81, 0x81, 0x51, 0xF7, 0xED, 0x58, 0xE7, 0xB7, 0x5F, 0x62, 0xFF, 0xBB, 0x36, + 0x3E, 0xDC, 0x54, 0x84, 0xC8, 0x90, 0xC8, 0x32, 0x11, 0x13, 0x69, 0x17, 0x8F, 0x8F, 0x70, 0x3B, + 0x3E, 0xE9, 0x02, 0xC4, 0xBD, 0xE5, 0x6B, 0x76, 0xF0, 0x8F, 0x43, 0xCF, 0x98, 0xF2, 0xF8, 0x70, + 0x1B, 0x5B, 0x66, 0xCC, 0x89, 0xAF, 0xAC, 0x0D, 0x7E, 0x09, 0x00, 0x00, 0x00, 0xC8, 0xC2, 0x3B, + 0xBC, 0x7A, 0x83, 0x8E, 0x8D, 0xF8, 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, + 0x74, 0x3A, 0x3E, 0xEA, 0x02, 0xC4, 0x86, 0x47, 0xF8, 0xCC, 0x47, 0x3C, 0x3E, 0x26, 0xDC, 0x9E, + 0xA8, 0xCC, 0xFD, 0xFF, 0x67, 0xB7, 0x7C, 0xDA, 0x4C, 0x3C, 0xD3, 0x6F, 0xCE, 0x0D, 0xD9, 0x10, + 0x79, 0xCA, 0xFD, 0x77, 0x2F, 0xD2, 0x11, 0xB2, 0x49, 0x85, 0x44, 0x96, 0x89, 0x98, 0x48, 0x3B, + 0x15, 0x1E, 0xD1, 0x1D, 0xBC, 0xD6, 0xBD, 0x96, 0x77, 0x30, 0xF8, 0xC7, 0xA1, 0x27, 0x74, 0x24, + 0x3E, 0xDC, 0x5E, 0xBC, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0xB4, 0xCB, 0x3B, 0x78, 0x4D, 0x82, + 0x37, 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0xE1, 0x11, + 0x2E, 0x1E, 0x1F, 0xE1, 0xED, 0x47, 0xE4, 0x99, 0x0F, 0x17, 0x1F, 0xD1, 0xF0, 0x98, 0x78, 0x3C, + 0x98, 0xFB, 0xBF, 0x1F, 0x9B, 0x65, 0x4E, 0x3F, 0x72, 0x9D, 0x39, 0xF3, 0xF0, 0x25, 0x7E, 0x80, + 0x9C, 0xF3, 0x1F, 0x58, 0x8F, 0x05, 0x88, 0x8B, 0x8F, 0x5C, 0x02, 0x44, 0xC4, 0x44, 0xDA, 0xA9, + 0xE0, 0x88, 0xAF, 0xC7, 0x6E, 0x41, 0x3A, 0x16, 0x1F, 0xC1, 0xBC, 0x5F, 0xDC, 0x39, 0x14, 0xFC, + 0x52, 0x00, 0x00, 0x00, 0x90, 0x85, 0xB7, 0xFF, 0xEA, 0x93, 0x3A, 0x3A, 0xC2, 0xA9, 0xA0, 0x48, + 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x78, 0xB8, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, + 0xDE, 0x7E, 0xD4, 0x7E, 0xEB, 0x55, 0x34, 0x3E, 0xCE, 0xD8, 0xE8, 0x38, 0xF3, 0xF8, 0xFB, 0x82, + 0x55, 0x22, 0xE4, 0xF4, 0xFD, 0x17, 0x99, 0x53, 0xF7, 0x5E, 0x6C, 0x4E, 0xDD, 0x7D, 0x91, 0x39, + 0x6B, 0xFF, 0x33, 0x75, 0xB7, 0x20, 0x36, 0x3C, 0xDC, 0xDA, 0x0F, 0x10, 0x11, 0x13, 0x69, 0xA7, + 0x62, 0xA3, 0xD1, 0x7A, 0xE4, 0x16, 0xA4, 0xD3, 0xF1, 0xE1, 0xE6, 0x1D, 0xFB, 0x53, 0xDE, 0x84, + 0x05, 0x00, 0x00, 0xD0, 0x8E, 0xE6, 0x6F, 0xC0, 0x52, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, + 0x46, 0x45, 0xD2, 0xC5, 0xA2, 0x23, 0xBA, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDC, 0x7E, 0xD4, 0x7C, + 0xDB, 0x55, 0x18, 0x1F, 0x8F, 0xD9, 0xF0, 0xB0, 0x3B, 0x1D, 0xFC, 0x78, 0xE6, 0x91, 0xF7, 0xF9, + 0xE1, 0x11, 0xEE, 0xF4, 0x7D, 0x36, 0x42, 0x36, 0x4E, 0x46, 0x88, 0xF7, 0x74, 0x25, 0x3E, 0xAA, + 0x01, 0x92, 0x39, 0x42, 0x44, 0x4C, 0xA4, 0x9D, 0x8A, 0x8C, 0x66, 0xDB, 0x7E, 0x71, 0xD7, 0xDF, + 0x82, 0x74, 0x43, 0x7C, 0xF8, 0x3B, 0x76, 0x0B, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xC8, 0xCA, 0x7F, + 0x03, 0xD6, 0xEE, 0x79, 0xF6, 0xE0, 0x5F, 0xFE, 0xF8, 0x70, 0x3F, 0x36, 0xBF, 0xFD, 0xB0, 0xF1, + 0xE1, 0x02, 0x24, 0x88, 0x0F, 0x17, 0x1E, 0xA7, 0x1F, 0x9D, 0xDC, 0xA9, 0x7B, 0x67, 0xD5, 0x04, + 0x88, 0xDB, 0xBB, 0x3F, 0x0E, 0x02, 0xE4, 0xA9, 0x0B, 0xED, 0xCF, 0x67, 0xE3, 0x23, 0x1E, 0x21, + 0x32, 0x30, 0x9A, 0x4D, 0xC4, 0x44, 0xDA, 0xA9, 0xC0, 0x48, 0xB2, 0x7D, 0x57, 0x18, 0x6F, 0x78, + 0x79, 0x57, 0x7E, 0xD0, 0x5E, 0xD7, 0xC4, 0x87, 0x9B, 0x7B, 0x13, 0xD6, 0xCB, 0x77, 0xF6, 0xDC, + 0x43, 0xFB, 0x00, 0x00, 0x00, 0x5D, 0xC1, 0x1C, 0x5A, 0xB5, 0xD6, 0xEC, 0x9C, 0x6D, 0x0F, 0xFF, + 0x25, 0x8E, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDD, 0x7E, 0xB8, 0xD7, 0xEC, 0x46, 0x6F, + 0x3F, 0xE2, 0xF1, 0x71, 0xFA, 0x81, 0xDA, 0xDB, 0x8F, 0x70, 0xEE, 0x16, 0xE4, 0xDC, 0x93, 0x76, + 0x1B, 0x2F, 0xF2, 0x23, 0xA4, 0x26, 0x40, 0x5C, 0x50, 0xA4, 0x8A, 0x10, 0x11, 0x13, 0x69, 0xA7, + 0xC2, 0x22, 0xE9, 0xB6, 0x7D, 0x24, 0xB8, 0x05, 0x59, 0x3A, 0x10, 0xFC, 0xE3, 0xD1, 0x15, 0xBA, + 0x2A, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0xB3, 0xAB, 0xFE, 0x1E, 0x01, 0x00, 0x00, 0xF4, + 0x0C, 0x73, 0x78, 0xF5, 0x7A, 0xB3, 0xF5, 0xC3, 0x36, 0x00, 0x4A, 0x1C, 0x1F, 0xC1, 0xD4, 0xED, + 0xC7, 0x59, 0x3F, 0x40, 0x6C, 0x7C, 0xB8, 0xDB, 0x8F, 0xC8, 0xB7, 0x5E, 0x55, 0xC3, 0xE3, 0xC7, + 0x95, 0xA9, 0xDB, 0x0F, 0x7F, 0x5F, 0xBF, 0xD0, 0xBC, 0xFB, 0x48, 0x25, 0x40, 0xCE, 0xB5, 0x75, + 0x0B, 0x22, 0x62, 0x22, 0xED, 0x54, 0x54, 0xA4, 0x9D, 0xBB, 0x05, 0x39, 0xB8, 0xAC, 0x6B, 0x6E, + 0x41, 0xBA, 0x2E, 0x3E, 0xDC, 0x78, 0x13, 0x16, 0x00, 0x00, 0x40, 0x76, 0xDE, 0xC8, 0x8A, 0xA1, + 0xD2, 0xC7, 0x47, 0xC3, 0xDB, 0x8F, 0x59, 0xD5, 0xF8, 0xA8, 0xDE, 0x7E, 0x84, 0xF1, 0x11, 0x84, + 0x87, 0x1F, 0x1F, 0x3F, 0xD2, 0xB7, 0x1F, 0x2E, 0x3E, 0xDC, 0x4E, 0x7F, 0xEB, 0x42, 0x73, 0xB6, + 0xAD, 0x5B, 0x10, 0x11, 0x13, 0x69, 0xA7, 0x62, 0x22, 0xCB, 0xB6, 0xD9, 0x18, 0x1D, 0x5E, 0xD6, + 0x15, 0xB7, 0x20, 0x5D, 0x19, 0x1F, 0xC1, 0xBC, 0x13, 0x5F, 0xEE, 0xA9, 0xD7, 0x16, 0x03, 0x00, + 0x00, 0x74, 0x0D, 0x6F, 0xDF, 0x55, 0x63, 0x65, 0xBF, 0xF9, 0x70, 0xAB, 0xBF, 0xFD, 0x88, 0x04, + 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x70, 0x44, 0x02, 0xE4, 0x94, 0x7B, 0xE8, 0xDC, 0xED, 0xDB, 0xE2, + 0xF6, 0x23, 0x88, 0x8F, 0x70, 0x13, 0x0F, 0x64, 0xBD, 0x05, 0x11, 0x31, 0x91, 0x76, 0x2A, 0x24, + 0x32, 0xED, 0x82, 0xCA, 0xF6, 0x5C, 0xD6, 0xF1, 0x5B, 0x90, 0x6E, 0x8E, 0x0F, 0x37, 0xEF, 0xF8, + 0x9F, 0x75, 0xE5, 0xB3, 0x32, 0x00, 0x00, 0x00, 0x5D, 0xCF, 0xEC, 0xBD, 0xDC, 0x86, 0x40, 0x89, + 0xE3, 0x23, 0xC1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xC1, 0xB7, 0x5E, 0x9D, 0x0A, 0x03, 0xE4, 0x07, + 0xAD, 0xE3, 0xC3, 0xED, 0xF4, 0x3D, 0x2D, 0x6E, 0x41, 0xE4, 0x44, 0x4C, 0xA4, 0x9D, 0x0C, 0x89, + 0x2C, 0x0B, 0xE2, 0xC3, 0xCD, 0xFD, 0xFD, 0xF5, 0x6F, 0x41, 0x96, 0xAF, 0x0B, 0xFE, 0x31, 0x99, + 0x52, 0xDD, 0x1E, 0x1F, 0xFE, 0x8E, 0xFF, 0x29, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x48, 0xCB, 0xBD, + 0x72, 0xD5, 0xEC, 0x59, 0x64, 0x63, 0x40, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0xBA, 0xA0, + 0x48, 0x33, 0x11, 0x1A, 0x8D, 0x16, 0x0F, 0x90, 0xE0, 0xF6, 0xE3, 0x6C, 0x92, 0xDB, 0x8F, 0x87, + 0xED, 0xEE, 0x69, 0x1D, 0x1F, 0xE1, 0xC2, 0x5B, 0x90, 0x64, 0x6F, 0xC4, 0x12, 0x31, 0x91, 0x76, + 0x32, 0x24, 0xB2, 0x2C, 0x12, 0x1F, 0xE1, 0x86, 0x16, 0x1A, 0xEF, 0xE0, 0xD2, 0x93, 0xC1, 0x3F, + 0x2A, 0x53, 0xA6, 0x27, 0xE2, 0xC3, 0xED, 0xC8, 0x6A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0x90, 0x96, + 0xFF, 0x0A, 0xDE, 0x9D, 0x9F, 0xB2, 0x41, 0xA0, 0xA2, 0x22, 0xE9, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, + 0x8A, 0xA4, 0x13, 0x91, 0xA1, 0x66, 0x83, 0xA3, 0x1A, 0x1F, 0x36, 0x3C, 0x12, 0xDF, 0x7E, 0x44, + 0xBF, 0xF5, 0xEA, 0xFB, 0xB1, 0xDB, 0x0F, 0x11, 0x1D, 0xD1, 0x25, 0xBF, 0x05, 0x11, 0x31, 0x91, + 0x76, 0x32, 0x24, 0xB2, 0x4C, 0xC4, 0x87, 0x9B, 0xFB, 0x7B, 0x3D, 0xC5, 0xB7, 0x20, 0x3D, 0x13, + 0x1F, 0x3F, 0xBF, 0xDC, 0x98, 0xB1, 0x15, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x20, 0x2D, 0x73, 0x78, + 0xE5, 0x7A, 0xB3, 0xED, 0xA3, 0x36, 0x0A, 0x54, 0x58, 0x24, 0x99, 0x88, 0x8B, 0x56, 0xAB, 0x0B, + 0x8A, 0x34, 0x8B, 0x45, 0x46, 0xB3, 0x45, 0x03, 0xC4, 0xAE, 0x12, 0x1F, 0x36, 0x0E, 0xC2, 0x00, + 0x69, 0xF4, 0xDA, 0xDD, 0x46, 0xB7, 0x1F, 0x22, 0x38, 0xD4, 0x26, 0x7E, 0x50, 0x09, 0x90, 0x9A, + 0x67, 0x41, 0x82, 0x10, 0xA9, 0xDC, 0x82, 0x88, 0x98, 0x48, 0x3B, 0x19, 0x12, 0x59, 0x26, 0xC2, + 0x23, 0xBA, 0x29, 0xBC, 0x05, 0xE9, 0xA9, 0xF8, 0x70, 0x7B, 0xF1, 0x3A, 0x63, 0x7F, 0xBD, 0x77, + 0x05, 0xBF, 0x7C, 0x00, 0x00, 0x00, 0x24, 0xE1, 0x1D, 0x5E, 0xB9, 0x41, 0x87, 0x45, 0x92, 0x89, + 0xB8, 0x68, 0x35, 0x19, 0x15, 0x49, 0x17, 0x0B, 0x8C, 0x66, 0x8B, 0xC5, 0x47, 0xE5, 0xF6, 0x23, + 0x12, 0x1F, 0xCD, 0x6E, 0x3F, 0xC2, 0x00, 0x89, 0xDE, 0x7E, 0x88, 0xD0, 0x68, 0xB8, 0x6F, 0x5C, + 0x68, 0xCE, 0x3E, 0xD1, 0xE0, 0x16, 0x64, 0x93, 0x88, 0x89, 0xB4, 0x93, 0x21, 0x91, 0x65, 0x22, + 0x38, 0xE2, 0x73, 0x7F, 0xDF, 0x0F, 0x5E, 0x57, 0xF8, 0x2D, 0x48, 0xCF, 0xC5, 0x47, 0x30, 0xEF, + 0xC4, 0x9D, 0x1B, 0x82, 0xDF, 0x02, 0x00, 0x00, 0x00, 0x92, 0xF0, 0x0E, 0x5E, 0x3D, 0xAA, 0xE3, + 0xA2, 0xD5, 0x44, 0x5C, 0xB4, 0x5A, 0x5D, 0x50, 0xA4, 0x59, 0x2C, 0x30, 0x9A, 0xAD, 0x41, 0x7C, + 0xF8, 0xB7, 0x1F, 0x2E, 0x3E, 0xD4, 0xED, 0x47, 0x10, 0x1F, 0xD5, 0xDB, 0x8F, 0x87, 0xEC, 0xBE, + 0x91, 0x21, 0x3E, 0x82, 0x85, 0xB7, 0x20, 0xE7, 0x9F, 0x72, 0x7F, 0xDD, 0x20, 0x42, 0x9E, 0x9E, + 0x69, 0x7F, 0x2D, 0x2E, 0x20, 0x82, 0xA9, 0xB8, 0x68, 0x35, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, + 0xD1, 0x76, 0xCD, 0x31, 0xDE, 0xF0, 0xD2, 0x71, 0x33, 0xD4, 0x3F, 0x2B, 0xF8, 0xC7, 0x26, 0x57, + 0xBD, 0x1A, 0x1F, 0x7E, 0x80, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x74, 0xBC, 0xFD, 0x9F, 0x1D, + 0xD7, 0x81, 0xD1, 0x6C, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xC5, 0x02, 0xA3, 0xD5, 0xEA, + 0x02, 0x24, 0x88, 0x8F, 0xF8, 0xED, 0x47, 0x10, 0x1F, 0xF2, 0xD9, 0x8F, 0xFB, 0x83, 0xDB, 0x0F, + 0x11, 0x17, 0x89, 0x16, 0xBB, 0x05, 0x39, 0x1F, 0xC4, 0x47, 0x5B, 0x01, 0x22, 0x43, 0x22, 0xCB, + 0x44, 0x64, 0x34, 0x9B, 0x7B, 0x66, 0xC5, 0xDD, 0x82, 0x1C, 0x5C, 0x9A, 0xFB, 0x07, 0xEF, 0xF5, + 0x72, 0x7C, 0xB8, 0x79, 0xC7, 0xFE, 0x64, 0x3C, 0xF8, 0xAD, 0x00, 0x00, 0x00, 0xA0, 0x15, 0x33, + 0xDA, 0x3F, 0x2B, 0xFD, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x8B, 0xC5, 0x45, + 0x92, 0xC5, 0xE3, 0x23, 0x7A, 0xFB, 0x11, 0xC4, 0x47, 0xCD, 0x9B, 0xAF, 0x1A, 0xDD, 0x7E, 0xA8, + 0xB0, 0x48, 0xB1, 0x33, 0xDF, 0xBB, 0x70, 0xF2, 0x59, 0x90, 0xA7, 0x6C, 0x7C, 0xB4, 0x13, 0x21, + 0x32, 0x24, 0xB2, 0x4C, 0x04, 0x46, 0x92, 0x15, 0x70, 0x0B, 0xD2, 0xEB, 0xF1, 0xE1, 0xEF, 0xC8, + 0x4D, 0xC6, 0x8C, 0xFD, 0x87, 0x42, 0x6E, 0x86, 0x00, 0x00, 0x00, 0x4A, 0xC7, 0x7F, 0x03, 0xD6, + 0xAE, 0x4F, 0xDB, 0x48, 0x50, 0xA1, 0xA1, 0x26, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, + 0x8B, 0x56, 0xB3, 0xD1, 0x31, 0x19, 0x20, 0x17, 0x55, 0x02, 0x24, 0xB8, 0xFD, 0xA8, 0xBE, 0x76, + 0xB7, 0x7A, 0xFB, 0xF1, 0xBE, 0xC6, 0xB7, 0x1F, 0x22, 0x28, 0xB2, 0xEC, 0xEC, 0x63, 0x2E, 0x42, + 0x2A, 0x01, 0xE2, 0xDF, 0x82, 0x64, 0x89, 0x10, 0x19, 0x12, 0x59, 0x26, 0xC2, 0x22, 0xE9, 0x72, + 0xBE, 0x05, 0x29, 0x45, 0x7C, 0xB8, 0xBD, 0x34, 0xC0, 0x9B, 0xB0, 0x00, 0x00, 0x00, 0x92, 0x32, + 0x87, 0x57, 0xAD, 0x4B, 0xFE, 0x0A, 0x5E, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x61, + 0x91, 0x74, 0xF1, 0xF8, 0xC8, 0x74, 0xFB, 0xA1, 0x63, 0x22, 0xFD, 0x66, 0x9A, 0x33, 0xF7, 0xCF, + 0x34, 0x67, 0x9F, 0x9C, 0x8C, 0x90, 0xD4, 0x01, 0x22, 0x43, 0x22, 0xCB, 0x44, 0x54, 0xA4, 0xDD, + 0xCE, 0xD9, 0xC6, 0x1B, 0xBE, 0xBE, 0xED, 0x5B, 0x90, 0xD2, 0xC4, 0x87, 0x1B, 0x6F, 0xC2, 0x02, + 0x00, 0x00, 0x48, 0xCE, 0xB8, 0x57, 0xF0, 0xCA, 0xD8, 0x88, 0x4F, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, + 0x48, 0x3A, 0x11, 0x16, 0x49, 0xE6, 0x6E, 0x3F, 0xEC, 0x8F, 0x7E, 0x7C, 0xC4, 0x6E, 0x3F, 0xEA, + 0x9F, 0xFD, 0x68, 0x70, 0xFB, 0x71, 0x5F, 0xFB, 0xDF, 0x7A, 0x55, 0xD9, 0xCC, 0xEA, 0xDE, 0x0D, + 0x6E, 0x41, 0xCE, 0x35, 0xBA, 0x05, 0x51, 0xE1, 0xE1, 0x26, 0x43, 0x22, 0xCB, 0x44, 0x4C, 0x64, + 0xDA, 0x7B, 0x8D, 0x39, 0x70, 0xB5, 0x7B, 0x2D, 0xEF, 0x60, 0xF0, 0x8F, 0x50, 0x6A, 0xA5, 0x8A, + 0x0F, 0xB7, 0xE7, 0xAF, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x49, 0x79, 0x07, 0xAF, 0x4B, 0xF0, + 0x06, 0x2C, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x51, 0x91, 0x66, 0xE1, 0xCD, 0x47, + 0x83, 0xDB, 0x8F, 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0x78, 0x30, 0xAF, 0x6F, 0xBD, 0x9A, 0x8C, 0x0F, + 0xB7, 0x4C, 0xB7, 0x20, 0x32, 0x24, 0xB2, 0x4C, 0x85, 0x44, 0x96, 0xD9, 0xF8, 0x70, 0xDB, 0xFE, + 0x71, 0xF7, 0x6D, 0x58, 0xC6, 0x8C, 0x5C, 0x9B, 0xFA, 0x13, 0xC0, 0x4B, 0x17, 0x1F, 0xC1, 0xBC, + 0x13, 0x77, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x24, 0xBC, 0x7D, 0x57, 0x8E, 0xE9, 0xE8, 0x08, + 0x27, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, 0x8A, 0xA4, 0xF3, 0x6F, 0x3F, 0x82, 0xF8, + 0x88, 0xDD, 0x7E, 0xA8, 0x67, 0x3F, 0xEA, 0x3F, 0x74, 0xD0, 0xC6, 0x47, 0x2E, 0xB7, 0x1F, 0xB5, + 0xF1, 0x11, 0xEE, 0xDD, 0x47, 0x5A, 0x3C, 0x0B, 0xD2, 0x0B, 0xF1, 0xF1, 0x74, 0xB0, 0xFD, 0xE9, + 0x6F, 0x41, 0xCA, 0x1A, 0x1F, 0x6E, 0xDE, 0xB1, 0x5B, 0xA6, 0xE4, 0x83, 0x1A, 0x01, 0x00, 0x00, + 0x7A, 0x9E, 0xD9, 0x7B, 0x99, 0x8D, 0x06, 0x15, 0x1E, 0x6E, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, + 0xD2, 0xC5, 0x82, 0x22, 0xED, 0xC2, 0xF0, 0x68, 0x70, 0xFB, 0x51, 0xF7, 0xEC, 0x47, 0x10, 0x20, + 0x95, 0xDB, 0x0F, 0x1B, 0x1F, 0xB9, 0xDC, 0x7E, 0xE8, 0xF8, 0x70, 0x3B, 0x7D, 0xEF, 0x4C, 0x73, + 0xAE, 0xD1, 0x2D, 0x88, 0x1F, 0x1D, 0x3D, 0x12, 0x1F, 0xF6, 0xFF, 0xF6, 0xB6, 0x7F, 0xDC, 0x05, + 0x48, 0xE2, 0x5B, 0x90, 0x32, 0xC7, 0x87, 0xBF, 0x23, 0x37, 0x99, 0xE0, 0xB7, 0x0A, 0x00, 0x00, + 0x80, 0x46, 0xCC, 0xE1, 0xFE, 0x25, 0x66, 0x68, 0xBE, 0x0D, 0x87, 0x72, 0xC4, 0x47, 0xCB, 0xDB, + 0x0F, 0x11, 0x1F, 0x95, 0xDB, 0x0F, 0x1B, 0x1E, 0xB9, 0xDC, 0x7E, 0xE8, 0xF0, 0x88, 0x2E, 0xBC, + 0x05, 0x69, 0xF8, 0x2C, 0x88, 0x0C, 0x89, 0x2C, 0x53, 0x21, 0x91, 0x65, 0x22, 0x3E, 0xEC, 0x8F, + 0xFE, 0xF6, 0x7C, 0xC6, 0x9C, 0x3F, 0x70, 0xFD, 0x50, 0xF0, 0x8F, 0x53, 0x43, 0xA5, 0x8F, 0x0F, + 0x37, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x9A, 0xFF, 0x0A, 0x5E, 0xF9, 0x06, 0x2C, 0x11, 0x17, + 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x50, 0xA4, 0x9A, 0x8D, 0x8F, 0x30, 0x3C, 0xC2, 0xF8, 0x48, + 0x7A, 0xFB, 0xF1, 0x63, 0x1B, 0x1E, 0x2E, 0x40, 0x7E, 0xD8, 0xEE, 0xED, 0x87, 0x0E, 0x8E, 0xF8, + 0xDC, 0x2D, 0x48, 0xE3, 0x67, 0x41, 0x54, 0x48, 0x64, 0x99, 0x0A, 0x89, 0x2C, 0x6B, 0x12, 0x1F, + 0x4F, 0xBD, 0xD7, 0x9C, 0xDF, 0xF2, 0x21, 0x73, 0x7E, 0xFF, 0x32, 0x73, 0x76, 0xFF, 0xD2, 0x86, + 0x07, 0xEF, 0x69, 0x11, 0x1F, 0x6E, 0x2F, 0x5E, 0xE7, 0x02, 0x64, 0x5D, 0xF0, 0xDB, 0x06, 0x00, + 0x00, 0x80, 0xE2, 0xBF, 0x01, 0x6B, 0xEB, 0x87, 0x6C, 0x40, 0xF4, 0x7E, 0x7C, 0x64, 0xB9, 0xFD, + 0xA8, 0xC6, 0x87, 0xBB, 0xFD, 0xF8, 0x56, 0x3B, 0xB7, 0x1F, 0x3A, 0x36, 0x1A, 0x6D, 0xE2, 0x21, + 0x75, 0x0B, 0x32, 0xC3, 0x9F, 0x0E, 0x8A, 0x34, 0x53, 0x21, 0x91, 0x65, 0x2D, 0xE2, 0xC3, 0x6D, + 0xE3, 0x05, 0xE6, 0xFC, 0xEE, 0x25, 0xE6, 0xDC, 0xDE, 0x65, 0xF2, 0x01, 0xEC, 0x69, 0x13, 0x1F, + 0x6E, 0xCF, 0x5F, 0x69, 0xCC, 0x89, 0x3B, 0x73, 0xFF, 0x94, 0x78, 0x00, 0x00, 0x80, 0x52, 0xF1, + 0x0E, 0xAD, 0x1C, 0xEC, 0xF9, 0xF8, 0xC8, 0x78, 0xFB, 0x71, 0xEA, 0x51, 0x1B, 0x1D, 0xB9, 0xDC, + 0x7E, 0xE8, 0xC8, 0x68, 0xB6, 0xD3, 0xF7, 0xC4, 0x6F, 0x41, 0x2A, 0xF1, 0xD1, 0x7E, 0x80, 0xA8, + 0x90, 0xC8, 0xB2, 0x64, 0xF1, 0x71, 0xEE, 0x49, 0xBB, 0x4D, 0x1F, 0x76, 0x01, 0x62, 0xCE, 0x0E, + 0xD5, 0xDE, 0x82, 0x4C, 0xAB, 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x6F, 0xC2, 0x02, 0x00, 0x00, + 0x68, 0xC6, 0xDB, 0x77, 0x45, 0xE4, 0x15, 0xBC, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xA9, + 0xA0, 0x48, 0xB3, 0x20, 0x3E, 0x82, 0xA5, 0xBB, 0xFD, 0x88, 0xC4, 0x47, 0x5B, 0xB7, 0x1F, 0x3A, + 0x30, 0x92, 0x6C, 0xE2, 0x81, 0xE8, 0x2D, 0x88, 0x8D, 0x8F, 0xB6, 0x23, 0x44, 0x85, 0x44, 0x96, + 0x25, 0x8F, 0x8F, 0xB3, 0x83, 0x76, 0x4F, 0x5C, 0x60, 0xDE, 0xDD, 0xB1, 0xC4, 0x4C, 0xEC, 0x5E, + 0x5E, 0x3D, 0x7C, 0x4F, 0xC7, 0xF8, 0x70, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x2D, 0x98, 0x7D, + 0xF6, 0x70, 0xD7, 0xEB, 0xF1, 0x91, 0xE6, 0xF6, 0x23, 0x8C, 0x8F, 0x5C, 0x6E, 0x3F, 0x74, 0x58, + 0x24, 0x5D, 0xE5, 0x16, 0x64, 0xA6, 0x8D, 0x10, 0x1B, 0x20, 0x4F, 0xB5, 0x1B, 0x20, 0x2A, 0x24, + 0xB2, 0x2C, 0x43, 0x7C, 0x3C, 0x7E, 0x81, 0x39, 0x33, 0xF8, 0x41, 0x17, 0x20, 0xE6, 0xF4, 0x8E, + 0xA5, 0x03, 0xD3, 0x35, 0x3E, 0xFC, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x00, 0x34, 0x62, + 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x0B, 0x75, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, + 0x66, 0x91, 0xF8, 0x08, 0xA6, 0x6E, 0x3F, 0xAA, 0x01, 0x52, 0x73, 0xFB, 0x31, 0xAB, 0xFE, 0xF6, + 0xE3, 0x9B, 0x2A, 0x2E, 0x5A, 0x4D, 0x47, 0x45, 0x9A, 0xBD, 0xF3, 0xD7, 0x33, 0xCC, 0x99, 0x1F, + 0x4E, 0x06, 0x48, 0xF6, 0x5B, 0x10, 0x15, 0x12, 0x59, 0x96, 0x31, 0x3E, 0x1E, 0x9D, 0x61, 0x4E, + 0xFF, 0xD8, 0xEE, 0x99, 0x45, 0x66, 0xE2, 0xC0, 0xAA, 0x93, 0xD3, 0x36, 0x3E, 0xDC, 0x8E, 0xAC, + 0x32, 0xE6, 0xF8, 0x1D, 0x4B, 0x82, 0x2F, 0x31, 0x00, 0x00, 0x00, 0x44, 0x99, 0x91, 0xFE, 0x01, + 0xB3, 0xF3, 0x12, 0x1D, 0x18, 0xCD, 0x26, 0xA3, 0x22, 0xE9, 0x54, 0x50, 0xA4, 0x59, 0x2C, 0x3E, + 0x12, 0xDC, 0x7E, 0x4C, 0xB8, 0x00, 0x79, 0xDC, 0xDD, 0x7E, 0xC4, 0xE2, 0xC3, 0xED, 0x7B, 0x59, + 0xBE, 0xF5, 0x4A, 0x07, 0x45, 0x9A, 0xB9, 0xF8, 0xF0, 0x77, 0xF7, 0x0C, 0x7B, 0x90, 0x6F, 0xE7, + 0x16, 0x44, 0x85, 0x44, 0x96, 0xB5, 0x17, 0x1F, 0xA7, 0x1E, 0x76, 0x01, 0x32, 0xDB, 0x98, 0x63, + 0x77, 0x9A, 0x69, 0x1B, 0x1F, 0x3F, 0xBF, 0xCC, 0x98, 0x17, 0x3F, 0x67, 0xCC, 0x89, 0x2F, 0xAD, + 0x0D, 0xBE, 0xC4, 0x00, 0x00, 0x00, 0x10, 0xE5, 0x1D, 0x5A, 0x75, 0x97, 0xD9, 0x7E, 0xB1, 0x8E, + 0x8C, 0x46, 0x93, 0x51, 0x91, 0x74, 0x2A, 0x28, 0xD2, 0x2C, 0x16, 0x1F, 0x2A, 0x40, 0x1A, 0x3E, + 0xFB, 0x61, 0xE3, 0x23, 0x97, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0x56, 0x8D, 0x8F, 0x60, 0x67, 0xBE, + 0x5F, 0x09, 0x90, 0x73, 0xD1, 0x5B, 0x90, 0x20, 0x44, 0x74, 0x74, 0x84, 0x53, 0x21, 0x91, 0x65, + 0x39, 0xC4, 0xC7, 0xD3, 0x1F, 0x33, 0xDE, 0xD1, 0xDB, 0xA7, 0x77, 0x7C, 0xB8, 0x3D, 0xFF, 0x59, + 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x88, 0x19, 0x59, 0xB9, 0x5E, 0x46, 0x46, 0xA3, 0xC9, 0xA8, + 0x48, 0x3A, 0x15, 0x14, 0x69, 0x56, 0x1F, 0x1E, 0xD5, 0xF8, 0xB0, 0xE1, 0x31, 0x79, 0xFB, 0x11, + 0xF9, 0xD6, 0xAB, 0xEA, 0xED, 0xC7, 0x45, 0x95, 0xDB, 0x0F, 0xBB, 0xF6, 0x6E, 0x3F, 0x74, 0x50, + 0xA4, 0x59, 0x3C, 0x3E, 0xFC, 0x65, 0xBA, 0x05, 0x51, 0x21, 0x91, 0x65, 0xC4, 0x47, 0xFB, 0x0B, + 0xE2, 0x23, 0x98, 0xF7, 0x8B, 0x3B, 0x5B, 0x7E, 0x30, 0x23, 0x00, 0x00, 0xC0, 0xB4, 0xE4, 0x1D, + 0xB8, 0x7A, 0x54, 0x86, 0x86, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, 0x66, 0xB1, 0xF8, 0x88, + 0x07, 0x88, 0x5D, 0xF5, 0x5B, 0xAF, 0xC2, 0x00, 0xA9, 0x3E, 0x78, 0x6E, 0xE3, 0xC3, 0x06, 0x48, + 0xFB, 0xB7, 0x1F, 0x3A, 0x28, 0xD2, 0x4C, 0xC6, 0x47, 0xB0, 0xF0, 0x16, 0xC4, 0xBD, 0x92, 0xB7, + 0xF5, 0x2D, 0x88, 0x0A, 0x89, 0x2C, 0x23, 0x3E, 0xDA, 0x5F, 0x6D, 0x7C, 0xF8, 0x01, 0x72, 0xF4, + 0xD6, 0xB1, 0xE0, 0x4B, 0x0C, 0x00, 0x00, 0x00, 0x51, 0xDE, 0xFE, 0x2B, 0x4F, 0xCA, 0xD8, 0x88, + 0x4F, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x78, 0x88, 0xF8, 0x08, 0x6F, 0x3F, 0x6A, + 0x1E, 0x3C, 0xF7, 0x6F, 0x3F, 0x2E, 0x9A, 0xBC, 0xFD, 0x08, 0xE3, 0x23, 0x0C, 0x90, 0xFB, 0xD3, + 0xDC, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x1D, 0x35, 0x73, 0xB7, 0x20, 0x8F, 0x4D, 0xDE, 0x82, + 0xF8, 0x11, 0x62, 0x63, 0xA3, 0x3E, 0x40, 0x54, 0x48, 0x64, 0x19, 0xF1, 0xD1, 0xFE, 0xEA, 0xE3, + 0xC3, 0xDF, 0xB1, 0x2F, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x00, 0x25, 0xD1, 0x1B, 0xB0, 0x64, 0x54, + 0x24, 0x9D, 0x0A, 0x8A, 0x34, 0x8B, 0x85, 0x47, 0x93, 0xF8, 0xA8, 0x3E, 0x78, 0x5E, 0xBD, 0xFD, + 0xB0, 0xF1, 0x11, 0xDE, 0x7E, 0xC4, 0xE3, 0xE3, 0x21, 0xBB, 0xBB, 0x55, 0x68, 0xA8, 0xE9, 0xA0, + 0x48, 0x33, 0x19, 0x1C, 0x62, 0xA7, 0xBF, 0x3B, 0x23, 0x78, 0x16, 0xA4, 0xC1, 0xB7, 0x62, 0x3D, + 0xAD, 0x42, 0x22, 0xCB, 0x88, 0x8F, 0xF6, 0x27, 0xC2, 0x23, 0x1C, 0x6F, 0xC2, 0x02, 0x00, 0x00, + 0xA8, 0xE7, 0xBF, 0x01, 0x6B, 0xD7, 0x1C, 0x1D, 0x1D, 0xE1, 0x64, 0x54, 0x24, 0x9D, 0x0A, 0x8A, + 0x34, 0x8B, 0x85, 0x47, 0x38, 0x15, 0x20, 0xF1, 0xD7, 0xEE, 0x3E, 0x39, 0x19, 0x1F, 0xF2, 0xCD, + 0x57, 0x89, 0x6F, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0A, 0x8D, 0x66, 0x7B, 0x37, 0x7E, 0x0B, 0x12, + 0x46, 0x88, 0x8B, 0x8F, 0x70, 0x32, 0x2A, 0x92, 0x8E, 0xF8, 0x68, 0x7F, 0x22, 0x3A, 0xA2, 0x7B, + 0xF1, 0x7A, 0x63, 0x5E, 0xBE, 0xB3, 0xE6, 0x53, 0xE1, 0x01, 0x00, 0x00, 0xA6, 0x3D, 0x73, 0xA8, + 0x7F, 0xAD, 0xD9, 0xF1, 0x49, 0x1D, 0x1E, 0x6E, 0x32, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, 0xC5, + 0xA2, 0x23, 0xBA, 0x78, 0x7C, 0x44, 0x6F, 0x3F, 0x82, 0xF8, 0x98, 0xBC, 0xFD, 0x10, 0xDF, 0x7A, + 0x95, 0xF8, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xA9, 0xC0, 0x68, 0x35, 0x77, 0x0B, 0x52, 0xF7, 0xE1, + 0x84, 0x36, 0x3A, 0xF2, 0x09, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xE0, 0x88, 0xEF, 0x85, 0xAB, 0x79, + 0x13, 0x16, 0x00, 0x00, 0x40, 0x9C, 0xFF, 0x06, 0xAC, 0xAD, 0x1F, 0xEC, 0xB9, 0xF8, 0x68, 0x74, + 0xFB, 0xE1, 0xE2, 0xE3, 0x6C, 0x2C, 0x3E, 0xB2, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x17, + 0x49, 0xF7, 0xEE, 0x8F, 0x2B, 0x01, 0xE2, 0xBF, 0x96, 0xF7, 0x29, 0x1B, 0x1F, 0x6E, 0xD1, 0x08, + 0x91, 0x71, 0xD1, 0x6A, 0xC4, 0x47, 0xFB, 0x13, 0xB1, 0xD1, 0x60, 0xDE, 0x89, 0x2F, 0x0D, 0x06, + 0x5F, 0x6A, 0x00, 0x00, 0x00, 0x70, 0xBC, 0xE1, 0xE5, 0x43, 0x3D, 0x15, 0x1F, 0x6E, 0xF1, 0xF8, + 0x88, 0xDE, 0x7E, 0xB8, 0xF8, 0x68, 0x75, 0xFB, 0xF1, 0xA0, 0x9D, 0x0C, 0x8E, 0xE8, 0x74, 0x50, + 0xA4, 0x99, 0x8A, 0x8A, 0x34, 0x3B, 0xFD, 0xED, 0xE0, 0x16, 0xE4, 0x49, 0x1B, 0x20, 0x36, 0x0A, + 0xEA, 0x02, 0x24, 0x75, 0x84, 0x10, 0x1F, 0xED, 0x4F, 0x87, 0x46, 0xA3, 0x79, 0x47, 0x6F, 0x1D, + 0x0D, 0xBE, 0xD4, 0x00, 0x00, 0x00, 0xE0, 0x78, 0x7B, 0xAF, 0xA8, 0x7F, 0x05, 0xAF, 0x8C, 0x8A, + 0xA4, 0x53, 0x41, 0x91, 0x66, 0x22, 0x38, 0xA2, 0xB3, 0xD1, 0xE1, 0x7E, 0xAC, 0xBB, 0xFD, 0xB0, + 0xF1, 0x71, 0x6E, 0xE3, 0x45, 0xC9, 0x6E, 0x3F, 0xEE, 0x6B, 0x75, 0xFB, 0xA1, 0x83, 0x22, 0xCD, + 0x54, 0x50, 0x64, 0xD9, 0xBB, 0xF6, 0xD0, 0x1F, 0x06, 0x48, 0x7B, 0xB7, 0x20, 0xC4, 0x47, 0xFB, + 0xD3, 0x91, 0xD1, 0x74, 0xC7, 0x6E, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x51, 0x66, 0xEF, 0xE2, + 0xDE, 0x89, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x08, 0x03, 0x24, 0x88, 0x8F, 0x78, 0x80, 0xD4, + 0xC5, 0x47, 0xCB, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0xA6, 0x42, 0x22, 0xDB, 0x2E, 0x30, 0xA7, 0xBF, + 0x6D, 0xA3, 0x60, 0x70, 0x32, 0x42, 0x6A, 0x02, 0xC4, 0x85, 0x45, 0xA2, 0x08, 0x21, 0x3E, 0xDA, + 0x9F, 0x88, 0x8B, 0x24, 0x73, 0x6F, 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x1B, 0x00, 0x00, + 0xC0, 0xF4, 0x66, 0x46, 0xFA, 0x67, 0xD7, 0xBC, 0x82, 0x57, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, + 0x33, 0x11, 0x1B, 0xF1, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, 0xDF, 0x7E, 0xD8, 0xF0, 0x10, 0xB7, 0x1F, + 0xF2, 0x43, 0x07, 0x9B, 0xDE, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x76, 0x41, 0x75, + 0xE1, 0x2D, 0xC8, 0xB9, 0x4C, 0xB7, 0x20, 0xC4, 0x47, 0xFB, 0x13, 0x61, 0x91, 0x74, 0x63, 0xCB, + 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xC8, 0x7F, 0x05, 0x6F, 0xF8, 0x06, 0x2C, 0x19, 0x15, 0x49, + 0xA7, 0x82, 0x22, 0xCD, 0x62, 0xA1, 0xD1, 0x68, 0x61, 0x78, 0x84, 0xF1, 0xE1, 0xF6, 0xD4, 0x85, + 0x35, 0xDF, 0x7A, 0x15, 0x0F, 0x90, 0x53, 0x2E, 0x40, 0xC2, 0xDB, 0x8F, 0x1F, 0xD9, 0xC9, 0xF0, + 0x70, 0xD3, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x6C, 0x32, 0x3E, 0xDC, 0x4E, 0x7D, 0xD3, 0xC5, + 0x41, 0x96, 0x5B, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xA8, 0x48, 0xB3, 0x17, 0x3F, 0xC7, 0x9B, 0xB0, + 0x00, 0x00, 0x00, 0x42, 0xFE, 0x1B, 0xB0, 0xB6, 0x7D, 0xC4, 0x1E, 0xEE, 0x55, 0x54, 0x24, 0x9D, + 0x0A, 0x8A, 0x34, 0x13, 0xA1, 0xA1, 0x66, 0xA3, 0xC3, 0xFD, 0x58, 0x7B, 0xFB, 0x61, 0xE3, 0x23, + 0xCD, 0xED, 0xC7, 0xB7, 0x1A, 0xDD, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x56, 0x1B, + 0x1F, 0xE1, 0x26, 0x7E, 0x94, 0xF6, 0x16, 0x84, 0xF8, 0x68, 0x7F, 0x22, 0x28, 0x32, 0x8C, 0x37, + 0x61, 0x01, 0x00, 0x00, 0x04, 0xBC, 0x91, 0x81, 0x0D, 0x3A, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, + 0xC5, 0x22, 0xA3, 0xD9, 0xC2, 0xF0, 0x88, 0xC4, 0x47, 0xA2, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x68, + 0xD7, 0xA3, 0xF1, 0xE1, 0xD6, 0xF2, 0x16, 0x84, 0xF8, 0xC8, 0x79, 0x3A, 0x26, 0xB2, 0xCC, 0x3B, + 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0x38, 0xDE, 0x81, 0xAB, 0x47, 0x75, 0x58, 0x24, 0x99, + 0x0A, 0x8A, 0x34, 0x13, 0x91, 0xD1, 0x62, 0xD5, 0x00, 0x09, 0xE3, 0xA3, 0xED, 0xDB, 0x0F, 0x1D, + 0x14, 0x69, 0xA6, 0x43, 0x22, 0xCB, 0x74, 0x78, 0x44, 0x17, 0xDE, 0x82, 0xB8, 0x78, 0x68, 0x7C, + 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x12, 0x59, 0xE7, 0x1D, 0xBB, 0x65, 0x3C, 0xF8, 0x92, 0x03, + 0x00, 0x00, 0x98, 0xDE, 0xBC, 0x7D, 0x57, 0x8C, 0xEB, 0xB8, 0x68, 0x35, 0x15, 0x14, 0x69, 0xA6, + 0x03, 0xA3, 0xE1, 0x6A, 0x6E, 0x3F, 0x6C, 0x7C, 0x34, 0xBB, 0xFD, 0x08, 0xE3, 0xA3, 0xE5, 0xED, + 0x87, 0x0E, 0x8A, 0x34, 0xD3, 0x21, 0x91, 0x65, 0x3A, 0x38, 0xE2, 0xF3, 0x6F, 0x41, 0x1E, 0x6F, + 0x76, 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x11, 0x6D, 0xCD, 0xBD, 0x09, 0x6B, 0xEC, 0x8B, 0xB3, + 0x82, 0x2F, 0x3B, 0x00, 0x00, 0x80, 0xE9, 0xCB, 0x0C, 0x2D, 0xB0, 0x07, 0x7C, 0x15, 0x18, 0xCD, + 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x60, 0x24, 0x58, 0x18, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xB9, 0x1F, + 0xC9, 0x6E, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0E, 0x89, 0x2C, 0xD3, 0xB1, 0xD1, 0x68, 0x67, 0xBE, + 0x2F, 0x9E, 0x05, 0xF1, 0x43, 0x24, 0x12, 0x1E, 0x6E, 0xC4, 0x47, 0x86, 0x89, 0x78, 0xC8, 0x63, + 0x63, 0xCB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x80, 0xFF, 0x06, 0xAC, 0x9D, 0xB3, 0xED, 0xE1, 0x5E, + 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0x33, 0x1D, 0x17, 0x4D, 0x17, 0xB9, 0xF9, 0xF0, 0xE3, 0x43, + 0xDC, 0x7E, 0x4C, 0xB8, 0x3D, 0x1E, 0xB9, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xE5, 0x89, 0x0F, + 0x7F, 0x77, 0xAB, 0x5B, 0x90, 0x4A, 0x68, 0x18, 0x1B, 0x19, 0xC4, 0x47, 0xD6, 0x89, 0x70, 0xC8, + 0x65, 0x8B, 0x8D, 0x79, 0xF1, 0x5A, 0xE3, 0xFD, 0xE2, 0x4B, 0x77, 0x05, 0x5F, 0x7A, 0x00, 0x00, + 0x00, 0xD3, 0x93, 0x0D, 0x90, 0x75, 0x66, 0xC7, 0x27, 0xEC, 0x21, 0x5F, 0x85, 0x86, 0x9A, 0x0A, + 0x8A, 0x34, 0x13, 0x71, 0x91, 0x64, 0x61, 0x7C, 0xC4, 0x6E, 0x3F, 0x12, 0x3F, 0xFB, 0xF1, 0xCD, + 0x12, 0xC5, 0x47, 0xB0, 0x33, 0xDF, 0x8B, 0x3E, 0x0B, 0x52, 0x89, 0x8C, 0x70, 0x2E, 0x40, 0xC2, + 0xF0, 0x20, 0x3E, 0x92, 0x4E, 0x85, 0x43, 0x1E, 0xB3, 0xF1, 0xE1, 0x66, 0x7F, 0xED, 0xDE, 0x89, + 0x3B, 0x36, 0x04, 0x5F, 0x7A, 0x00, 0x00, 0x00, 0xD3, 0x93, 0xFF, 0x0A, 0x5E, 0x19, 0x1A, 0x6A, + 0x2A, 0x28, 0xD2, 0x4C, 0x84, 0x45, 0xAB, 0xD9, 0xF0, 0xA8, 0xC6, 0x87, 0x0D, 0x8F, 0xC9, 0xDB, + 0x8F, 0xD8, 0xB7, 0x5E, 0x45, 0x6F, 0x3F, 0xEC, 0x1A, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, + 0x12, 0x59, 0xA6, 0xC3, 0x22, 0xF1, 0xAA, 0xB7, 0x20, 0x36, 0x40, 0x36, 0xBA, 0xC0, 0x08, 0x82, + 0x23, 0x12, 0x1E, 0xC4, 0x47, 0xD2, 0xA9, 0x70, 0xC8, 0x63, 0x41, 0x7C, 0x04, 0xF3, 0x4E, 0xFC, + 0x39, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x9B, 0x77, 0xF0, 0xBA, 0x84, 0x6F, 0xC0, 0x52, 0x41, + 0x91, 0x66, 0xB1, 0xB0, 0x48, 0x3A, 0x17, 0x20, 0xE1, 0xCD, 0x87, 0x5D, 0xF5, 0x5B, 0xAF, 0xE4, + 0xB3, 0x1F, 0x17, 0xB5, 0xB8, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x04, 0x45, + 0x86, 0x9D, 0xFE, 0xCE, 0x7B, 0xFD, 0xB0, 0x08, 0x23, 0xA4, 0x1A, 0x1C, 0x2E, 0x3E, 0x82, 0x28, + 0x21, 0x3E, 0x5A, 0x4D, 0x85, 0x43, 0x1E, 0xAB, 0x8D, 0x0F, 0x3F, 0x40, 0x8E, 0x7D, 0x81, 0x37, + 0x61, 0x01, 0x00, 0x80, 0xE9, 0xCD, 0xDB, 0xFB, 0xD9, 0x31, 0x1D, 0x1C, 0xD1, 0xA9, 0xA0, 0x48, + 0xB3, 0x58, 0x54, 0x24, 0x5D, 0x2C, 0x3E, 0xC2, 0xDB, 0x8F, 0xBA, 0xF8, 0x88, 0xDE, 0x7E, 0x84, + 0xF1, 0x11, 0x06, 0xC8, 0x86, 0xF0, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xE9, 0x90, 0xC8, 0x32, 0x1D, + 0x13, 0xA9, 0xF7, 0x57, 0xEF, 0xF5, 0xF7, 0xEE, 0xA3, 0x93, 0x01, 0x12, 0x9F, 0x1F, 0x27, 0x2E, + 0x3C, 0x88, 0x8F, 0x06, 0x53, 0xE1, 0x90, 0xC7, 0xEA, 0xE3, 0xC3, 0xDF, 0x91, 0x1B, 0x4C, 0xF0, + 0xA5, 0x07, 0x00, 0x00, 0x30, 0x3D, 0x99, 0x3D, 0xF6, 0x50, 0x24, 0xA3, 0x23, 0x9C, 0x0A, 0x8A, + 0x34, 0x8B, 0x45, 0x45, 0xD2, 0x35, 0x88, 0x8F, 0xEA, 0x83, 0xE7, 0xEA, 0xF6, 0x23, 0x1E, 0x1F, + 0x0F, 0xD9, 0xDD, 0x5D, 0xEE, 0xF8, 0x70, 0x73, 0xB7, 0x20, 0x7E, 0x60, 0xD8, 0x9D, 0x7B, 0xD2, + 0x86, 0x87, 0xDD, 0xB9, 0x68, 0x7C, 0xD8, 0xF0, 0x38, 0x6B, 0xC3, 0x83, 0xF8, 0x88, 0x4F, 0x85, + 0x43, 0x1E, 0x8B, 0x45, 0x47, 0x74, 0x2F, 0xAD, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xFA, 0x32, + 0x87, 0xFB, 0x97, 0x98, 0xDD, 0xF3, 0xEC, 0x81, 0x5F, 0x85, 0x87, 0x9B, 0x0A, 0x8A, 0x34, 0x8B, + 0x45, 0x45, 0x9A, 0xD9, 0xE8, 0xA8, 0x0B, 0x90, 0x26, 0xDF, 0x7A, 0x25, 0xDF, 0x7C, 0x75, 0xBF, + 0xBB, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x45, 0xE2, 0x23, + 0x9C, 0xBB, 0x05, 0xF1, 0x43, 0x63, 0xD0, 0xC6, 0x88, 0x0D, 0x90, 0xB3, 0xB1, 0x6F, 0xB9, 0x7A, + 0xF7, 0x31, 0xE2, 0xA3, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x88, 0x8E, 0xE8, 0x5E, 0xBC, 0xD6, 0x06, + 0xC8, 0x1D, 0xEB, 0x82, 0x2F, 0x41, 0x00, 0x00, 0x80, 0xE9, 0xC5, 0x7F, 0x05, 0x6F, 0xC3, 0x37, + 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x15, 0x49, 0xF7, 0x8C, 0x88, 0x8F, 0xE8, 0xED, 0x87, 0x8B, + 0x8F, 0x9A, 0x00, 0x11, 0xDF, 0x7A, 0xE5, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, + 0x26, 0x42, 0x22, 0xCB, 0x44, 0x7C, 0xBC, 0xBD, 0xFE, 0xBD, 0xE6, 0xD4, 0x3D, 0x36, 0x42, 0x5C, + 0x68, 0xB8, 0xE0, 0x70, 0x21, 0x12, 0xFC, 0xE8, 0xFE, 0xB5, 0x09, 0x17, 0x1F, 0x36, 0x3C, 0x4E, + 0x3F, 0x42, 0x7C, 0x54, 0xA6, 0xC2, 0x21, 0x8F, 0x89, 0xE0, 0x88, 0xCF, 0xFD, 0xBE, 0x4E, 0xDC, + 0xB1, 0x3E, 0xF8, 0x12, 0x04, 0x00, 0x00, 0x98, 0x5E, 0xFC, 0x37, 0x60, 0x6D, 0xF9, 0x80, 0x3D, + 0xF4, 0x77, 0x5F, 0x7C, 0x34, 0xBA, 0xFD, 0x50, 0xAF, 0xDD, 0xD5, 0xB7, 0x1F, 0xED, 0x7F, 0xEB, + 0x95, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0x0D, 0xE2, 0x23, 0xDC, 0x99, 0x07, 0x6D, 0x6C, + 0x3C, 0x3E, 0xA3, 0x12, 0x22, 0x41, 0x78, 0x4C, 0x3C, 0x7A, 0x81, 0x7F, 0xEB, 0x41, 0x7C, 0x84, + 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x6C, 0x34, 0x98, 0x77, 0xE2, 0x0E, 0xDE, 0x84, 0x05, 0x00, 0x00, + 0xA6, 0x27, 0xEF, 0xD0, 0xCA, 0xC1, 0xAE, 0x8B, 0x8F, 0x5C, 0x6E, 0x3F, 0x2E, 0x6A, 0xFB, 0xF6, + 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0xD6, 0xD7, 0xEC, 0xBF, 0xF6, + 0x4D, 0x17, 0x1D, 0x33, 0xFC, 0x9D, 0xB1, 0xE1, 0xE1, 0xE6, 0x7F, 0xCB, 0x55, 0x18, 0x1F, 0x4F, + 0x11, 0x1F, 0xC5, 0x4C, 0x87, 0x46, 0xA3, 0x79, 0xC7, 0xBE, 0x70, 0x32, 0xF8, 0x12, 0x04, 0x00, + 0x00, 0x98, 0x5E, 0xBC, 0xBD, 0x57, 0xC4, 0x5E, 0xC1, 0xAB, 0x82, 0x22, 0xCD, 0x44, 0x54, 0x24, + 0x5D, 0x24, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0xA3, 0xFE, 0xD9, 0x0F, 0x75, 0xFB, 0x61, 0xE3, 0xE3, + 0xBE, 0xF6, 0x6E, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x4B, 0x10, 0x1F, 0x6F, 0x7D, + 0xED, 0x02, 0xF3, 0xD6, 0x7F, 0xB9, 0xC0, 0x9C, 0xFA, 0xA1, 0x0D, 0x0D, 0x77, 0xE3, 0xF1, 0x63, + 0x1B, 0x1F, 0x41, 0x78, 0xBC, 0xF3, 0x90, 0xFD, 0x91, 0xF8, 0x28, 0x68, 0x3A, 0x32, 0x9A, 0xEE, + 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x4C, 0x4F, 0x66, 0xAF, 0x3D, 0xF0, 0x75, 0x53, 0x7C, + 0x04, 0x01, 0xD2, 0xEC, 0xF6, 0x23, 0x1E, 0x20, 0x75, 0xF1, 0xF1, 0x60, 0x7B, 0x0F, 0x9E, 0xEB, + 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x96, 0x22, 0x3E, 0xDE, 0xFC, 0xCF, 0xF6, 0xC7, 0xBB, 0x6D, + 0x84, 0x04, 0xD1, 0xE1, 0xEF, 0x41, 0xE2, 0x43, 0x87, 0x43, 0x1E, 0x13, 0x71, 0x91, 0x64, 0x47, + 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xFD, 0x98, 0xD1, 0xFE, 0x59, 0x66, 0x68, 0x81, 0x0D, + 0x80, 0xEE, 0x8A, 0x0F, 0xF7, 0xA3, 0xBA, 0xFD, 0x50, 0xCF, 0x7E, 0xD4, 0x7E, 0xE8, 0xA0, 0x0D, + 0x8F, 0x87, 0xDB, 0xBB, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x2C, 0x65, 0x7C, 0xB8, + 0xFD, 0xE1, 0xFF, 0xB1, 0xFF, 0xFF, 0x77, 0x66, 0x98, 0xB7, 0x1F, 0x98, 0x69, 0x67, 0xE3, 0x63, + 0x23, 0xF1, 0x51, 0xCC, 0x44, 0x58, 0x24, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x2F, 0xAD, 0x0D, 0xBE, + 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0xFF, 0x0D, 0x58, 0x3B, 0x67, 0xDB, 0x08, 0x50, 0x41, 0x91, + 0x66, 0x22, 0x2A, 0x92, 0x2E, 0x1A, 0x1F, 0x41, 0x80, 0x34, 0xBB, 0xFD, 0x70, 0xF1, 0x11, 0x0F, + 0x90, 0x6A, 0x7C, 0xB4, 0x79, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, 0x64, 0x59, 0xC6, 0xF8, + 0x78, 0xE3, 0x2F, 0x67, 0x98, 0xF1, 0xFF, 0x3C, 0xC3, 0xBC, 0xF5, 0x23, 0xFB, 0x7B, 0x7A, 0x92, + 0xF8, 0x28, 0x66, 0x22, 0x2A, 0xD2, 0xEC, 0xF9, 0x2B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x7E, + 0xBC, 0x43, 0xAB, 0xEE, 0x32, 0xDB, 0x3E, 0x6A, 0x43, 0x40, 0x45, 0x45, 0xD2, 0x89, 0xA8, 0x48, + 0x3A, 0x11, 0x1F, 0xEE, 0xC7, 0xD4, 0xB7, 0x1F, 0x61, 0x7C, 0xB8, 0xDB, 0x8F, 0x7B, 0xB3, 0xDD, + 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x4E, 0x7C, 0xFC, 0xA7, 0x19, 0xE6, 0xF7, + 0xFF, 0xF7, 0x0C, 0xF3, 0xE6, 0x03, 0xC4, 0x47, 0x31, 0x13, 0x41, 0x91, 0x61, 0xDE, 0x2F, 0xEE, + 0x18, 0x0A, 0xBE, 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0x33, 0xD2, 0xBF, 0x5E, 0x47, 0x45, 0xD2, + 0x89, 0xA8, 0x48, 0xBA, 0x78, 0x7C, 0xB8, 0x85, 0xE1, 0x11, 0xC6, 0x47, 0xAB, 0xDB, 0x0F, 0xFF, + 0x5B, 0xAF, 0x82, 0xF8, 0x70, 0xFB, 0xA1, 0x9D, 0x88, 0x8B, 0x56, 0xD3, 0x21, 0x91, 0x65, 0x22, + 0x24, 0xB2, 0x2C, 0x87, 0xF8, 0x78, 0xE3, 0xDB, 0x36, 0x3E, 0x5E, 0x22, 0x3E, 0xF2, 0x9F, 0x8E, + 0x89, 0x2C, 0xF3, 0x8E, 0xDE, 0x3C, 0x16, 0x7C, 0x29, 0x02, 0x00, 0x00, 0x4C, 0x0F, 0xDE, 0x81, + 0xAB, 0x46, 0x75, 0x58, 0x24, 0x99, 0x88, 0x8A, 0xA4, 0x6B, 0x10, 0x1F, 0xEE, 0xC7, 0x54, 0xB7, + 0x1F, 0xD1, 0xF8, 0x70, 0xB7, 0x1F, 0xDF, 0x4A, 0x7F, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, + 0x64, 0x19, 0xF1, 0x91, 0xC3, 0x54, 0x38, 0xE4, 0x31, 0x1D, 0x12, 0x99, 0xC7, 0x9B, 0xB0, 0x00, + 0x00, 0xC0, 0x74, 0xE3, 0xED, 0xFF, 0xEC, 0x49, 0x1D, 0x17, 0xAD, 0x26, 0xA2, 0x22, 0xE9, 0xE2, + 0xE1, 0x11, 0x2E, 0x0C, 0x8F, 0x30, 0x3E, 0x9A, 0xDD, 0x7E, 0x3C, 0x76, 0x91, 0x39, 0xFD, 0xA8, + 0x0D, 0x8E, 0x36, 0x6F, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, + 0x0A, 0x87, 0x3C, 0x26, 0x02, 0xA2, 0xDD, 0xB9, 0x37, 0x61, 0x1D, 0xBF, 0x63, 0x49, 0xF0, 0xE5, + 0x08, 0x00, 0x00, 0x50, 0x7E, 0x66, 0x68, 0xBE, 0x8D, 0x02, 0x15, 0x18, 0xCD, 0x26, 0xA2, 0x22, + 0xE9, 0x54, 0x78, 0x44, 0x96, 0xE8, 0xF6, 0x23, 0x88, 0x8F, 0x76, 0x6F, 0x3F, 0x74, 0x48, 0x64, + 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0x26, 0xE2, 0x21, 0x8F, 0xBD, + 0x78, 0x1D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x87, 0xFF, 0x06, 0xAC, 0x5D, 0x9F, 0xB6, 0x61, + 0xA0, 0x22, 0xA3, 0xD1, 0x44, 0x54, 0x24, 0x9D, 0x08, 0x8E, 0xEA, 0x92, 0xDE, 0x7E, 0x3C, 0x6E, + 0x03, 0x24, 0x8C, 0x8F, 0x68, 0x80, 0xFC, 0x80, 0xF8, 0x20, 0x3E, 0x54, 0x38, 0xE4, 0x31, 0x11, + 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x3E, 0xCC, 0xA1, 0xFE, 0xB5, + 0x66, 0xC7, 0xC7, 0x6D, 0x1C, 0xA8, 0xD0, 0x50, 0x13, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0x62, 0x53, + 0xB7, 0x1F, 0xD1, 0x00, 0xF1, 0xE3, 0xA3, 0xD1, 0xED, 0xC7, 0x37, 0x75, 0x68, 0xA8, 0xE9, 0x90, + 0xC8, 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x44, 0x43, 0xCE, + 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xDA, 0xF0, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0x36, 0x10, 0x54, + 0x6C, 0xC4, 0x27, 0xA2, 0x22, 0xE9, 0x44, 0x6C, 0xD4, 0x2C, 0xC1, 0xED, 0x87, 0xFB, 0xD6, 0xAB, + 0x89, 0xC7, 0x2E, 0x9C, 0xBC, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xC9, 0x6F, 0x3F, 0x74, 0x48, + 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0xA6, 0x83, 0x21, 0xEF, + 0x79, 0x47, 0xFF, 0x64, 0x34, 0xF8, 0x92, 0x04, 0x00, 0x00, 0x28, 0x37, 0x6F, 0x78, 0xE9, 0x90, + 0x8E, 0x8D, 0xF8, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8E, 0xF8, 0xE2, 0x01, 0xA2, 0x9E, 0xFD, 0x78, + 0xDC, 0xC6, 0x47, 0x9B, 0xB7, 0x1F, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x11, 0x1F, 0x39, + 0x4C, 0x85, 0x43, 0x1E, 0xD3, 0xB1, 0x50, 0xC8, 0x8E, 0x7D, 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, + 0xE9, 0xC1, 0xDB, 0xBB, 0x24, 0xC1, 0x2B, 0x78, 0x45, 0x54, 0x24, 0x9D, 0x8A, 0x8D, 0xE8, 0x6C, + 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, 0x47, 0xEC, 0x5B, 0xAF, 0x9E, 0xB8, 0x70, 0xF2, + 0xF6, 0xC3, 0x2E, 0xCB, 0xED, 0x87, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, + 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x24, 0x14, 0xB6, 0x45, 0x95, 0x37, 0x61, 0xBD, 0x7C, 0xE7, 0xEC, + 0xE0, 0xCB, 0x12, 0x00, 0x00, 0xA0, 0xBC, 0xCC, 0x1E, 0x7B, 0xF8, 0x91, 0xD1, 0x11, 0x4E, 0x44, + 0x45, 0xD2, 0xA9, 0xE0, 0x88, 0x2F, 0x1A, 0x20, 0x76, 0xD5, 0x6F, 0xBD, 0x8A, 0x06, 0x88, 0x8B, + 0x0F, 0xFF, 0xF6, 0xE3, 0xC2, 0xFA, 0xDB, 0x8F, 0x87, 0xEC, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, + 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xB3, + 0x5F, 0x7F, 0x6E, 0x2F, 0x7E, 0xCE, 0x05, 0xC8, 0x40, 0xF0, 0x65, 0x09, 0x00, 0x00, 0x50, 0x4E, + 0x66, 0xA4, 0x7F, 0x76, 0xF3, 0x57, 0xF0, 0x8A, 0xA8, 0x48, 0x3A, 0x15, 0x1B, 0xF1, 0xC5, 0xE2, + 0x23, 0xBC, 0xFD, 0xA8, 0x7D, 0xF0, 0xDC, 0xC6, 0x47, 0xF4, 0xF6, 0x23, 0xFE, 0xAD, 0x57, 0xF7, + 0xB7, 0xBE, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, + 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x16, 0xC4, 0x87, 0x1F, 0x20, 0xD7, 0xF0, 0x26, 0x2C, 0x00, 0x00, + 0x50, 0x7E, 0xFE, 0x2B, 0x78, 0x1B, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, 0xA9, 0xD8, 0x88, 0xAF, + 0x41, 0x7C, 0x54, 0x1F, 0x3C, 0x77, 0xB3, 0xF1, 0x51, 0x73, 0xFB, 0x11, 0x7F, 0xF0, 0xDC, 0xDD, + 0x7E, 0xDC, 0xAD, 0xA3, 0x23, 0x9C, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, + 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0xB5, 0x48, 0x7C, 0x04, 0xF3, 0x4E, 0x7C, 0x69, 0x30, + 0xF8, 0xD2, 0x04, 0x00, 0x00, 0x28, 0x27, 0xFF, 0x0D, 0x58, 0x5B, 0x3F, 0x64, 0xA3, 0x61, 0x8A, + 0xE3, 0xC3, 0x4D, 0x05, 0x48, 0xCD, 0xB7, 0x5E, 0xD9, 0xF8, 0x70, 0xB7, 0x1F, 0x41, 0x7C, 0x64, + 0xB9, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x56, 0x1F, 0x1F, 0x6E, 0xDE, 0xF1, 0x3F, 0xE5, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0xDC, 0xBC, 0x91, 0x81, 0x0D, 0x1D, 0x89, 0x0F, 0xB7, 0x78, 0x7C, 0x54, 0x6F, 0x3F, 0x2E, + 0xAC, 0xC6, 0xC7, 0xE4, 0xED, 0x47, 0x2C, 0x3E, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, + 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xF1, 0xE1, + 0xEF, 0xD8, 0x2D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x94, 0x9B, 0x77, 0xE0, 0xAA, 0xD8, 0x1B, 0xB0, + 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x8C, 0x46, 0xB3, 0xD1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0x44, 0x02, + 0x24, 0x8C, 0x0F, 0xF9, 0xB9, 0x1F, 0xDF, 0x69, 0x7C, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, + 0x64, 0x59, 0x34, 0x3A, 0x88, 0x8F, 0x8C, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x11, + 0x1D, 0xD1, 0xB9, 0x37, 0x61, 0x8D, 0x7D, 0x71, 0x56, 0xF0, 0xE5, 0x09, 0x00, 0x00, 0x50, 0x3E, + 0xDE, 0xBE, 0x25, 0xE3, 0x53, 0x1E, 0x1F, 0x6E, 0xF1, 0xF8, 0x48, 0x7B, 0xFB, 0xF1, 0xA0, 0x9D, + 0x08, 0x0F, 0x37, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x52, 0xC4, 0x47, 0x18, 0x20, 0x2E, + 0x3E, 0xFE, 0x40, 0x7C, 0x44, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x38, 0xE2, + 0x1B, 0x5B, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB9, 0x4D, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, + 0xA9, 0xC0, 0x68, 0x36, 0x1B, 0x1D, 0xEE, 0x47, 0x75, 0xFB, 0x11, 0x0D, 0x90, 0xA6, 0xB7, 0x1F, + 0xF7, 0xE9, 0xDB, 0x0F, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x22, 0xF1, 0x11, 0xAE, 0x3E, + 0x3E, 0xEC, 0x5C, 0x78, 0x84, 0xB7, 0x1F, 0xC4, 0x47, 0x6C, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, + 0xA2, 0x26, 0x62, 0x43, 0xED, 0xC5, 0x6B, 0x8C, 0xF7, 0x8B, 0x2F, 0xDD, 0x15, 0x7C, 0x79, 0x02, + 0x00, 0x00, 0x94, 0x8B, 0xFF, 0x06, 0xAC, 0x9D, 0x9F, 0xD2, 0x51, 0x91, 0x74, 0xF1, 0xB8, 0x48, + 0xB2, 0x30, 0x3C, 0xC2, 0xF8, 0xF0, 0x03, 0x64, 0x66, 0x35, 0x3E, 0x6A, 0xDF, 0x7C, 0x95, 0xFC, + 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0x76, 0x24, 0x3E, 0xE2, + 0x37, 0x1F, 0x6F, 0x04, 0xF1, 0xF1, 0x07, 0xE2, 0xA3, 0xA0, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x34, + 0x9A, 0xCC, 0x3B, 0x71, 0xC7, 0x86, 0xE0, 0x4B, 0x14, 0x00, 0x00, 0xA0, 0x5C, 0x6C, 0x80, 0xAC, + 0x33, 0xDB, 0x2F, 0xD6, 0x61, 0x91, 0x64, 0x2A, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0xF6, + 0xF6, 0xC3, 0xC6, 0x47, 0x83, 0x67, 0x3F, 0xEA, 0x3E, 0x74, 0xD0, 0xBD, 0xF9, 0x4A, 0xDC, 0x7E, + 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x22, 0x3E, 0xA2, 0x37, 0x1F, 0x61, 0x7C, 0x84, + 0x37, 0x1F, 0xC4, 0x47, 0x38, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x91, 0xD1, 0x6C, + 0xDE, 0x89, 0x3F, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x9C, 0xFC, 0x57, 0xF0, 0xAA, 0xB0, 0x48, + 0xB2, 0x78, 0x58, 0x24, 0x5D, 0x18, 0x1E, 0x61, 0x7C, 0x3C, 0x3D, 0xB3, 0xE6, 0xF6, 0xA3, 0xEE, + 0xD9, 0x0F, 0x1B, 0x20, 0xA7, 0xA2, 0x01, 0xF2, 0x23, 0xBB, 0x1E, 0x8C, 0x0F, 0xB7, 0xBA, 0x00, + 0x69, 0x10, 0x1F, 0xE3, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0xC0, + 0x68, 0x35, 0xEF, 0xD8, 0x17, 0xC6, 0x83, 0x2F, 0x51, 0x00, 0x00, 0x80, 0x72, 0xF1, 0x0E, 0x5C, + 0x33, 0x2A, 0xE3, 0xA2, 0xD5, 0x54, 0x58, 0x24, 0x99, 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, + 0xF1, 0x11, 0xBD, 0xFD, 0x88, 0xC5, 0x47, 0xDD, 0xED, 0xC7, 0xB7, 0x6A, 0x6F, 0x3F, 0x74, 0x48, + 0x64, 0x99, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x56, 0x17, 0x1F, 0xEA, 0x8D, 0x57, 0xC4, 0x47, + 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x71, 0x91, 0x68, 0x47, 0x56, 0xF3, 0x26, + 0x2C, 0x00, 0x00, 0x50, 0x4E, 0xDE, 0xDE, 0x25, 0x63, 0x32, 0x30, 0x9A, 0x2D, 0x1E, 0x15, 0x69, + 0x16, 0x86, 0x47, 0x18, 0x1F, 0x69, 0x6F, 0x3F, 0x7E, 0x68, 0x57, 0xB6, 0xF8, 0x70, 0x37, 0x1F, + 0x2E, 0x3E, 0xDC, 0x43, 0xE7, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, + 0xA8, 0x48, 0xB3, 0x97, 0x56, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x4E, 0x66, 0xCF, 0x42, 0x1D, + 0x19, 0x8D, 0xA6, 0xA2, 0x22, 0xE5, 0x2A, 0x01, 0x32, 0xB3, 0xED, 0xDB, 0x0F, 0x1D, 0x12, 0x59, + 0x26, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0xB5, 0x8C, 0x8F, 0xBF, 0x9C, 0xFC, 0xAC, 0x8F, 0x3F, + 0xDC, 0x4B, 0x7C, 0x14, 0x33, 0x15, 0x09, 0x45, 0x4D, 0x04, 0x45, 0xDA, 0xBD, 0x78, 0x8D, 0x0D, + 0x90, 0x3B, 0xD6, 0x05, 0x5F, 0xA6, 0x00, 0x00, 0x00, 0xE5, 0x60, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, + 0xE6, 0xE8, 0xD0, 0x50, 0x13, 0x31, 0x91, 0x6A, 0xD5, 0xDB, 0x8F, 0x20, 0x3E, 0x9A, 0xDD, 0x7E, + 0x84, 0xF1, 0xD1, 0xE0, 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, + 0x0D, 0xE3, 0x23, 0x08, 0x90, 0xE8, 0x07, 0x0D, 0x12, 0x1F, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, + 0xA2, 0x26, 0x62, 0x22, 0xCB, 0x9E, 0xB7, 0x7F, 0x3F, 0x4E, 0xDC, 0xB1, 0x3E, 0xF8, 0x52, 0x05, + 0x00, 0x00, 0x28, 0x07, 0xFF, 0x15, 0xBC, 0x49, 0xDF, 0x80, 0xA5, 0x82, 0x22, 0xC3, 0xFC, 0xF8, + 0x88, 0xDD, 0x7E, 0x54, 0x03, 0xA4, 0xD5, 0xED, 0xC7, 0x3D, 0xBD, 0x1B, 0x1F, 0x95, 0xD7, 0xED, + 0x12, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x24, 0xDA, 0x18, 0x6F, + 0xC2, 0x02, 0x00, 0x00, 0xA5, 0xE3, 0xBF, 0x01, 0x6B, 0xEB, 0x07, 0x75, 0x70, 0x44, 0x27, 0x42, + 0x22, 0xF5, 0xC2, 0x9B, 0x8F, 0x26, 0xB7, 0x1F, 0x13, 0x2E, 0x40, 0x1E, 0x8B, 0xDC, 0x7E, 0x84, + 0xF1, 0xE1, 0xF6, 0xBD, 0xCA, 0xB7, 0x5E, 0xE9, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x26, 0xC2, + 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x11, 0xD1, 0xCE, + 0xBC, 0x63, 0x5F, 0x38, 0x19, 0x7C, 0xA9, 0x02, 0x00, 0x00, 0x94, 0x83, 0x37, 0xBC, 0x62, 0x50, + 0x06, 0x47, 0x74, 0x2A, 0x26, 0xB2, 0x2C, 0x8C, 0x8F, 0xD8, 0xED, 0x47, 0xE2, 0x67, 0x3F, 0xBE, + 0xC9, 0xB7, 0x5D, 0x25, 0x9B, 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, + 0x2A, 0x12, 0x8A, 0x9A, 0x0E, 0x88, 0xB6, 0x77, 0x64, 0xB5, 0x09, 0xBE, 0x54, 0x01, 0x00, 0x00, + 0xCA, 0xC1, 0xDB, 0x7B, 0x79, 0xF3, 0x57, 0xF0, 0xAA, 0x90, 0x48, 0xBB, 0x4D, 0x6E, 0x93, 0xE1, + 0x31, 0x79, 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xFC, 0xF6, 0x43, 0x87, 0x44, + 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0x0D, 0xE3, 0xC3, 0x3D, 0x70, 0x1E, 0x8B, 0x8F, + 0xF1, 0xFF, 0x32, 0xCB, 0x9C, 0xFF, 0xD7, 0x5B, 0x83, 0xF8, 0x58, 0x65, 0x0F, 0xFA, 0x2A, 0x28, + 0xD2, 0x4C, 0x84, 0x43, 0x1E, 0x93, 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x84, 0x43, 0x5E, 0x3B, 0xB2, 0x92, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF1, 0xF6, 0x2C, + 0x1A, 0x97, 0xE1, 0xE1, 0xA6, 0x62, 0x22, 0xCB, 0x6C, 0x78, 0x44, 0x6F, 0x3F, 0xAA, 0xDF, 0x7A, + 0x15, 0x06, 0x48, 0xCD, 0x6B, 0x77, 0x2F, 0x94, 0xB7, 0x1F, 0xEF, 0x7C, 0x23, 0xAF, 0xDB, 0x0F, + 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x2D, 0x6D, 0x7C, 0x9C, 0xFB, 0xE9, 0x17, 0x2A, 0xF1, 0x71, + 0xD4, 0xFE, 0x28, 0x83, 0x22, 0xCD, 0x44, 0x38, 0xE4, 0x31, 0x19, 0x0E, 0x79, 0x4C, 0x85, 0x43, + 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x44, 0x34, 0xE4, 0x39, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xCA, 0xC4, + 0x0C, 0xF5, 0xCF, 0x32, 0x43, 0x7D, 0x53, 0x1A, 0x1F, 0xE1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xCD, + 0x9E, 0xFD, 0x70, 0xF1, 0x71, 0x7F, 0x5E, 0xB7, 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, + 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x82, 0x21, 0xEF, 0xB9, 0xFF, + 0x6D, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0x0B, 0xFF, 0x0D, 0x58, 0x3B, 0x3E, 0x39, 0xE5, 0xF1, + 0x51, 0x7D, 0xF0, 0x5C, 0xDD, 0x7E, 0xC4, 0x1E, 0x3C, 0x7F, 0xE7, 0x41, 0x1B, 0x1F, 0x5F, 0x57, + 0x31, 0x91, 0x76, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x62, 0xA1, 0xA0, 0x79, 0x27, 0xEE, 0xE0, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0x1C, 0xBC, 0xE1, 0xFE, 0xBB, 0xCC, 0xB6, 0x8F, 0x14, 0x13, 0x1F, 0xCF, 0x54, 0xE2, 0xA3, + 0x2E, 0x40, 0xE2, 0xAF, 0xDD, 0x75, 0xB7, 0x1F, 0x41, 0x7C, 0xC4, 0x6F, 0x3F, 0xDE, 0x79, 0xD8, + 0xC6, 0xC7, 0x77, 0xF3, 0xF8, 0xD6, 0x2B, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, + 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xA1, 0x50, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, + 0x82, 0x2F, 0x59, 0x00, 0x00, 0x80, 0xDE, 0xE6, 0xBF, 0x82, 0xB7, 0xA8, 0xF8, 0x08, 0x02, 0xA4, + 0xE1, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0x8A, 0xC7, 0x47, 0x2E, 0xB7, 0x1F, 0x22, 0x24, + 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0xA6, + 0x23, 0xA1, 0xD0, 0x1D, 0xB9, 0x91, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF0, 0x0E, 0x5C, 0x33, + 0xF9, 0x06, 0x2C, 0x19, 0x12, 0x59, 0x36, 0x19, 0x1F, 0x8D, 0x6E, 0x3F, 0xAA, 0xAF, 0xDD, 0xAD, + 0xDE, 0x7E, 0x5C, 0x14, 0xBB, 0xFD, 0xB0, 0xE1, 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, + 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x38, 0x98, + 0x8A, 0xBD, 0x34, 0x60, 0xCC, 0xF1, 0x3B, 0x96, 0x04, 0x5F, 0xB6, 0x00, 0x00, 0x00, 0xBD, 0xCB, + 0xDB, 0x77, 0xC5, 0xC9, 0x42, 0xE2, 0xA3, 0xAD, 0xDB, 0x8F, 0x20, 0x3E, 0x1E, 0x68, 0xF7, 0xF6, + 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, + 0x50, 0xD4, 0x44, 0x18, 0x4C, 0xD5, 0xDC, 0x9B, 0xB0, 0x4E, 0x7C, 0x69, 0x6D, 0xF0, 0x65, 0x0B, + 0x00, 0x00, 0xD0, 0xBB, 0xCC, 0xEE, 0xBE, 0x48, 0x3C, 0xB4, 0xBB, 0xDA, 0xF8, 0x70, 0x3F, 0xAA, + 0xDB, 0x8F, 0xFA, 0x67, 0x3F, 0xA2, 0xB7, 0x1F, 0x41, 0x7C, 0xB8, 0xDD, 0xDB, 0xCE, 0xED, 0x87, + 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, + 0xA8, 0x89, 0x28, 0x98, 0xCA, 0xBD, 0x70, 0x25, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xCF, 0x1C, + 0xE8, 0x5F, 0x62, 0x76, 0xCE, 0x0E, 0xE2, 0xA1, 0xDD, 0x45, 0xE2, 0x23, 0x08, 0x90, 0x66, 0xB7, + 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xE1, 0x6E, 0x3F, 0x64, 0x58, 0x24, 0x99, 0x08, 0x89, 0x2C, + 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x20, + 0xE8, 0xC0, 0xBC, 0xE3, 0xB7, 0x0F, 0x05, 0x5F, 0xBA, 0x00, 0x00, 0x00, 0xBD, 0xC9, 0x1C, 0x5C, + 0xB6, 0xD6, 0x6C, 0xFF, 0x58, 0x10, 0x10, 0xED, 0xAC, 0x3E, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0x43, + 0x3D, 0xFB, 0x51, 0xF9, 0xD0, 0xC1, 0x0B, 0x27, 0x03, 0xE4, 0x21, 0xBB, 0xCC, 0xB7, 0x1F, 0x22, + 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0xA6, 0x63, 0xA0, 0x13, 0xF3, 0x8E, 0xDE, 0xC2, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x33, 0x23, + 0xCB, 0xD7, 0x9B, 0xCD, 0xEF, 0xB3, 0xB1, 0xA0, 0xA2, 0x22, 0xE9, 0x62, 0xF1, 0xE1, 0x16, 0x86, + 0x47, 0x18, 0x1F, 0xB1, 0xDB, 0x8F, 0xBA, 0x67, 0x3F, 0x1E, 0xB5, 0xF1, 0xE1, 0x02, 0xA4, 0xED, + 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, + 0x45, 0x42, 0x51, 0xD3, 0x21, 0xD0, 0xB1, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, + 0xE6, 0x1D, 0xB8, 0x7E, 0xA8, 0x36, 0x26, 0xD2, 0x4E, 0xC7, 0x87, 0xFB, 0xB1, 0xE9, 0xED, 0x47, + 0x2C, 0x3E, 0xEA, 0x6E, 0x3F, 0xEE, 0xC9, 0x72, 0xFB, 0x21, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, + 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x00, 0x3A, 0x3D, 0xF7, + 0x26, 0xAC, 0x97, 0xEF, 0x9C, 0x1D, 0x7C, 0xF9, 0x02, 0x00, 0x00, 0xF4, 0x1E, 0x6F, 0xEF, 0x65, + 0xA3, 0xF5, 0x51, 0x91, 0x74, 0xB1, 0xF0, 0x08, 0x17, 0x86, 0x47, 0x18, 0x1F, 0x4D, 0x6F, 0x3F, + 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x4E, 0x06, 0x46, 0xB3, 0x89, 0x90, 0xC8, + 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xFC, 0x77, 0xC3, 0x5E, 0xFC, 0x9C, 0x31, 0xC7, 0x6E, 0x1B, 0x08, 0xBE, 0x7C, 0x01, 0x00, 0x00, + 0x7A, 0x8F, 0xD9, 0x63, 0x0F, 0x5B, 0x32, 0x2E, 0x5A, 0x4D, 0x84, 0x47, 0x64, 0xC9, 0x6E, 0x3F, + 0x2A, 0xF1, 0xD1, 0xFE, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, + 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xFE, 0xDD, 0x32, 0xDE, 0x84, 0x05, 0x00, + 0x00, 0x7A, 0x99, 0x19, 0xE9, 0x9F, 0x6D, 0x76, 0xCF, 0xB3, 0xC1, 0xA0, 0x02, 0xA3, 0xD9, 0x74, + 0x74, 0xF8, 0x4B, 0x7C, 0xFB, 0x31, 0xD3, 0x9C, 0x09, 0xE3, 0xA3, 0xAD, 0xDB, 0x0F, 0x11, 0x12, + 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xFE, 0x2E, 0x9B, 0x77, 0xE2, 0xF6, 0xC1, 0xE0, 0x4B, 0x18, 0x00, 0x00, 0xA0, 0xB7, 0xD8, + 0x00, 0x19, 0x48, 0xFF, 0x06, 0x2C, 0x11, 0x1D, 0xB1, 0xA9, 0xDB, 0x8F, 0x6A, 0x80, 0x84, 0xF1, + 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, + 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7F, 0xB7, 0xCD, 0x3B, 0xFA, 0x85, 0xD1, 0xE0, 0x4B, + 0x18, 0x00, 0x00, 0xA0, 0xB7, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0x3E, 0x60, 0xA3, 0x41, 0x85, + 0x86, 0x9A, 0x0E, 0x8E, 0xEA, 0x12, 0xDC, 0x7E, 0x4C, 0x3C, 0x31, 0xD3, 0x4C, 0x3C, 0x16, 0xB9, + 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0xFB, 0xC4, 0x47, 0x65, 0x22, 0x1C, 0xF2, 0x98, 0x0C, 0x87, 0x3C, + 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0xB0, 0xDF, 0x95, 0x3B, 0x76, 0x0B, 0x6F, + 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xC9, 0x1B, 0x59, 0xB1, 0xA1, 0x3E, 0x32, 0x1A, 0x4D, 0x04, 0x47, + 0x7C, 0xF1, 0x00, 0xA9, 0x7B, 0xF6, 0xC3, 0xC6, 0x47, 0xB3, 0xDB, 0x8F, 0x6F, 0xA8, 0xD0, 0x50, + 0x13, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, + 0x14, 0x35, 0x71, 0xC8, 0xEF, 0xE6, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xAB, 0xBC, 0x7D, 0x57, + 0x24, 0x7C, 0x03, 0x96, 0x88, 0x8D, 0xE8, 0x6C, 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, + 0x47, 0xE4, 0x5B, 0xAF, 0x06, 0x6D, 0x7C, 0x44, 0x6F, 0x3F, 0xEC, 0x6A, 0x6E, 0x3F, 0x36, 0x24, + 0xBD, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, + 0x54, 0x24, 0x14, 0x35, 0x71, 0xC0, 0xEF, 0xF6, 0x8D, 0x2D, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0xA0, + 0x37, 0x79, 0x7B, 0x2F, 0x1B, 0xAF, 0x8F, 0x8D, 0xF8, 0x62, 0xB1, 0xA1, 0x16, 0x0D, 0x10, 0xBB, + 0xEA, 0xB7, 0x5E, 0x85, 0x01, 0x62, 0xE3, 0x63, 0xF2, 0xF6, 0x63, 0x66, 0x1B, 0xB7, 0x1F, 0x22, + 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0x26, 0x0E, 0xF7, 0xBD, 0xB0, 0x17, 0xAF, 0x31, 0xDE, 0x2F, 0x6E, 0xBF, 0x2B, 0xF8, 0x32, 0x06, + 0x00, 0x00, 0xE8, 0x1D, 0xAD, 0xDF, 0x80, 0x15, 0x0B, 0x0D, 0xB5, 0x58, 0x7C, 0x84, 0xB7, 0x1F, + 0x93, 0x0F, 0x9E, 0xDB, 0xF8, 0x88, 0xDF, 0x7E, 0x84, 0xF1, 0x11, 0x06, 0x48, 0xA2, 0xDB, 0x0F, + 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, + 0x51, 0x13, 0x07, 0xFB, 0x1E, 0x9A, 0x77, 0xFC, 0x8E, 0x0D, 0xC1, 0x97, 0x31, 0x00, 0x00, 0x40, + 0x6F, 0xF0, 0xDF, 0x80, 0xB5, 0x73, 0xB6, 0x8D, 0x08, 0x15, 0x1E, 0x6E, 0xB1, 0xD0, 0x50, 0x6B, + 0x10, 0x1F, 0xD5, 0x07, 0xCF, 0x37, 0xCE, 0xAC, 0xBF, 0xFD, 0x08, 0xE2, 0xA3, 0x7A, 0xFB, 0xF1, + 0xA0, 0xDD, 0xD7, 0x55, 0x70, 0x44, 0x27, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, + 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0x50, 0xDF, 0x4B, 0xF3, 0x8E, 0xDE, 0xCA, + 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x31, 0x23, 0xCB, 0xD7, 0x35, 0x7E, 0x05, 0x6F, 0x2C, 0x34, + 0x1A, 0x4D, 0x05, 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x41, 0x7C, 0xC8, 0x37, + 0x5F, 0x7D, 0xB7, 0xD5, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, + 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7D, 0xAF, 0xCD, 0x3B, 0xFA, 0xF9, 0xF1, + 0xE0, 0x4B, 0x19, 0x00, 0x00, 0xA0, 0x37, 0xD8, 0x00, 0x59, 0x5F, 0x1F, 0x1E, 0x29, 0xE2, 0xC3, + 0x2D, 0x1E, 0x1F, 0xD5, 0xDB, 0x8F, 0xC9, 0xF8, 0xA8, 0x79, 0xF3, 0x55, 0xEA, 0xDB, 0x0F, 0x11, + 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, + 0xD3, 0x87, 0xF9, 0x9E, 0x9C, 0x7B, 0x13, 0xD6, 0xD8, 0x17, 0x67, 0x05, 0x5F, 0xCE, 0x00, 0x00, + 0x00, 0xDD, 0xCF, 0x3B, 0x70, 0xD5, 0x50, 0xBB, 0xF1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0xD4, 0xDD, + 0x7E, 0x5C, 0x98, 0xE1, 0xF6, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, + 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBE, 0x97, 0x37, 0xB6, 0x9C, 0x37, 0x61, + 0x01, 0x00, 0x80, 0xDE, 0xE2, 0xED, 0xBD, 0x7C, 0x2C, 0x73, 0x7C, 0xB8, 0xC5, 0xE3, 0xC3, 0x0F, + 0x90, 0x19, 0x39, 0xDD, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xC0, 0xF7, 0xFA, 0x78, 0x13, 0x16, 0x00, 0x00, + 0xE8, 0x35, 0x66, 0x68, 0x81, 0x0D, 0x89, 0xEC, 0xF1, 0xE1, 0x7E, 0xAC, 0xBD, 0xFD, 0xB0, 0xF1, + 0x11, 0xFB, 0xF6, 0xAB, 0xA6, 0xB7, 0x1F, 0xF7, 0x35, 0xBA, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, + 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x78, 0x2F, + 0xC3, 0x9E, 0xBF, 0x9C, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, 0x61, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, + 0x2E, 0xB5, 0x11, 0x91, 0x21, 0x3E, 0xDC, 0xC2, 0xF0, 0x08, 0xE3, 0xE3, 0xE9, 0x19, 0x35, 0xB7, + 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xF1, 0x80, 0x1D, 0xF1, 0x91, 0xCF, 0x64, 0x38, 0xE4, 0x31, + 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x07, 0xF7, 0x12, 0xCD, 0x3B, 0xFE, 0x67, 0xBC, + 0x09, 0x0B, 0x00, 0x00, 0xF4, 0x06, 0xFF, 0x15, 0xBC, 0xFE, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, + 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, 0xF1, 0xD1, 0xE0, 0xD9, 0x0F, 0xF9, 0xA1, 0x83, 0xF7, + 0xAA, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, + 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x87, 0xF6, 0x32, 0xCD, 0x3B, 0xFA, 0xF9, 0x93, 0xC1, 0x97, 0x34, + 0x00, 0x00, 0x40, 0x77, 0xF3, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0xF5, 0x71, 0x91, 0x64, 0x61, 0x78, + 0x84, 0xF1, 0x11, 0xBB, 0xFD, 0xA8, 0x7B, 0xF6, 0xC3, 0x06, 0xC8, 0x29, 0x17, 0x20, 0x4D, 0x6F, + 0x3F, 0x44, 0x48, 0x64, 0x99, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1F, 0xD8, 0x4B, 0xB7, 0x23, 0xAB, 0x4C, 0xF0, 0x25, 0x0D, 0x00, 0x00, 0xD0, + 0xDD, 0xBC, 0xE1, 0x65, 0x83, 0x32, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0x12, 0x20, 0x33, + 0xF4, 0xED, 0x47, 0x2C, 0x3E, 0x5A, 0xDF, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, + 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA8, 0x97, 0x75, 0x63, 0xCB, + 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0D, 0xDE, 0xDE, 0xCB, 0x46, 0xEB, 0xE2, 0x22, 0xC9, 0xAA, + 0xB7, 0x1F, 0x41, 0x7C, 0x24, 0xBD, 0xFD, 0x08, 0x03, 0xE4, 0x07, 0x76, 0xC4, 0x47, 0x7B, 0x93, + 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0xBA, 0x7F, + 0x5D, 0x68, 0xCC, 0x0B, 0x57, 0x1B, 0x73, 0xFC, 0x8E, 0x75, 0xC1, 0x97, 0x35, 0x00, 0x00, 0x40, + 0xF7, 0xF2, 0xF6, 0x2C, 0x18, 0x97, 0x81, 0xD1, 0x6C, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0x59, 0x6F, + 0x3F, 0xEE, 0x89, 0xDE, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2E, 0x3E, 0xDC, 0x7E, 0x6E, + 0xFF, 0x99, 0x38, 0x71, 0xDB, 0xFA, 0xE0, 0xCB, 0x1A, 0x00, 0x00, 0xA0, 0x3B, 0x99, 0xA1, 0xFE, + 0x59, 0x66, 0xF7, 0xDC, 0xFA, 0xC0, 0x68, 0xB5, 0xF0, 0xE6, 0x23, 0x97, 0xDB, 0x0F, 0x11, 0x12, + 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x2E, 0x8C, 0x8F, 0x60, 0xDE, 0x89, 0xDB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, + 0x6E, 0x66, 0x64, 0xE9, 0x80, 0xD9, 0xF1, 0x71, 0x1D, 0x19, 0xCD, 0x16, 0xC6, 0x47, 0xDB, 0xB7, + 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, + 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x5D, 0x2C, 0x3E, 0xFC, 0x00, 0x39, 0x7A, 0x33, 0x6F, 0xC2, + 0x02, 0x00, 0x00, 0xDD, 0xCD, 0x1B, 0x5E, 0x7E, 0x97, 0xD9, 0xFA, 0x21, 0x1D, 0x19, 0x8D, 0x16, + 0x8F, 0x8F, 0x66, 0xB7, 0x1F, 0x61, 0x7C, 0xC8, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, + 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, + 0xC4, 0x87, 0xBF, 0x23, 0x37, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xDD, 0xFC, 0x57, 0xF0, 0xAA, + 0xC8, 0x68, 0x34, 0x1B, 0x1D, 0x8D, 0x6E, 0x3F, 0xAA, 0x01, 0xD2, 0xEA, 0xF6, 0xE3, 0x1B, 0xC4, + 0x47, 0xA6, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, + 0x65, 0x9D, 0x0A, 0x8F, 0x70, 0x2F, 0xF5, 0xBB, 0x07, 0xD1, 0x97, 0x04, 0x5F, 0xDE, 0x00, 0x00, + 0x00, 0xDD, 0xC7, 0x3B, 0x70, 0x75, 0xF2, 0x37, 0x60, 0x45, 0xE3, 0xC3, 0x86, 0x47, 0xA3, 0xDB, + 0x8F, 0x09, 0x17, 0x20, 0x8F, 0x45, 0x6E, 0x3F, 0xC2, 0xF8, 0x70, 0xDB, 0xE0, 0xBE, 0xF5, 0x4A, + 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xD1, 0x11, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x3F, 0x5F, 0x1B, + 0x7C, 0x79, 0x03, 0x00, 0x00, 0x74, 0x1F, 0x6F, 0xDF, 0xE5, 0x27, 0x65, 0x6C, 0xC4, 0x17, 0xC4, + 0x47, 0xA3, 0xDB, 0x8F, 0xC4, 0xCF, 0x7E, 0x7C, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, + 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xC1, + 0x11, 0x1F, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xDD, 0x2E, 0xD1, 0x1B, 0xB0, 0xE2, 0xF1, 0x51, 0x73, + 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xED, 0xED, 0x47, 0x4E, 0xDF, 0x7A, 0x25, + 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, + 0xB2, 0x4E, 0xC5, 0x46, 0x83, 0x79, 0xC7, 0x6F, 0x1F, 0x0A, 0xBE, 0xBC, 0x01, 0x00, 0x00, 0xBA, + 0x8B, 0x39, 0x70, 0xFD, 0x12, 0xB3, 0xF3, 0x53, 0x3A, 0x3A, 0xC2, 0x45, 0xE2, 0xA3, 0x1A, 0x20, + 0x76, 0xD5, 0x6F, 0xBD, 0x0A, 0x03, 0xA4, 0xE6, 0xB5, 0xBB, 0x33, 0xC5, 0xED, 0xC7, 0xCC, 0x7C, + 0x6E, 0x3F, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, + 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0xC8, 0x68, 0x36, 0xEF, 0xC8, 0x9A, 0xB1, 0xE0, 0x4B, 0x1C, 0x00, + 0x00, 0xA0, 0xBB, 0x98, 0x83, 0xCB, 0xD6, 0x9A, 0xED, 0x1F, 0xD5, 0xE1, 0xE1, 0x16, 0x09, 0x8F, + 0x68, 0x7C, 0x84, 0xB7, 0x1F, 0x35, 0x0F, 0x9E, 0x37, 0x7A, 0xF6, 0xC3, 0x0F, 0x10, 0x1B, 0x1F, + 0xDF, 0xCD, 0xE1, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, + 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x08, 0x8C, 0x96, 0x3B, 0xBA, 0x86, 0x37, 0x61, 0x01, + 0x00, 0x80, 0xEE, 0xE4, 0xBF, 0x01, 0x6B, 0xF3, 0xAC, 0x4C, 0xF1, 0x51, 0x7D, 0xF0, 0x5C, 0xDD, + 0x7E, 0x04, 0xF1, 0x51, 0xB9, 0xFD, 0xB0, 0xF1, 0xF1, 0xA0, 0xDD, 0xD7, 0x45, 0x50, 0xA4, 0x99, + 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, + 0xCB, 0x3A, 0x15, 0x17, 0x49, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB7, 0xF2, 0x0E, 0x7C, 0x6E, + 0x28, 0x49, 0x7C, 0xD4, 0x05, 0x48, 0xFC, 0xB5, 0xBB, 0xEE, 0xF6, 0x23, 0x88, 0x8F, 0xDA, 0x37, + 0x5F, 0xD9, 0xF0, 0xC8, 0xE3, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x0A, 0x8B, 0xA4, 0x7B, 0xE1, 0x5A, 0x63, + 0x8E, 0xDD, 0x36, 0x10, 0x7C, 0x99, 0x03, 0x00, 0x00, 0x74, 0x0F, 0x6F, 0xEF, 0x65, 0xF5, 0xAF, + 0xE0, 0x8D, 0x44, 0x87, 0x8C, 0x8F, 0xE8, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0xAA, 0xDE, + 0x7E, 0x04, 0xF1, 0xD1, 0xEE, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, + 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x15, 0x69, 0xF6, 0xFC, 0x67, 0x79, + 0x13, 0x16, 0x00, 0x00, 0xE8, 0x4E, 0x66, 0x8F, 0x3D, 0xEC, 0xB4, 0x88, 0x0F, 0x37, 0x75, 0xFB, + 0x51, 0x7D, 0xED, 0x6E, 0xF5, 0xF6, 0xE3, 0xC2, 0xC8, 0xED, 0x47, 0x10, 0x1F, 0xED, 0xDE, 0x7E, + 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x62, 0x07, + 0xF4, 0x32, 0x4F, 0x05, 0x45, 0x86, 0x79, 0x27, 0x6E, 0x1B, 0x0C, 0xBE, 0xCC, 0x01, 0x00, 0x00, + 0xBA, 0x83, 0x19, 0xE9, 0x9F, 0x5D, 0xF3, 0x0A, 0xDE, 0x48, 0x70, 0x44, 0x97, 0xFE, 0xF6, 0x63, + 0xE6, 0x64, 0x80, 0x3C, 0x60, 0xA7, 0xC2, 0x22, 0xC9, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, + 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0x90, 0xC8, 0x3A, 0xEF, + 0xC8, 0xE7, 0x47, 0x83, 0x2F, 0x75, 0x00, 0x00, 0x80, 0xEE, 0x60, 0x46, 0x96, 0x0E, 0x54, 0xDF, + 0x80, 0x15, 0x09, 0x8E, 0xF8, 0xD4, 0xED, 0x47, 0xFD, 0xB3, 0x1F, 0xE1, 0xED, 0x47, 0x24, 0x3E, + 0xDC, 0xEE, 0xCD, 0x78, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, + 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x44, 0x44, 0x5B, 0xE3, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0xDB, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0xDE, 0x2F, 0xA3, 0x23, 0x5C, 0xB3, 0xDB, 0x8F, + 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0xC8, 0x7A, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, + 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x05, 0x44, 0xBB, 0x73, 0x6F, + 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x3B, 0x00, 0x00, 0x40, 0xE7, 0x79, 0x23, 0xCB, 0x36, + 0xA8, 0xE8, 0x88, 0x4E, 0xDD, 0x7E, 0xD4, 0x3F, 0xFB, 0xE1, 0x3E, 0x74, 0xD0, 0xBD, 0x7A, 0x37, + 0x12, 0x20, 0xEE, 0x43, 0x07, 0xB3, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, + 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xF1, 0x90, 0xC7, 0x5E, 0xBC, + 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, 0xEE, 0xE2, 0xED, 0xBD, 0x62, 0x54, 0x45, 0x47, 0xB8, 0x66, + 0xB7, 0x1F, 0xD5, 0x67, 0x3F, 0xFC, 0xD7, 0xEE, 0x06, 0xF1, 0xE1, 0xD6, 0xCE, 0xED, 0x87, 0x08, + 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, + 0x3A, 0x15, 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x2E, 0xDE, 0xDE, + 0xC5, 0xE3, 0x2A, 0x3C, 0xC2, 0x35, 0xBD, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC5, 0x87, 0xBA, 0xFD, + 0xB8, 0x27, 0xE5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x0D, 0x39, 0xCF, 0x3B, 0xB6, 0x96, 0x37, 0x61, + 0x01, 0x00, 0x80, 0xEE, 0xE1, 0xBF, 0x01, 0x2B, 0x12, 0x1C, 0xD1, 0xB5, 0xBC, 0xFD, 0xB0, 0xF1, + 0x31, 0xF1, 0xD8, 0x8C, 0xDA, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x60, 0xA7, 0x22, 0xA3, 0xD1, 0x44, + 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0x89, 0x58, 0x28, 0x62, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0E, 0xFE, + 0x1B, 0xB0, 0x76, 0x7C, 0x52, 0xC6, 0x87, 0x5B, 0xCB, 0xDB, 0x8F, 0x30, 0x3E, 0xDA, 0xBD, 0xFD, + 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, + 0x7A, 0x59, 0x27, 0x42, 0xA1, 0xA8, 0x79, 0x47, 0x6F, 0x1E, 0x0F, 0xBE, 0xE4, 0x01, 0x00, 0x00, + 0x3A, 0xCB, 0x8C, 0x2C, 0x5F, 0x67, 0xB6, 0x7D, 0xA4, 0x75, 0x7C, 0xC8, 0xDB, 0x8F, 0x19, 0xF9, + 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, + 0xC4, 0x21, 0xBD, 0xAC, 0x13, 0x91, 0x50, 0xE8, 0xDC, 0x9B, 0xB0, 0xC6, 0xBE, 0x38, 0x2B, 0xF8, + 0xB2, 0x07, 0x00, 0x00, 0xE8, 0x1C, 0x1B, 0x20, 0xEB, 0x55, 0x7C, 0xB8, 0xA9, 0xDB, 0x0F, 0x3F, + 0x40, 0x44, 0x7C, 0x64, 0xBE, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, + 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA1, 0xE8, 0xF1, 0x26, 0x2C, 0x00, + 0x00, 0xD0, 0x2D, 0xBC, 0x03, 0x57, 0x0D, 0x35, 0x8C, 0x0F, 0x1B, 0x1E, 0xF2, 0xF6, 0xE3, 0x09, + 0x1B, 0x1F, 0x2E, 0x40, 0x1E, 0x8D, 0xDC, 0x7E, 0x84, 0xF1, 0xE1, 0xB6, 0x81, 0xF8, 0xA8, 0x9B, + 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xA9, + 0x38, 0x98, 0x8A, 0xBD, 0x70, 0xB5, 0xF1, 0x7E, 0x71, 0xFB, 0x5D, 0xC1, 0x97, 0x3D, 0x00, 0x00, + 0x40, 0xE7, 0x78, 0x7B, 0x2F, 0x1B, 0x6B, 0x18, 0x20, 0x6E, 0x91, 0xDB, 0x0F, 0x17, 0x1F, 0x67, + 0x07, 0x67, 0xD4, 0xDE, 0x7E, 0xA8, 0x67, 0x3F, 0xBE, 0x21, 0x62, 0x23, 0x3E, 0x11, 0x1E, 0x6E, + 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2A, + 0x0C, 0xA6, 0x70, 0xDE, 0xF1, 0xDB, 0x36, 0x04, 0x5F, 0xF6, 0x00, 0x00, 0x00, 0x9D, 0x63, 0x86, + 0xE6, 0xEB, 0xF8, 0xA8, 0xB9, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC6, 0x47, 0x1E, 0xB7, 0x1F, 0x22, + 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, + 0xEB, 0x44, 0x10, 0x4C, 0xF5, 0xBC, 0xE3, 0x7F, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x67, 0x99, + 0x91, 0xFE, 0xD9, 0x66, 0xE7, 0x25, 0x3A, 0x40, 0xEC, 0xA2, 0xDF, 0x7A, 0x75, 0xEE, 0xC9, 0x19, + 0xE6, 0xAC, 0x8D, 0x8F, 0xC9, 0xDB, 0x8F, 0x19, 0xFA, 0xD9, 0x8F, 0x56, 0xB7, 0x1F, 0x22, 0x3C, + 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, + 0x44, 0x0C, 0x74, 0x62, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x74, 0x9C, 0xFF, 0x0A, 0xDE, 0xD8, 0x1B, + 0xB0, 0x6A, 0xBE, 0xF5, 0xCA, 0xEE, 0x9C, 0x0B, 0x10, 0x17, 0x1F, 0xF1, 0xDB, 0x8F, 0x68, 0x7C, + 0x84, 0x01, 0x72, 0x7F, 0x8B, 0xDB, 0x0F, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, + 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x22, 0x04, 0x3A, 0xB6, 0x97, 0x56, 0x99, + 0xE0, 0x4B, 0x1F, 0x00, 0x00, 0xA0, 0x33, 0xFC, 0x37, 0x60, 0x6D, 0xFE, 0xE3, 0x86, 0xF1, 0x51, + 0xB9, 0xFD, 0xB0, 0xF1, 0xD1, 0xE0, 0xF6, 0xC3, 0xC5, 0x47, 0xF5, 0xF6, 0xE3, 0x41, 0xBB, 0xAF, + 0x8B, 0xE8, 0x08, 0x27, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, + 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x45, 0x40, 0x27, 0x37, 0xB6, 0x8C, 0x37, 0x61, 0x01, 0x00, + 0x80, 0xCE, 0xF2, 0x86, 0x97, 0x0D, 0x36, 0xBC, 0xFD, 0x08, 0xE2, 0xA3, 0xE6, 0xF6, 0x23, 0x88, + 0x8F, 0x9A, 0xDB, 0x8F, 0xF0, 0xD9, 0x8F, 0xEF, 0x36, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, + 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA0, + 0xD3, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0xF2, 0x07, 0x00, 0x00, 0x98, 0x7A, + 0xDE, 0xDE, 0xCB, 0x46, 0x1B, 0xDE, 0x7E, 0x6C, 0xBC, 0xA0, 0x26, 0x3E, 0xEA, 0x3E, 0x74, 0x30, + 0xE9, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x75, 0xF8, 0xEF, 0xF8, 0x16, 0xD8, 0x5F, 0x9B, 0xFD, 0xDF, 0xE1, + 0xC4, 0x6D, 0xEB, 0x83, 0x2F, 0x7F, 0x00, 0x00, 0x80, 0xA9, 0xE7, 0xED, 0x9E, 0x3F, 0xAE, 0x6F, + 0x3F, 0x6C, 0x7C, 0x84, 0xDF, 0x7A, 0x55, 0x73, 0xFB, 0x31, 0x33, 0xDD, 0xED, 0x87, 0x08, 0x0F, + 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0xB1, 0x78, 0x20, 0x14, 0x39, 0x71, 0x48, 0x2F, 0xEB, + 0xE4, 0xE1, 0xBF, 0xD3, 0xB3, 0xF1, 0x11, 0xCC, 0x3B, 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x80, + 0xCE, 0x30, 0x43, 0xFD, 0xB3, 0xCC, 0xEE, 0xB9, 0x32, 0x3E, 0x72, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, + 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, + 0x0F, 0xFF, 0x9D, 0xDE, 0x64, 0x7C, 0xF8, 0x01, 0x72, 0xF4, 0xE6, 0x93, 0xC1, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x53, 0xCB, 0x7F, 0x03, 0xD6, 0xF6, 0x8B, 0x6B, 0x03, 0x24, 0x8C, 0x0F, 0xF9, 0xEC, + 0x47, 0x83, 0xDB, 0x8F, 0x7B, 0xC5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, + 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x6A, 0xE3, + 0xC3, 0xDF, 0x91, 0x1B, 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0C, 0x33, 0xB2, 0x7C, 0x9D, 0xD9, + 0xFA, 0xC1, 0xC8, 0xED, 0x87, 0x8D, 0x8F, 0xD8, 0xED, 0x47, 0xED, 0x9B, 0xAF, 0x44, 0x7C, 0x3C, + 0x60, 0x47, 0x7C, 0x14, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x11, 0x1F, 0x6E, 0x2F, 0xF5, 0xF3, 0x26, 0x2C, 0x00, 0x00, 0xD0, + 0x19, 0xE6, 0xE0, 0xF2, 0xF5, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xEC, 0xC7, + 0xE9, 0x78, 0x80, 0xB8, 0x0F, 0x1D, 0x8C, 0xDF, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, + 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, + 0x84, 0x47, 0x38, 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x00, 0x00, 0x00, 0x60, + 0xEA, 0x78, 0xFB, 0xAE, 0x1E, 0xAD, 0x89, 0x8F, 0x24, 0xCF, 0x7E, 0xB8, 0x35, 0xBA, 0xFD, 0x10, + 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, + 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x88, 0x8E, 0xE8, 0xDC, 0x3F, 0x67, 0xBC, 0x09, 0x0B, 0x00, + 0x00, 0x74, 0x82, 0xB7, 0xF7, 0xF2, 0x93, 0x7E, 0x7C, 0x34, 0xBA, 0xFD, 0x88, 0xC6, 0x87, 0xBA, + 0xFD, 0xF8, 0x76, 0xE4, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, + 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x38, 0xC4, 0xBC, + 0xE3, 0xB7, 0x0F, 0x05, 0x7F, 0x0C, 0x00, 0x00, 0x00, 0x4C, 0x1D, 0x6F, 0xE7, 0x9C, 0xF4, 0xB7, + 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x8E, 0xF8, 0xC8, 0x71, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x36, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, + 0x82, 0x3F, 0x06, 0x00, 0x00, 0x00, 0xA6, 0x86, 0x39, 0x70, 0xFD, 0x12, 0x6F, 0xFB, 0x27, 0xB2, + 0xDF, 0x7E, 0xDC, 0x13, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, + 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x87, 0x46, 0xC3, + 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xD5, 0xCC, 0xC1, 0x65, 0x6B, 0xBD, 0xAD, 0x1F, 0x6E, 0xEF, + 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, + 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x30, 0x5A, 0xCD, 0xBD, 0x09, 0xEB, 0xF8, + 0x1D, 0x4B, 0x82, 0x3F, 0x0E, 0x00, 0x00, 0x00, 0x8A, 0x77, 0xFE, 0xE0, 0xD2, 0xF5, 0xDE, 0xA6, + 0x0B, 0x33, 0xDE, 0x7E, 0x10, 0x1F, 0xF9, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, + 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC4, 0x45, 0x92, 0xBD, 0x70, 0x0D, 0x6F, 0xC2, + 0x02, 0x00, 0x00, 0x53, 0xEB, 0xFC, 0xFE, 0x6B, 0x06, 0xB3, 0xDD, 0x7E, 0xCC, 0x90, 0xE1, 0xE1, + 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, + 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x8B, 0xA4, 0x7B, 0xFE, 0x0A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xA6, + 0xD6, 0xF9, 0xDD, 0x8B, 0x47, 0xA3, 0xB7, 0x1F, 0xD5, 0x00, 0x89, 0xC5, 0x47, 0xDD, 0xED, 0xC7, + 0xDD, 0xC4, 0x47, 0xFB, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, + 0xE4, 0xE1, 0xBF, 0xD3, 0x13, 0x51, 0x91, 0x72, 0xDE, 0xB1, 0xB5, 0xBC, 0x09, 0x0B, 0x00, 0x00, + 0x4C, 0x1D, 0x6F, 0xF7, 0x42, 0x79, 0xFB, 0x31, 0xE1, 0x02, 0xE4, 0xD1, 0xC8, 0xED, 0x47, 0x18, + 0x1F, 0x6E, 0xF7, 0xEB, 0x6F, 0xBD, 0x22, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x07, 0x45, 0xDA, 0x79, 0x47, 0x3E, + 0x3F, 0x1A, 0xFC, 0x71, 0x00, 0x00, 0x00, 0x50, 0x2C, 0x33, 0xD2, 0x3F, 0xDB, 0xDB, 0x31, 0x27, + 0xDD, 0xB3, 0x1F, 0x0F, 0xCE, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, + 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x98, 0xC8, 0xB4, 0xA3, + 0x6B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x1A, 0x66, 0xFF, 0xD2, 0x81, 0xF3, 0x5B, 0x3E, 0x6C, + 0x03, 0x24, 0xF2, 0xAD, 0x57, 0xCD, 0x6E, 0x3F, 0x1E, 0xB2, 0xF1, 0x21, 0x6E, 0x3F, 0x88, 0x8F, + 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, + 0xD3, 0x13, 0x11, 0xD1, 0xCE, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0x73, 0x76, 0xF0, 0xC7, 0x02, 0x00, + 0x00, 0x40, 0x71, 0xCE, 0xED, 0x5F, 0x7A, 0xD7, 0xF9, 0x4D, 0xEF, 0x9B, 0x7C, 0xF6, 0xA3, 0xE6, + 0xC1, 0xF3, 0x19, 0xB5, 0xCF, 0x7E, 0xB8, 0xF8, 0x78, 0xA0, 0xFE, 0xF6, 0x83, 0xF8, 0x48, 0x33, + 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, + 0x11, 0x10, 0xED, 0xCE, 0xBD, 0x09, 0xEB, 0xD8, 0x6D, 0x03, 0xC1, 0x1F, 0x0B, 0x00, 0x00, 0x00, + 0xC5, 0x39, 0x7F, 0x60, 0xD9, 0x86, 0x9A, 0x07, 0xCF, 0xA3, 0xB7, 0x1F, 0xD1, 0xF8, 0x78, 0xD8, + 0x86, 0x87, 0x0B, 0x90, 0xEF, 0xD4, 0xDE, 0x7E, 0x10, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x21, 0x8F, 0xF1, + 0x26, 0x2C, 0x00, 0x00, 0x30, 0x55, 0xCE, 0xEF, 0x5E, 0x32, 0xEA, 0xC7, 0x47, 0x83, 0xDB, 0x0F, + 0x17, 0x1F, 0xA7, 0xC2, 0xF8, 0x70, 0xB7, 0x1F, 0x7F, 0x4D, 0x7C, 0x64, 0x9B, 0x0A, 0x87, 0x3C, + 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x87, 0x1C, + 0xE7, 0x9D, 0xB8, 0x6D, 0x30, 0xF8, 0x63, 0x01, 0x00, 0x00, 0xA0, 0x38, 0xE7, 0x76, 0x2E, 0x3A, + 0x59, 0x73, 0xFB, 0x11, 0xC4, 0x47, 0xF5, 0xD9, 0x8F, 0x30, 0x3E, 0x62, 0xB7, 0x1F, 0xC4, 0x47, + 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, + 0xE9, 0xE9, 0x68, 0xC8, 0x73, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0xDE, 0xF9, + 0xED, 0x73, 0xAA, 0xF1, 0x51, 0xF7, 0xA1, 0x83, 0x8F, 0xCC, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, + 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, + 0xE9, 0x60, 0xC8, 0x7D, 0x47, 0x3F, 0xCF, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB1, 0xCE, 0xEE, 0x5F, + 0x3A, 0x70, 0x6E, 0xCB, 0x27, 0x63, 0xB7, 0x1F, 0x33, 0x2B, 0xCF, 0x7E, 0x44, 0xE3, 0xC3, 0xED, + 0xDE, 0xCA, 0xED, 0x07, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, + 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x14, 0x8A, 0x9A, 0x7B, 0x13, 0xD6, 0xD8, 0x17, + 0x67, 0x05, 0x7F, 0x3C, 0x00, 0x00, 0x00, 0xE4, 0xEF, 0xDC, 0xDE, 0xE5, 0xEB, 0xCE, 0x6D, 0xFA, + 0x48, 0xEC, 0xF6, 0x63, 0x46, 0x35, 0x3E, 0xAA, 0x01, 0xF2, 0x23, 0x3B, 0xE2, 0x23, 0xE5, 0x54, + 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x44, + 0x24, 0x14, 0xB9, 0x17, 0xAF, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x58, 0xE7, 0xF7, 0x2E, 0x5F, + 0x5F, 0xF7, 0xEC, 0xC7, 0x8F, 0x27, 0x03, 0xA4, 0x7A, 0xFB, 0xF1, 0xED, 0x0B, 0x88, 0x8F, 0x54, + 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, + 0x13, 0x81, 0x50, 0xF4, 0x5E, 0xB8, 0xCA, 0x78, 0xBF, 0xB8, 0xFD, 0xAE, 0xE0, 0x8F, 0x07, 0x00, + 0x00, 0x80, 0xFC, 0x9D, 0xDB, 0x7D, 0xD5, 0x50, 0xCD, 0x9B, 0xAF, 0xC2, 0xF8, 0x88, 0x06, 0xC8, + 0x8F, 0x66, 0x10, 0x1F, 0xA9, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x60, 0x8A, 0xE6, 0x1D, 0xBF, 0x6D, 0x43, 0xF0, 0xC7, + 0x03, 0x00, 0x00, 0x40, 0xFE, 0xCE, 0xED, 0xB8, 0x6C, 0x6C, 0xF2, 0xF6, 0xE3, 0x02, 0x79, 0xFB, + 0xF1, 0x76, 0xE4, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x06, 0x53, 0x35, 0xDE, 0x84, 0x05, 0x00, + 0x00, 0x0A, 0x75, 0x76, 0xDB, 0xFC, 0xE0, 0xF6, 0xC3, 0xC6, 0x87, 0x78, 0xF6, 0xE3, 0xED, 0x1F, + 0x4C, 0xDE, 0x7E, 0x10, 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, + 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0xA3, 0x60, 0x2A, 0xE7, 0x1D, 0xBD, 0x79, 0x3C, 0xF8, + 0xE3, 0x01, 0x00, 0x00, 0x20, 0x5F, 0x66, 0xA8, 0x7F, 0xF6, 0xD9, 0xCD, 0x97, 0x04, 0xF1, 0x51, + 0x7B, 0xFB, 0x71, 0x2A, 0xBC, 0xFD, 0xF8, 0x66, 0xE5, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, + 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x04, + 0x53, 0xBE, 0x97, 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x8C, 0xB3, 0x43, 0x4B, 0x07, 0xDE, + 0xDD, 0xF8, 0xE1, 0x6A, 0x80, 0x9C, 0xB6, 0x01, 0x52, 0xF3, 0xEC, 0xC7, 0xF7, 0x2B, 0xB7, 0x1F, + 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, + 0xF0, 0xDF, 0xE9, 0x89, 0x10, 0xE8, 0xD4, 0xC6, 0x96, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x0C, + 0x1B, 0x20, 0xEB, 0x27, 0x06, 0xDF, 0x57, 0x73, 0xFB, 0x11, 0x7D, 0xFE, 0xC3, 0xDD, 0x7E, 0x10, + 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, + 0x7F, 0xA7, 0x27, 0x22, 0xA0, 0x93, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0x63, + 0x02, 0x00, 0x00, 0x20, 0x3F, 0xEF, 0xEE, 0x59, 0x3A, 0xE8, 0xDF, 0x7E, 0x88, 0xF8, 0x70, 0xB7, + 0x1F, 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, + 0xF2, 0xF0, 0xDF, 0xE9, 0x89, 0x00, 0xE8, 0xF4, 0xDC, 0x3F, 0x17, 0x27, 0x6E, 0x5B, 0x1F, 0xFC, + 0x31, 0x01, 0x00, 0x00, 0x90, 0x9F, 0x89, 0x6D, 0x8B, 0x47, 0xEB, 0xDE, 0x7C, 0x15, 0xDE, 0x7E, + 0xDC, 0x4D, 0x7C, 0x34, 0x9F, 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xE9, 0x65, + 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xE2, 0xF0, 0xDF, 0x25, 0xF3, 0x8E, 0xAF, 0xE5, 0x4D, 0x58, 0x00, + 0x00, 0x20, 0x7F, 0x13, 0x5B, 0xFA, 0xC6, 0xE5, 0xC3, 0xE7, 0xF7, 0xBB, 0x6F, 0xBD, 0x22, 0x3E, + 0x1A, 0x4F, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, + 0x4E, 0x4F, 0x1F, 0xFC, 0xBB, 0x65, 0xDE, 0xD1, 0x9B, 0x4F, 0x06, 0x7F, 0x4C, 0x00, 0x00, 0x00, + 0xE4, 0xC3, 0x0C, 0xF5, 0xCF, 0x7A, 0xF7, 0x99, 0x39, 0x95, 0xF8, 0xB0, 0x8B, 0x3E, 0x7C, 0xFE, + 0xD6, 0x5F, 0x11, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFD, 0x5D, 0xB5, 0x97, 0x56, 0x9A, 0xE0, 0x8F, 0x0A, + 0x00, 0x00, 0x80, 0x7C, 0xB8, 0x37, 0x60, 0x4D, 0x6C, 0xFC, 0x98, 0x0D, 0x90, 0x0B, 0xCC, 0xE9, + 0x47, 0xEC, 0xDC, 0xED, 0x87, 0x0B, 0x90, 0xFB, 0x6D, 0x80, 0x10, 0x1F, 0x0D, 0xA6, 0xC2, 0x21, + 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xFB, + 0xDD, 0x38, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x7C, 0xDD, 0xC4, 0x13, 0x1F, + 0x30, 0xA7, 0xFD, 0x00, 0x09, 0xBE, 0xFD, 0xEA, 0xE1, 0x99, 0xFE, 0xED, 0x07, 0xF1, 0xA1, 0xA6, + 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, + 0x0E, 0xFA, 0xDD, 0x3A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x74, 0x7D, 0x78, + 0xFB, 0x71, 0xCA, 0xCD, 0xDD, 0x7E, 0x7C, 0x67, 0x06, 0xF1, 0x21, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF9, 0xDD, 0x3C, + 0xF7, 0xCF, 0x3D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x79, 0x9A, 0xD8, 0x79, 0xD5, 0x68, 0xF5, 0xDB, + 0xAF, 0xDC, 0x0D, 0x88, 0x7B, 0xF6, 0xE3, 0x6B, 0xC4, 0x47, 0xFD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, 0x01, 0xBF, 0x07, 0xC6, + 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xAE, 0x26, 0xB6, 0x5D, 0x76, 0xB2, 0x7A, 0x03, 0xF2, 0xF0, 0x0C, + 0xF3, 0xF6, 0x7D, 0xC1, 0xED, 0x87, 0x8D, 0x8F, 0x3F, 0x10, 0x1F, 0xC1, 0x54, 0x38, 0xE4, 0x31, + 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0xE1, 0xBE, 0x17, + 0xE6, 0x1D, 0x59, 0x33, 0x16, 0xFC, 0x71, 0x01, 0x00, 0x00, 0xD0, 0xBE, 0x09, 0xFF, 0x0D, 0x58, + 0x93, 0xB7, 0x1F, 0x6F, 0x7E, 0x6D, 0xF2, 0xE6, 0xE3, 0x0D, 0xE2, 0xC3, 0x4E, 0x85, 0x43, 0x1E, + 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xEC, 0x7B, + 0x66, 0x47, 0x6E, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x20, 0x1F, 0x13, 0x43, 0xD7, 0x2F, 0x99, 0x78, + 0xFA, 0x13, 0xE6, 0xCC, 0xA3, 0x95, 0xCF, 0xFF, 0x70, 0xB7, 0x1F, 0x95, 0xF8, 0xB8, 0xC0, 0xBF, + 0xF9, 0x78, 0x83, 0xF8, 0x28, 0x68, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, + 0xDF, 0xE9, 0x89, 0x03, 0x7D, 0xAF, 0xED, 0xA5, 0x7E, 0xF7, 0x20, 0xFA, 0x92, 0xE0, 0x8F, 0x0D, + 0x00, 0x00, 0x80, 0xEC, 0xCE, 0x0C, 0x2D, 0x5B, 0x3B, 0xF1, 0xE4, 0x87, 0x2B, 0x9F, 0x01, 0xF2, + 0x60, 0xE5, 0xB5, 0xBB, 0xD5, 0xDB, 0x8F, 0xAF, 0xD9, 0xF8, 0xF8, 0x47, 0xE2, 0x23, 0xFF, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF3, 0xBD, 0x38, + 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x03, 0x00, 0x00, 0x20, 0x3B, 0xF7, 0x06, + 0xAC, 0x89, 0xC7, 0x2F, 0xF2, 0x03, 0xE4, 0xED, 0x6F, 0x55, 0x9E, 0xFB, 0x20, 0x3E, 0xDC, 0x54, + 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, + 0x41, 0xBE, 0x57, 0xE7, 0xBE, 0x26, 0x78, 0x13, 0x16, 0x00, 0x00, 0xC8, 0xC3, 0xD9, 0x5D, 0xD7, + 0x0C, 0x4E, 0x3C, 0x36, 0xC3, 0x9C, 0x71, 0xCF, 0x7E, 0x04, 0x6F, 0xBD, 0xFA, 0xC3, 0x7A, 0xE2, + 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, + 0xF1, 0x3D, 0xBB, 0xF9, 0xFE, 0xBC, 0xE3, 0xB7, 0x0D, 0x05, 0x7F, 0x6C, 0x00, 0x00, 0x00, 0x64, + 0xF7, 0xEE, 0xB6, 0xC5, 0xA3, 0x13, 0x8F, 0xCF, 0x30, 0xEF, 0x7C, 0xBB, 0x72, 0xFB, 0xF1, 0xE6, + 0x5F, 0x5D, 0x44, 0x7C, 0x14, 0x32, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, + 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x57, 0x89, 0x0F, 0x3F, 0x40, 0x8E, 0xDC, 0xCC, 0x9B, 0xB0, + 0x00, 0x00, 0x40, 0xFB, 0xCE, 0x6D, 0x5F, 0x60, 0x26, 0x1E, 0xB9, 0xC0, 0xBC, 0xE5, 0x5E, 0xBB, + 0xFB, 0xD7, 0xC4, 0x47, 0x31, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, + 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0xE1, 0xEF, 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, + 0x00, 0xB4, 0xC7, 0x0C, 0x5D, 0x3B, 0xFB, 0xDC, 0xB6, 0x4B, 0xCD, 0x3B, 0xDF, 0xB4, 0x01, 0xF2, + 0x75, 0xE2, 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, + 0xA7, 0x0E, 0xF1, 0xBD, 0xBA, 0x58, 0x7C, 0xB8, 0xBD, 0xB4, 0xC2, 0x98, 0x97, 0xBF, 0x38, 0x3B, + 0xF8, 0xE3, 0x03, 0x00, 0x00, 0x20, 0xBD, 0xB3, 0xFB, 0x97, 0x0E, 0xBC, 0xFB, 0xD8, 0x87, 0xCC, + 0xDB, 0x77, 0x5F, 0x64, 0xCE, 0x13, 0x1F, 0x05, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x89, 0xF8, 0x70, 0x7B, 0xE1, 0x6A, 0x63, + 0x8E, 0xDD, 0x36, 0x10, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDE, 0x99, 0x5D, 0x9F, 0xBB, 0xEB, + 0xD4, 0x86, 0x0F, 0x98, 0xF3, 0xFF, 0x44, 0x7C, 0xE4, 0x3F, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, + 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x27, 0xC2, 0x23, 0x98, 0xF7, 0xAF, + 0x4B, 0xCC, 0xE9, 0x9F, 0xDD, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x76, 0xAF, 0x3D, 0x70, 0xED, + 0x86, 0xF1, 0xDD, 0xAB, 0xCD, 0xD9, 0x17, 0xBF, 0x44, 0x7C, 0xE4, 0x3A, 0x15, 0x09, 0x45, 0x4D, + 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0xA7, 0xC3, 0xC3, 0xED, + 0xD4, 0xB3, 0xF3, 0xCC, 0xEF, 0x77, 0xCC, 0x31, 0xBF, 0xDB, 0x77, 0xD3, 0x60, 0xF0, 0xC7, 0x07, + 0x00, 0x00, 0x40, 0x7A, 0xAF, 0xEF, 0xB9, 0x75, 0xF8, 0xF7, 0x07, 0x6F, 0x35, 0xBF, 0xDF, 0xB7, + 0xD2, 0xBC, 0x79, 0xE0, 0x32, 0x73, 0xFE, 0x9F, 0x55, 0x54, 0x24, 0x9D, 0x08, 0x87, 0x3C, 0x26, + 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, + 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0x4E, 0x87, 0xC7, 0x99, 0xBF, 0xEB, 0x33, 0xE3, 0xBB, + 0xE6, 0x9A, 0xDF, 0x6D, 0xB3, 0xF1, 0xE1, 0xB6, 0x67, 0x39, 0xAF, 0xE2, 0x05, 0x00, 0x00, 0xD9, + 0xFD, 0xF3, 0xFF, 0xFE, 0x17, 0x17, 0xFE, 0x76, 0xFB, 0xEA, 0xFB, 0x7E, 0xB7, 0x6D, 0xF1, 0x5B, + 0xBF, 0xDF, 0xB9, 0xD8, 0xB8, 0xBD, 0x7D, 0xE8, 0x72, 0xFF, 0x5B, 0x2D, 0x74, 0x64, 0x34, 0x9A, + 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0xAE, 0x3E, 0x3C, 0xCE, 0xFE, + 0x43, 0x9F, 0x79, 0x73, 0xEF, 0x64, 0x78, 0xBC, 0xBE, 0x75, 0xCE, 0xF8, 0xEF, 0xB6, 0x5D, 0xBA, + 0x7E, 0xB4, 0xFF, 0x3D, 0x7F, 0x14, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDD, 0x7F, 0xBF, 0xFB, + 0x33, 0x17, 0xBF, 0xB6, 0x79, 0xF1, 0x96, 0x30, 0x42, 0xC6, 0x77, 0x2F, 0x36, 0xA7, 0xFF, 0xC6, + 0x1E, 0xD4, 0x65, 0x6C, 0xC4, 0x27, 0xC2, 0x21, 0x8F, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, 0xDF, + 0xAB, 0xAB, 0x0D, 0x8F, 0xF3, 0xFF, 0x34, 0xDF, 0xBC, 0xB5, 0x3F, 0x72, 0xE3, 0x61, 0xF7, 0xEA, + 0x33, 0x73, 0x7E, 0x34, 0x3E, 0xF4, 0xA9, 0x59, 0xC1, 0x1F, 0x17, 0x00, 0x00, 0x00, 0xF9, 0xF9, + 0xEF, 0xDF, 0x5D, 0xF2, 0x99, 0xD7, 0xB6, 0x2C, 0xFA, 0x59, 0x18, 0x22, 0x6F, 0xEC, 0xB9, 0xCC, + 0x4C, 0xFC, 0xBD, 0x0B, 0x02, 0x15, 0x1E, 0x6E, 0xB1, 0x68, 0xC8, 0x6B, 0x32, 0x1C, 0xF2, 0x98, + 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, + 0x3A, 0xC4, 0xF7, 0xEA, 0x26, 0xC3, 0xC3, 0xFB, 0xE7, 0xF9, 0xE6, 0x9D, 0x91, 0x79, 0x35, 0xE1, + 0xF1, 0xDA, 0xE6, 0x4B, 0xF7, 0x8F, 0x6F, 0xE9, 0xE3, 0xB5, 0xBB, 0x00, 0x00, 0xA0, 0x78, 0xFF, + 0xEB, 0xA1, 0xCB, 0xBE, 0xF8, 0xBB, 0x6D, 0x8B, 0x7E, 0x19, 0x86, 0x88, 0x7B, 0x3E, 0xE4, 0xEC, + 0x4F, 0x5D, 0x1C, 0x10, 0x1F, 0xF5, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, + 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0x51, 0x7D, 0xC0, 0x3C, 0x08, 0x8F, 0xD7, + 0xB7, 0x5E, 0x3A, 0xF6, 0xDA, 0x96, 0x4B, 0x79, 0xDD, 0x2E, 0x00, 0x00, 0x98, 0x5A, 0xA3, 0xFD, + 0xFD, 0x7F, 0xF4, 0xAB, 0x27, 0x2E, 0xFB, 0x3F, 0xA2, 0xCF, 0x87, 0xBC, 0x35, 0xEC, 0x1E, 0x54, + 0x17, 0xD1, 0x90, 0xD7, 0x64, 0x38, 0xE4, 0x31, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x55, 0xC2, 0x23, 0xFE, + 0x80, 0xB9, 0x8D, 0x8E, 0x5F, 0xBE, 0xBE, 0x7D, 0xEE, 0xBA, 0xE0, 0x8F, 0x00, 0x00, 0x00, 0x80, + 0xCE, 0xF8, 0xD5, 0x23, 0x57, 0x7E, 0xE0, 0x37, 0x4F, 0x2E, 0xDE, 0x30, 0x19, 0x22, 0x8B, 0xCC, + 0xE9, 0xBF, 0xB9, 0xCC, 0x78, 0xFF, 0x2A, 0x02, 0xA2, 0x9D, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, + 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, + 0xDF, 0xAB, 0x6B, 0xFC, 0x80, 0x39, 0xCF, 0x79, 0x00, 0x00, 0x80, 0xAE, 0x72, 0xF2, 0x91, 0xC5, + 0xF3, 0x5F, 0x7D, 0x66, 0xF1, 0x0E, 0x17, 0x20, 0x6E, 0xE3, 0xBB, 0x17, 0x99, 0x33, 0x7F, 0x67, + 0x0F, 0xE2, 0x2A, 0x26, 0xD2, 0x4E, 0x86, 0x43, 0x1E, 0x8B, 0x47, 0x43, 0x5E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x73, 0xEA, 0x01, + 0xF3, 0xDF, 0x6D, 0xBD, 0x74, 0xF0, 0xBF, 0x7D, 0x67, 0xDE, 0x07, 0x82, 0x2F, 0x73, 0x00, 0x00, + 0x80, 0xEE, 0xF3, 0xAB, 0x8D, 0x8B, 0xD6, 0xBC, 0xFA, 0xCC, 0xC2, 0x9F, 0x87, 0x21, 0xF2, 0xC6, + 0x9E, 0xC5, 0xE6, 0xDD, 0x7F, 0xB0, 0x87, 0x7D, 0x15, 0x16, 0x49, 0x26, 0xC3, 0x21, 0x8F, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, + 0x83, 0x7C, 0xAF, 0xCD, 0xFB, 0xE7, 0x05, 0x75, 0x0F, 0x98, 0xDB, 0x8D, 0xFE, 0x7F, 0x8F, 0x5E, + 0x3A, 0x27, 0xF8, 0xB2, 0x06, 0x00, 0x00, 0xE8, 0x6E, 0xFE, 0xF3, 0x21, 0x83, 0x8B, 0xFF, 0xE2, + 0x77, 0xDB, 0x16, 0xFE, 0x32, 0x0C, 0x91, 0x37, 0x0F, 0x2C, 0x36, 0x67, 0x7F, 0x6A, 0x0F, 0xFE, + 0x2A, 0x32, 0x1A, 0x4D, 0x86, 0x43, 0x1E, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, + 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x87, 0xF9, 0x5E, 0xDB, 0xE9, 0xBF, 0xE9, 0xAB, + 0x79, 0xC0, 0xFC, 0xB5, 0x67, 0xE6, 0x1C, 0xE3, 0x01, 0x73, 0x00, 0x00, 0xD0, 0xB3, 0x6C, 0x88, + 0xFC, 0xBB, 0x57, 0x37, 0x2F, 0xBA, 0xE7, 0x77, 0xDB, 0x16, 0xBD, 0x15, 0x86, 0xC8, 0xDB, 0x87, + 0x12, 0x3E, 0xA8, 0x2E, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xC3, 0x7C, 0x2F, 0x6D, 0xE2, 0xEF, 0xE7, 0xF3, + 0x80, 0x39, 0x00, 0x00, 0x28, 0xAF, 0x93, 0xF7, 0x2E, 0xFC, 0xC8, 0x2B, 0x9B, 0x16, 0x3F, 0x1A, + 0x46, 0x88, 0x7B, 0x3E, 0xA4, 0xE9, 0x83, 0xEA, 0x32, 0x1C, 0xF2, 0x98, 0x0A, 0x87, 0x3C, 0xA6, + 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x3E, 0xD0, 0xF7, 0xCA, + 0xCE, 0xFE, 0xC3, 0x7C, 0xF3, 0xE6, 0x5E, 0xF7, 0xED, 0x56, 0x95, 0xF8, 0xE0, 0x01, 0x73, 0x00, + 0x00, 0x50, 0x6A, 0xFF, 0xE3, 0xFE, 0xCF, 0x2C, 0x7A, 0x75, 0xF3, 0xA2, 0xE7, 0xA2, 0x21, 0x32, + 0xF1, 0xF7, 0x36, 0x0C, 0x88, 0x8F, 0x84, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, + 0x7D, 0xA8, 0xEF, 0x85, 0x9D, 0xFF, 0xA7, 0x05, 0xE6, 0xED, 0x83, 0x7D, 0x41, 0x78, 0x04, 0x37, + 0x1F, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0xA6, 0x8B, 0x5F, 0x3E, 0xB6, 0xF8, 0x96, 0xD7, 0xB7, 0x2E, + 0x7C, 0x39, 0x0C, 0x11, 0xF7, 0xA0, 0xBA, 0xFF, 0x7C, 0x88, 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, + 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xF6, + 0xDD, 0x3E, 0xF7, 0x80, 0xF9, 0xA9, 0x67, 0xA3, 0xE1, 0xE1, 0xC7, 0x07, 0x0F, 0x98, 0x03, 0x00, + 0x80, 0xE9, 0xC7, 0x3D, 0xA8, 0xFE, 0xDB, 0xA7, 0x17, 0x7F, 0xF5, 0xF5, 0xAD, 0x8B, 0x7E, 0xE3, + 0x22, 0xE4, 0x77, 0x3B, 0x16, 0x9A, 0x37, 0xF7, 0x2F, 0x32, 0xE7, 0xFE, 0xD1, 0x1D, 0xEC, 0x55, + 0x44, 0x64, 0x5D, 0x3C, 0x1A, 0xF2, 0x9A, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, + 0xFC, 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xED, 0xAB, 0x3C, 0x60, 0x3E, 0x19, 0x1E, 0xAF, 0x3D, 0x33, + 0x97, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x7E, 0xF5, 0xC8, 0xBC, 0x0F, 0xFC, 0xE6, 0xE9, 0x85, 0xF7, + 0xBD, 0xBE, 0x75, 0xC1, 0x5B, 0x2E, 0x42, 0xDC, 0xDE, 0x1E, 0x59, 0x6C, 0xBC, 0x7F, 0x51, 0x31, + 0x91, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, + 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xCD, 0xAB, 0x3C, 0x60, 0x1E, 0x3E, 0xE7, 0x61, 0xC3, 0x63, 0xCB, + 0x5C, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x88, 0x1B, 0xFB, 0x4F, 0x9F, 0xB9, 0xF8, 0x95, 0xCD, 0x0B, + 0xB7, 0x84, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCD, 0xA9, 0xE7, 0xDA, 0x09, 0x11, 0x15, 0x0E, 0x79, + 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC0, 0xEF, + 0xD6, 0xD5, 0x3E, 0x60, 0x3E, 0xD7, 0xBC, 0xBE, 0x75, 0xEE, 0xB8, 0xFD, 0x91, 0x07, 0xCC, 0x01, + 0x00, 0x00, 0x9A, 0xF9, 0x9F, 0x0F, 0x2D, 0x5A, 0xFA, 0xEA, 0xE6, 0x85, 0x3F, 0x0B, 0x43, 0x64, + 0x7C, 0x68, 0x91, 0x39, 0x33, 0xEA, 0x0E, 0xFE, 0x2A, 0x32, 0x1A, 0x2D, 0x1E, 0x0D, 0x79, 0x4D, + 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC8, 0xEF, 0xC6, + 0xD5, 0x3F, 0x60, 0x6E, 0xB7, 0x75, 0x0E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA4, 0xF1, 0xBF, 0x1E, + 0x5A, 0xF0, 0xC5, 0xD7, 0xB6, 0x2E, 0xF8, 0x65, 0x18, 0x22, 0x6F, 0xEC, 0x5D, 0x64, 0xCE, 0xFE, + 0xC4, 0x45, 0x80, 0x0A, 0x8E, 0xE8, 0xE2, 0xD1, 0x90, 0xD7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, + 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x07, 0xFD, 0x6E, 0x9B, 0x7E, 0xC0, 0x7C, 0x2E, 0x0F, + 0x98, 0x03, 0x00, 0x00, 0x64, 0xE5, 0x1E, 0x54, 0xFF, 0xF5, 0xC6, 0x45, 0x7F, 0x19, 0x7D, 0x3E, + 0xC4, 0x3D, 0xA8, 0x7E, 0xFE, 0x67, 0x2A, 0x3C, 0xDC, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0x61, 0xBF, 0xDB, 0xC6, 0x03, 0xE6, + 0x00, 0x00, 0x00, 0x05, 0x72, 0x0F, 0xAA, 0xFF, 0xFA, 0xC9, 0x85, 0x1B, 0xC2, 0x08, 0x71, 0x7B, + 0xE7, 0x70, 0xFC, 0xF9, 0x10, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xD8, 0xEF, 0xA6, 0xF1, 0x80, 0x39, 0x00, 0x00, 0xC0, 0x14, + 0x3A, 0xF9, 0xC8, 0xE2, 0xF9, 0xBF, 0xDD, 0xB4, 0x60, 0x47, 0x18, 0x21, 0xE1, 0x83, 0xEA, 0x3A, + 0x1C, 0xF2, 0x58, 0x3C, 0x10, 0x8A, 0x9C, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, + 0x03, 0x7F, 0xB7, 0x8C, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x3A, 0xE8, 0x57, 0x1B, 0x17, 0xAD, 0x79, + 0x65, 0xD3, 0x82, 0x9F, 0x57, 0x42, 0x64, 0x81, 0x19, 0x1F, 0x5A, 0x68, 0xCE, 0x8C, 0xBA, 0x43, + 0xBC, 0x8A, 0x88, 0xAC, 0x8B, 0x07, 0x42, 0x91, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, + 0x3D, 0x7D, 0xE8, 0xEF, 0x86, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x40, 0x97, 0xA8, 0x7C, 0x90, 0xE1, + 0xC2, 0xAF, 0xBE, 0xB6, 0x75, 0xFE, 0x2F, 0x5D, 0x84, 0xB8, 0xBD, 0xB9, 0x7F, 0xA1, 0x39, 0xFB, + 0x13, 0x77, 0xA0, 0x57, 0x41, 0x91, 0x66, 0xF1, 0x40, 0x28, 0x72, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, + 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFE, 0x9D, 0x5E, 0xA3, 0x07, 0xCC, 0x4F, 0x7E, 0xE7, 0x53, 0xF3, + 0x83, 0x2F, 0x01, 0x00, 0x00, 0x00, 0x74, 0xC2, 0x60, 0xFF, 0xA7, 0xFE, 0xDD, 0xAB, 0x9B, 0x16, + 0xDC, 0xF3, 0xFA, 0xD6, 0xF9, 0x6F, 0x85, 0x21, 0xF2, 0xF6, 0x88, 0x7B, 0x50, 0x5D, 0x85, 0x45, + 0x92, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFF, + 0x9D, 0x9E, 0x7A, 0xC0, 0xFC, 0xB7, 0x1B, 0xE7, 0xDE, 0x10, 0xFC, 0x23, 0x0F, 0x00, 0x00, 0x80, + 0x6E, 0xF0, 0xFF, 0x7E, 0x63, 0xF1, 0x87, 0x7F, 0xF3, 0xD4, 0x82, 0x47, 0xC3, 0x08, 0x71, 0x3B, + 0xF5, 0xDC, 0x22, 0xE3, 0xFD, 0x8B, 0x8A, 0x8C, 0x46, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, + 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xFE, 0x3B, 0xB9, 0xF8, 0x03, 0xE6, 0xEE, 0x39, 0x8F, + 0x57, 0x9F, 0xBE, 0xF4, 0x3F, 0x06, 0xFF, 0x88, 0x03, 0x00, 0x00, 0xA0, 0x1B, 0xFD, 0x8F, 0xFB, + 0x17, 0x2C, 0x7A, 0x75, 0xF3, 0x82, 0x9F, 0x85, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCC, 0xE9, 0xBF, + 0x75, 0x07, 0x61, 0x15, 0x1C, 0xD1, 0xA9, 0x48, 0x28, 0x6A, 0xB1, 0x03, 0x7A, 0x99, 0x27, 0x0F, + 0xFF, 0x9D, 0x9E, 0x0E, 0x80, 0x4E, 0xAD, 0xEE, 0x01, 0xF3, 0xCD, 0x73, 0xDE, 0xB2, 0x3F, 0xF2, + 0x80, 0x39, 0x00, 0x00, 0x40, 0x2F, 0xF9, 0xE5, 0xC3, 0xF3, 0x6F, 0x79, 0x75, 0xCB, 0x82, 0x97, + 0xC3, 0x10, 0x71, 0x0F, 0xAA, 0x4F, 0xFC, 0x57, 0x77, 0xF8, 0x27, 0x3E, 0xA6, 0x6C, 0xF2, 0xF0, + 0xDF, 0xE9, 0xE9, 0x08, 0xE8, 0xC4, 0x1A, 0x3D, 0x60, 0x3E, 0xBE, 0xA5, 0x6F, 0x76, 0xF0, 0x8F, + 0x31, 0x00, 0x00, 0x00, 0x7A, 0x49, 0xF8, 0xA0, 0x7A, 0xF4, 0xF9, 0x10, 0xF7, 0xA0, 0xFA, 0xB9, + 0x7F, 0x74, 0x21, 0x40, 0x7C, 0x14, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x74, 0x08, 0x4C, 0xF5, 0x1A, + 0x3D, 0x60, 0xFE, 0xEB, 0xC7, 0x3E, 0x7D, 0x55, 0xF0, 0x8F, 0x2E, 0x00, 0x00, 0x00, 0x7A, 0x99, + 0xFB, 0x20, 0xC3, 0xDF, 0x6C, 0x9C, 0x7F, 0x5F, 0xED, 0x83, 0xEA, 0x0B, 0xCD, 0xF9, 0x9F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x63, 0x60, 0xAA, 0x17, + 0x7F, 0xC0, 0xFC, 0xF5, 0x6D, 0x73, 0x4E, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x40, 0x49, 0xFD, 0xDB, + 0x83, 0x7D, 0x7D, 0xAF, 0x6C, 0x5E, 0xB0, 0xA5, 0x12, 0x21, 0xF3, 0xCD, 0xEF, 0x77, 0xCD, 0x37, + 0xA7, 0x9E, 0x5B, 0x68, 0xBC, 0x7F, 0x51, 0xC1, 0x90, 0xE7, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, + 0xFF, 0x4E, 0x4F, 0xC7, 0xC0, 0x54, 0x8E, 0x07, 0xCC, 0x01, 0x00, 0x00, 0xA6, 0xB1, 0xFF, 0xF9, + 0xD0, 0xBC, 0xA5, 0xAF, 0x6E, 0xEE, 0xFB, 0x99, 0x8B, 0x90, 0x30, 0x44, 0xCE, 0x8C, 0xBA, 0x03, + 0xB4, 0x8A, 0x87, 0x76, 0x17, 0x3B, 0xA0, 0x97, 0x79, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x20, 0x98, + 0xAA, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xAA, 0x7E, 0xF5, 0x58, 0xDF, 0x5F, 0x54, 0x3E, 0xC8, + 0xB0, 0x12, 0x22, 0xE3, 0x43, 0xF6, 0xC0, 0xF8, 0x13, 0x77, 0x98, 0x56, 0x21, 0x91, 0x65, 0xB1, + 0x03, 0x7A, 0x99, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x82, 0xA9, 0x18, 0x0F, 0x98, 0x03, 0x00, + 0x00, 0x40, 0x72, 0x0F, 0xAA, 0xFF, 0x7A, 0x63, 0xDF, 0x5F, 0xBE, 0xBE, 0xB5, 0xEF, 0xAD, 0x30, + 0x44, 0xDE, 0xDC, 0x6F, 0x0F, 0x90, 0x6D, 0x3F, 0x1F, 0x22, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, + 0x77, 0x7A, 0x3A, 0x0C, 0x8A, 0x1E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x20, 0x11, 0xFF, 0x41, 0xF5, + 0xA7, 0xFA, 0x1E, 0x0D, 0x23, 0xC4, 0xCD, 0x3D, 0xA8, 0x9E, 0xED, 0xF9, 0x10, 0x71, 0x48, 0x2F, + 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x71, 0x50, 0xF4, 0xCE, 0xFC, 0xDD, 0x7C, 0x1E, 0x30, 0x07, + 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x41, 0xF5, 0x57, 0x9F, 0x99, 0x3F, 0x12, 0x46, 0x48, 0xFA, 0x07, + 0xD5, 0xC5, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x41, 0x91, 0x73, 0xCF, 0x79, + 0xF0, 0x80, 0x39, 0x00, 0x00, 0x00, 0xDA, 0xF2, 0xAB, 0x27, 0xFA, 0xD6, 0x44, 0x1F, 0x54, 0x77, + 0xCF, 0x87, 0xB4, 0x7E, 0x50, 0x3D, 0x76, 0x40, 0x2F, 0xF3, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x81, + 0x50, 0xD4, 0xCE, 0xFD, 0x94, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x90, 0xA3, 0xCA, 0x07, 0x19, 0xF6, + 0x7D, 0x35, 0xFA, 0xA0, 0xBA, 0x7B, 0x3E, 0x44, 0x3F, 0xA8, 0x1E, 0x3B, 0xA0, 0x97, 0x79, 0xF2, + 0xF0, 0xDF, 0xE9, 0xE9, 0x48, 0x28, 0x62, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x42, 0xB9, 0xE7, + 0x43, 0x5E, 0xDD, 0xD4, 0x77, 0x4F, 0xF4, 0x41, 0xF5, 0xB7, 0x0E, 0x46, 0x1F, 0x54, 0x17, 0x87, + 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0A, 0x79, 0x2F, 0x7C, 0xC0, 0x3C, 0xFA, 0x9C, + 0x87, 0x1D, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA0, 0x18, 0x47, 0xBF, 0xB1, 0xF8, 0xC3, 0xAF, 0x6C, + 0xEE, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0x3B, 0x87, 0xEC, 0xC1, 0xF4, 0x5F, 0xC4, 0x41, 0xBD, 0x8C, + 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x42, 0xDE, 0x53, 0x0F, 0x98, 0xFF, 0xFA, 0xE1, 0x4B, 0x6F, + 0x0E, 0xFE, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0x3F, 0xA8, 0xEE, 0x9E, 0x0F, 0xD9, 0xDE, + 0x67, 0xDC, 0x7E, 0xBF, 0xB3, 0xCF, 0x9C, 0x7A, 0xCE, 0x1E, 0x54, 0xD5, 0xA1, 0xBD, 0x2C, 0x93, + 0x87, 0xFF, 0x4E, 0xAF, 0x3E, 0x14, 0xF2, 0x9E, 0x7A, 0xC0, 0xFC, 0xD7, 0x83, 0x73, 0xFE, 0xB7, + 0xE0, 0x1F, 0x05, 0x00, 0x00, 0x00, 0x60, 0xEA, 0xFC, 0xF2, 0xE1, 0xB9, 0xB7, 0xBC, 0xB6, 0xB5, + 0xEF, 0x97, 0x61, 0x88, 0x8C, 0xEF, 0x9E, 0x6F, 0x26, 0xFE, 0xAB, 0x3D, 0x18, 0xAB, 0x03, 0x7C, + 0x2F, 0x4F, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0C, 0x79, 0x4D, 0x3D, 0x60, 0xFE, 0xDA, 0xA6, 0x39, + 0x77, 0xF3, 0x80, 0x39, 0x00, 0x00, 0x00, 0x3A, 0xCA, 0x7F, 0x50, 0xFD, 0xC9, 0xBE, 0xAF, 0xBE, + 0xBE, 0x65, 0xDE, 0x5B, 0x61, 0x88, 0xBC, 0xB9, 0x6F, 0xBE, 0x39, 0xFB, 0x13, 0x7B, 0x48, 0x56, + 0x87, 0xF9, 0x5E, 0x9B, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x1A, 0xF2, 0x98, 0x7A, 0xC0, 0xFC, 0xD5, + 0xCD, 0x73, 0x37, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xBA, 0x8A, 0x7B, 0x50, 0xFD, 0xB7, 0x9B, + 0xFA, 0xEE, 0x09, 0x23, 0xC4, 0xED, 0xED, 0x61, 0xF7, 0xA0, 0xBA, 0x38, 0xD4, 0xF7, 0xCA, 0xE4, + 0xE1, 0xBF, 0xD3, 0xD3, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0xC9, 0x3D, + 0x1F, 0xF2, 0xCA, 0xA6, 0xBE, 0x2D, 0xD1, 0x10, 0x71, 0xCF, 0x87, 0xF4, 0xDC, 0x83, 0xEA, 0xF2, + 0xF0, 0xDF, 0xE9, 0xE9, 0x78, 0x68, 0x77, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x9E, 0x57, 0xF9, + 0x20, 0xC3, 0x79, 0x35, 0x0F, 0xAA, 0x9F, 0xFE, 0x5B, 0x7B, 0xE0, 0x55, 0x87, 0xFD, 0x6E, 0x9B, + 0x3C, 0xFC, 0x77, 0x7A, 0xF5, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xA5, 0xF3, + 0xAB, 0xC7, 0xFA, 0xFE, 0x22, 0xFE, 0xA0, 0x7A, 0x57, 0x3F, 0x1F, 0x22, 0x0F, 0xFF, 0x9D, 0x9E, + 0x0E, 0x88, 0xAC, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0x94, 0x9A, 0x7B, 0x50, 0xFD, 0xB5, 0x2D, + 0xF3, 0xBE, 0x1E, 0x7F, 0x50, 0xFD, 0xDC, 0x3F, 0xDA, 0xC3, 0xB5, 0x8A, 0x80, 0x4E, 0x4D, 0x1E, + 0xFE, 0x3B, 0x3D, 0x1D, 0x11, 0x59, 0xC6, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x98, 0x56, 0xDC, 0x83, + 0xEA, 0xBF, 0x79, 0xAA, 0xEF, 0xC7, 0x61, 0x84, 0xB8, 0x75, 0xCD, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, + 0xE9, 0xE9, 0x90, 0x48, 0xBB, 0x46, 0x0F, 0x98, 0xBF, 0xB6, 0xE5, 0xD2, 0x81, 0xE0, 0x7F, 0x1A, + 0x00, 0x00, 0x00, 0xA0, 0xBC, 0xFC, 0x0F, 0x32, 0xDC, 0xD4, 0x37, 0x12, 0x46, 0x48, 0xF8, 0x41, + 0x86, 0x1D, 0x7B, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x13, 0x69, 0xA7, 0x1E, 0x30, 0x7F, + 0xE5, 0xC9, 0x39, 0xB7, 0x07, 0xFF, 0x53, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x87, 0x7B, 0x50, 0xFD, + 0xB5, 0x2D, 0xF3, 0x8E, 0x85, 0x21, 0xE2, 0x9E, 0x0F, 0x39, 0x33, 0x6A, 0x0F, 0xDF, 0x2A, 0x12, + 0x8A, 0x9A, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x26, 0xD2, 0x4C, 0x3D, 0x60, 0xFE, 0xCA, 0xA6, 0xB9, + 0xFF, 0x57, 0xF0, 0xB7, 0x1E, 0x00, 0x00, 0x00, 0x98, 0x9E, 0xC2, 0x0F, 0x32, 0x8C, 0x3E, 0xA8, + 0xFE, 0xC6, 0x9E, 0x29, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x14, 0x49, 0x17, 0x7F, + 0xC0, 0xDC, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x98, 0xF0, 0x83, 0x0C, 0xE3, 0x0F, 0xAA, + 0x17, 0xF6, 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2A, 0x92, 0x8C, 0x07, 0xCC, 0x01, 0x00, + 0x00, 0x80, 0x0C, 0x5E, 0x79, 0x72, 0xCE, 0xA5, 0xF1, 0x0F, 0x32, 0x74, 0x0F, 0xAA, 0xE7, 0xFA, + 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2C, 0x5A, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, + 0x1C, 0xFC, 0x7A, 0x63, 0xDF, 0x55, 0xAF, 0x6E, 0x9E, 0xF7, 0x4F, 0x61, 0x84, 0x84, 0x0F, 0xAA, + 0xCB, 0xA0, 0x48, 0x33, 0x79, 0xF8, 0xEF, 0xF4, 0xEA, 0xC3, 0x22, 0xC9, 0x78, 0xC0, 0x1C, 0x00, + 0x00, 0x00, 0xC8, 0xD9, 0x2F, 0x1F, 0x9E, 0x7B, 0x4B, 0xFC, 0x83, 0x0C, 0x33, 0x3F, 0xA8, 0x2E, + 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x8B, 0x66, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, 0x40, 0xFE, + 0x07, 0x19, 0x6E, 0xEE, 0xFB, 0x3F, 0xE3, 0xCF, 0x87, 0xA4, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, + 0x3D, 0x1D, 0x18, 0x8D, 0xA6, 0x1E, 0x30, 0xFF, 0xED, 0xC6, 0x4B, 0xBF, 0xC5, 0x03, 0xE6, 0x00, + 0x00, 0x00, 0x40, 0x01, 0xC2, 0x07, 0xD5, 0xC3, 0x08, 0x71, 0x7B, 0xEB, 0x40, 0x82, 0x07, 0xD5, + 0xE5, 0xE1, 0xBF, 0xD3, 0xD3, 0x91, 0xA1, 0xE6, 0x9E, 0xF3, 0x88, 0x3F, 0x60, 0xFE, 0xCA, 0x53, + 0x73, 0xB6, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x00, 0x30, 0x05, 0xDC, 0x07, 0x19, 0xBE, 0xBE, 0x75, + 0xDE, 0xFE, 0x68, 0x88, 0xBC, 0x73, 0xA8, 0xC1, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xD0, + 0x88, 0x4F, 0x3D, 0x60, 0xFE, 0xDA, 0xE6, 0x39, 0x3F, 0xE1, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, + 0x03, 0xDC, 0x07, 0x19, 0xC6, 0x1F, 0x54, 0x3F, 0xFD, 0xB7, 0xF6, 0xF0, 0x5E, 0x82, 0xF8, 0x70, + 0x0F, 0x98, 0xD7, 0x3C, 0xE7, 0xC1, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x40, 0x77, 0x88, 0x7F, 0x90, + 0xE1, 0xF8, 0xEE, 0x3E, 0x33, 0xF1, 0xF7, 0xEE, 0x20, 0xAF, 0x02, 0xA0, 0x93, 0xAB, 0x0F, 0x8D, + 0xF8, 0xDC, 0x03, 0xE6, 0x6F, 0x0C, 0xD5, 0x3F, 0x60, 0x3E, 0xDA, 0xFF, 0x9E, 0x3F, 0x0A, 0x7E, + 0xBB, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xCD, 0x7F, 0x50, 0x7D, 0xCB, 0xBC, 0xAF, 0x57, 0x1E, 0x54, + 0xB7, 0x07, 0x78, 0xBB, 0x37, 0xF7, 0xF5, 0xD9, 0x03, 0xBD, 0x3B, 0xD8, 0xAB, 0x18, 0x98, 0xEA, + 0xD5, 0xC7, 0x46, 0x74, 0xEE, 0x83, 0x04, 0x79, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xE8, 0x31, 0xEE, + 0x41, 0xF5, 0x57, 0x36, 0xCD, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0xDB, 0xC3, 0xF3, 0xED, 0x01, 0x5F, + 0x45, 0xC1, 0x54, 0x4D, 0x47, 0x87, 0x1B, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x00, 0x25, 0xF0, 0x6F, + 0x1B, 0xFA, 0xFA, 0x5E, 0xDB, 0x32, 0xF7, 0x27, 0x61, 0x84, 0xFC, 0x7E, 0xE7, 0x3C, 0x73, 0xEA, + 0xD9, 0xF9, 0xF6, 0xC0, 0xAF, 0x02, 0xA1, 0xC8, 0x35, 0x0E, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, + 0x00, 0x4A, 0xE6, 0x57, 0x4F, 0x5C, 0xBA, 0xC6, 0x86, 0xC8, 0xB1, 0x68, 0x88, 0x9C, 0xF9, 0x3B, + 0x17, 0x01, 0x2A, 0x16, 0xF2, 0x5E, 0x7D, 0x78, 0xB8, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0x50, + 0x62, 0xEE, 0x01, 0xEE, 0xDF, 0x3E, 0x39, 0xF7, 0xAB, 0xAF, 0x6F, 0x9B, 0x37, 0x1E, 0x86, 0x88, + 0x7B, 0x50, 0xBD, 0xD8, 0xE7, 0x43, 0xEA, 0xC3, 0x83, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x69, + 0xA4, 0xF2, 0x41, 0x86, 0x73, 0xEF, 0x79, 0x7D, 0xCB, 0xDC, 0x9A, 0x07, 0xD5, 0xCF, 0xFD, 0x34, + 0xEF, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, 0xA6, 0xB1, 0x57, 0x9E, 0x9C, + 0x73, 0xA9, 0x7A, 0x50, 0x3D, 0x9F, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, + 0xE0, 0x7B, 0x6D, 0x47, 0xDF, 0x40, 0xE5, 0x83, 0x0C, 0x27, 0x43, 0xE4, 0x8D, 0x3D, 0x7D, 0xFE, + 0x33, 0x22, 0xD9, 0xDE, 0x9A, 0x55, 0x79, 0xB8, 0xDC, 0x3D, 0xE3, 0x11, 0xBF, 0xF1, 0xE0, 0x01, + 0x73, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x57, 0x9E, 0x99, 0x73, 0xDB, 0xEB, 0xDB, 0xE7, 0x9E, 0x8C, + 0x86, 0x48, 0x18, 0x23, 0xEF, 0x1C, 0x9A, 0x6F, 0x4E, 0xFF, 0xCD, 0x7C, 0xFF, 0x79, 0x91, 0xF8, + 0x0D, 0x89, 0xFB, 0xFF, 0xDD, 0xBF, 0xEE, 0xFE, 0xFD, 0x77, 0x0E, 0xF5, 0xD5, 0x3C, 0xDF, 0x11, + 0xCE, 0x3D, 0x60, 0x6E, 0x7F, 0xEE, 0x75, 0xC1, 0x5F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xDC, + 0x1B, 0xB3, 0x5E, 0x79, 0x66, 0xEE, 0x70, 0x3C, 0x44, 0x5A, 0x2E, 0x16, 0x1D, 0x95, 0xCD, 0x19, + 0xFA, 0xF5, 0xA3, 0x97, 0xDE, 0x1C, 0xFC, 0xD4, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xB9, 0x87, 0xD5, + 0x7F, 0xB3, 0x71, 0xDE, 0x9D, 0xAF, 0x3E, 0x3D, 0xEF, 0xA1, 0x57, 0x37, 0xCF, 0x7D, 0x59, 0x46, + 0x47, 0xB8, 0x20, 0x38, 0x5E, 0xDB, 0x3C, 0xF7, 0xD8, 0xAB, 0xCF, 0xCC, 0x7D, 0xDA, 0xDD, 0x76, + 0xFC, 0xB7, 0xEF, 0xCC, 0xFB, 0x40, 0xF0, 0x53, 0x01, 0x00, 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x35, + 0xB9, 0xFE, 0x07, 0x1B, 0xEE, 0xE8, 0x1B, 0x88, 0xEF, 0xDF, 0x36, 0xCC, 0xEE, 0x0B, 0xFE, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD0, 0x15, 0xDE, 0xF3, 0x9E, 0xFF, 0x1F, 0x5B, 0xE2, 0x94, 0x1D, 0x86, + 0x86, 0x23, 0x09, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; + +static const uint8_t tree_img_gif[] PROGMEM = { + + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x28, 0x00, 0x3C, 0x00, 0x83, 0x0B, 0x00, 0x00, 0xFF, 0xFF, + 0x00, 0x21, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x94, 0x00, 0x00, 0xB5, 0x00, 0x00, + 0xDE, 0x00, 0x00, 0xFF, 0x00, 0x6B, 0x00, 0x00, 0xFF, 0x33, 0x33, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x00, 0xCC, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0xA0, 0x0F, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, + 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, + 0x8C, 0xCA, 0xE8, 0x85, 0xE8, 0xA5, 0xAC, 0x67, 0xEA, 0x8A, 0xE5, 0x2B, 0x2F, 0xE3, 0x31, 0xCE, + 0xAF, 0x41, 0x1C, 0xB8, 0x1B, 0x24, 0x80, 0x04, 0xAF, 0x87, 0x02, 0x26, 0x88, 0xA1, 0x07, 0x60, + 0xB9, 0x44, 0x82, 0x04, 0x02, 0x80, 0x61, 0x30, 0x70, 0x6E, 0x0C, 0x86, 0x03, 0x60, 0x20, 0xB0, + 0x6A, 0xA8, 0xD3, 0x03, 0x21, 0xEC, 0xAD, 0x18, 0x12, 0xE8, 0xF4, 0xB1, 0x4C, 0x51, 0xA0, 0x07, + 0xEA, 0x07, 0x5B, 0xF2, 0x70, 0x13, 0x76, 0xD4, 0xA8, 0xBC, 0xBC, 0xEA, 0x1F, 0x06, 0x77, 0x51, + 0x73, 0x50, 0x0A, 0x80, 0x7F, 0x04, 0x4C, 0x4D, 0x65, 0x06, 0x0A, 0x3B, 0x3B, 0x62, 0x5A, 0x53, + 0x65, 0x05, 0x02, 0x04, 0x68, 0x0C, 0x6A, 0x00, 0x5D, 0x5E, 0x0F, 0x0F, 0x6A, 0x98, 0x6A, 0x09, + 0x7B, 0x56, 0x9D, 0x09, 0x0C, 0xA7, 0xA7, 0x7F, 0x06, 0x9D, 0xA3, 0x44, 0x02, 0x01, 0x03, 0x90, + 0x0C, 0x87, 0x03, 0x06, 0x02, 0x05, 0x56, 0x06, 0x01, 0x02, 0x53, 0xB1, 0xB3, 0x04, 0x79, 0xAF, + 0x55, 0x48, 0x51, 0xB0, 0x87, 0xC0, 0x7F, 0x07, 0x95, 0x05, 0x85, 0x44, 0xB6, 0x00, 0x05, 0x53, + 0x96, 0x6A, 0x60, 0x02, 0x0A, 0x48, 0x89, 0x00, 0x07, 0xA1, 0x69, 0x7D, 0x2B, 0x3D, 0x9D, 0x41, + 0xA1, 0x04, 0xA0, 0xDD, 0x9D, 0x38, 0x02, 0xE1, 0x6A, 0x07, 0x62, 0x0C, 0x77, 0xE6, 0xAD, 0x2F, + 0x05, 0x01, 0xB6, 0x90, 0x07, 0xA8, 0xA7, 0x54, 0xB5, 0xBC, 0x06, 0x33, 0x50, 0x53, 0x3A, 0x00, + 0x39, 0x62, 0x10, 0x6B, 0xDF, 0xBE, 0x19, 0x03, 0x18, 0x40, 0xA9, 0x15, 0x4B, 0xCC, 0x0E, 0x77, + 0x3B, 0x04, 0xC4, 0x02, 0x38, 0x43, 0x21, 0x96, 0x2C, 0xD3, 0xD6, 0x81, 0x01, 0x26, 0x2A, 0xFB, + 0xDE, 0x07, 0x7C, 0x0A, 0xB7, 0x71, 0x1B, 0x79, 0xEE, 0xC5, 0x83, 0x72, 0xDD, 0x84, 0xBC, 0x4B, + 0x13, 0xA4, 0x13, 0x15, 0x17, 0xAB, 0x18, 0x78, 0x4A, 0x43, 0x40, 0x81, 0x43, 0x76, 0x8E, 0xB6, + 0x04, 0x7C, 0x19, 0x02, 0x98, 0xC4, 0x86, 0x35, 0xBD, 0xE1, 0x1C, 0x90, 0x4D, 0x62, 0xBF, 0x14, + 0xFC, 0x7E, 0x02, 0x1A, 0x60, 0xD3, 0xD1, 0x9D, 0x3B, 0x3A, 0x09, 0xFC, 0x44, 0xB1, 0xD0, 0x96, + 0x8E, 0x43, 0x8D, 0x9E, 0xDA, 0xDB, 0x22, 0x11, 0x8A, 0x42, 0x10, 0x5C, 0x00, 0x1A, 0x2D, 0x38, + 0xF2, 0x0E, 0xA0, 0x4A, 0x03, 0x4E, 0xA2, 0xF0, 0xF4, 0x80, 0x17, 0x95, 0x8C, 0x23, 0xD1, 0xD8, + 0x12, 0x00, 0x92, 0x03, 0xAB, 0x99, 0x23, 0x71, 0x3E, 0x8D, 0xEB, 0x6E, 0x18, 0x07, 0x66, 0x23, + 0x05, 0x3E, 0x72, 0xE4, 0x06, 0x0D, 0x81, 0x02, 0xE4, 0x36, 0x5D, 0xD9, 0xA5, 0xC0, 0xAD, 0x59, + 0xA2, 0x86, 0x6E, 0xD6, 0xC4, 0x73, 0xEB, 0x15, 0xA5, 0xC5, 0xDE, 0x14, 0xF4, 0x62, 0x07, 0xC0, + 0xE9, 0x9D, 0xCC, 0x58, 0x02, 0x14, 0xA0, 0x84, 0x45, 0x83, 0x68, 0x7A, 0x8D, 0x81, 0x66, 0xC3, + 0xE9, 0xD0, 0xA6, 0x3E, 0x03, 0xF3, 0x80, 0x7D, 0x90, 0xD8, 0x58, 0xA2, 0x59, 0x2D, 0x90, 0x68, + 0xD6, 0x64, 0x17, 0x76, 0x5A, 0x23, 0xBF, 0x13, 0x58, 0x89, 0x7A, 0xC3, 0xF0, 0x8F, 0xB6, 0xB8, + 0x4B, 0xD3, 0x74, 0x52, 0x50, 0x92, 0xC2, 0x03, 0xD1, 0x78, 0xD7, 0x89, 0x4C, 0x23, 0x26, 0x6E, + 0x82, 0xCC, 0x15, 0x5E, 0x05, 0x08, 0x30, 0x06, 0x8A, 0x75, 0x64, 0xFA, 0x42, 0xF1, 0x12, 0xAD, + 0x60, 0xDE, 0x51, 0x0A, 0x94, 0xBA, 0x5E, 0x2C, 0x8C, 0x86, 0xDD, 0x3D, 0xDE, 0x8F, 0x0A, 0x70, + 0x51, 0x5F, 0xFE, 0xF2, 0x84, 0xD1, 0xD0, 0xA6, 0x68, 0xB7, 0x96, 0x62, 0x14, 0x0C, 0xC1, 0xB7, + 0x90, 0x68, 0x72, 0xD1, 0x7C, 0xD9, 0x3D, 0xA3, 0x94, 0x35, 0xDE, 0x54, 0x06, 0x92, 0x51, 0x50, + 0x68, 0xC2, 0xC5, 0x44, 0xB7, 0x30, 0x70, 0xDE, 0x6A, 0x49, 0x69, 0x86, 0xC5, 0x2D, 0xA3, 0x29, + 0x04, 0x05, 0x2F, 0xD9, 0xC4, 0x02, 0x0C, 0x6C, 0x0C, 0x48, 0xB0, 0x94, 0x01, 0xDA, 0x3C, 0xF2, + 0x56, 0x21, 0xFA, 0xE8, 0xA3, 0xA1, 0x55, 0x12, 0xE9, 0xF4, 0x56, 0x42, 0xF8, 0x50, 0x00, 0x40, + 0x08, 0x08, 0xD4, 0x88, 0x80, 0x05, 0x33, 0x66, 0x10, 0xA2, 0x0C, 0xDC, 0xA0, 0xB0, 0xA3, 0x0B, + 0x71, 0xCD, 0xB1, 0x80, 0x75, 0x69, 0x20, 0x41, 0xE4, 0x91, 0x6B, 0x64, 0x10, 0x01, 0x00, 0x21, + 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, 0x00, + 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, 0x8C, + 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0x31, 0x1C, 0x34, + 0x1B, 0x24, 0x4C, 0x82, 0xE7, 0x28, 0x5E, 0x02, 0x78, 0x7A, 0x30, 0x8E, 0x47, 0x62, 0x48, 0x20, + 0x60, 0xD8, 0x06, 0x4A, 0x8E, 0xC1, 0x70, 0x60, 0x0C, 0x04, 0xD1, 0xCD, 0x60, 0x60, 0x3B, 0x10, + 0xBA, 0x59, 0x8B, 0x21, 0x41, 0x2E, 0x0F, 0xC3, 0x16, 0xF2, 0xC0, 0xAC, 0x40, 0x4F, 0x1E, 0x80, + 0x04, 0x81, 0x70, 0xD8, 0x0A, 0x14, 0x0F, 0xF7, 0x42, 0x00, 0xA0, 0xD6, 0x09, 0x0A, 0x81, 0x81, + 0x68, 0x00, 0x85, 0x85, 0x7F, 0x07, 0x07, 0x0A, 0x06, 0x7A, 0x06, 0x00, 0x74, 0x74, 0x5E, 0x8A, + 0x36, 0x68, 0x05, 0x7C, 0x66, 0x3D, 0x64, 0x58, 0x61, 0x0F, 0x0F, 0x66, 0x64, 0x99, 0x64, 0x79, + 0x9C, 0x9E, 0xA0, 0x48, 0x4E, 0x9D, 0xA3, 0x4A, 0x02, 0x01, 0x37, 0x90, 0x55, 0x04, 0x5C, 0x02, + 0x05, 0x59, 0x06, 0x01, 0x02, 0x4F, 0x89, 0x55, 0x76, 0xAC, 0x50, 0xAB, 0x0A, 0xAD, 0x7F, 0xB1, + 0x75, 0x07, 0x02, 0x04, 0x05, 0x00, 0xBE, 0x39, 0x06, 0x77, 0x05, 0x36, 0x04, 0x9F, 0x5B, 0xCC, + 0x00, 0x4A, 0x82, 0x81, 0x07, 0x9F, 0x65, 0x86, 0x85, 0x40, 0x9D, 0x0A, 0x9F, 0x0C, 0xD0, 0x9F, + 0x00, 0x9D, 0x39, 0x02, 0xDE, 0x66, 0xB0, 0x73, 0xE2, 0x09, 0xE4, 0xAA, 0x2F, 0x05, 0x01, 0xCC, + 0x5E, 0xA7, 0x56, 0x75, 0xD2, 0xB8, 0x8C, 0x2F, 0x4C, 0x36, 0x06, 0xB1, 0x73, 0xE1, 0x88, 0xC9, + 0x92, 0x45, 0x43, 0x96, 0x00, 0x2E, 0x37, 0xE8, 0x79, 0x99, 0x53, 0xEC, 0x86, 0x0D, 0x06, 0x05, + 0xF3, 0x51, 0x61, 0x57, 0xE6, 0x9E, 0xBF, 0x35, 0x0C, 0xDE, 0x81, 0xE8, 0x64, 0x10, 0xFB, 0x5B, + 0xB6, 0x6C, 0xF5, 0x56, 0x94, 0x22, 0x13, 0xA7, 0xE2, 0x9C, 0x04, 0xDF, 0xCA, 0x74, 0xB2, 0xB2, + 0xC2, 0x40, 0x2A, 0x92, 0x72, 0x20, 0x45, 0x52, 0xE0, 0x45, 0x1A, 0x01, 0x2B, 0xCA, 0x3E, 0xC4, + 0x3A, 0x38, 0x60, 0xDB, 0x23, 0x86, 0xD6, 0x14, 0x0C, 0x20, 0xC0, 0x84, 0xCB, 0x8A, 0x7C, 0x3C, + 0x1F, 0x25, 0x94, 0xA9, 0x80, 0x21, 0x17, 0xA2, 0x5B, 0x4E, 0x34, 0x91, 0xE5, 0x2F, 0x99, 0x4C, + 0xA0, 0x89, 0xEC, 0x5C, 0xC1, 0xB5, 0x89, 0xC3, 0x15, 0x2B, 0xCC, 0x10, 0xD6, 0xF9, 0x38, 0x67, + 0xA8, 0xB1, 0x01, 0xE5, 0x40, 0xD4, 0x7B, 0x42, 0xF1, 0x63, 0x02, 0x66, 0x02, 0x12, 0xA4, 0xFA, + 0x90, 0x2A, 0x54, 0xB6, 0x44, 0xEB, 0xDA, 0x96, 0x19, 0x9A, 0x53, 0x43, 0x01, 0xBB, 0x64, 0x84, + 0xAE, 0xC3, 0xBB, 0xB0, 0xCC, 0x31, 0x40, 0x5D, 0x35, 0xD8, 0x62, 0x82, 0x6B, 0x68, 0xAC, 0xA6, + 0x43, 0xF1, 0xD2, 0x01, 0x20, 0xE9, 0x8A, 0x25, 0x05, 0x96, 0x36, 0xD8, 0x8A, 0xD7, 0xD8, 0x46, + 0xD0, 0x85, 0xEB, 0x7E, 0x72, 0x31, 0x10, 0x54, 0x9F, 0x85, 0x00, 0xF1, 0xA6, 0x1C, 0x94, 0x2C, + 0x34, 0xB2, 0x17, 0x9F, 0x5B, 0xB8, 0x14, 0x80, 0xFC, 0x41, 0x28, 0x63, 0xC7, 0x03, 0x9A, 0x4A, + 0x32, 0x9C, 0x2C, 0x2B, 0x2E, 0x40, 0x72, 0x63, 0x59, 0x48, 0x85, 0x47, 0x8D, 0xD8, 0xC8, 0xD9, + 0xE2, 0xF0, 0x55, 0x99, 0x4A, 0xE3, 0x82, 0x07, 0x41, 0x3F, 0x25, 0x92, 0xAE, 0xD7, 0x4C, 0x3C, + 0xE7, 0xAC, 0x02, 0x04, 0x58, 0xC4, 0xC4, 0xAD, 0x9C, 0x1B, 0xB1, 0x3F, 0xE1, 0x42, 0x3D, 0x4B, + 0x9E, 0x85, 0xCB, 0x57, 0xA6, 0x30, 0x4B, 0x97, 0x88, 0x26, 0xA2, 0x03, 0x7F, 0x8B, 0x72, 0x2D, + 0x90, 0x79, 0x02, 0xFD, 0x59, 0x36, 0xB2, 0xF3, 0x41, 0x2A, 0x65, 0xAD, 0x75, 0x64, 0x3A, 0x0C, + 0x48, 0xB4, 0x15, 0x35, 0x13, 0xE0, 0xC2, 0xC0, 0x2D, 0xB1, 0x15, 0x95, 0x0C, 0x13, 0x97, 0x59, + 0x73, 0x90, 0x01, 0xF5, 0xAC, 0x36, 0x8D, 0x79, 0x12, 0x40, 0xB8, 0x45, 0x22, 0xB8, 0xF8, 0xC4, + 0x0C, 0x7D, 0xB3, 0x31, 0x96, 0xCF, 0x00, 0x01, 0x76, 0x41, 0x80, 0x4F, 0x0B, 0x80, 0x78, 0x4A, + 0x24, 0x5B, 0x8C, 0x18, 0xDB, 0x8A, 0x0A, 0xF0, 0xC3, 0x15, 0x88, 0x08, 0xF1, 0xC5, 0xC7, 0x3C, + 0x13, 0x40, 0x94, 0x01, 0x81, 0x13, 0x20, 0xA0, 0x23, 0x02, 0x27, 0xE0, 0x58, 0x63, 0x08, 0xD9, + 0xE8, 0x41, 0x81, 0x5B, 0x42, 0x7A, 0x57, 0x86, 0x12, 0x46, 0x26, 0x79, 0x46, 0x06, 0x11, 0x00, + 0x00, 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x3C, 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, + 0xE4, 0x8C, 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0xA1, + 0x1C, 0x34, 0x1B, 0x24, 0x4A, 0x82, 0xE7, 0x27, 0x85, 0x50, 0x08, 0x0C, 0x3D, 0x12, 0xBC, 0xC4, + 0xA3, 0x18, 0x12, 0x08, 0x14, 0x86, 0xC1, 0x80, 0xC9, 0x31, 0x18, 0x0E, 0x84, 0x81, 0x80, 0xBA, + 0x91, 0x46, 0xB1, 0x51, 0x06, 0xD7, 0x62, 0x40, 0x9A, 0x91, 0xE2, 0x71, 0xA5, 0x37, 0x40, 0x33, + 0xDE, 0xE9, 0xF1, 0xE3, 0xA1, 0x20, 0x10, 0x0E, 0x52, 0x01, 0x63, 0xA9, 0x5E, 0x0C, 0x85, 0x03, + 0x76, 0x7A, 0x7D, 0x0B, 0x4E, 0x03, 0x75, 0x78, 0x77, 0x78, 0x06, 0x84, 0x51, 0x37, 0x8A, 0x77, + 0x02, 0x51, 0x6A, 0x05, 0x02, 0x04, 0x67, 0x67, 0x5B, 0x72, 0x47, 0x98, 0x98, 0x7C, 0x5C, 0x73, + 0x66, 0x58, 0x07, 0x8B, 0x0F, 0x00, 0x9F, 0x45, 0x02, 0x01, 0x03, 0xA3, 0x0C, 0x89, 0x03, 0x06, + 0x02, 0x00, 0x5C, 0x06, 0x01, 0x92, 0x52, 0x07, 0xAE, 0x59, 0x03, 0x00, 0xBD, 0xBD, 0x4C, 0x02, + 0x05, 0xAB, 0xB9, 0x70, 0x0C, 0xAC, 0x96, 0x00, 0x52, 0x45, 0x36, 0xC1, 0x51, 0x97, 0x0C, 0x66, + 0x5E, 0x00, 0x8C, 0x4C, 0x0A, 0x05, 0x5F, 0x68, 0x98, 0x4E, 0x56, 0x40, 0x7F, 0x3D, 0x67, 0x97, + 0x9D, 0x73, 0x39, 0x02, 0x74, 0x9C, 0x48, 0xA4, 0x76, 0x76, 0x66, 0x73, 0xA8, 0x2C, 0x05, 0x50, + 0x02, 0xA3, 0xA3, 0x59, 0x78, 0x5E, 0x92, 0xD4, 0x2C, 0xDB, 0xB0, 0x59, 0x76, 0x07, 0x00, 0x78, + 0x16, 0x09, 0x80, 0xF5, 0xE4, 0x05, 0xC1, 0x81, 0x5F, 0xB0, 0x10, 0x00, 0xA0, 0xEE, 0xC0, 0xC0, + 0x03, 0x8E, 0x68, 0x68, 0xB1, 0x72, 0xE5, 0x92, 0xAF, 0x5E, 0xF6, 0x0C, 0x10, 0xF0, 0x86, 0x62, + 0xFB, 0xCE, 0xC1, 0x03, 0x98, 0x00, 0x74, 0x42, 0x42, 0xE7, 0xC5, 0xB9, 0x4E, 0xFF, 0xC2, 0x9D, + 0x99, 0xA3, 0x60, 0x0A, 0x0A, 0x03, 0xED, 0xC0, 0xDD, 0xF1, 0x47, 0xCF, 0xCB, 0x2E, 0x97, 0x20, + 0x92, 0x0D, 0x64, 0x85, 0xA5, 0x65, 0x43, 0x2C, 0x3C, 0x19, 0x10, 0x30, 0x94, 0x2F, 0x27, 0xBE, + 0x9D, 0x87, 0x78, 0xCE, 0x54, 0x47, 0xC0, 0x98, 0xC6, 0x9D, 0x39, 0x2F, 0xC6, 0xB2, 0xF1, 0x87, + 0x29, 0x96, 0x62, 0xC6, 0xB6, 0x69, 0xE2, 0xC0, 0x2B, 0x4A, 0x2C, 0x58, 0x49, 0x47, 0xDA, 0x11, + 0x6A, 0x69, 0xC0, 0xB8, 0x10, 0x22, 0x1F, 0xDC, 0x0A, 0xF4, 0x6D, 0x64, 0x02, 0x06, 0xB1, 0x04, + 0x28, 0x39, 0xBB, 0xA1, 0xDD, 0x49, 0x4C, 0xE9, 0xD4, 0xB9, 0x4D, 0x0A, 0xA2, 0x40, 0x81, 0x91, + 0x81, 0x68, 0x2E, 0x35, 0x43, 0xA0, 0xC0, 0x50, 0x05, 0x1F, 0x6A, 0x39, 0xB9, 0x65, 0x47, 0x4A, + 0xBF, 0xBC, 0xF4, 0xF0, 0x04, 0xE3, 0x98, 0xA1, 0x96, 0x02, 0x5B, 0x5E, 0x71, 0xA5, 0x53, 0xA8, + 0x4E, 0x68, 0x16, 0x2B, 0x01, 0xFC, 0x42, 0x29, 0x4A, 0x21, 0xF4, 0xE8, 0x87, 0x0A, 0xA5, 0x04, + 0xDA, 0xDC, 0x94, 0x95, 0x6A, 0x03, 0xC2, 0x5A, 0x6E, 0xF0, 0x66, 0xC8, 0x0E, 0xC0, 0x99, 0x20, + 0xDF, 0x16, 0x93, 0xAC, 0x91, 0x64, 0x16, 0x0B, 0xED, 0x14, 0x70, 0xF2, 0xC2, 0x6B, 0x75, 0x27, + 0x68, 0x81, 0xDA, 0x90, 0xB4, 0x0B, 0xDC, 0x74, 0xC8, 0x8B, 0x67, 0xB0, 0xBC, 0x75, 0x2B, 0xCC, + 0x5D, 0xA1, 0x00, 0xD8, 0x09, 0xC4, 0x3D, 0x23, 0x92, 0xB0, 0x6B, 0x29, 0xDA, 0x6A, 0x55, 0x12, + 0x46, 0x7A, 0x41, 0xA5, 0x81, 0xF8, 0x62, 0x25, 0xE8, 0x4E, 0x2A, 0x60, 0x22, 0x52, 0x05, 0xB4, + 0xB4, 0x94, 0x14, 0xAC, 0x12, 0x05, 0xBF, 0xCD, 0xB4, 0x60, 0xA7, 0x6F, 0x66, 0x65, 0xE7, 0x57, + 0xC7, 0xA3, 0xC8, 0x67, 0x85, 0x16, 0x5B, 0x49, 0xF0, 0x84, 0x2A, 0x48, 0x19, 0x92, 0x47, 0x30, + 0x4E, 0x00, 0x60, 0xC9, 0x57, 0x71, 0x79, 0x03, 0x51, 0x30, 0xD3, 0x4C, 0xA0, 0xC0, 0x4E, 0xA4, + 0x1C, 0x45, 0x51, 0x2C, 0x7E, 0x39, 0xB8, 0x18, 0x3E, 0x04, 0xB5, 0x04, 0x14, 0x6C, 0xB3, 0xF8, + 0xF1, 0xC7, 0x3C, 0x00, 0xAA, 0xC6, 0xCB, 0x45, 0xFC, 0x21, 0xD5, 0x52, 0x72, 0x17, 0x95, 0x88, + 0xD8, 0x09, 0x08, 0x00, 0x80, 0x00, 0x02, 0x28, 0x94, 0x28, 0xC1, 0x8C, 0x20, 0x20, 0xD1, 0x5D, + 0x02, 0x27, 0xE8, 0x88, 0x82, 0x5B, 0x84, 0x2C, 0xE0, 0xD6, 0x19, 0x4C, 0x1C, 0xA9, 0xA4, 0x19, + 0x1B, 0x44, 0x00, 0x00, 0x21, 0xFE, 0x19, 0x42, 0x6F, 0x79, 0x27, 0x73, 0x20, 0x48, 0x61, 0x70, + 0x70, 0x79, 0x20, 0x48, 0x6F, 0x6C, 0x69, 0x64, 0x61, 0x79, 0x73, 0x20, 0x50, 0x61, 0x67, 0x65, + 0x00, 0x3B + +}; + +static const uint8_t bird_img_gif[] PROGMEM = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x74, 0x00, 0x4E, 0x00, 0xCC, 0x13, 0x00, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFF, 0xBD, 0xE7, 0xE7, 0xD6, 0xEF, 0xEF, 0x63, 0x63, 0x63, 0xAD, 0xAD, 0xAD, 0xCE, + 0xCE, 0xCE, 0xD6, 0xDE, 0xDE, 0x4A, 0x4A, 0x4A, 0x7B, 0x84, 0x84, 0x94, 0x9C, 0x9C, 0xE7, 0xE7, + 0xE7, 0x84, 0x94, 0x94, 0xB5, 0xC6, 0xC6, 0x73, 0x7B, 0x7B, 0x31, 0x31, 0x31, 0xF7, 0xF7, 0xF7, + 0x18, 0x10, 0x10, 0xCE, 0x63, 0x39, 0x6B, 0x39, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x4B, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0xAE, 0xEC, 0x68, 0x2C, + 0x6D, 0x2C, 0xCF, 0x74, 0x6D, 0x03, 0x46, 0x84, 0x40, 0x77, 0xEF, 0xFF, 0x40, 0x51, 0x42, 0x41, + 0x0C, 0x1A, 0x8F, 0x48, 0x13, 0xC1, 0xD0, 0x20, 0x00, 0x0E, 0x8E, 0x42, 0x72, 0x4A, 0xAD, 0x21, + 0x0E, 0xCD, 0x05, 0xE1, 0x80, 0xA8, 0x7A, 0xBF, 0x29, 0xC2, 0xA0, 0x91, 0x28, 0x34, 0x02, 0x5D, + 0xB0, 0x5A, 0xFD, 0x08, 0x34, 0x14, 0x84, 0x00, 0x7A, 0x4D, 0xF7, 0x22, 0xDC, 0x89, 0xB8, 0xC1, + 0xB9, 0x80, 0xD5, 0xFF, 0x40, 0x0B, 0x77, 0x0C, 0x0F, 0x05, 0x01, 0x0C, 0x0A, 0x0B, 0x0F, 0x08, + 0x06, 0x80, 0x8E, 0x37, 0x7B, 0x01, 0x09, 0x11, 0x03, 0x68, 0x5C, 0x4C, 0x0A, 0x8F, 0x9A, 0x33, + 0x06, 0x09, 0x01, 0x0E, 0x71, 0x68, 0x88, 0x92, 0x07, 0x9B, 0xA6, 0x2C, 0x0A, 0x86, 0x07, 0x95, + 0x05, 0x04, 0xA1, 0x5D, 0x8D, 0xA7, 0xB2, 0x26, 0x09, 0x06, 0x72, 0x72, 0x0E, 0x94, 0x01, 0xA9, + 0x04, 0x08, 0x52, 0xB3, 0xC0, 0x00, 0x09, 0x95, 0xB7, 0x0D, 0x86, 0x01, 0x04, 0x0A, 0xC3, 0x09, + 0x34, 0x43, 0xC1, 0x54, 0x0E, 0xB7, 0xD2, 0x87, 0xAE, 0xBB, 0x99, 0x32, 0x7B, 0x0E, 0xCF, 0x49, + 0x0B, 0xD1, 0xD3, 0x72, 0x0C, 0xDE, 0x57, 0x33, 0xBE, 0xCC, 0xDB, 0x47, 0x05, 0x0C, 0xDF, 0xD3, + 0x05, 0xD7, 0x31, 0x0C, 0xE1, 0xA5, 0xE7, 0x46, 0xBE, 0xEB, 0xD2, 0x04, 0x05, 0xBF, 0x2C, 0x5C, + 0x4D, 0xF3, 0x46, 0x0B, 0x11, 0x56, 0xD9, 0x3B, 0x14, 0x01, 0x14, 0x0F, 0x16, 0x04, 0x1A, 0x30, + 0x28, 0x00, 0x81, 0xA1, 0x3F, 0x1F, 0xAD, 0x02, 0x10, 0x5B, 0x87, 0x6F, 0x0E, 0x8B, 0x02, 0x0E, + 0x04, 0x5C, 0x41, 0x10, 0xF0, 0x61, 0x8F, 0x25, 0x03, 0x26, 0xDA, 0x43, 0xC4, 0x42, 0x8B, 0x00, + 0x05, 0x0E, 0x7C, 0xFF, 0xED, 0xF0, 0x68, 0x83, 0x8B, 0x44, 0x91, 0xDF, 0x06, 0xAC, 0x54, 0x01, + 0x21, 0xA1, 0x80, 0x07, 0x0F, 0x1A, 0x38, 0x70, 0xC7, 0x72, 0x46, 0xC2, 0x97, 0x03, 0x3F, 0xC5, + 0x52, 0xE1, 0x80, 0x81, 0x00, 0x01, 0x19, 0x1B, 0x3C, 0x38, 0xD8, 0x53, 0xC6, 0x81, 0x38, 0x21, + 0x61, 0x4A, 0xEB, 0xB7, 0x42, 0x01, 0x82, 0xA3, 0x58, 0x7D, 0xC9, 0x6B, 0x1A, 0x63, 0x0B, 0xD0, + 0x81, 0x11, 0x08, 0x74, 0x44, 0x61, 0xE0, 0x01, 0xD6, 0xA3, 0x05, 0x16, 0x2D, 0xE5, 0xDA, 0xC2, + 0x80, 0xB7, 0x90, 0x41, 0xCB, 0xA4, 0x39, 0xC1, 0xEF, 0x2C, 0x56, 0xAA, 0x6C, 0x57, 0x38, 0xA8, + 0x14, 0x35, 0xA8, 0x35, 0x14, 0x10, 0x10, 0x34, 0xB0, 0x9B, 0xD5, 0x4F, 0xDE, 0x14, 0x06, 0x8E, + 0xF5, 0x1D, 0xC8, 0x25, 0x85, 0x83, 0xC1, 0x84, 0x05, 0x20, 0x32, 0x30, 0xF4, 0x30, 0x2D, 0x39, + 0x8B, 0x07, 0x32, 0x42, 0xA1, 0x00, 0x72, 0xE4, 0x45, 0x08, 0x7C, 0x59, 0x36, 0x91, 0x18, 0x73, + 0xE6, 0x6F, 0x79, 0x38, 0x2B, 0x88, 0x7C, 0x54, 0xE7, 0xE0, 0x2D, 0xA3, 0x4B, 0x78, 0x7A, 0x79, + 0x7A, 0x1A, 0xCE, 0x04, 0x4C, 0x85, 0xAC, 0x66, 0x7D, 0x96, 0x80, 0xB9, 0xD8, 0x22, 0x4A, 0x4B, + 0x14, 0x00, 0x97, 0xF1, 0xD3, 0x12, 0x3B, 0x79, 0x9F, 0x45, 0xC0, 0x13, 0xB8, 0xB7, 0xE1, 0xC5, + 0x19, 0x33, 0xEB, 0x53, 0xD3, 0xA8, 0x72, 0x01, 0x0D, 0x44, 0x97, 0x5C, 0x90, 0x7B, 0x9B, 0x01, + 0x05, 0xA6, 0x89, 0xFB, 0x3D, 0x54, 0x20, 0x81, 0xDA, 0x8C, 0xD7, 0x91, 0x16, 0x22, 0x91, 0xF8, + 0x80, 0x9F, 0x86, 0x08, 0x1E, 0xF4, 0xF2, 0xD5, 0x7D, 0x96, 0x18, 0xCC, 0x47, 0xA3, 0xDB, 0x7B, + 0xCA, 0x60, 0x40, 0xCA, 0xF4, 0x58, 0x81, 0xE2, 0x42, 0x04, 0x11, 0x4C, 0x80, 0x53, 0x7C, 0x3F, + 0xC9, 0xB1, 0xC7, 0xFF, 0x7A, 0xC1, 0x18, 0xA0, 0x0E, 0x7E, 0xC4, 0x49, 0xA5, 0x99, 0x67, 0xD7, + 0xA5, 0xB4, 0x15, 0x04, 0x93, 0x48, 0xA0, 0xA1, 0x81, 0x7C, 0x49, 0xB3, 0xC7, 0x38, 0xF6, 0x11, + 0x13, 0x52, 0x7E, 0x12, 0xAE, 0x63, 0xC0, 0x55, 0x00, 0x82, 0x62, 0xD8, 0x08, 0x0B, 0x24, 0xA0, + 0xA1, 0x86, 0x57, 0x3C, 0xF0, 0xE0, 0x2D, 0x05, 0x68, 0x67, 0x4A, 0x27, 0xB7, 0x0C, 0x80, 0x95, + 0x7E, 0x41, 0x11, 0x80, 0x5E, 0x85, 0xBF, 0x9D, 0xD0, 0xC0, 0x04, 0x2F, 0x2E, 0x62, 0xCB, 0x34, + 0x03, 0xE4, 0xB1, 0xA2, 0x23, 0x5E, 0x41, 0xC8, 0x63, 0x50, 0x0E, 0x9A, 0x75, 0x5D, 0x68, 0x5B, + 0x9D, 0xA0, 0x45, 0x04, 0x38, 0x2D, 0x72, 0xCC, 0x34, 0x7B, 0x24, 0xF2, 0x88, 0x5B, 0x39, 0xEA, + 0x18, 0xE1, 0x78, 0xD2, 0x58, 0x05, 0x20, 0x6C, 0x2B, 0xD4, 0x78, 0x64, 0x89, 0x6E, 0xB8, 0xF2, + 0xC2, 0x1F, 0x4D, 0xBE, 0x44, 0x22, 0x99, 0x72, 0xE4, 0x01, 0x60, 0x19, 0x31, 0x68, 0xB1, 0xC4, + 0x78, 0x50, 0xF4, 0xE2, 0x9B, 0x43, 0x5E, 0x80, 0x99, 0xE3, 0x8E, 0x6C, 0x4E, 0xE3, 0x63, 0x7A, + 0xD9, 0x55, 0xD6, 0x82, 0x4E, 0x04, 0x30, 0xD0, 0xC0, 0x01, 0x7C, 0x2A, 0xE4, 0xA3, 0xA2, 0x47, + 0xDC, 0x37, 0xE8, 0x9C, 0xE3, 0xC9, 0x64, 0x9D, 0x72, 0x70, 0x54, 0x29, 0x03, 0x04, 0xDF, 0xE5, + 0xE1, 0x4A, 0x19, 0x06, 0xB0, 0xD9, 0xC4, 0x66, 0x48, 0x7C, 0x27, 0xCD, 0x88, 0x98, 0x92, 0x89, + 0xE2, 0x75, 0x69, 0x2D, 0x69, 0xC3, 0x02, 0x07, 0xA4, 0x03, 0x8A, 0x2B, 0x8E, 0xC2, 0x04, 0x05, + 0x03, 0x48, 0x3C, 0x17, 0x5E, 0xAB, 0x7E, 0x61, 0x04, 0x20, 0x03, 0x33, 0x21, 0x01, 0xC1, 0x02, + 0xDF, 0x81, 0x52, 0x8B, 0x34, 0xAD, 0xC8, 0x6A, 0x43, 0x3E, 0x48, 0x9E, 0xF5, 0x24, 0x45, 0xAF, + 0xF2, 0x96, 0x9D, 0xFF, 0x03, 0xF5, 0x51, 0xD1, 0xA2, 0x03, 0x90, 0xCA, 0xF1, 0x94, 0x3E, 0x37, + 0x68, 0x81, 0xA4, 0x98, 0xC0, 0x9A, 0xF8, 0xC0, 0x8F, 0xCA, 0x39, 0xA0, 0xCD, 0x1F, 0x0B, 0x10, + 0x21, 0x0D, 0x03, 0xB8, 0x7D, 0x74, 0x64, 0x98, 0xD2, 0x16, 0x8A, 0x0C, 0xBA, 0xCA, 0x29, 0xF5, + 0x48, 0x8B, 0x53, 0xA1, 0x19, 0x03, 0xA8, 0x18, 0x85, 0xB2, 0x2A, 0xB9, 0x63, 0x06, 0x45, 0x06, + 0x80, 0x48, 0x05, 0xC9, 0x6E, 0x9C, 0x4F, 0xE1, 0xA3, 0xC2, 0x77, 0xF0, 0x16, 0x95, 0x4B, 0xB7, + 0xF4, 0x12, 0xEA, 0x57, 0x59, 0x14, 0xB2, 0x46, 0x08, 0xB8, 0x8E, 0x08, 0x72, 0x06, 0xB3, 0x3E, + 0xA6, 0xF2, 0x28, 0x46, 0x8B, 0x2C, 0xEB, 0xED, 0x03, 0xF3, 0x56, 0x5C, 0xF0, 0x40, 0xE6, 0xED, + 0xA6, 0x9C, 0x7C, 0xD9, 0x02, 0xA2, 0x48, 0xCA, 0x98, 0x25, 0xD6, 0xCE, 0x4E, 0x14, 0x2B, 0x18, + 0xE7, 0xC0, 0xE5, 0xAE, 0x93, 0x00, 0xC2, 0x45, 0x01, 0xB3, 0xC0, 0x8C, 0x74, 0xFA, 0xF7, 0x80, + 0x84, 0xAC, 0xAE, 0x6C, 0xCF, 0x00, 0x04, 0xA4, 0x47, 0x2C, 0x02, 0xCE, 0x6A, 0xF2, 0x06, 0x9D, + 0x98, 0xE5, 0x3C, 0xB0, 0x98, 0xB5, 0x4D, 0xD3, 0x40, 0x04, 0x05, 0x28, 0x57, 0x40, 0x04, 0x0A, + 0x50, 0x2A, 0x4B, 0x02, 0x1F, 0x53, 0xBD, 0x74, 0x54, 0x59, 0xBF, 0x1B, 0x5A, 0x41, 0xAC, 0x65, + 0xA7, 0xF0, 0x33, 0x0C, 0x58, 0x6D, 0xB6, 0x69, 0x68, 0x4F, 0x2B, 0x87, 0x55, 0xB7, 0x38, 0x50, + 0xC8, 0x5D, 0x7E, 0x8A, 0x1D, 0x0C, 0x04, 0x8F, 0xCD, 0x1D, 0x94, 0xDD, 0x4F, 0xA1, 0xEC, 0xA1, + 0x7C, 0xAD, 0x8D, 0xC5, 0x52, 0x4D, 0xBE, 0x0A, 0x3E, 0x9E, 0x55, 0x32, 0xDA, 0xA3, 0x37, 0x03, + 0xBD, 0x44, 0x3D, 0x8F, 0x55, 0x34, 0x3B, 0x6E, 0x4F, 0x03, 0x99, 0x73, 0x89, 0x93, 0xE5, 0xFE, + 0x74, 0x13, 0xB7, 0xCB, 0xE6, 0xA4, 0x4B, 0x63, 0x90, 0x65, 0xED, 0x16, 0x25, 0x77, 0xE9, 0x54, + 0x67, 0x11, 0xDB, 0x89, 0x44, 0xB3, 0x6E, 0xF6, 0x89, 0x7E, 0x37, 0x05, 0x47, 0xE7, 0xB2, 0xFB, + 0xF5, 0x2D, 0x70, 0xDD, 0x80, 0x37, 0xDE, 0x0A, 0x8E, 0xFB, 0x06, 0x1C, 0x00, 0x4D, 0xE0, 0x1E, + 0x80, 0x0C, 0x73, 0xFB, 0x47, 0x00, 0xE8, 0x2C, 0x89, 0x6E, 0xCF, 0x0C, 0x66, 0x87, 0x64, 0x55, + 0x73, 0x87, 0xB5, 0xD2, 0x39, 0xF2, 0x54, 0xA3, 0xAD, 0x24, 0xEF, 0x09, 0xC4, 0x2E, 0x47, 0x0C, + 0x83, 0x4F, 0x44, 0x6E, 0x25, 0xA9, 0x0C, 0x8F, 0x43, 0xE0, 0xD3, 0xB4, 0x30, 0x50, 0x54, 0xF9, + 0x41, 0x57, 0xC9, 0x63, 0xE6, 0x03, 0x00, 0xC1, 0xED, 0xE9, 0xAB, 0x60, 0x4F, 0x62, 0x94, 0x41, + 0x2A, 0xFE, 0x01, 0x56, 0x11, 0x10, 0xB3, 0x65, 0x4F, 0x11, 0xCC, 0x37, 0x4A, 0x10, 0x2C, 0x8E, + 0x3C, 0x80, 0x40, 0x3A, 0x30, 0x20, 0x02, 0x96, 0x10, 0x3F, 0x13, 0x64, 0xA7, 0x1E, 0x17, 0x53, + 0x90, 0x02, 0x28, 0x87, 0x00, 0xB2, 0xC1, 0xE0, 0x29, 0x08, 0x24, 0x50, 0xC9, 0xFE, 0x37, 0x3C, + 0x28, 0x30, 0x67, 0x75, 0x01, 0x9C, 0x20, 0x4E, 0x0A, 0xE0, 0xAC, 0xAF, 0x21, 0x90, 0x3E, 0x0D, + 0x4C, 0x41, 0xBB, 0x42, 0x13, 0x05, 0x63, 0xA4, 0x64, 0x81, 0x43, 0x28, 0x40, 0xED, 0x44, 0x00, + 0x01, 0x2C, 0x78, 0x29, 0x85, 0x2C, 0x38, 0x56, 0x62, 0x1A, 0xC0, 0x1D, 0x35, 0x84, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, + 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, + 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, + 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, + 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, + 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, + 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, + 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, + 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, + 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, + 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, + 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, + 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, + 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, + 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, + 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, + 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, + 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, + 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, + 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, + 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, + 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, + 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, + 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, + 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, + 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, + 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, + 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, + 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, + 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, + 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, + 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, + 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, + 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, + 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, + 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, + 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, + 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, + 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, + 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, + 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, + 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, + 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, + 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, + 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, + 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, + 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, + 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, + 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, + 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, + 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, + 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, + 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, + 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, + 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, + 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, + 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, + 0x0D, 0x21, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, + 0x00, 0x6A, 0x00, 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, + 0xAE, 0x6C, 0xEB, 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, + 0x0A, 0xC7, 0x03, 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, + 0xA4, 0x10, 0xA8, 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, + 0x9E, 0x18, 0x02, 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, + 0xD4, 0x81, 0x01, 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, + 0x0D, 0x08, 0x05, 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, + 0x04, 0x06, 0x10, 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, + 0x93, 0x09, 0x0C, 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, + 0x0C, 0x39, 0x9A, 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, + 0xAB, 0x5B, 0x4A, 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, + 0x0D, 0x0D, 0x07, 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, + 0x0E, 0x7B, 0x04, 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, + 0x92, 0x0C, 0x0E, 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, + 0x5B, 0x03, 0x0E, 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, + 0x98, 0xBE, 0x73, 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, + 0xB0, 0x6A, 0xA3, 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, + 0xBC, 0xA5, 0x0C, 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, + 0x04, 0x32, 0x53, 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, + 0x67, 0x8E, 0xA2, 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, + 0x33, 0xA0, 0x2B, 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, + 0x0E, 0x10, 0xC0, 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, + 0x0A, 0x08, 0xF8, 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, + 0x1D, 0x8A, 0x47, 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, + 0x22, 0x22, 0x82, 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, + 0x6B, 0x50, 0xE0, 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, + 0xA3, 0x2D, 0x60, 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, + 0x94, 0x14, 0x7F, 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, + 0x05, 0x30, 0x4A, 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, + 0x53, 0x20, 0xC1, 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, + 0x10, 0x03, 0x80, 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, + 0x26, 0x0F, 0x28, 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, + 0xC6, 0x0A, 0x02, 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, + 0xA0, 0xC0, 0x28, 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, + 0x42, 0x01, 0x5A, 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, + 0x88, 0x33, 0x14, 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, + 0x6A, 0xC4, 0x80, 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, + 0x28, 0xC2, 0xE2, 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, + 0x21, 0xA4, 0x0C, 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, + 0x4A, 0x93, 0x29, 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, + 0x94, 0x0C, 0x38, 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, + 0x56, 0x74, 0x54, 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, + 0x99, 0x83, 0x8A, 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, + 0x10, 0x02, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, + 0x6A, 0x00, 0x2E, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x00, 0x40, 0x62, 0xB9, 0x28, 0x08, 0x41, 0x28, + 0x4B, 0xE9, 0xBE, 0x70, 0x2C, 0xCF, 0x74, 0x6D, 0xDF, 0xE5, 0xF1, 0x3C, 0x69, 0x52, 0x24, 0x0F, + 0x82, 0xE1, 0x60, 0x00, 0x26, 0x5A, 0xB8, 0xA4, 0x72, 0xC9, 0x94, 0xE9, 0x22, 0x12, 0xC9, 0x64, + 0xF2, 0x18, 0x04, 0xAE, 0xD7, 0x01, 0xB0, 0xD0, 0xEC, 0x7A, 0xBF, 0x31, 0x48, 0x61, 0x12, 0x95, + 0x32, 0x02, 0x8E, 0x06, 0x36, 0x70, 0x50, 0x21, 0xC1, 0xF0, 0x78, 0x72, 0x91, 0x20, 0x4B, 0x55, + 0x85, 0xF5, 0xB5, 0x81, 0xE0, 0xCA, 0xFF, 0x80, 0x32, 0x0D, 0x0F, 0x53, 0x11, 0x11, 0x04, 0x07, + 0x7A, 0x57, 0x0E, 0x04, 0x6F, 0x81, 0x8F, 0x7F, 0x0B, 0x2A, 0x06, 0x94, 0x6A, 0x8A, 0x01, 0x06, + 0x04, 0x05, 0x07, 0x0B, 0x0B, 0x44, 0x94, 0xA0, 0x43, 0x24, 0x90, 0xA4, 0x37, 0x05, 0x04, 0x96, + 0x97, 0x58, 0x45, 0x09, 0x0A, 0x0C, 0x0C, 0x0A, 0x05, 0x0D, 0xB3, 0x05, 0x0A, 0x09, 0x0C, 0x05, + 0x06, 0xA3, 0x4D, 0x9F, 0xA0, 0x0B, 0xBB, 0xA5, 0x33, 0x6D, 0x08, 0x0C, 0x89, 0xAA, 0xC7, 0x8A, + 0x07, 0xAE, 0x3E, 0xC0, 0x32, 0x10, 0x07, 0x3F, 0x2A, 0x0E, 0x8C, 0x2A, 0x08, 0xD6, 0x29, 0x0E, + 0xB9, 0xCD, 0xC1, 0x22, 0x10, 0x45, 0xD2, 0xB8, 0x07, 0x56, 0x97, 0x22, 0xC8, 0x01, 0x0D, 0x0C, + 0x3E, 0x9C, 0x25, 0xCF, 0xA7, 0x04, 0xD9, 0xE2, 0xC8, 0x03, 0xD0, 0x09, 0x04, 0xD6, 0x09, 0xBA, + 0xDC, 0x30, 0x10, 0x0B, 0x06, 0xB6, 0x2A, 0x04, 0x12, 0xDC, 0x52, 0x40, 0x90, 0x60, 0x81, 0x5C, + 0x07, 0x20, 0xA8, 0x1A, 0xD0, 0x20, 0x01, 0x35, 0x07, 0x3C, 0x1C, 0x18, 0x30, 0x87, 0xCC, 0x00, + 0x03, 0x02, 0x0F, 0x12, 0x34, 0xD8, 0xA6, 0xCF, 0x44, 0xA7, 0x8F, 0x9D, 0x0E, 0x88, 0xAC, 0x75, + 0x6B, 0x22, 0xC5, 0x4B, 0x44, 0x4E, 0xFF, 0x26, 0x63, 0x80, 0x20, 0xE3, 0x81, 0x8E, 0x5D, 0x0E, + 0xA4, 0x33, 0xA6, 0x92, 0x8D, 0x03, 0x04, 0x35, 0x2F, 0x35, 0xC0, 0x98, 0xE0, 0x25, 0x4C, 0x26, + 0x07, 0x7C, 0xE4, 0xBC, 0x82, 0x40, 0xE1, 0x50, 0x3D, 0xCA, 0x52, 0x38, 0xFA, 0x89, 0xE3, 0x47, + 0xCE, 0x1F, 0x00, 0x8E, 0xAA, 0x02, 0xC2, 0x80, 0xE9, 0x92, 0x86, 0x2A, 0x0D, 0x3C, 0xA0, 0x29, + 0x55, 0xD1, 0x00, 0x8C, 0x06, 0xAC, 0x26, 0x31, 0x80, 0xC0, 0x24, 0x32, 0x04, 0x09, 0xBA, 0x9A, + 0x1B, 0x94, 0x80, 0xA3, 0x58, 0x18, 0x5A, 0xCF, 0x1C, 0x13, 0x78, 0x69, 0x9C, 0xDA, 0x2C, 0x04, + 0x22, 0x34, 0x78, 0x6B, 0x03, 0x82, 0x02, 0x44, 0x97, 0x5E, 0xD5, 0x1D, 0x60, 0xF7, 0xEE, 0xB9, + 0x07, 0x61, 0xF9, 0xD6, 0x58, 0xC0, 0x20, 0xDB, 0x1A, 0x82, 0x0B, 0x09, 0x17, 0xBE, 0xFB, 0x55, + 0x81, 0xE2, 0x1B, 0x99, 0x10, 0x39, 0xF6, 0x2A, 0x99, 0xB0, 0x61, 0x3D, 0x0E, 0x2F, 0xDF, 0x18, + 0x94, 0x87, 0xF3, 0x00, 0x01, 0x02, 0x24, 0x7F, 0x7E, 0x8C, 0x60, 0xA9, 0x68, 0x17, 0x6D, 0xCC, + 0x62, 0x91, 0x8C, 0x1A, 0x75, 0xE7, 0x2B, 0x30, 0xBA, 0xF2, 0xF1, 0xF9, 0xDA, 0x45, 0x26, 0xAE, + 0x59, 0x4E, 0xD7, 0x4E, 0xED, 0x19, 0xF7, 0x8C, 0xA3, 0x5A, 0xF7, 0xF6, 0x16, 0xF1, 0xC3, 0x68, + 0x70, 0xE1, 0xC3, 0x8B, 0xAF, 0xA1, 0x31, 0xF4, 0xB4, 0xD2, 0xD7, 0x10, 0x60, 0xE9, 0x21, 0x3C, + 0x3C, 0xFA, 0x64, 0xE3, 0x32, 0x6A, 0xD2, 0x56, 0xF0, 0xC0, 0x0F, 0x5F, 0x3A, 0xA9, 0x02, 0x70, + 0xEF, 0x4E, 0x5C, 0x3A, 0x68, 0xD7, 0xE5, 0x54, 0x72, 0xB7, 0xF2, 0xD5, 0xBC, 0xD5, 0xA0, 0x34, + 0xD7, 0xDB, 0x6E, 0xAF, 0x5A, 0x95, 0x03, 0xDE, 0x2F, 0x98, 0x73, 0xDB, 0x70, 0x01, 0xC4, 0xF2, + 0x96, 0x45, 0xB3, 0x41, 0x67, 0x5B, 0xFF, 0x7F, 0xE6, 0x00, 0x20, 0x51, 0x0C, 0xF2, 0xD0, 0x47, + 0x9C, 0x7A, 0xEA, 0x91, 0x07, 0x20, 0x4C, 0x05, 0xC8, 0xA5, 0x9E, 0x70, 0xA7, 0x31, 0x78, 0x92, + 0x24, 0x89, 0xB9, 0x70, 0x4C, 0x26, 0x41, 0x04, 0xA4, 0x40, 0x03, 0x19, 0x32, 0x72, 0xC8, 0x85, + 0x1D, 0xB9, 0x92, 0x20, 0x7F, 0xEE, 0x9D, 0x94, 0xE1, 0x49, 0x0C, 0xDD, 0x84, 0x16, 0x79, 0x11, + 0xF4, 0x11, 0x0B, 0x42, 0x62, 0x41, 0x70, 0xCB, 0x73, 0x1E, 0x0E, 0xE5, 0x20, 0x70, 0x7B, 0x10, + 0x40, 0x58, 0x5E, 0xC4, 0xE4, 0x23, 0x42, 0x02, 0x86, 0x34, 0xA2, 0x98, 0x24, 0x0A, 0x00, 0x19, + 0x63, 0x4E, 0xFD, 0x10, 0x43, 0x93, 0x32, 0x79, 0xF1, 0x90, 0x42, 0x88, 0x2E, 0x2C, 0xF0, 0x80, + 0x21, 0x0F, 0x30, 0x00, 0x5F, 0x30, 0x62, 0xF4, 0xB1, 0x61, 0x90, 0x47, 0x39, 0x18, 0xCB, 0x3F, + 0xEF, 0xF8, 0x60, 0xC0, 0x2F, 0x36, 0x3C, 0xB1, 0x22, 0x53, 0x99, 0x20, 0x90, 0x08, 0x9A, 0x5D, + 0x79, 0xD9, 0x80, 0x00, 0x29, 0xB4, 0xD6, 0x04, 0x59, 0x2C, 0xFC, 0x24, 0x13, 0x2A, 0x78, 0x76, + 0xF5, 0x95, 0x03, 0x0C, 0xA0, 0xA6, 0xA3, 0x17, 0x6E, 0x3D, 0xB2, 0xC0, 0x0F, 0x0A, 0x10, 0xB9, + 0xDA, 0x39, 0x08, 0x08, 0x90, 0x86, 0x00, 0x4E, 0x2E, 0x17, 0x86, 0x3B, 0xA5, 0x4D, 0xAA, 0x87, + 0x42, 0xAF, 0x0C, 0xE2, 0x00, 0xA6, 0x63, 0x8A, 0xF6, 0xA8, 0x0A, 0x91, 0x06, 0xF0, 0x4B, 0x9E, + 0xCE, 0x29, 0xF2, 0x17, 0x4B, 0x96, 0x16, 0x50, 0xA9, 0x9F, 0x9A, 0x02, 0x50, 0x00, 0x23, 0x81, + 0x9E, 0x1A, 0x41, 0x94, 0x47, 0x31, 0x10, 0xE6, 0x01, 0xD3, 0x98, 0xA5, 0x10, 0x2A, 0x2D, 0xF1, + 0x21, 0x46, 0x40, 0xB5, 0xDA, 0x8A, 0xD8, 0x02, 0x0D, 0x21, 0x9A, 0x80, 0x99, 0x98, 0xE0, 0x63, + 0xCE, 0x10, 0x01, 0xC8, 0x7A, 0xC2, 0x79, 0x11, 0x50, 0x65, 0x26, 0x2B, 0x9F, 0x64, 0xF9, 0xD1, + 0xE8, 0x93, 0x29, 0x32, 0x30, 0x84, 0x03, 0x0A, 0x28, 0x04, 0x2C, 0x46, 0x0B, 0x5C, 0x91, 0xAE, + 0x22, 0x64, 0x21, 0xB0, 0x13, 0x30, 0x99, 0xDC, 0xB4, 0xD3, 0xB3, 0xE9, 0x00, 0x50, 0x6A, 0xB2, + 0x00, 0xB4, 0xD1, 0x42, 0x50, 0x42, 0x00, 0xF6, 0x55, 0x51, 0xAA, 0x6A, 0x82, 0x09, 0x22, 0x08, + 0x38, 0xB0, 0x4D, 0xB7, 0x88, 0x2C, 0x60, 0x0D, 0x8B, 0xF8, 0xBE, 0x90, 0x89, 0x02, 0x0E, 0xE0, + 0x03, 0x81, 0xC0, 0x99, 0xDC, 0xAA, 0x2A, 0x44, 0xB3, 0xF8, 0xE9, 0x16, 0x04, 0x08, 0xD8, 0xC2, + 0x1C, 0x97, 0x0D, 0xCB, 0xE0, 0xC9, 0x28, 0x3A, 0x28, 0xF3, 0x5F, 0x6B, 0xBF, 0xD9, 0x72, 0xC4, + 0x62, 0x1D, 0x7F, 0x1B, 0x72, 0x0D, 0xCA, 0xBC, 0xD4, 0x86, 0x2D, 0x3E, 0xB9, 0xBC, 0x5C, 0x08, + 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, 0x6A, 0x00, + 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, 0xAE, 0x6C, 0xEB, + 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, 0x0A, 0xC7, 0x03, + 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, 0xA4, 0x10, 0xA8, + 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, 0x9E, 0x18, 0x02, + 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, 0xD4, 0x81, 0x01, + 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, 0x0D, 0x08, 0x05, + 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, 0x04, 0x06, 0x10, + 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, 0x93, 0x09, 0x0C, + 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, 0x0C, 0x39, 0x9A, + 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, 0xAB, 0x5B, 0x4A, + 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, 0x0D, 0x0D, 0x07, + 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, 0x0E, 0x7B, 0x04, + 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, 0x92, 0x0C, 0x0E, + 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, 0x5B, 0x03, 0x0E, + 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, 0x98, 0xBE, 0x73, + 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, 0xB0, 0x6A, 0xA3, + 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, 0xBC, 0xA5, 0x0C, + 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, 0x04, 0x32, 0x53, + 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, 0x67, 0x8E, 0xA2, + 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, 0x33, 0xA0, 0x2B, + 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, 0x0E, 0x10, 0xC0, + 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, 0x0A, 0x08, 0xF8, + 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, 0x1D, 0x8A, 0x47, + 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, 0x22, 0x22, 0x82, + 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, 0x6B, 0x50, 0xE0, + 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, 0xA3, 0x2D, 0x60, + 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, 0x94, 0x14, 0x7F, + 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, 0x05, 0x30, 0x4A, + 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, 0x53, 0x20, 0xC1, + 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, 0x10, 0x03, 0x80, + 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, 0x26, 0x0F, 0x28, + 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, 0xC6, 0x0A, 0x02, + 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, 0xA0, 0xC0, 0x28, + 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, 0x42, 0x01, 0x5A, + 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, 0x88, 0x33, 0x14, + 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, 0x6A, 0xC4, 0x80, + 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, 0x28, 0xC2, 0xE2, + 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, 0x21, 0xA4, 0x0C, + 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, 0x4A, 0x93, 0x29, + 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, 0x94, 0x0C, 0x38, + 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, 0x56, 0x74, 0x54, + 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, 0x99, 0x83, 0x8A, + 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, 0x10, 0x02, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, + 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, + 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, + 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, + 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, + 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, + 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, + 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, + 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, + 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, + 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, + 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, + 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, + 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, + 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, + 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, + 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, + 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, + 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, + 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, + 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, + 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, + 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, + 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, + 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, + 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, + 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, + 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, + 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, + 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, + 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, + 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, + 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, + 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, + 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, + 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, + 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, + 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, + 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, + 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, + 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, + 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, + 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, + 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, + 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, + 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, + 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, + 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, + 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, + 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, + 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, + 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, + 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, + 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, + 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, + 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, + 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, + 0x0D, 0x21, 0x00, 0x00, 0x3B}; diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_File/Send_Attachment_File.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_File/Send_Attachment_File.ino new file mode 100644 index 000000000..d615e9f3a --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_File/Send_Attachment_File.ino @@ -0,0 +1,443 @@ + + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email with attachments and inline images stored in SD card. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** Assign SD card type and FS used in src/ESP_Mail_FS.h and + * change the config for that card interfaces in src/extras/SDHelper.h + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// Provide the SD card interfaces setting and mounting +#include + +// To use only SMTP functions, you can exclude the IMAP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + +#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h + + // Mount SD card. + SD_Card_Mounting(); // See src/extras/SDHelper.h + + Serial.println("Preparing SD file attachments..."); + + const char *orangeImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RMQ0AMAgAsCFgftHLiQpsENJaaFT+fqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBGi/oCaOpTXoAAAAASUVORK5CYII="; + + // Write demo data to file + + static uint8_t buf[512]; + +// SDFat? +#if defined(ESP_MAIL_USE_SDFAT) // ESP_MAIL_USE_SDFAT is auto defined when you set to use SdFat in src/ESP_Mail_FS.h + SdFile file; + file.open("/orange.png", O_RDWR | O_CREAT); + file.print(orangeImg); + file.close(); + + file.open("/bin1.dat", O_RDWR | O_CREAT); + buf[0] = 'H'; + buf[1] = 'E'; + buf[2] = 'A'; + buf[3] = 'D'; + file.write(buf, 4); + + size_t i; + + for (i = 0; i < 4; i++) + { + memset(buf, i + 1, 512); + file.write(buf, 512); + } + + buf[0] = 'T'; + buf[1] = 'A'; + buf[2] = 'I'; + buf[3] = 'L'; + file.write(buf, 4); + file.close(); + +#else + +#if defined(ESP32) + File file = ESP_MAIL_DEFAULT_SD_FS.open("/orange.png", FILE_WRITE); +#else + File file = ESP_MAIL_DEFAULT_SD_FS.open("/orange.png", "w"); +#endif + file.print(orangeImg); + file.close(); + +#if defined(ESP32) + file = ESP_MAIL_DEFAULT_SD_FS.open("/bin1.dat", FILE_WRITE); +#else + file = ESP_MAIL_DEFAULT_SD_FS.open("/bin1.dat", "w"); +#endif + + buf[0] = 'H'; + buf[1] = 'E'; + buf[2] = 'A'; + buf[3] = 'D'; + file.write(buf, 4); + + size_t i; + + for (i = 0; i < 4; i++) + { + memset(buf, i + 1, 512); + file.write(buf, 512); + } + + buf[0] = 'T'; + buf[1] = 'A'; + buf[2] = 'I'; + buf[3] = 'L'; + file.write(buf, 4); + file.close(); +#endif + +#endif + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + + message.subject = F("Test sending Email with attachments and inline images from SD card and Flash"); + + message.addRecipient(F("user1"), RECIPIENT_EMAIL); + + /** Two alternative content versions are sending in this example e.g. plain text and html */ + String htmlMsg = "This message contains 1 inline image and 1 attachment file.

"; + + message.html.content = htmlMsg; + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = F("utf-8"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + message.text.content = F("This message contains 1 inline image and 1 attachment file.\r\nThe inline image will not show in the plain text message."); + + message.text.charSet = F("utf-8"); + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* The attachment data item */ + SMTP_Attachment att[2]; + int attIndex = 0; + + /** Set the inline image info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + att[attIndex].descr.filename = F("orange.png"); + att[attIndex].descr.mime = F("image/png"); + att[attIndex].file.path = F("/orange.png"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + att[attIndex].file.storage_type = esp_mail_file_storage_type_sd; + + /* Need to be base64 transfer encoding for inline image */ + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The orange.png file is already base64 encoded file. + * Then set the content encoding to match the transfer encoding + * which no encoding was taken place prior to sending. + */ + att[attIndex].descr.content_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att[attIndex]); + + /** Set the attachment info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + + attIndex++; + att[attIndex].descr.filename = F("bin1.dat"); + att[attIndex].descr.mime = F("application/octet-stream"); // binary data + att[attIndex].descr.description = F("This is binary data"); + att[attIndex].file.path = F("/bin1.dat"); + att[attIndex].file.storage_type = esp_mail_file_storage_type_sd; + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add attachment to the message */ + message.addAttachment(att[attIndex]); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Flash/Send_Attachment_Flash.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Flash/Send_Attachment_Flash.ino new file mode 100644 index 000000000..49ef4f54f --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_Flash/Send_Attachment_Flash.ino @@ -0,0 +1,411 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email with attachments and inline images stored in SPIFFS/LittleFS filesystem. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +/** Assign SD card type and FS used in src/ESP_Mail_FS.h and + * change the config for that card interfaces in src/extras/SDHelper.h + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only SMTP functions, you can exclude the IMAP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + +#if defined(ESP_MAIL_DEFAULT_FLASH_FS) // defined in src/ESP_Mail_FS.h + + // Mount SPIFFS/LittleFS filesystem. + ESP_MAIL_DEFAULT_FLASH_FS.begin(); + + Serial.println("Preparing flash file attachments..."); + + const char *orangeImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RMQ0AMAgAsCFgftHLiQpsENJaaFT+fqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBGi/oCaOpTXoAAAAASUVORK5CYII="; + + // Write demo data to file + + static uint8_t buf[512]; + +#if defined(ESP32) + File file = ESP_MAIL_DEFAULT_FLASH_FS.open("/orange.png", FILE_WRITE); +#else + File file = ESP_MAIL_DEFAULT_FLASH_FS.open("/orange.png", "w"); +#endif + + file.print(orangeImg); + file.close(); + +#if defined(ESP32) + file = ESP_MAIL_DEFAULT_FLASH_FS.open("/bin1.dat", FILE_WRITE); +#else + file = ESP_MAIL_DEFAULT_FLASH_FS.open("/bin1.dat", "w"); +#endif + + buf[0] = 'H'; + buf[1] = 'E'; + buf[2] = 'A'; + buf[3] = 'D'; + file.write(buf, 4); + + size_t i; + + for (i = 0; i < 4; i++) + { + memset(buf, i + 1, 512); + file.write(buf, 512); + } + + buf[0] = 'T'; + buf[1] = 'A'; + buf[2] = 'I'; + buf[3] = 'L'; + file.write(buf, 4); + file.close(); + +#endif + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + + message.subject = F("Test sending Email with attachments and inline images from flash filesystem"); + + message.addRecipient(F("user1"), RECIPIENT_EMAIL); + + /** Two alternative content versions are sending in this example e.g. plain text and html */ + String htmlMsg = "This message contains 1 inline image and 1 attachment file.

"; + + message.html.content = htmlMsg; + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = F("utf-8"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + message.text.content = F("This message contains 1 inline image and 1 attachment file.\r\nThe inline image will not show in the plain text message."); + + message.text.charSet = F("utf-8"); + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* The attachment data item */ + SMTP_Attachment att[2]; + int attIndex = 0; + + /** Set the inline image info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + att[attIndex].descr.filename = F("orange.png"); + att[attIndex].descr.mime = F("image/png"); + att[attIndex].file.path = F("/orange.png"); + + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + att[attIndex].file.storage_type = esp_mail_file_storage_type_flash; + + /* Need to be base64 transfer encoding for inline image */ + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The orange.png file is already base64 encoded file. + * Then set the content encoding to match the transfer encoding + * which no encoding was taken place prior to sending. + */ + att[attIndex].descr.content_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att[attIndex]); + + /** Set the attachment info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + + attIndex++; + att[attIndex].descr.filename = F("bin1.dat"); + att[attIndex].descr.mime = F("application/octet-stream"); // binary data + att[attIndex].descr.description = F("This is binary data"); + att[attIndex].file.path = F("/bin1.dat"); + att[attIndex].file.storage_type = esp_mail_file_storage_type_flash; + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add attachment to the message */ + message.addAttachment(att[attIndex]); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_PSRAM/Send_Attachment_PSRAM.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_PSRAM/Send_Attachment_PSRAM.ino new file mode 100644 index 000000000..2cd102ea6 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Attachment_PSRAM/Send_Attachment_PSRAM.ino @@ -0,0 +1,318 @@ + + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email with attachment stored in PSRAM (ESP32 only). + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif + +#include + +// To use only SMTP functions, you can exclude the IMAP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" + "-----END CERTIFICATE-----\n"; + +void setup() +{ + + Serial.begin(115200); + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email with PSRAM attachment"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + String textMsg = "This is simple plain text message with PSRAM attachment"; + message.text.content = textMsg; + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + // If this is a reply message + // message.in_reply_to = ""; + // message.references = " "; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + // message.response.reply_to = "someone@somemail.com"; + // message.response.return_path = "someone@somemail.com"; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + // For Root CA certificate verification (ESP8266 and ESP32 only) + // config.certificate.cert_data = rootCACert; + // or + // config.certificate.cert_file = "/path/to/der/file"; + // config.certificate.cert_file_storage_type = esp_mail_file_storage_type_flash; // esp_mail_file_storage_type_sd + // config.certificate.verify = true; + + // The WiFiNINA firmware the Root CA certification can be added via the option in Firmware update tool in Arduino IDE + + /* The attachment data item */ + SMTP_Attachment att[1]; + int attIndex = 0; + +#if defined(ESP32) + + int dlen = 3 * 1024 * 1024 + 512 * 1024; + uint8_t *data = (uint8_t *)ps_malloc(dlen); + + if (psramFound()) + { + memset(data, 0xff, dlen); + + att[attIndex].descr.filename = F("data.dat"); + att[attIndex].descr.mime = F("application/octet-stream"); + att[attIndex].descr.description = F("This is binary data"); + att[attIndex].blob.data = data; + att[attIndex].blob.size = dlen; + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att[attIndex]); + } + +#endif + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Camera_Image/ESP_Camera/ESP_Camera.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Camera_Image/ESP_Camera/ESP_Camera.ino new file mode 100644 index 000000000..ca1d27850 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Camera_Image/ESP_Camera/ESP_Camera.ino @@ -0,0 +1,325 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +/** + * This example shows how to send Email with inline image from ESP32 camera module. + * + * The ESP32 board used in this example is ESP32 PSRAM Timer Camera X (OV3660). + */ + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) +#include +#endif + +#include + +#include "esp_camera.h" + +// =================== +// Select camera model +// =================== +//#define CAMERA_MODEL_WROVER_KIT // Has PSRAM +#define CAMERA_MODEL_ESP_EYE // Has PSRAM +//#define CAMERA_MODEL_ESP32S3_EYE // Has PSRAM +//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM +//#define CAMERA_MODEL_M5STACK_V2_PSRAM // M5Camera version B Has PSRAM +//#define CAMERA_MODEL_M5STACK_WIDE // Has PSRAM +//#define CAMERA_MODEL_M5STACK_ESP32CAM // No PSRAM +//#define CAMERA_MODEL_M5STACK_UNITCAM // No PSRAM +//#define CAMERA_MODEL_AI_THINKER // Has PSRAM +//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM +//#define CAMERA_MODEL_XIAO_ESP32S3 // Has PSRAM +// ** Espressif Internal Boards ** +//#define CAMERA_MODEL_ESP32_CAM_BOARD +//#define CAMERA_MODEL_ESP32S2_CAM_BOARD +//#define CAMERA_MODEL_ESP32S3_CAM_LCD +//#define CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3 // Has PSRAM +//#define CAMERA_MODEL_DFRobot_Romeo_ESP32S3 // Has PSRAM +#include "camera_pins.h" + +// The camera_pins.h was taken from +//https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/Camera/CameraWebServer + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +void setup() +{ + + Serial.begin(115200); + + Serial.println(); + + camera_config_t camCfg; + camCfg.ledc_channel = LEDC_CHANNEL_0; + camCfg.ledc_timer = LEDC_TIMER_0; + camCfg.pin_d0 = Y2_GPIO_NUM; + camCfg.pin_d1 = Y3_GPIO_NUM; + camCfg.pin_d2 = Y4_GPIO_NUM; + camCfg.pin_d3 = Y5_GPIO_NUM; + camCfg.pin_d4 = Y6_GPIO_NUM; + camCfg.pin_d5 = Y7_GPIO_NUM; + camCfg.pin_d6 = Y8_GPIO_NUM; + camCfg.pin_d7 = Y9_GPIO_NUM; + camCfg.pin_xclk = XCLK_GPIO_NUM; + camCfg.pin_pclk = PCLK_GPIO_NUM; + camCfg.pin_vsync = VSYNC_GPIO_NUM; + camCfg.pin_href = HREF_GPIO_NUM; + camCfg.pin_sscb_sda = SIOD_GPIO_NUM; + camCfg.pin_sscb_scl = SIOC_GPIO_NUM; + camCfg.pin_pwdn = PWDN_GPIO_NUM; + camCfg.pin_reset = RESET_GPIO_NUM; + camCfg.xclk_freq_hz = 20000000; + camCfg.pixel_format = PIXFORMAT_JPEG; + camCfg.frame_size = FRAMESIZE_QXGA; + camCfg.jpeg_quality = 10; + camCfg.fb_count = 2; + + // camera init + esp_err_t err = esp_camera_init(&camCfg); + if (err != ESP_OK) + { + Serial.printf("Camera init failed with error 0x%x", err); + return; + } + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + + message.subject = F("Test sending camera image"); + message.addRecipient(F("user1"), RECIPIENT_EMAIL); + + message.html.content = F("The camera image.

\"esp32"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) <- not supported for message from blob and file + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = F("utf-8"); + + camera_fb_t *fb = esp_camera_fb_get(); + + SMTP_Attachment att; + + /** Set the inline image info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + att.descr.filename = F("camera.jpg"); + att.descr.mime = F("image/jpg"); + + att.blob.data = fb->buf; + att.blob.size = fb->len; + + att.descr.content_id = F("image-001"); // The content id (cid) of camera.jpg image in the src tag + + /* Need to be base64 transfer encoding for inline image */ + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Camera_Image/ESP_Camera/camera_pins.h b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Camera_Image/ESP_Camera/camera_pins.h new file mode 100644 index 000000000..fdbdd1a31 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Camera_Image/ESP_Camera/camera_pins.h @@ -0,0 +1,317 @@ + +#if defined(CAMERA_MODEL_WROVER_KIT) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 21 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 + +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 19 +#define Y4_GPIO_NUM 18 +#define Y3_GPIO_NUM 5 +#define Y2_GPIO_NUM 4 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +#elif defined(CAMERA_MODEL_ESP_EYE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 4 +#define SIOD_GPIO_NUM 18 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 36 +#define Y8_GPIO_NUM 37 +#define Y7_GPIO_NUM 38 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 35 +#define Y4_GPIO_NUM 14 +#define Y3_GPIO_NUM 13 +#define Y2_GPIO_NUM 34 +#define VSYNC_GPIO_NUM 5 +#define HREF_GPIO_NUM 27 +#define PCLK_GPIO_NUM 25 + +#define LED_GPIO_NUM 22 + +#elif defined(CAMERA_MODEL_M5STACK_PSRAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_V2_PSRAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 22 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_WIDE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 22 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#define LED_GPIO_NUM 2 + +#elif defined(CAMERA_MODEL_M5STACK_ESP32CAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 17 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_UNITCAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_AI_THINKER) +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 0 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 + +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 21 +#define Y4_GPIO_NUM 19 +#define Y3_GPIO_NUM 18 +#define Y2_GPIO_NUM 5 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +// 4 for flash led or 33 for normal led +#define LED_GPIO_NUM 4 + +#elif defined(CAMERA_MODEL_TTGO_T_JOURNAL) +#define PWDN_GPIO_NUM 0 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 17 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_XIAO_ESP32S3) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 10 +#define SIOD_GPIO_NUM 40 +#define SIOC_GPIO_NUM 39 + +#define Y9_GPIO_NUM 48 +#define Y8_GPIO_NUM 11 +#define Y7_GPIO_NUM 12 +#define Y6_GPIO_NUM 14 +#define Y5_GPIO_NUM 16 +#define Y4_GPIO_NUM 18 +#define Y3_GPIO_NUM 17 +#define Y2_GPIO_NUM 15 +#define VSYNC_GPIO_NUM 38 +#define HREF_GPIO_NUM 47 +#define PCLK_GPIO_NUM 13 + +#elif defined(CAMERA_MODEL_ESP32_CAM_BOARD) +// The 18 pin header on the board has Y5 and Y3 swapped +#define USE_BOARD_HEADER 0 +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM 33 +#define XCLK_GPIO_NUM 4 +#define SIOD_GPIO_NUM 18 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 36 +#define Y8_GPIO_NUM 19 +#define Y7_GPIO_NUM 21 +#define Y6_GPIO_NUM 39 +#if USE_BOARD_HEADER +#define Y5_GPIO_NUM 13 +#else +#define Y5_GPIO_NUM 35 +#endif +#define Y4_GPIO_NUM 14 +#if USE_BOARD_HEADER +#define Y3_GPIO_NUM 35 +#else +#define Y3_GPIO_NUM 13 +#endif +#define Y2_GPIO_NUM 34 +#define VSYNC_GPIO_NUM 5 +#define HREF_GPIO_NUM 27 +#define PCLK_GPIO_NUM 25 + +#elif defined(CAMERA_MODEL_ESP32S3_CAM_LCD) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 40 +#define SIOD_GPIO_NUM 17 +#define SIOC_GPIO_NUM 18 + +#define Y9_GPIO_NUM 39 +#define Y8_GPIO_NUM 41 +#define Y7_GPIO_NUM 42 +#define Y6_GPIO_NUM 12 +#define Y5_GPIO_NUM 3 +#define Y4_GPIO_NUM 14 +#define Y3_GPIO_NUM 47 +#define Y2_GPIO_NUM 13 +#define VSYNC_GPIO_NUM 21 +#define HREF_GPIO_NUM 38 +#define PCLK_GPIO_NUM 11 + +#elif defined(CAMERA_MODEL_ESP32S2_CAM_BOARD) +// The 18 pin header on the board has Y5 and Y3 swapped +#define USE_BOARD_HEADER 0 +#define PWDN_GPIO_NUM 1 +#define RESET_GPIO_NUM 2 +#define XCLK_GPIO_NUM 42 +#define SIOD_GPIO_NUM 41 +#define SIOC_GPIO_NUM 18 + +#define Y9_GPIO_NUM 16 +#define Y8_GPIO_NUM 39 +#define Y7_GPIO_NUM 40 +#define Y6_GPIO_NUM 15 +#if USE_BOARD_HEADER +#define Y5_GPIO_NUM 12 +#else +#define Y5_GPIO_NUM 13 +#endif +#define Y4_GPIO_NUM 5 +#if USE_BOARD_HEADER +#define Y3_GPIO_NUM 13 +#else +#define Y3_GPIO_NUM 12 +#endif +#define Y2_GPIO_NUM 14 +#define VSYNC_GPIO_NUM 38 +#define HREF_GPIO_NUM 4 +#define PCLK_GPIO_NUM 3 + +#elif defined(CAMERA_MODEL_ESP32S3_EYE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 15 +#define SIOD_GPIO_NUM 4 +#define SIOC_GPIO_NUM 5 + +#define Y2_GPIO_NUM 11 +#define Y3_GPIO_NUM 9 +#define Y4_GPIO_NUM 8 +#define Y5_GPIO_NUM 10 +#define Y6_GPIO_NUM 12 +#define Y7_GPIO_NUM 18 +#define Y8_GPIO_NUM 17 +#define Y9_GPIO_NUM 16 + +#define VSYNC_GPIO_NUM 6 +#define HREF_GPIO_NUM 7 +#define PCLK_GPIO_NUM 13 + +#elif defined(CAMERA_MODEL_DFRobot_FireBeetle2_ESP32S3) || defined(CAMERA_MODEL_DFRobot_Romeo_ESP32S3) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 45 +#define SIOD_GPIO_NUM 1 +#define SIOC_GPIO_NUM 2 + +#define Y9_GPIO_NUM 48 +#define Y8_GPIO_NUM 46 +#define Y7_GPIO_NUM 8 +#define Y6_GPIO_NUM 7 +#define Y5_GPIO_NUM 4 +#define Y4_GPIO_NUM 41 +#define Y3_GPIO_NUM 40 +#define Y2_GPIO_NUM 39 +#define VSYNC_GPIO_NUM 6 +#define HREF_GPIO_NUM 42 +#define PCLK_GPIO_NUM 5 + +#else +#error "Camera model not selected" +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Embedded_Message/Send_Embedded_Message.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Embedded_Message/Send_Embedded_Message.ino new file mode 100644 index 000000000..2f4da480e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Embedded_Message/Send_Embedded_Message.ino @@ -0,0 +1,303 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email which the html and text message will be embedded as attachment or inline content. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +// To use only SMTP functions, you can exclude the IMAP from compilation, see ESP_Mail_FS.h. + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending message as embedded files"); + message.addRecipient(F("Admin"), RECIPIENT_EMAIL); + + message.html.content = F("This is html message"); + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = F("utf-8"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + /* Enable to send this message body as file */ + message.html.embed.enable = true; + + /* The name of embedded file */ + message.html.embed.filename = F("test.html"); + + /** The embedded type + * esp_mail_smtp_embed_message_type_attachment or 0 + * esp_mail_smtp_embed_message_type_inline or 1 + */ + message.html.embed.type = esp_mail_smtp_embed_message_type_attachment; + + message.text.content = F("This is simple plain text message"); + message.text.charSet = F("utf-8"); + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + message.text.embed.enable = true; + message.text.embed.filename = F("test.txt"); + message.text.embed.type = esp_mail_smtp_embed_message_type_inline; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Enriched_Text/Send_Enriched_Text.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Enriched_Text/Send_Enriched_Text.ino new file mode 100644 index 000000000..99c162a6b --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Enriched_Text/Send_Enriched_Text.ino @@ -0,0 +1,293 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email in enriched text version. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending enriched text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + message.text.content = F("This is enriched as defined in RFC 1896\r\n\r\nIsn't it cool?"); + + message.text.content_type = F("text/enriched"); + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Flash_Message_with_Inline_Image/Send_Flash_Message_with_Inline_Image.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Flash_Message_with_Inline_Image/Send_Flash_Message_with_Inline_Image.ino new file mode 100644 index 000000000..dacf96434 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Flash_Message_with_Inline_Image/Send_Flash_Message_with_Inline_Image.ino @@ -0,0 +1,370 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email with inline images stored in flash memory. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +// The file systems for flash and sd memory can be changed in ESP_Mail_FS.h. + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + Serial.println("Mounting flash..."); + + const char *html = "This message contains inline image.

\"orange"; + const char *base64Img = "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAkGBggGBQkIBwgKCQkKDRYODQwMDRoTFBAWHxwhIB8cHh4jJzIqIyUvJR4eKzssLzM1ODg4ISo9QTw2QTI3ODX/2wBDAQkKCg0LDRkODhk1JB4kNTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTX/wgARCAFoAoADAREAAhEBAxEB/8QAGwABAQEBAQEBAQAAAAAAAAAAAAECAwUGBAf/xAAbAQEBAQADAQEAAAAAAAAAAAAAAQIDBAUGB//aAAwDAQACEAMQAAAAn5/+igVVBAAAFIWJQsAAAgAAAAAAAoIAAAAgKFBAAUIWAAAAAAASUIoKFCwAAAAAAAACUQAAAAACAAoICgAgKFCAAAAFECUAAAACCWgoAsAAAAAAAACoBCgAQACACghSAAUBCkCgAAAAAAAoIAACDN0BSFECkKAAAAAACpCgEKBABAKQAAAAUIAAoEAABSFACiUAAEgAloALQgARQAAAAEAAABBRAAAoBCkAFCAAABYCVSFAChAUAAIAEAKACgCgskKAAAAEAAABBRAAAoIAABUAABAFEoAAUKIAAAAARAFtEAoAAoACABFCQFAACAAAUAAQFAQAAAgAM7fIe10tRuXcu866YvXG95v6uLf7+rsKEABSAAIUUgUCiAAAQAUCQAAUIAABQACAFIAAAAQCoTkz/Gvtvi4zpdTW869Tqet+7rd39fDz+10ez7HR0AAAIUgAQtCgAAAAWJZRABBSFhRECgAAFABCkAAAAIACUG5/F/t/h86xELT2uj7fs9D1fQ63Y9Dr8nq9LQAAABSAAoAAAFAACCxAVAAKEQBQAAUAgAAAAABACUGp/GfuPh+WsELT3vP933PO9f8Af1+b9HHv1+jQAUAEKQALQACgJABQRKAECABQgFAgCgAAAAAAgoAQCgs/jn2/xPDfEID6Hzvd+g8z2f08XJ349ex0tQoCgAQpCpCrCgBRCoAEAgAqAABCywABRAoAAAAAIBQAgJQWfx/7b4n83JxCA+i873fovL9vrx67Y17PR0CgAAAAgKWVRICikKRKAEQAQUgKAlgAUARQAAAAQAUBBUAGp/Ivtfi/x8nAID6Lzfd+i8v2uuN9c32ehukWghQSgAAlUKIEKAAgFCIAIAAKEsACgCAAAABSACgIKgILP5L9r8Z+Hl64gPofO9z6Pyvc6410zfZ6PJQAAQpAUEKoAAAoAEgFQBAWIABBQCwBQAABAUAAAJQgIBp/J/s/jPP5usBD6Dzva+k8r3emd9cX2ejyAUgUAAAgqgAAAAUklCAACoAEEFABYFAAAEBQAAEFQEAJX8q+y+N83sdUCHv+f7P0vle90xvpm+z0eSwACiAAAJpQAAAABUAhZABUAASCgFAgUAAAAAAgBKAgoZr+XfX/AB3k9rqUA9zoex9N5Pv9Ma6Z17HS5NZFAACoAAaigAAAABBQJABUAgLIBQCiBQAAAQoIAAShBQhmv5j9d8f4/b6dAPb6Xr/TeP8AQdc63nXsdLk1mikAAIAKG8gKRRQEhQAgpCogCoAQIFAKIAFBACkKQACoCChAZr+Z/W/I+L3OjQD2en631HjfQ9c63nXr9Pk1i0AEAtgKRB0yBQAAQACoAKiACUhUCBQCiABQECILaQACoQCoCUP5p9Z8l4fd6AoPY6fqfU+N9H1zrWdev0+TeKBKpFAEKEh1yAKAAIVACCgJQJAKAiABQCgACKkAUKAgIKAgoZP5z9V8p8/3/OoB63U9L6rxfpeudbzr1upybxQCgCAUAOuIIFACkCoAQUBBRIAKEARQAACkLBAChZAogFCAVCL/ADz6n5X530PMAHqdX0frPF+l6Y1vOvW6nLvFAqwChACg64glqAFIUioABEoCUFQBBBQBFAIUAASUloICwAVAShCL/P8A6j5b5v0fMBB6XW9D67xPpumNdJv1enybxQpKoAQAEO2IChSBKsAgUEEFCWFEFEEAoEAAAUJCgLAABQgBKgJb8D9N8v8AL+n5IoPR63f+w8P6npi9Jv1OnydMUKKBABQEOuJSKAAAAQAJKCoAQUFCCRSgEAKQsCpBaEBUKQAGaAlvwv0fzXyfreMLA/fwdz7LwvrOuLvO/U6vJ0xRFAgLUABDtiAoAAAEQAWQUIKAgFCCwABQQApBFJVABAAQVACW/E/Q/PfJet4sog/bw9v7Lwfqu2Nbzv1OrydMWEtpAAQAVDvxyBaQApACJQAlAkVYFQACoBSFgAAAAAAAAShCAWw+P93w/kvX8aWElfp4+f7LwfqeuNdM79LrcnXjqooAlIUInPc/NzZ9PpbBQoIAAIACUBAKJBQAlAAEUAAAAAAEBKKSEoo+X9jy/lvW8qCzFxpr67xPo+uN9M79Lq8nXFgUCan5+XPLc5bzx3nlqCx9F5nYBQAAACIAIAASgsikUBBSFBQIAEKKEKSAqAEFRYSvC9Lp/P8Ao9LedamtSq/Z1+z3xyduPfp9Tl6S/n5Jy5M8tTnqctTUAZoll1Hv+dziKAKQFIEQASgAIKEsKQKgAoAECkKCUBCkAICVCWiV5fd4fH7fX3Nal1LZdKIu5cVqEVS2BVsDcuoh7fQ5RFAAFIEACQUABBQlgACoAABQAAAQAAgoQzaJWdTzO3xfg7HHrNssoWXSpRV3mwoUUAABPc8/mgUAAAEACQCgBBQgsAKJYAAAoBAAAQCoTT83NjhyTjvPHknHUxRIShqWy1bLqWwWqNS2KqJZmqgsuo9jo8oAAAAEKEQBQEAFCAAWCUAAAAAlhRnU/NzT83Lx8OTPHkcdZ3m7xqgGKzqctZzVLLqXtjdl3LvOhmpUSqilWwkVAez0eUAAAAAAiAKAgAFQACwQCgAgonPkn5ebPLc/PyZ5anPTeUUgsoKJZChSZrNSkVRuXpjVWywpqIUlZqwBT2ehygCFAAAAQAACoAEgoBQELBZx5Jw5MceSfn5M/m5cw6YtgsqILLRULFLKJUJZixbYzVXebAVbEoF1LY1FUBCoez0OSrAACgAAIBAUBABURQShw5s/n5MceTPDc4cksbySywACrcqozZLM0illoWgiys3IBZWbN51qWxVFgpM0NRVsCHtdHlKgAACkAKEAhQEKSUs/LzY57nPU4cmfz7mosZKUiUsooUZSWStRZdyolZsxpE1KLFUCUAWyxFFsal1LmtRVgQZsgtsnt9DmKgAAAAUBAARXHkn5+XHDkz+fkzy3NZWWiM2CmpYZsok0ozVgUhLIblssBQZrNmbBqWrYlFRV1GdIagupdQlpCgAESWex0eagAKgKQFBDU4cmePJOPJjjucdSkjNixFNSw1GpZZirGixnUylWxQCAAhK1LqICrYlnPUzqQsupdQUtIVYllpDSwsaNZtISoZufZ6PNQAFEBjefz8ueO5y5M89TlqazSZoWBC2ZCCm5cljcozZK1CFZslWLAsolgsShmty7zRBViVmrErnqCy6lFWIWliqigiKsaiy6l9TqcipCuW5+flx+fln5+TMM10yzRLKAiWZrRYAhm5pCmpbErUpM1LEblETNkKuoollhaWJUM2bl3KlzYWWCEFAVUCiKtlpqXUZsxqQESn6cXjuc9TluZBY1LZQBLLLSiJZmhYGozSyFBDUVcpqBLJWTUajGpKQNLrKqjRkVZZZmyFXpm6lxWbKCEoWWwqENFlsopmyxVBInDlxCy1RmyllsuozYqBdQLEqIIaECVLAKQJYlWNSiGdQmoxW5ZWE0WWrrNVYJKssrKShuWwWWRSCVK1m0ENSixqFsKIIPyc3GqxrOlRKFBc2CpZbLSVYAiCiJUsAAzYNRmwbzdTVTFma1FWxLMUssus2lXUtjFUJKzZihuXUWXNWCkVmrFgujJKqCy2BU/Ny8dlqiygApFqM2ClWJvNlEhKsUzZSAApiylliDpLc2VLOepqN51qKctZlShrN3LqXUQzZLLLDOmbCWa6SolAFshZZDUsFkIlLLU//EAEYQAAEDAQMJBgIIAwQLAAAAAAEAAhEDBBASBQYgITFBYXGxEzAyQFFyM1AiNENgc4GR0aGywRQlUoIVIyQ1NkRTYnDC4f/aAAgBAQABPwDyE3z5yfMzoToDRH3CHyAf+FR9wh87n5eO7HlXmKbiNoBQy/bR9u79AhnFbR9t+rAhnJbd72fmwIZz2r0on/L/APU3OivvpUf4oZzv30Kf5OKGc3rZ/wBHoZy0t9B/5OCsmV6drqhjKVQE7zEedHyp2tpCdVeHGHuQtFUbKj/1QtlcbKr/ANULfaBsqvQylaR9osn2h9ehiedcpgVCjKyewU6rBx7gXjy48gPLVRFRw4nRyMJsp9xVCmrOwKzaq7OaHejRn5oNoVoEWmpweeujkETZXe9UmqmMLVZzFZnMd6O7nzQ8qPEOatww2+uPSo7roBZvfVanvVBiaqGqqzmNIfcEbRzWUxGVLV+K7roBZtCaFX3BMTVS+I3mPIjTHy/eOayxqyzbPxn9To5r/Cr82piaqfjHPux8jHmstiMuW3hXf/MdHNbZaP8AKmpqZtCH3HzgEZw2/wDHf1OjmrttI9qampm0fKh507FnKIzkt347tHNXx2jkE1BNTdnyEdwPOnYs6RGc1u/FKGhmuYr1/YOqamoJh1D7jFZ2/wDE9t946DRzX+tVvZ/UJqagmbBy+VDup8kVngIzotfNv8o0c2PrtX8P+oTU1BU/A3kEPOjuRpDSGhHkM8hGc9p5M/lFwvzZ+vv/AAympqCp66beQ84Lgh3o70d9nsIzkq8WM6aObZjKJ9hTU1BUfhN5DTHywXTonvCs+RGcPOkzRzc/3oPYU1BBUfgs9o+QT5DfcdAXnvSs+9WXWfgN6nRzeMZWZyd0KaggqGugz2/Ix5AaRuPeZ/CMs0fwB1cpUqVKyAf73o/n0KaggrP9XZy+aToDv8/x/eNm40f/AGOjkPVlihzTE1BWb6uzl8xGhPks/wAf7VZD603ddHI2rK1n96Ympqs31dnLzQ0BfKlDRHn8/WS+xcnrAuzWBYVkvVlOz+8dUxBBWb6u3vKlpo0/HUaE/KlMGGU6j/ygd4O7HyPPVmNtj5v/AKLsF/ZyUbK7eEbM7cFY6ZZb6JO6oOqYmpqsuuzt0iYT8oWam4tNdmL0GvonZVpjwUqr+Yw9U7KdY+GmxvEnF+ydbLQ/bWI9gDU4l+suLj6uMoSgD5YaAuHns6mY6Nm4OchQCbZ0LIhYwdqGTqYeHAQQZTar27gUy0N3ghUqjX7HKymLOAnVGsEuIA4mE7KFnZtqtPt19E7KrB4KdR3P6KOVKp8LGM5yUbXXftrOHtgItDzL5cfVxnqg2FhWFFiwIMUfJh5TLzMVClweeiZSQpIUl2aDEGKPQI059AgaoYGio8Abg5dlJ1ieJQYVgQYVBCg3An0UkIOQUcFCHkR3Y83Ke9tNsvc1vMwsp16Vei1tOo15DpOHWgPQKD6KCsPC4IKY2hShKgELCsPFBkIcQsBO5YFhaN6DmhdodzVLigO9HyWUTCq5TsdHx2miOAfJ/gnZaofZsr1eLaUD+MJ+WK32dkjjUqfsnZRtrtr6dP2056p9avV8des7hMdEGRuB4kSiSu1K7Y7AV2j/APEhUcVjKmd0oNulCVJWtBpO9BoG9bEJRneVhHogAPQLkEGu9EGefHeypTnhgl5DRxMJ+VLIzUazXcGDF0VTLX/Qs1R/F8M/dOypbX7BZ6X6vRtFreIfa6vKmAzonWWnUM1A6ofWo4uTKQp6qQaz2iEHOG3Wsbd4QwnYUWLAU4FEIhNQCamQRJKAbuchTYd6FELsQFs3FTvlfqg70ClEJrD6LAoAWMLEdEd+PKSgVVtNKj8Wqyn7nAJ+WbINTKhqcKbC5OyyT8KzP51HhvSU/KlqfsNKnybi6o2mu/x2mseTsPRdmycRY0n1Os/xQUAXAraoQWpFih7dhQqPG0LtGngoa5GmFgXZoNcpcgJMlNJahXEawu2lB4O+4H1CDPUyvoNWMIvX0kJUXATpDy40ZUqrbrNQ1Va9JnN0lf6YspnB2j/awp+WH7KdCOL3/sn5Rtb9lRjB6MZ+6ealX41es/gahhMo0meFjP0U3QsCwFCRcAi24FTeeSDwi0ORoqXt3rtfVqLz6JrkCiFKgKPQosNweUHneFjahhcsC1jcpKxLGVJ87KmJJT8oWWkTjr0wfQOk/wAFUy1RHw6dapybHVOyxXfOCgxnvfPRPtlsqf8AMFnCm0DrKfT7XXVfUq+95KZTYzU1jW8hdChYVhuFwKkKJRYoLUSUCgbgpUoEHcsAUEKVqWAINgoyEHQdYQM70HFqkFQNoK1rVvCwgrAixAuGwoPcg4bxCDgiT5mYReBJJgKrlax0dTq7eTdfRHLNJwmlSrP5tw9U7Klod4KVNnFxLv2T7Zan7a7m+wBqc0Vfi4qnvcXdU1oYIYA3ldru/O8BQgVqULDeHEIOCD/zWoosRYti1oOQchdJulQ07kGoSEGbysAWBBqDUGLBdK13QFhCLFCghAnytS22elqfXYOTp6J+VaOvAypU5NjrCdlaqfBRYz3vnon261P21sAO6m0BFoqyapfU97pTabWD6DQ1SgZuwXNi7DcCgpui6b4uDm+kKLgpuwLs1hNweVKEOUKCgLpGwohqF30eKHBykrE1AArChIUoRfAUDvycIJJgJ+ULKwwa7OTTPROytSE4KdV/5R1T8q1nTgpU2cXuJ6J1stL9tcjhTaAnf6zXULqh9XuJQ1amgN5LaiLtaa5RiuBuIuBugFFim6VKCgKLhChQhI2IP/xBAYthUXa7ixGmiwgoSgUHkIPlqEbAsKwuC4EKFqQhQFJCxSFAQLgsfqEHBywqLoWDuZT69Kn8SoxnudCflayt2PL/AGNJTssbqdneeLnBv7o5StT9nZU+QLuqNe0VJx2mpybDeiNJpMubjPq4z1Q1CBA7g3hy2qEDdChAoOQKgKNKAi1C4i9tQ79abhdsMFEEKb9SwLCiAnMTZCDyEHzcBdrCEIC4BQVChSUKhQqjeEHNcsOhKqWuhSkPqsaRxTsrUB4cb+TVUyxVMilQA4ucv7da3iH1QPYIXaVH+J7jzchSY3Y0XygdAoJt8KERdCEhA7ii2FJQN0XByBUqAiFKnSEqAsKwolNqkIOY/wD7SixFAhawpUDcdGEJu5G4BQgYQIucEQo9QtVweRsKdluh9kyrV5NjqnZYtDtTLOxnvfPROtlseJNdrOFNic+o/wCJWqvn1cg0AGBBQCChBFNKcINwUII6GooXSVruF0IOhETsuBm+FsQcoTpG9NcHLWgSECgSgQhAuKFxChQQmvLdhTaodqeEGA62lOChABbL5CBF5lSsSn0KAWxYisSBlQRcGhYDwNxQMtuPhQF7UbiVKnUhowpi4acKYukoPuACIRTXrU4LCJQai24FAoEoISCoBRkXkKBdMGQhVO/WgWv2FFpQF8Suz9FrCD0IO9EINWBAkIOQAI2oNUBTeCgYEIlUxtlTfBulFyMoG4HQAUXQgh3BQ23FNJGxAhyBWpFqhNIUXFiNwKDljQTSsAdrCghAqVCLbgUKpCDwboIQIF5YCsJCBvBRUldoQu0O8Jjg66YTSgEB6BQgFqQIF8KAg0LVeJF0JutqIWrebxN0aUKEFF7DPAqFCLUQmOhCHISEWByLS1RcHoQCmv8AW4HVB1hFgOsIghA3FiLFhuDiEHnY5QCsCi6UEWKXBYgVBWtQCsFwKD1IK//EAC4RAAIBAQUHBQEAAgMAAAAAAAABEQIDBBAgMRIwMjNAQWAFEyFQURQiQmFxkP/aAAgBAgEBPwD/AMGKVLP5aPw/ks/w/ks/w/jsx3Kg/iX6O5f8n8T/AEru+wtfB7PiQqUbKNik9un8PZoLWhUsZVUWrleD0cSKdMt41KmVMq0fg9HEijhWW9alTGVaeD06os+BZb3qirCrTwenUsuBZb5qh4PTwenUseWst97Dwfg61LHlr/rLfew8H4PTqXflU5b7oh4Pwdal25VOW+6IfhKLpyKct94UPF+DIufIpy3zhHi/BkXHkU5b5wDxfg9w5FOW+cGSrwf0/kLLeuXkq18GR6dyFlvXLyV6+D+ncnLeeW8levg/pvJy3nlPJXr4P6XynlvHKY8a+LwZHpfA8tvy2PGvi8H9Lf8AjUSSTha8DHjXxbxWdTFYPu/uvTXCqNo2zbQq0VuaWPGvXNDYrGt9hWD7sVjSKihdvvbi4k2jbPcPcPecQNJjoHSytSxUNisaxWH6xWNKFTSuxJJJJJJP3d1cSbRJJJJOEnwbRJJPgMCpbLGh0a5J3Mk4zhBH2qpZTd7SrRCutXdiu9Hdis7NdhKlaIkRBskIjfTkn65Utiu9o+wrsv8AZisbJa/IlQtKT3KloOva1wjGRZmfJLNpm1kjJOEEfUwU2dVeiFdqxXZd6hWNmhU0rRG09zOEIh4SSSTk2TZIxk+SCPqIKbGurRCu1fcV3p7sVnZrsJpaIdbeSSd3GG0fBBBG5gjCcYII66GKxtHohXZ/7MVhQtWKizXYVUaDqb1xkknPO6nLOEZ5Jw+CCCOrSbFd7R6IV2fdisaFqKihaITa0G56OScYIzzjJOMk55JwjpIFY1vsK7vuxWFC1YrOhdiY0Np98k5J6OScYI3kEdRDYrGv8Fd33YrChasVFC7Exp0E72M0kk4wRhJO5hEEYTjO5hlNnVVoK71iu67sVjZoSpWiNp9HBHQRnknBPCCN7BBGWBWdT7Cu9RTd6Vqz27NaIhEvpo6XZIgnpFlgV1q7iu9C1ZsWa0R8dkTlXXIjdrGCMF0MZZyr6KMJwnfxnnCMk4RhO4eeOlW4TyzljGcs4wRmncQQNfUPcJ5IwjGRYyTkjCeg/8QALBEAAgECBAYCAgEFAAAAAAAAAAERAhIFEyBgAwQQMjNQMUAwURQhQUJhkP/aAAgBAwEBPwD/AIMMz/8AZns/kGexcYzjOM0pqnY9fayviVS/6mbX+zOr/Z/I4n7FzXE/ZyvEq4lMsRTSUqNj1fDK+56eR7ClFKFser4ZxO56cP7ClCFser4Zxe96cN7WU7Jfwzjd704Z2sWyavhnH8j04X8PohbHfwzmPK9OF/3EIWx2c15qtOFf5CELZHN+arThXzUIQtjv4Od89WnC+5iFsnnvPVpwzufRbJxDz1acM72LZWIeerThvk0LY+I+d6cO8ouiFsfEvO9OH+bQtj4n5tPIeZaFsfFfKSSSSch5loWx8W8i08j5loWx8W7kQR15PzIXVbHxSmWi0tLS05byoQhC/HJci/3XP0zBlGUZLHwmcGmK0L4EIWqS9GYXlzJfvOapksMsyjKFwEnInAmJlJKL0Xl7Ln0jRHvOMpLS0gggjpHWOkbClIraZGyJHXSZiMx/ouqJfWSSSdgSh1ozC+olssElqjShdIII0z7C5GYi9lzJeqPxRpkknVPqZL0XozGXVdEtMfnkkX4JJ9PejML2SyCFojXH3Z+7KL6TML2S/SR6S5F5ey59IRH2oI9TKLkXl5c/SwR1n7skl6MwuZL9ZBH0pJ13IvMxl7JI9ZP2pM1GYy6ol+zn7EaF9+fYr3Ek/nknUvRr1n//2Q=="; + +#if defined(ESP32) || defined(ESP8266) +#if defined(ESP32) + if (ESP_MAIL_DEFAULT_FLASH_FS.begin(true)) +#elif defined(ESP8266) + if (ESP_MAIL_DEFAULT_FLASH_FS.begin()) +#endif + { + + // ESP_MAIL_DEFAULT_FLASH_FS.format(); + + if (ESP_MAIL_DEFAULT_FLASH_FS.exists("/base64Img.jpg")) + ESP_MAIL_DEFAULT_FLASH_FS.remove("/base64Img.jpg"); + + Serial.println("Preparing flash file attachments..."); + +#if defined(ESP32) + File file = ESP_MAIL_DEFAULT_FLASH_FS.open("/base64Img.jpg", FILE_WRITE); +#elif defined(ESP8266) + File file = ESP_MAIL_DEFAULT_FLASH_FS.open("/base64Img.jpg", "w"); +#endif + file.print(base64Img); + file.close(); + +#if defined(ESP32) + file = ESP_MAIL_DEFAULT_FLASH_FS.open("/msg.html", FILE_WRITE); +#elif defined(ESP8266) + file = ESP_MAIL_DEFAULT_FLASH_FS.open("/msg.html", "w"); +#endif + file.print(html); + file.close(); + } + else + { + Serial.println("Flash filesystem monting Failed"); + } +#endif + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + + message.subject = F("Test sending base64 inline image stored in flash memory"); + message.addRecipient(F("user1"), RECIPIENT_EMAIL); + + /* Two alternative content versions are sending in this example e.g. plain text and html */ + + /* Assign blob data (in flash or ram) as HTML message */ + message.html.blob.data = (const uint8_t *)html; + message.html.blob.size = strlen(html); + + // Or get the content from file + // message.html.file.name = "/msg.html"; + // message.html.file.type = esp_mail_file_storage_type_flash; + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) <- not supported for message from blob and file + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = F("utf-8"); + + message.text.content = F("This message contains inline image.\r\nThe inline image was not shown in the plain text message."); + message.text.charSet = F("utf-8"); + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* The attachment data item */ + SMTP_Attachment att; + /** Set the inline image info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + att.descr.filename = F("base64Img.jpg"); + att.descr.mime = F("image/jpg"); + +#if defined(ESP32) || defined(ESP8266) + att.file.path = F("/base64Img.jpg"); + /** The file storage type e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + att.file.storage_type = esp_mail_file_storage_type_flash; +#elif defined(ARDUINO_ARCH_SAMD) + att.blob.data = (const uint8_t *)base64Img; + att.blob.size = sizeof(base64Img); +#endif + + att.descr.content_id = F("image-001"); // The content id (cid) of orange image in the src tag + + /* Need to be base64 transfer encoding for inline image */ + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The attach image file is already base64 encoded file. + * Then set the content encoding to match the transfer encoding + * which no encoding was taken place prior to sending. + */ + att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add inline image to the message */ + message.addInlineImage(att); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_HTML/Send_HTML.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_HTML/Send_HTML.ino new file mode 100644 index 000000000..1a4af3860 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_HTML/Send_HTML.ino @@ -0,0 +1,301 @@ + + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send html message. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* The full message sending logs can now save to file */ + /* Since v3.0.4, the sent logs stored in smtp.sendingResult will store only the latest message logs */ + // config.sentLogs.filename = "/path/to/log/file"; + // config.sentLogs.storage_type = esp_mail_file_storage_type_flash; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending html Email"); + message.addRecipient(F("Admin"), RECIPIENT_EMAIL); + + String htmlMsg = "

This is the html text message.

The message was sent via ESP device.

"; + message.html.content = htmlMsg; + + /** The html text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* Set the TCP response read timeout in seconds */ + // smtp.setTCPTimeout(10); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Parallel_Attachment/Send_Parallel_Attachment.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Parallel_Attachment/Send_Parallel_Attachment.ino new file mode 100644 index 000000000..bb7221272 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Parallel_Attachment/Send_Parallel_Attachment.ino @@ -0,0 +1,334 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + * +*/ + + +/** + * This example shows how to send Email with media e.g. audio and images as parallen attachments, + * and play or display them simultaneously on the Email client (depends on the Mail client supports). + */ + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +/* This is for attachment data */ +#include "data.h" + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Enable the chunked data transfer with pipelining for large message if server supported */ + message.enable.chunking = true; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + + message.subject = F("Test sending Email with parallel attachments"); + message.addRecipient(F("user1"), RECIPIENT_EMAIL); + + message.html.content = F("This message contains image and audio file which will play on the Mail client in parallel or simultaneously (depends on the client supports)."); + + /** The HTML text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.html.charSet = F("utf-8"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + message.text.content = F("This message contains image and audio file which will play on the Mail client in parallel or simultaneously (depends on the client supports)."); + message.text.charSet = F("us-ascii"); + message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* The attachment data item */ + SMTP_Attachment att; + + /** Set the attachment info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + att.descr.filename = F("haun.png"); + att.descr.mime = F("image/png"); + att.blob.data = shaun_png; + att.blob.size = sizeof(shaun_png); + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + message.addParallelAttachment(att); + + /** Set the attachment info e.g. + * file name, MIME type, file path, file storage type, + * transfer encoding and content encoding + */ + message.resetAttachItem(att); // Clear the attach item data to reuse + att.descr.filename = F("mu_law.wav"); + att.descr.mime = F("audio/basic"); + att.blob.data = mu_law_wave; + att.blob.size = sizeof(mu_law_wave); + att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + message.addParallelAttachment(att); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + + /* Start sending the Email and close the session */ + if (!MailClient.sendMail(&smtp, &message, true)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Parallel_Attachment/data.h b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Parallel_Attachment/data.h new file mode 100644 index 000000000..c7a88aeab --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Parallel_Attachment/data.h @@ -0,0 +1,1957 @@ +#include + +static const uint8_t mu_law_wave[] PROGMEM = { +0x52, 0x49, 0x46, 0x46, 0x84, 0x5D, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, +0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x40, 0x1F, 0x00, 0x00, 0x40, 0x1F, 0x00, 0x00, +0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, 0x61, 0x63, 0x74, 0x04, 0x00, 0x00, 0x00, 0x00, 0x5D, +0x00, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5D, 0x00, 0x00, 0xFB, 0xFD, 0xFF, 0xFE, 0xFF, 0x7F, +0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7C, 0x7D, +0x7C, 0x7C, 0x7D, 0x7F, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7E, 0xFF, 0x7F, +0x7D, 0x7C, 0x7B, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7C, 0x7C, 0x7B, +0x7B, 0x7B, 0x7A, 0x7A, 0x7B, 0x7A, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x7C, 0x7E, +0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x79, 0x79, 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x7E, 0xFF, 0xFE, 0xFE, +0xFF, 0x7E, 0x7C, 0x7D, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x79, 0x78, 0x79, +0x7A, 0x79, 0x78, 0x78, 0x78, 0x77, 0x78, 0x78, 0x79, 0x79, 0x78, 0x77, 0x77, 0x78, 0x78, 0x79, +0x7A, 0x79, 0x79, 0x78, 0x78, 0x7A, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, +0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFC, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF8, +0xF7, 0xF7, 0xF8, 0xF9, 0xF9, 0xFB, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFE, +0xFF, 0xFF, 0xFE, 0x7E, 0x7D, 0x7D, 0x7C, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7C, +0x7B, 0x7A, 0x79, 0x79, 0x79, 0x77, 0x77, 0x78, 0x79, 0x7B, 0x7C, 0x7B, 0x7B, 0x7C, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x79, 0x79, +0x78, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7B, 0x7B, 0x7A, 0x7C, 0x7E, 0x7D, 0x7E, 0x7E, 0x7C, 0x7C, +0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x79, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x78, 0x78, 0x7A, 0x7A, 0x79, +0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFC, 0xFB, 0xFB, 0xFC, +0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFE, 0xFF, 0x7E, 0x7E, 0xFF, 0xFF, 0x7E, 0x7E, 0x7D, 0x7B, +0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, +0x7C, 0x7B, 0x79, 0x7A, 0x7A, 0x7A, 0x7A, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7C, 0x79, 0x79, 0x7A, +0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7C, 0x7C, 0x7C, 0x7E, 0x7D, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0xFE, +0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, +0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7D, 0x7E, 0x7D, 0x7B, 0x7B, 0x7B, 0x79, 0x78, 0x77, +0x78, 0x78, 0x77, 0x77, 0x77, 0x78, 0x78, 0x76, 0x76, 0x75, 0x73, 0x73, 0x73, 0x72, 0x73, 0x73, +0x74, 0x74, 0x74, 0x75, 0x77, 0x78, 0x78, 0x77, 0x76, 0x77, 0x76, 0x76, 0x78, 0x79, 0x79, 0x79, +0x78, 0x79, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7E, +0x7E, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFD, 0xFE, 0xFF, 0xFD, 0xFE, 0x7F, 0xFF, +0x7F, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7E, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7D, 0x7F, +0xFF, 0xFF, 0xFE, 0xFE, 0x7F, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7C, 0x7D, +0x7D, 0x7D, 0x7D, 0x7E, 0x7F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFF, 0xFE, 0xFC, 0xFD, 0xFC, 0xFC, 0xFD, +0xFC, 0xFB, 0xFB, 0xFC, 0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFC, 0xFD, 0xFE, +0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7D, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7D, 0x7B, 0x7B, 0x79, +0x78, 0x78, 0x78, 0x76, 0x74, 0x74, 0x73, 0x72, 0x75, 0x77, 0x77, 0x76, 0x75, 0x75, 0x76, 0x77, +0x77, 0x76, 0x74, 0x74, 0x74, 0x74, 0x76, 0x76, 0x76, 0x77, 0x75, 0x76, 0x78, 0x79, 0x77, 0x77, +0x79, 0x7B, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7D, 0x7F, 0x7E, 0xFF, 0xFF, 0x7F, 0xFE, 0xFC, 0xFE, +0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFD, 0xFC, 0xFE, 0xFF, 0x7E, 0x7F, 0x7F, 0x7D, 0x7E, 0xFF, 0x7F, +0x7F, 0xFF, 0x7F, 0x7E, 0x7D, 0x7E, 0xFF, 0x7E, 0x7F, 0x7F, 0x7C, 0x7D, 0x7F, 0x7D, 0x7E, 0x7E, +0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7B, 0x7D, 0x7B, 0x7A, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7C, +0x7D, 0x7E, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0xFF, 0xFD, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFB, 0xFB, +0xFA, 0xFB, 0xFB, 0xFB, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0x7E, 0x7E, 0x7D, 0x7B, 0x7B, 0x7B, +0x78, 0x79, 0x78, 0x75, 0x76, 0x76, 0x76, 0x76, 0x74, 0x74, 0x73, 0x73, 0x74, 0x73, 0x72, 0x73, +0x75, 0x75, 0x74, 0x76, 0x74, 0x72, 0x73, 0x74, 0x75, 0x75, 0x76, 0x77, 0x77, 0x78, 0x77, 0x77, +0x77, 0x78, 0x78, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x79, 0x79, 0x7A, 0x79, 0x7B, 0x7C, 0x7B, 0x7B, +0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7C, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, +0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, +0xFE, 0x7E, 0x7E, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7E, 0xFF, 0x7E, 0x7E, 0x7E, 0x7D, +0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFC, 0xFE, 0x7F, 0x7E, 0x7E, 0x7F, 0xFF, 0xFF, +0x7F, 0x7E, 0x7D, 0x7D, 0x7D, 0x7B, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, 0x7D, 0x7C, 0x7C, +0x7D, 0x7C, 0x7C, 0x7E, 0x7E, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x7F, 0xFF, 0xFF, +0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFB, +0xFB, 0xFB, 0xFA, 0xFB, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, +0x7E, 0x7E, 0x7E, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7E, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7F, +0x7D, 0x7B, 0x7C, 0x7C, 0x7D, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7E, +0x7F, 0x7E, 0x7D, 0x7C, 0x7B, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x78, 0x77, 0x77, 0x76, 0x74, 0x73, +0x72, 0x73, 0x74, 0x75, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, +0x7C, 0x7D, 0x7E, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7D, 0x7C, 0x7B, +0x7A, 0x7B, 0x7B, 0x7A, 0x7A, 0x79, 0x79, 0x7A, 0x79, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x79, 0x79, +0x79, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7C, 0x7B, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7F, +0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7D, 0x7D, +0x7D, 0x7D, 0x7E, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7F, 0x7F, 0x7E, 0x7F, 0x7E, 0x7E, 0x7F, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7F, 0x7F, 0x7E, +0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, +0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, +0x7D, 0x7E, 0xFF, 0x7E, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7A, +0x7A, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7D, 0x7C, 0x7C, 0x7A, 0x79, 0x79, 0x78, 0x78, +0x78, 0x77, 0x77, 0x76, 0x75, 0x74, 0x74, 0x74, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x76, 0x75, +0x74, 0x75, 0x77, 0x78, 0x78, 0x7A, 0x7B, 0x7D, 0xFF, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, +0xFC, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, +0xF8, 0xFA, 0xF8, 0xF6, 0xF7, 0xF7, 0xF8, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFB, +0xFB, 0xFB, 0xFD, 0xFE, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, +0x7F, 0x7E, 0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0xFD, 0xFE, 0xFF, +0xFE, 0xFE, 0xFD, 0xFE, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7E, 0x7F, +0x7D, 0x7D, 0x7E, 0x7E, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x79, 0x77, 0x78, 0x79, 0x78, 0x77, 0x76, +0x76, 0x75, 0x73, 0x74, 0x73, 0x71, 0x70, 0x70, 0x71, 0x72, 0x71, 0x71, 0x70, 0x6F, 0x6F, 0x6F, +0x70, 0x71, 0x71, 0x72, 0x73, 0x74, 0x74, 0x74, 0x76, 0x77, 0x76, 0x78, 0x79, 0x79, 0x79, 0x78, +0x7A, 0x7B, 0x7B, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, +0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7D, +0x7D, 0x7D, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7C, 0x7A, 0x78, 0x79, 0x78, 0x77, +0x76, 0x78, 0x79, 0x78, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7A, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, +0x7E, 0xFF, 0xFD, 0xFC, 0xFC, 0xFA, 0xF9, 0xFA, 0xFB, 0xFA, 0xF9, 0xF8, 0xF8, 0xF9, 0xFA, 0xF9, +0xF9, 0xF9, 0xF9, 0xF9, 0xF8, 0xF7, 0xF9, 0xF9, 0xF8, 0xF8, 0xFA, 0xFB, 0xFA, 0xFB, 0xFD, 0xFD, +0xFC, 0xFD, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFF, 0x7F, 0x7F, 0x7E, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, +0x7A, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x75, 0x76, 0x77, 0x76, 0x75, 0x76, 0x76, 0x75, 0x76, 0x77, +0x78, 0x79, 0x7B, 0x7B, 0x7B, 0x7A, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7A, 0x7B, 0x7B, 0x7A, +0x7B, 0x7D, 0x7E, 0x7B, 0x7C, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFF, 0xFE, 0xFC, 0xFD, 0xFE, 0xFF, +0xFE, 0xFF, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7B, 0x7D, 0x7F, 0x7F, 0x7C, 0x7B, +0x7A, 0x78, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7C, 0x7C, 0x7A, 0x7B, 0x7C, 0x7C, 0x7B, 0x7C, 0x7C, +0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x79, 0x7A, 0x79, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, +0x7D, 0xFE, 0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFA, 0xF8, 0xF8, 0xF9, 0xF8, 0xF5, 0xF4, 0xF7, 0xF8, +0xF8, 0xF8, 0xF9, 0xFB, 0xFC, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7B, +0x7A, 0x7B, 0x7B, 0x7A, 0x78, 0x78, 0x77, 0x76, 0x76, 0x75, 0x76, 0x76, 0x76, 0x77, 0x75, 0x75, +0x76, 0x75, 0x76, 0x76, 0x78, 0x78, 0x77, 0x78, 0x76, 0x74, 0x75, 0x77, 0x79, 0x7A, 0x7A, 0x7B, +0x7C, 0x7D, 0x7D, 0x7D, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, +0xFE, 0x7F, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0xFF, 0xFD, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, +0xFC, 0xFD, 0xFE, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0x7E, 0x7D, 0x7C, +0x7B, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7A, 0x7A, 0x7C, 0x7A, 0x7B, 0x7C, 0x7C, 0x7E, 0x7E, 0xFF, +0xFF, 0x7F, 0x7F, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, +0x7C, 0x7D, 0xFF, 0x7E, 0x7C, 0x7D, 0xFF, 0xFF, 0xFF, 0xFD, 0xFD, 0xFF, 0x7E, 0x7F, 0x7E, 0x7E, +0x7F, 0x7E, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x79, +0x77, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7C, 0x7D, 0x7D, 0x7E, 0xFD, 0xFD, 0xFE, 0xFC, 0xFC, 0xFB, +0xFB, 0xFC, 0xFB, 0xFB, 0xFA, 0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFD, +0xFF, 0xFF, 0xFD, 0xFC, 0xFD, 0xFD, 0xFC, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0x7E, 0x7D, 0x7D, 0x7C, 0x7D, 0x7E, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, +0x7B, 0x7C, 0x7D, 0x7B, 0x7B, 0x7C, 0x7A, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x75, 0x73, 0x72, +0x72, 0x72, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x74, +0x75, 0x76, 0x76, 0x76, 0x77, 0x78, 0x77, 0x78, 0x79, 0x77, 0x78, 0x78, 0x79, 0x7A, 0x7A, 0x7A, +0x7A, 0x79, 0x77, 0x76, 0x76, 0x78, 0x78, 0x77, 0x77, 0x77, 0x75, 0x74, 0x74, 0x75, 0x75, 0x76, +0x79, 0x79, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7D, 0xFF, 0xFD, 0xFD, 0xFE, 0xFF, 0xFE, 0xFC, +0xF9, 0xF9, 0xFB, 0xFA, 0xF9, 0xF8, 0xF8, 0xF8, 0xF6, 0xF4, 0xF6, 0xF8, 0xF7, 0xF7, 0xF9, 0xF9, +0xF9, 0xF8, 0xF8, 0xFB, 0xFA, 0xF9, 0xFA, 0xFB, 0xFC, 0xFE, 0xFC, 0xFD, 0xFF, 0x7E, 0x7F, 0x7E, +0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7B, 0x7B, 0x7A, 0x79, 0x7A, 0x7A, 0x79, 0x79, 0x78, 0x77, 0x78, +0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7D, 0x7E, 0x7D, 0x7D, 0x7F, 0xFE, 0xFE, 0xFD, 0xFD, +0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xFC, 0xFB, 0xFC, +0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, +0x7C, 0x7B, 0x7B, 0x7C, 0x79, 0x79, 0x79, 0x78, 0x76, 0x75, 0x76, 0x78, 0x77, 0x76, 0x76, 0x77, +0x76, 0x74, 0x74, 0x75, 0x75, 0x75, 0x74, 0x74, 0x76, 0x77, 0x78, 0x7A, 0x7C, 0x7B, 0x7A, 0x7D, +0x7E, 0x7E, 0x7C, 0x7D, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFE, 0xFF, +0xFF, 0x7F, 0x7E, 0x7F, 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFC, 0xFB, 0xFC, 0xFE, 0xFD, 0xFC, 0xFE, +0xFF, 0xFE, 0xFD, 0xFF, 0x7E, 0x7F, 0xFE, 0xFC, 0xFD, 0xFE, 0xFD, 0xFD, 0xFE, 0x7F, 0x7E, 0xFF, +0xFF, 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, +0x7E, 0x7D, 0x7E, 0xFF, 0xFF, 0xFE, 0xFD, 0xFF, 0x7D, 0x7A, 0x79, 0x79, 0x7A, 0x7C, 0x7B, 0x7B, +0x7D, 0x7E, 0x7E, 0x7D, 0xFF, 0xFF, 0x7F, 0x7F, 0x7E, 0x7B, 0x7A, 0x7A, 0x7A, 0x78, 0x77, 0x77, +0x77, 0x78, 0x78, 0x76, 0x76, 0x76, 0x76, 0x74, 0x74, 0x73, 0x74, 0x74, 0x75, 0x74, 0x72, 0x74, +0x76, 0x74, 0x74, 0x76, 0x76, 0x74, 0x73, 0x73, 0x72, 0x73, 0x74, 0x76, 0x77, 0x75, 0x73, 0x75, +0x77, 0x78, 0x75, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7B, +0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x7D, 0x7C, 0x7D, 0x7B, 0x7C, 0x7F, +0xFF, 0xFF, 0x7E, 0x7D, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x79, 0x77, 0x77, +0x78, 0x76, 0x76, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x7B, 0x7C, 0x7B, 0x7C, 0x7D, 0xFF, +0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFB, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, +0xFA, 0xF9, 0xF9, 0xF7, 0xF7, 0xF7, 0xF4, 0xF4, 0xF4, 0xF2, 0xEF, 0xEE, 0xEF, 0xF2, 0xF2, 0xF1, +0xF2, 0xF5, 0xF5, 0xF3, 0xF1, 0xF2, 0xF5, 0xF7, 0xF8, 0xFA, 0xFB, 0xFC, 0xFC, 0xFB, 0xFC, 0xFC, +0xFD, 0xFF, 0x7F, 0x7E, 0x7C, 0x7A, 0x7A, 0x78, 0x77, 0x76, 0x75, 0x75, 0x74, 0x71, 0x70, 0x71, +0x71, 0x71, 0x70, 0x6F, 0x71, 0x71, 0x71, 0x73, 0x75, 0x77, 0x77, 0x76, 0x79, 0x7A, 0x79, 0x79, +0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7F, 0xFF, 0xFE, 0xFF, 0x7E, 0x7D, 0x7E, 0x7E, 0x7D, 0x7D, +0x7E, 0x7C, 0x7C, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x77, 0x75, 0x75, 0x76, 0x78, 0x79, 0x78, +0x7A, 0x7C, 0x7C, 0x7A, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7A, 0x79, 0x7A, 0x7B, 0x7D, 0x7D, 0x7C, +0x7C, 0x7E, 0xFF, 0x7F, 0x7D, 0x7E, 0x7F, 0x7D, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0xFF, 0x7F, 0x7E, +0x7D, 0x7D, 0xFF, 0xFF, 0x7F, 0xFF, 0xFC, 0xFC, 0xFD, 0xFD, 0xFC, 0xFB, 0xFA, 0xFA, 0xFB, 0xFB, +0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0x7F, 0x7F, 0x7E, 0x7D, 0x7E, 0x7D, 0x7B, 0x7C, 0x7B, +0x7B, 0x7C, 0x7C, 0x7A, 0x78, 0x78, 0x7B, 0x7A, 0x77, 0x75, 0x76, 0x75, 0x76, 0x76, 0x76, 0x76, +0x78, 0x79, 0x78, 0x75, 0x75, 0x76, 0x77, 0x7A, 0x7D, 0xFF, 0xFC, 0xFB, 0xFA, 0xFA, 0xFB, 0xFA, +0xFB, 0xFB, 0xFC, 0xFD, 0xFD, 0x7E, 0x78, 0x76, 0x72, 0x70, 0x71, 0x75, 0x77, 0x77, 0x79, 0x7A, +0x7A, 0x7A, 0x7B, 0xFF, 0xFB, 0xFA, 0xF9, 0xFB, 0xFD, 0xFE, 0x7E, 0x7F, 0xFF, 0xFC, 0xF6, 0xF3, +0xF7, 0xFC, 0xFF, 0x7A, 0x73, 0x6E, 0x6C, 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6F, 0x74, 0x73, 0x72, +0x75, 0x7A, 0x7D, 0x7D, 0xFF, 0xFF, 0x7C, 0x7C, 0x7D, 0x7B, 0x7A, 0x79, 0x7B, 0xFF, 0xFF, 0x7D, +0x7C, 0xFF, 0xFE, 0x7D, 0xFC, 0xF3, 0xF6, 0xFC, 0xFE, 0xFE, 0xFF, 0x78, 0x75, 0x79, 0x7A, 0x7E, +0xF8, 0xF6, 0xF6, 0xF2, 0xEF, 0xEE, 0xF0, 0xF7, 0xFD, 0xFE, 0xFD, 0x7B, 0x77, 0x7C, 0xFF, 0xFB, +0xFD, 0x7D, 0xFF, 0x7C, 0x78, 0x7A, 0x7A, 0xFF, 0xF9, 0xF5, 0xF1, 0xF4, 0xFA, 0xFC, 0xFC, 0xFA, +0xF8, 0xFA, 0xFB, 0xFA, 0xFB, 0xFC, 0xFD, 0xFF, 0x7D, 0x7B, 0x7D, 0x7E, 0x7A, 0x76, 0x76, 0x75, +0x72, 0x75, 0x7B, 0x7D, 0x7A, 0x7A, 0x7D, 0xFF, 0x7C, 0x7C, 0xFF, 0x7D, 0x7A, 0x7B, 0x7C, 0x7E, +0xFC, 0xFC, 0x7F, 0xFE, 0xFD, 0xFE, 0xFC, 0xF8, 0xF9, 0xFA, 0xFB, 0xFE, 0x7E, 0x79, 0x72, 0x72, +0x74, 0x76, 0x78, 0x76, 0x78, 0x7A, 0x75, 0x76, 0x77, 0x75, 0x73, 0x73, 0x73, 0x73, 0x74, 0x73, +0x73, 0x77, 0x78, 0x79, 0x79, 0x7A, 0x79, 0x73, 0x73, 0x7B, 0x7C, 0x7C, 0xFC, 0xFC, 0xFE, 0x7F, +0x76, 0x73, 0x76, 0x73, 0x73, 0x78, 0x7C, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0x7D, 0x7B, 0x7B, +0x7C, 0x7A, 0x78, 0x7B, 0x7B, 0x7D, 0x7F, 0x7A, 0x77, 0x73, 0x6F, 0x70, 0x72, 0x73, 0x72, 0x72, +0x73, 0x74, 0x74, 0x76, 0x7D, 0xFE, 0x7D, 0x7C, 0x7C, 0x78, 0x76, 0x77, 0x79, 0x7B, 0xFF, 0xFD, +0xFE, 0x7E, 0x7B, 0x7A, 0x78, 0x78, 0x7B, 0x7C, 0x7C, 0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x79, 0x7B, +0xFF, 0xFA, 0xF9, 0xFD, 0x7E, 0x7D, 0x7C, 0x7B, 0x7E, 0xFE, 0xFC, 0xFF, 0x7E, 0xFE, 0xFD, 0xFE, +0xFD, 0xFC, 0xFB, 0xFC, 0xFC, 0xFD, 0xF9, 0xF3, 0xF2, 0xF3, 0xF4, 0xF6, 0xF6, 0xF8, 0xFA, 0xFC, +0xFB, 0xF7, 0xF9, 0xFC, 0xFC, 0xFD, 0xFD, 0x7E, 0x7C, 0x7F, 0xFF, 0x7D, 0x7A, 0x7A, 0x7B, 0x78, +0x78, 0x78, 0x75, 0x75, 0x76, 0x79, 0x7A, 0x79, 0x7C, 0x7F, 0xFD, 0xFF, 0x7E, 0xFF, 0x7D, 0x79, +0x77, 0x78, 0x79, 0x78, 0x79, 0x7C, 0x7D, 0x7F, 0x7E, 0x7E, 0xFE, 0xFC, 0xF8, 0xF7, 0xFA, 0xFB, +0xFC, 0xFD, 0xFF, 0x7D, 0x7E, 0x7F, 0xFF, 0x7D, 0x7B, 0x7D, 0xFE, 0xF9, 0xF5, 0xF6, 0xF6, 0xF4, +0xF6, 0xFA, 0xFE, 0x7D, 0x79, 0x78, 0x77, 0x77, 0x7A, 0x7E, 0xFE, 0xFF, 0xFF, 0xFA, 0xFA, 0xFE, +0x7C, 0x75, 0x71, 0x72, 0x74, 0x75, 0x74, 0x75, 0x75, 0x77, 0x79, 0x79, 0x77, 0x74, 0x74, 0x74, +0x72, 0x71, 0x70, 0x71, 0x70, 0x6F, 0x72, 0x73, 0x72, 0x73, 0x71, 0x70, 0x73, 0x78, 0x7A, 0x78, +0x77, 0x77, 0x76, 0x74, 0x73, 0x72, 0x70, 0x71, 0x75, 0x78, 0x7B, 0x7F, 0xFF, 0xFE, 0xFB, 0xFD, +0x7E, 0xFF, 0xFD, 0x7F, 0x7C, 0x7B, 0x7F, 0xFD, 0xFF, 0xFE, 0xFC, 0xFE, 0xFD, 0xFC, 0xFA, 0xF7, +0xF7, 0xFB, 0xFD, 0xFE, 0x7E, 0x7C, 0x7B, 0x7A, 0x7B, 0x79, 0x75, 0x75, 0x76, 0x78, 0x7D, 0xFF, +0x7E, 0x7D, 0x7E, 0x7C, 0x77, 0x75, 0x76, 0x76, 0x78, 0x7E, 0xFD, 0xFB, 0xFC, 0xFD, 0xFE, 0x7C, +0x78, 0x78, 0x7A, 0x7B, 0x7E, 0x7E, 0x7D, 0x7D, 0x7C, 0x7A, 0x78, 0x79, 0x7B, 0x7A, 0x7D, 0xFC, +0xFD, 0x7E, 0xFF, 0xFB, 0xF7, 0xF6, 0xF7, 0xF7, 0xF6, 0xFA, 0xFF, 0xFE, 0xFD, 0xFF, 0x7D, 0xFF, +0xFC, 0xFB, 0xF9, 0xFD, 0xFE, 0xFD, 0x7E, 0x79, 0x76, 0x71, 0x6F, 0x6E, 0x6E, 0x6F, 0x72, 0x76, +0x7A, 0x7E, 0xFF, 0xFF, 0x7C, 0x7B, 0x7C, 0x7B, 0x7A, 0x79, 0x7A, 0x7E, 0xFF, 0xFF, 0x7E, 0x7D, +0x7D, 0x7E, 0x7C, 0x78, 0x79, 0x7A, 0x7B, 0xFF, 0xFF, 0x7F, 0x7E, 0x7B, 0x79, 0x79, 0x76, 0x72, +0x73, 0x7B, 0xFF, 0xFE, 0xFB, 0xFA, 0xFA, 0xFC, 0x7D, 0x78, 0x77, 0x78, 0x79, 0x79, 0x78, 0x79, +0x77, 0x73, 0x74, 0x76, 0x77, 0x79, 0x7A, 0x7B, 0x7F, 0xFD, 0xFE, 0xFF, 0x7F, 0x7E, 0x7E, 0x7C, +0x78, 0x78, 0x7B, 0x7B, 0x7A, 0x7C, 0x7F, 0xFE, 0xFD, 0xFE, 0x7E, 0xFF, 0xFD, 0xFC, 0xF9, 0xF5, +0xF2, 0xF0, 0xF2, 0xF3, 0xF0, 0xF1, 0xF2, 0xF1, 0xF4, 0xF7, 0xF8, 0xFC, 0xFC, 0xF6, 0xF3, 0xF4, +0xF5, 0xF5, 0xF6, 0xFB, 0xFF, 0xFF, 0xFF, 0x7D, 0x7D, 0x7E, 0x7D, 0x79, 0x75, 0x74, 0x75, 0x72, +0x72, 0x75, 0x75, 0x74, 0x77, 0x7A, 0x7A, 0x7A, 0x7A, 0x77, 0x74, 0x73, 0x72, 0x74, 0x75, 0x76, +0x77, 0x74, 0x74, 0x77, 0x79, 0x79, 0x79, 0x78, 0x77, 0x74, 0x70, 0x6F, 0x70, 0x6F, 0x6E, 0x6E, +0x6E, 0x6F, 0x6F, 0x72, 0x75, 0x72, 0x74, 0x79, 0x7B, 0x7B, 0x7B, 0x7D, 0xFF, 0x7E, 0x7F, 0xFE, +0xFE, 0x7F, 0x7D, 0x7D, 0xFF, 0xFD, 0xFE, 0x7E, 0x7D, 0x7D, 0x7E, 0x7C, 0x79, 0x77, 0x75, 0x76, +0x77, 0x78, 0x78, 0x74, 0x75, 0x7A, 0x7F, 0xFB, 0xF9, 0xF9, 0xF8, 0xFD, 0x7E, 0x7B, 0x76, 0x78, +0x7B, 0x7C, 0x7E, 0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x7C, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0x7D, 0x7B, +0x7B, 0x79, 0x79, 0x7A, 0x7D, 0xFF, 0x7F, 0x7F, 0xFF, 0xFD, 0xFB, 0xFD, 0xFE, 0xFE, 0xFF, 0x7D, +0x7C, 0x7F, 0xFB, 0xF7, 0xF6, 0xFC, 0x7F, 0xFF, 0xFE, 0xFB, 0xFD, 0xFE, 0xFC, 0xFD, 0xFE, 0x7C, +0x76, 0x74, 0x74, 0x79, 0x79, 0x76, 0x77, 0x79, 0x7C, 0x7D, 0x7B, 0x7B, 0x7B, 0x7E, 0xFD, 0xFB, +0xF9, 0xF9, 0xFE, 0x7C, 0x79, 0x79, 0x77, 0x76, 0x79, 0x7B, 0x7D, 0x7C, 0x7C, 0x7D, 0x7C, 0x78, +0x75, 0x74, 0x72, 0x72, 0x73, 0x71, 0x70, 0x73, 0x78, 0x7C, 0x7D, 0x7E, 0xFF, 0x7F, 0x7F, 0x7D, +0x7A, 0x78, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x7B, 0xFF, 0xFF, 0xFD, 0xFC, 0xFC, 0xFA, 0xF9, +0xF8, 0xF9, 0xFE, 0x7E, 0xFF, 0xFE, 0xFE, 0x7D, 0x7A, 0x78, 0x75, 0x75, 0x77, 0x7A, 0x7A, 0x79, +0x7B, 0x7D, 0xFF, 0xFD, 0xFC, 0xFC, 0xFB, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9, 0xFB, 0xFA, 0xF9, 0xF7, +0xF8, 0xFA, 0xF8, 0xF9, 0xFC, 0xFD, 0xFD, 0xFC, 0xF9, 0xF7, 0xF8, 0xFC, 0x7E, 0x7B, 0x7A, 0x7A, +0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x77, 0x72, 0x72, 0x74, 0x76, 0x7B, 0x7C, 0x7B, 0x7D, 0x7E, 0x7D, +0x7D, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x78, 0x78, 0x79, 0x79, 0x79, 0x78, 0x79, 0x7B, 0x7C, 0x7C, +0x7A, 0x7A, 0x77, 0x75, 0x75, 0x74, 0x73, 0x70, 0x6E, 0x6E, 0x6E, 0x6F, 0x72, 0x75, 0x77, 0x7A, +0x7D, 0x7D, 0x7D, 0x7E, 0xFF, 0x7D, 0x7A, 0x7A, 0x7A, 0x7B, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, +0x7D, 0x7B, 0x78, 0x75, 0x73, 0x74, 0x75, 0x75, 0x78, 0x79, 0x7A, 0x79, 0x79, 0x7D, 0xFE, 0xFC, +0xF9, 0xF8, 0xF8, 0xF8, 0xF6, 0xF5, 0xF6, 0xF8, 0xFB, 0xFC, 0xFB, 0xFD, 0xFF, 0x7E, 0x7D, 0x7C, +0x7C, 0x7B, 0x7C, 0x7B, 0x79, 0x79, 0x7A, 0x79, 0x76, 0x74, 0x72, 0x72, 0x73, 0x74, 0x75, 0x77, +0x78, 0x78, 0x78, 0x77, 0x76, 0x75, 0x75, 0x78, 0x7A, 0x79, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0x7F, +0xFE, 0xFC, 0xFC, 0xFC, 0xFA, 0xF8, 0xF7, 0xF7, 0xF8, 0xF7, 0xF5, 0xF5, 0xF5, 0xF4, 0xF5, 0xF6, +0xF7, 0xF8, 0xF9, 0xFB, 0xFE, 0x7F, 0x7D, 0x7C, 0x7D, 0x7E, 0x7E, 0x7E, 0x7D, 0x7A, 0x7A, 0x7A, +0x7A, 0x79, 0x79, 0x79, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7A, 0x7A, 0x7A, 0x79, 0x77, 0x76, +0x77, 0x77, 0x77, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0x7E, 0x7B, +0x78, 0x78, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0xFF, 0x7F, 0x7F, 0xFE, +0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFC, 0xFE, 0x7F, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, +0x7B, 0x7A, 0x7B, 0x7B, 0x7B, 0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x76, 0x77, 0x78, 0x77, 0x79, +0x7A, 0x7A, 0x7B, 0x7C, 0x7C, 0x7B, 0x7A, 0x7B, 0x7D, 0x7B, 0x7B, 0x7D, 0x7C, 0x7D, 0xFF, 0x7E, +0xFF, 0xFD, 0xFB, 0xF9, 0xF8, 0xF9, 0xF9, 0xF7, 0xF6, 0xF5, 0xF4, 0xF3, 0xF3, 0xF5, 0xF6, 0xF6, +0xF7, 0xF9, 0xFB, 0xFB, 0xFA, 0xFA, 0xFB, 0xFC, 0xFB, 0xFD, 0xFD, 0xFB, 0xFB, 0xFB, 0xFA, 0xF8, +0xF8, 0xF9, 0xFB, 0xFD, 0x7E, 0x7B, 0x78, 0x78, 0x77, 0x77, 0x77, 0x76, 0x76, 0x76, 0x75, 0x75, +0x73, 0x71, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6E, 0x6E, 0x6F, 0x6F, 0x6E, 0x6E, 0x6E, 0x6D, +0x6D, 0x6E, 0x6D, 0x6D, 0x6E, 0x6F, 0x70, 0x72, 0x73, 0x74, 0x75, 0x79, 0x7C, 0x7D, 0x7E, 0xFF, +0xFF, 0xFF, 0xFD, 0xFC, 0xFA, 0xF9, 0xFB, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0x7E, 0x7B, 0x7A, +0x79, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7C, 0x7C, 0x7B, 0x79, 0x79, 0x78, 0x78, 0x79, 0x7A, 0x7C, +0x7E, 0x7E, 0x7E, 0x7C, 0x7B, 0x7A, 0x7A, 0x7A, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7D, 0xFF, 0xFD, +0xFC, 0xFB, 0xFA, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFE, 0xFE, 0xFC, 0xFB, 0xFB, 0xFB, +0xFB, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFD, 0xFC, 0xFC, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9, 0xF8, 0xF7, +0xF6, 0xF7, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0x7E, 0x7D, 0x7C, 0x7C, +0x7C, 0x7A, 0x7A, 0x79, 0x79, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, +0x7C, 0x7C, 0x7D, 0x7D, 0x7C, 0x7B, 0x78, 0x77, 0x76, 0x75, 0x75, 0x75, 0x76, 0x76, 0x75, 0x76, +0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7B, 0x7D, 0x7D, 0x7E, 0x7F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, +0xFD, 0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFF, 0x7F, 0x7E, 0x7C, 0x7C, 0x7B, +0x7A, 0x7A, 0x7A, 0x78, 0x78, 0x77, 0x77, 0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7B, 0x7C, 0x7D, 0x7B, +0x7A, 0x7B, 0x7C, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7A, 0x7B, 0x7F, 0xFD, 0x7D, 0x79, 0xFE, +0xFA, 0xFE, 0xFC, 0xF8, 0xFC, 0xFF, 0xFF, 0xFE, 0xFB, 0xFC, 0x7F, 0xFF, 0x7F, 0x7C, 0x7D, 0x7D, +0x7E, 0x7E, 0x7B, 0x7A, 0x7A, 0x7B, 0x7C, 0x7E, 0x7E, 0x7C, 0x7B, 0x7A, 0x7A, 0x7B, 0x7C, 0x7D, +0x7D, 0x7E, 0x7F, 0x7E, 0x7F, 0xFF, 0xFE, 0xFD, 0xFE, 0xFF, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7E, +0x7D, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x7A, 0x7A, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x75, 0x74, 0x73, +0x74, 0x75, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x77, 0x76, 0x77, 0x77, 0x79, 0x7B, 0x7C, 0x7D, +0x7D, 0x7D, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFE, 0xFD, 0xFE, 0xFF, 0xFE, 0xFD, 0xFB, 0xFC, 0xFD, +0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0x7F, 0x7D, 0x7E, +0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, +0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, +0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, 0x7F, 0x7E, +0x7D, 0x7C, 0x7B, 0x7B, 0x79, 0x77, 0x77, 0x78, 0x76, 0x76, 0x78, 0x7A, 0x78, 0x78, 0x78, 0x77, +0x77, 0x76, 0x75, 0x76, 0x75, 0x75, 0x77, 0x77, 0x76, 0x74, 0x74, 0x75, 0x76, 0x75, 0x76, 0x76, +0x75, 0x76, 0x76, 0x75, 0x74, 0x73, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x78, 0x7A, 0x7A, 0x7B, +0x7C, 0x7B, 0x7D, 0x7E, 0x7D, 0x7D, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFE, 0xFD, 0xFD, 0xFD, 0xFF, 0x7F, 0xFE, 0xFF, 0xFF, 0xFE, +0xFE, 0xFE, 0x7F, 0x7E, 0xFF, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFD, 0xFD, 0xFD, +0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0xFE, 0xFC, 0xFA, 0xF9, 0xF8, 0xF8, 0xF8, 0xF9, 0xFA, +0xFD, 0xFE, 0xFC, 0xFD, 0xFE, 0xFE, 0xFF, 0x7F, 0xFF, 0x7E, 0x7D, 0x7B, 0x79, 0x79, 0x7B, 0x7C, +0x7C, 0x7D, 0x7E, 0x7F, 0x7E, 0x7D, 0x7D, 0x7B, 0x7B, 0x7A, 0x77, 0x78, 0x75, 0x75, 0x76, 0x76, +0x78, 0x75, 0x76, 0x77, 0x73, 0x75, 0x73, 0x77, 0x76, 0x73, 0x78, 0x73, 0x78, 0x77, 0x75, 0x7B, +0x70, 0x7E, 0x68, 0x5B, 0xE4, 0xD9, 0x77, 0x66, 0x5F, 0x6B, 0xEB, 0x78, 0x6B, 0xEC, 0xE9, 0x67, +0x5A, 0x62, 0xF8, 0xE2, 0xF1, 0x6B, 0x6F, 0x72, 0x6E, 0x6D, 0x72, 0xEF, 0xE7, 0xF7, 0x6D, 0x6A, +0x70, 0x7B, 0xFC, 0xF5, 0xED, 0xEF, 0x7D, 0x71, 0x70, 0xFF, 0xEE, 0xEF, 0xF8, 0xFC, 0x7B, 0x73, +0x6F, 0x71, 0x7E, 0xF2, 0xF2, 0x76, 0x67, 0x68, 0x78, 0xF7, 0xF5, 0xFC, 0x7E, 0x7B, 0x73, 0x70, +0x79, 0xF4, 0xEB, 0xEC, 0xF8, 0x7C, 0x7B, 0xFF, 0xF6, 0xEF, 0xEF, 0xF4, 0xF8, 0xFE, 0x7D, 0xFE, +0xF8, 0xF4, 0xF4, 0xF9, 0xFE, 0x7E, 0x7C, 0x7C, 0xFD, 0xF8, 0xF8, 0xFD, 0x7D, 0x7A, 0x79, 0x7C, +0xFF, 0xFD, 0xFB, 0xFC, 0x7D, 0x7B, 0x7D, 0x7F, 0xFD, 0xFD, 0xFF, 0x7E, 0x7C, 0x7A, 0x79, 0x7C, +0x7E, 0x7D, 0x7D, 0x7B, 0x78, 0x79, 0x7B, 0x7A, 0x78, 0x79, 0x77, 0x76, 0x78, 0x71, 0x70, 0x78, +0x7E, 0xF6, 0xFE, 0x67, 0x68, 0xF4, 0xEF, 0x74, 0x69, 0x6A, 0xFF, 0x7E, 0x6E, 0xF2, 0xFB, 0x69, +0x66, 0x69, 0xDD, 0xD9, 0x71, 0x7B, 0x74, 0x5F, 0x69, 0x61, 0x6A, 0xE6, 0xEC, 0x66, 0x55, 0x50, +0x5C, 0xFB, 0xED, 0xF5, 0xFA, 0x6F, 0x6E, 0x7B, 0xE8, 0xCF, 0xC7, 0xC6, 0xCA, 0xCB, 0xDB, 0x3A, +0x2E, 0x49, 0xBD, 0xB7, 0xC6, 0x4D, 0x41, 0x4B, 0x49, 0x4D, 0xD9, 0xBF, 0xC2, 0xFD, 0x3F, 0x3D, +0x51, 0xDF, 0xCD, 0xCC, 0xD5, 0xF4, 0x50, 0x46, 0x4D, 0xF0, 0xCB, 0xCA, 0xDA, 0x61, 0x51, 0x52, +0x5B, 0xE6, 0xD0, 0xCE, 0xDC, 0x5D, 0x53, 0x51, 0x6A, 0xF9, 0x48, 0x67, 0xC2, 0xE0, 0x5F, 0x5B, +0x4C, 0x71, 0xFA, 0x6E, 0xCE, 0xCF, 0x7A, 0x64, 0x79, 0xD8, 0xCE, 0xD1, 0xCD, 0xC3, 0xC5, 0xCD, +0xC7, 0xDC, 0x42, 0x3E, 0x53, 0xD2, 0xC0, 0xDE, 0x44, 0x48, 0x58, 0x53, 0x59, 0xFA, 0xD9, 0xD6, +0x5E, 0x43, 0x47, 0x61, 0xE1, 0xD8, 0xEA, 0x64, 0x46, 0x3C, 0x51, 0x7F, 0x77, 0xD0, 0xF6, 0x4B, +0x4B, 0x4A, 0x6F, 0xCA, 0xC6, 0xC9, 0xC7, 0xC2, 0xC8, 0xBD, 0xB0, 0xAB, 0xBB, 0x1F, 0x19, 0x5F, +0xA3, 0xA5, 0xBA, 0x30, 0x30, 0x47, 0x31, 0x37, 0xBC, 0xAB, 0xB8, 0x3D, 0x2B, 0x30, 0x4E, 0xBD, +0xB4, 0xC4, 0x5D, 0x3F, 0x38, 0x41, 0x6E, 0xC8, 0xC1, 0xDC, 0x4B, 0x3B, 0x3F, 0xE5, 0xBF, 0xBC, +0xC8, 0xE5, 0xDE, 0xC0, 0xAE, 0xAD, 0xAF, 0xC1, 0x20, 0x1A, 0x63, 0xA8, 0xA7, 0xB5, 0x36, 0x2E, +0x3D, 0x32, 0x3F, 0xBD, 0xB1, 0xC1, 0x39, 0x2E, 0x42, 0xE8, 0xCA, 0xC3, 0xDB, 0x5F, 0x47, 0x39, +0x47, 0xD5, 0xCB, 0xD1, 0x70, 0x4B, 0x4D, 0xF0, 0xC1, 0xB3, 0xAE, 0xB4, 0xBE, 0xB8, 0xB8, 0x34, +0x1C, 0x27, 0xB6, 0xA3, 0xAC, 0x4F, 0x2C, 0x32, 0x3B, 0x3E, 0xEB, 0xB9, 0xBB, 0x45, 0x2E, 0x39, +0x60, 0xC3, 0xBB, 0xD8, 0x4D, 0x45, 0x41, 0x57, 0xD6, 0xDE, 0x79, 0x5D, 0x50, 0x5B, 0xDB, 0xBE, +0xB4, 0xB3, 0xBC, 0xC4, 0xB6, 0xAC, 0xC2, 0x26, 0x1A, 0x30, 0xAB, 0xA9, 0xBB, 0x61, 0x33, 0x30, +0x36, 0x39, 0xCF, 0xB9, 0x64, 0x41, 0x42, 0x3E, 0x5E, 0xD3, 0xCF, 0xC4, 0xEC, 0x47, 0x56, 0x5C, +0x50, 0x57, 0x62, 0xDF, 0xD2, 0xD3, 0xC4, 0xB6, 0xB3, 0xBA, 0xB8, 0xAD, 0xAF, 0x3C, 0x1C, 0x1E, +0xCB, 0xA1, 0xA9, 0xFE, 0x2D, 0x2C, 0x39, 0x3D, 0x64, 0xBE, 0xD5, 0x4B, 0x42, 0x3A, 0x40, 0xEC, +0xC4, 0xBE, 0xD1, 0x4A, 0x3E, 0x47, 0x62, 0xE4, 0xD7, 0xD6, 0xDC, 0xDE, 0xCD, 0xB6, 0xAD, 0xAE, +0xAC, 0xAD, 0xE6, 0x22, 0x19, 0x2E, 0xA6, 0x9E, 0xB2, 0x39, 0x28, 0x2D, 0x39, 0x4E, 0xC2, 0xBE, +0x5B, 0x3E, 0x3B, 0x3C, 0x58, 0xC6, 0xBD, 0xC7, 0x60, 0x3F, 0x3F, 0x51, 0xED, 0xCF, 0xC8, 0xD1, +0xE0, 0xD9, 0xBC, 0xAC, 0xAB, 0xAB, 0xA9, 0xC2, 0x25, 0x17, 0x22, 0xAE, 0x9D, 0xA9, 0x47, 0x26, +0x29, 0x34, 0x47, 0xC5, 0xBB, 0x77, 0x3F, 0x3A, 0x38, 0x4E, 0xC6, 0xBC, 0xBE, 0xE6, 0x3D, 0x39, +0x43, 0x67, 0xCE, 0xC7, 0xD6, 0xED, 0xD9, 0xBD, 0xAB, 0xAB, 0xAE, 0xA9, 0xB4, 0x30, 0x1A, 0x1B, +0xD5, 0x9D, 0xA3, 0xDA, 0x2A, 0x26, 0x31, 0x3C, 0x6C, 0xBF, 0xCE, 0x5E, 0x42, 0x32, 0x3C, 0xD6, +0xBC, 0xB8, 0xCC, 0x3F, 0x37, 0x3B, 0x51, 0xCC, 0xC1, 0xCC, 0xE2, 0xDE, 0xBD, 0xAC, 0xAA, 0xA9, +0xA7, 0xC5, 0x26, 0x18, 0x1F, 0xB7, 0x9D, 0xA6, 0xDF, 0x2B, 0x26, 0x2D, 0x37, 0xEB, 0xBA, 0xCB, +0x5E, 0x3C, 0x30, 0x44, 0xC9, 0xBB, 0xB8, 0xCF, 0x3D, 0x34, 0x3B, 0x5F, 0xC1, 0xBE, 0xCE, 0xD6, +0xCE, 0xB8, 0xAB, 0xAA, 0xA4, 0xA8, 0x42, 0x1C, 0x18, 0x31, 0xA4, 0x9F, 0xAF, 0x48, 0x29, 0x28, +0x2C, 0x37, 0xCC, 0xBA, 0xC7, 0x57, 0x30, 0x31, 0x5A, 0xC6, 0xB6, 0xB7, 0x5F, 0x38, 0x34, 0x3D, +0xE2, 0xBD, 0xBD, 0xC7, 0xD2, 0xCA, 0xB2, 0xAB, 0xA7, 0xA2, 0xB3, 0x29, 0x18, 0x1C, 0xD2, 0x9F, +0xA5, 0xBC, 0x3A, 0x2A, 0x29, 0x2A, 0x3E, 0xC3, 0xBB, 0xC1, 0x43, 0x2D, 0x3A, 0xF5, 0xC1, 0xB5, +0xBE, 0x4F, 0x36, 0x32, 0x3F, 0xD2, 0xBB, 0xBA, 0xBE, 0xC5, 0xBF, 0xB1, 0xAB, 0xA4, 0xA7, 0x75, +0x1F, 0x18, 0x27, 0xAE, 0xA2, 0xAD, 0xD6, 0x36, 0x2B, 0x28, 0x2C, 0x4E, 0xC2, 0xB8, 0xC9, 0x35, +0x2F, 0x42, 0x71, 0xBA, 0xB4, 0xD2, 0x44, 0x34, 0x34, 0x4C, 0xCD, 0xBE, 0xBB, 0xB9, 0xBC, 0xB3, +0xAE, 0xAB, 0xA3, 0xB0, 0x2C, 0x1A, 0x1C, 0x5F, 0xA4, 0xA9, 0xBA, 0x6F, 0x34, 0x28, 0x26, 0x32, +0x77, 0xB9, 0xB3, 0x5E, 0x32, 0x38, 0x40, 0xD8, 0xB6, 0xBE, 0xF4, 0x40, 0x34, 0x3A, 0x5B, 0xC7, +0xB7, 0xB4, 0xB7, 0xB4, 0xB2, 0xAE, 0xA5, 0xAB, 0x3B, 0x1D, 0x1B, 0x34, 0xAE, 0xAA, 0xB4, 0xC7, +0x42, 0x2C, 0x25, 0x2B, 0x43, 0xCF, 0xB5, 0xBE, 0x3F, 0x38, 0x3D, 0x4D, 0xC4, 0xBD, 0xCF, 0x5D, +0x3E, 0x38, 0x43, 0xE4, 0xBF, 0xB4, 0xAF, 0xB0, 0xAF, 0xAE, 0xA8, 0xA7, 0xF6, 0x21, 0x1A, 0x27, +0xBA, 0xAC, 0xB5, 0xB9, 0xE2, 0x36, 0x26, 0x25, 0x33, 0x4E, 0xBA, 0xB2, 0x64, 0x41, 0x3F, 0x3D, +0xE6, 0xC6, 0xCD, 0xD4, 0x50, 0x3D, 0x3C, 0x48, 0xD4, 0xB9, 0xAF, 0xAD, 0xAE, 0xAE, 0xAA, 0xA7, +0xC0, 0x2A, 0x1B, 0x1F, 0x65, 0xAF, 0xB5, 0xB5, 0xBF, 0x4C, 0x2C, 0x23, 0x2A, 0x37, 0xE6, 0xAF, +0xBC, 0x5B, 0x4B, 0x3B, 0x49, 0xCF, 0xCE, 0xD0, 0xDE, 0x4F, 0x40, 0x3F, 0x57, 0xC7, 0xB3, 0xAA, +0xA9, 0xAC, 0xAE, 0xA9, 0xAE, 0x3B, 0x1E, 0x1E, 0x37, 0xBA, 0xB7, 0xB7, 0xB5, 0xC9, 0x3A, 0x26, +0x27, 0x2E, 0x37, 0xC1, 0xB1, 0xCA, 0xE8, 0x49, 0x3E, 0x62, 0x78, 0xEF, 0xD7, 0x69, 0x4F, 0x44, +0x48, 0xFB, 0xC5, 0xAF, 0xA9, 0xA8, 0xAA, 0xAB, 0xAA, 0xCF, 0x26, 0x1C, 0x22, 0x4A, 0xBD, 0xBB, +0xAF, 0xB1, 0xD7, 0x31, 0x25, 0x27, 0x28, 0x38, 0xB9, 0xB6, 0xC3, 0xCB, 0x4B, 0x45, 0x4E, 0x47, +0x62, 0xE0, 0xF9, 0x5C, 0x4C, 0x5C, 0xE4, 0xBF, 0xAD, 0xA8, 0xA5, 0xA7, 0xA9, 0xB2, 0x36, 0x20, +0x1E, 0x29, 0x56, 0xCC, 0xB8, 0xAC, 0xB5, 0xFA, 0x2F, 0x28, 0x25, 0x25, 0x45, 0xBE, 0xBF, 0xB8, +0xC5, 0x5F, 0x54, 0x41, 0x43, 0x4F, 0x56, 0x75, 0x70, 0xFE, 0xE2, 0xD3, 0xB9, 0xAD, 0xA8, 0xA6, +0xA6, 0xA8, 0xCA, 0x2D, 0x22, 0x21, 0x2E, 0x47, 0x77, 0xB4, 0xAD, 0xB7, 0xDC, 0x39, 0x2D, 0x24, +0x28, 0x40, 0x5A, 0xC7, 0xB5, 0xBD, 0xC0, 0xDB, 0x4E, 0x4C, 0x40, 0x44, 0x4E, 0x56, 0xDA, 0xCC, +0xC0, 0xB1, 0xAC, 0xA7, 0xA5, 0xA6, 0xAD, 0x4F, 0x2A, 0x23, 0x25, 0x2F, 0x39, 0x6C, 0xB6, 0xB1, +0xB7, 0xD6, 0x43, 0x2F, 0x26, 0x2C, 0x35, 0x3A, 0xDF, 0xC7, 0xBE, 0xBA, 0xCB, 0xD4, 0x6E, 0x48, +0x44, 0x3E, 0x4A, 0x6C, 0xD6, 0xB9, 0xB0, 0xA8, 0xA4, 0xA5, 0xA4, 0xB5, 0x42, 0x2C, 0x23, 0x27, +0x2B, 0x2E, 0x55, 0xC2, 0xB9, 0xB6, 0xC5, 0xF4, 0x3C, 0x32, 0x34, 0x2F, 0x37, 0x4A, 0x5B, 0xCF, +0xC9, 0xC6, 0xC0, 0xCA, 0xCF, 0xF4, 0x52, 0x51, 0x4E, 0xF8, 0xC4, 0xB7, 0xAD, 0xA9, 0xA6, 0xA7, +0xB8, 0x5D, 0x38, 0x2F, 0x2E, 0x2B, 0x2C, 0x35, 0x42, 0x5D, 0x7D, 0xE3, 0xDF, 0x6F, 0x73, 0x5A, +0x4D, 0x55, 0x4F, 0x4F, 0x58, 0x5C, 0x6E, 0xFA, 0xE2, 0xD4, 0xD4, 0xD6, 0xD9, 0xD6, 0xCC, 0xC6, +0xBF, 0xBB, 0xB8, 0xB6, 0xBC, 0xC9, 0xDC, 0x60, 0x59, 0x53, 0x4A, 0x49, 0x46, 0x45, 0x46, 0x43, +0x45, 0x45, 0x49, 0x56, 0x5A, 0x5D, 0x6E, 0x72, 0x7C, 0x74, 0x6D, 0x7A, 0x7A, 0xFC, 0xED, 0xE8, +0xEB, 0xFF, 0xFD, 0xEC, 0xDE, 0xD2, 0xCC, 0xC7, 0xC5, 0xCA, 0xD2, 0xD9, 0xDB, 0xD4, 0xCF, 0xD1, +0xD9, 0xE7, 0xFC, 0x6E, 0x60, 0x57, 0x50, 0x4C, 0x49, 0x47, 0x46, 0x45, 0x47, 0x4A, 0x4D, 0x4F, +0x4F, 0x53, 0x5A, 0x5F, 0x62, 0x60, 0x62, 0x6B, 0x77, 0xEC, 0xD8, 0xCC, 0xC7, 0xC7, 0xCB, 0xCF, +0xD3, 0xD3, 0xCE, 0xCB, 0xCA, 0xCC, 0xCF, 0xD4, 0xD9, 0xDF, 0xEB, 0xFE, 0x6A, 0x58, 0x4D, 0x46, +0x43, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x52, 0x54, 0x55, 0x54, 0x57, 0x5C, 0x61, 0x72, 0xE5, +0xD4, 0xCC, 0xCB, 0xCD, 0xD0, 0xD4, 0xD3, 0xD1, 0xD0, 0xCF, 0xD1, 0xD2, 0xD4, 0xD6, 0xD9, 0xDB, +0xDB, 0xDD, 0xEC, 0x6B, 0x59, 0x53, 0x54, 0x57, 0x59, 0x58, 0x57, 0x5A, 0x5C, 0x5A, 0x55, 0x52, +0x52, 0x51, 0x51, 0x57, 0x61, 0xFC, 0xE3, 0xDF, 0xE0, 0xE4, 0xE3, 0xE0, 0xDF, 0xDE, 0xDD, 0xDE, +0xDD, 0xDF, 0xE0, 0xDF, 0xDC, 0xD9, 0xDC, 0xE7, 0x7E, 0x6B, 0x6D, 0x7C, 0xEE, 0xE6, 0xE7, 0xEA, +0xEC, 0xF5, 0x7A, 0x6A, 0x61, 0x5A, 0x51, 0x4F, 0x50, 0x55, 0x5D, 0x62, 0x63, 0x60, 0x5F, 0x61, +0x65, 0x68, 0x6D, 0x75, 0xFA, 0xF1, 0xF1, 0xEE, 0xE6, 0xDD, 0xDB, 0xDE, 0xEB, 0x79, 0x6B, 0x6F, +0xF7, 0xE2, 0xDC, 0xDB, 0xDA, 0xDA, 0xDC, 0xDD, 0xDE, 0xE0, 0xF1, 0x6B, 0x5F, 0x5F, 0x66, 0x6B, +0x6A, 0x65, 0x5E, 0x5B, 0x5A, 0x59, 0x5A, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x68, 0xFC, 0xE8, 0xE5, +0xEB, 0xFB, 0x71, 0x6D, 0x78, 0xEE, 0xE2, 0xDE, 0xDD, 0xDC, 0xDE, 0xDF, 0xDC, 0xD9, 0xD9, 0xE0, +0xED, 0xF0, 0xEC, 0xE4, 0xE2, 0xE6, 0xEE, 0x7C, 0x6D, 0x65, 0x5E, 0x5E, 0x62, 0x64, 0x61, 0x5C, +0x5B, 0x5F, 0x70, 0xF7, 0xF8, 0x78, 0x6B, 0x65, 0x61, 0x69, 0xFA, 0xE9, 0xE5, 0xE2, 0xE5, 0xEA, +0xED, 0xEB, 0xE5, 0xE5, 0xED, 0xF9, 0xFC, 0xEF, 0xE3, 0xDE, 0xDE, 0xE1, 0xE9, 0xF4, 0x74, 0x6A, +0x6B, 0x6F, 0x6F, 0x67, 0x5E, 0x5C, 0x5F, 0x6A, 0x6F, 0x6C, 0x66, 0x5F, 0x5D, 0x5E, 0x64, 0x6F, +0xFE, 0xEF, 0xEC, 0xF2, 0xFD, 0x7E, 0xFB, 0xF6, 0xFF, 0x6F, 0x6A, 0x6A, 0x74, 0xF4, 0xE9, 0xE4, +0xE7, 0xEE, 0x7D, 0x6A, 0x69, 0x6F, 0xFE, 0xF7, 0x7B, 0x6B, 0x68, 0x6E, 0x79, 0x78, 0x6F, 0x69, +0x62, 0x5F, 0x60, 0x66, 0x72, 0xF6, 0xEB, 0xEC, 0xF3, 0xFC, 0xFA, 0xF2, 0xF2, 0xFE, 0x70, 0x69, +0x69, 0x71, 0xF7, 0xE8, 0xE3, 0xE4, 0xED, 0x76, 0x69, 0x6A, 0x6F, 0x7E, 0xFB, 0x7D, 0x75, 0x73, +0x7C, 0xFB, 0xFC, 0x7D, 0x73, 0x6D, 0x6A, 0x69, 0x6F, 0xFD, 0xEC, 0xE8, 0xED, 0xF6, 0xF7, 0xF1, +0xED, 0xEF, 0xF6, 0x7E, 0x76, 0x78, 0xFB, 0xEC, 0xE2, 0xDE, 0xE0, 0xEB, 0xFE, 0x73, 0x73, 0x7E, +0xFA, 0xFC, 0xFF, 0x7B, 0x7D, 0xFC, 0xFE, 0x7B, 0x74, 0x6F, 0x6D, 0x6C, 0x6E, 0x77, 0xFA, 0xEE, +0xED, 0xF6, 0x7A, 0x73, 0x77, 0x7B, 0x7C, 0x78, 0x6E, 0x6B, 0x6F, 0x7C, 0xEF, 0xE7, 0xE2, 0xE6, +0xF2, 0x7A, 0x71, 0x75, 0x7D, 0xFE, 0xFD, 0xFD, 0xFB, 0xF5, 0xF7, 0xFE, 0x77, 0x6E, 0x6A, 0x67, +0x67, 0x6C, 0x76, 0xF7, 0xEE, 0xEF, 0xFA, 0x7B, 0x78, 0x7B, 0xFF, 0x7F, 0x78, 0x6F, 0x6C, 0x6C, +0x72, 0xFE, 0xEF, 0xEC, 0xEF, 0xFD, 0x76, 0x70, 0x71, 0x75, 0x7A, 0x7E, 0x7E, 0xFF, 0xFC, 0xFD, +0x7C, 0x73, 0x6D, 0x69, 0x65, 0x63, 0x65, 0x6B, 0x79, 0xFB, 0xFD, 0x78, 0x70, 0x70, 0x74, 0x79, +0x7C, 0x7B, 0x79, 0x77, 0x78, 0x7F, 0xF4, 0xED, 0xED, 0xF2, 0xFB, 0x7A, 0x74, 0x74, 0x76, 0x7A, +0x7F, 0xFB, 0xF5, 0xF4, 0xF6, 0xFA, 0x7D, 0x75, 0x6E, 0x6B, 0x6B, 0x6F, 0x7D, 0xF3, 0xEF, 0xF4, +0x7E, 0x78, 0x7A, 0xFF, 0xFA, 0xF7, 0xF5, 0xF4, 0xF4, 0xF1, 0xED, 0xE9, 0xE6, 0xE8, 0xEE, 0xF8, +0x7F, 0x7C, 0x7A, 0x7A, 0x7B, 0x7D, 0xFD, 0xF8, 0xF8, 0xF9, 0xFC, 0x7D, 0x74, 0x6C, 0x69, 0x69, +0x6C, 0x76, 0xFA, 0xF6, 0xFD, 0x78, 0x71, 0x6F, 0x6F, 0x6F, 0x71, 0x74, 0x77, 0x7C, 0xFD, 0xF5, +0xEC, 0xE9, 0xEA, 0xEF, 0xFB, 0x7A, 0x74, 0x73, 0x73, 0x73, 0x73, 0x78, 0x7E, 0xFE, 0xFD, 0xFE, +0x7B, 0x74, 0x6D, 0x68, 0x66, 0x69, 0x6F, 0x7B, 0x7F, 0x7C, 0x77, 0x73, 0x72, 0x6F, 0x6D, 0x6D, +0x6D, 0x6D, 0x6E, 0x72, 0x7A, 0xFA, 0xF1, 0xEE, 0xEF, 0xF6, 0xFD, 0x7D, 0x7B, 0x7A, 0x78, 0x78, +0x79, 0x79, 0x7A, 0x7C, 0x7D, 0x7E, 0x7D, 0x77, 0x70, 0x6E, 0x71, 0x79, 0x7E, 0x7E, 0x7E, 0x7D, +0x7E, 0x7D, 0x7C, 0x7A, 0x78, 0x76, 0x74, 0x73, 0x75, 0x7A, 0xFC, 0xF6, 0xF4, 0xF4, 0xF6, 0xF6, +0xF6, 0xF9, 0xF9, 0xF7, 0xF5, 0xF3, 0xF1, 0xF1, 0xF3, 0xF5, 0xF7, 0xFA, 0x7B, 0x6F, 0x6D, 0x6D, +0x6F, 0x6F, 0x6E, 0x6E, 0x70, 0x70, 0x71, 0x74, 0x78, 0x7C, 0x7D, 0x7E, 0x7D, 0xFF, 0xFB, 0xF7, +0xF4, 0xF4, 0xF6, 0xF8, 0xFB, 0xFD, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x7F, 0xFF, 0xFC, 0xF8, +0xF9, 0xFD, 0x7D, 0x7C, 0x7F, 0xFE, 0x7E, 0x7C, 0x7A, 0x79, 0x77, 0x75, 0x75, 0x76, 0x79, 0x76, +0x71, 0x6F, 0x6F, 0x71, 0x76, 0x78, 0x78, 0x78, 0x7B, 0x7D, 0x7A, 0x77, 0x76, 0x76, 0x78, 0x79, +0x78, 0x79, 0x7C, 0xFD, 0xF4, 0xF1, 0xF2, 0xF5, 0xF9, 0xFB, 0x7F, 0x79, 0x76, 0x76, 0x78, 0x77, +0x77, 0x7B, 0xFF, 0xFA, 0xF6, 0xF6, 0xF7, 0xF6, 0xF6, 0xF7, 0xF9, 0xFA, 0xF9, 0xF6, 0xF6, 0xF9, +0xFB, 0xFE, 0x7F, 0x7E, 0x7C, 0x79, 0x7A, 0xFE, 0xF5, 0xEF, 0xEE, 0xEF, 0xF1, 0xF3, 0xF4, 0xFB, +0x79, 0x73, 0x72, 0x6E, 0x6B, 0x68, 0x68, 0x6C, 0x73, 0x7A, 0x7C, 0x7B, 0x7B, 0x7D, 0x7D, 0xFD, +0xF6, 0xF0, 0xEE, 0xEF, 0xF6, 0xFB, 0xFF, 0x7D, 0x7F, 0x7D, 0x7A, 0x7A, 0x7B, 0x7C, 0x7D, 0x7B, +0x7A, 0xFF, 0xFD, 0xFF, 0x7E, 0x7A, 0x75, 0x74, 0x71, 0x6F, 0x6F, 0x70, 0x77, 0x7A, 0x78, 0x75, +0x72, 0x75, 0x73, 0x6F, 0x6F, 0x70, 0x75, 0x77, 0x76, 0x78, 0x75, 0x78, 0x7B, 0x7B, 0x7F, 0x7B, +0x7E, 0x7F, 0x7E, 0x7E, 0x77, 0x79, 0x73, 0x71, 0x71, 0x6B, 0x6F, 0x60, 0x5B, 0x6F, 0x72, 0x69, +0x71, 0x72, 0x7E, 0xFC, 0xF7, 0xEE, 0xF4, 0xFB, 0x7E, 0x7E, 0xFC, 0xF9, 0xFD, 0x7F, 0xFC, 0x72, +0x78, 0x64, 0x53, 0x71, 0xDF, 0xF0, 0xEB, 0xE9, 0xF0, 0x7C, 0x7B, 0xEA, 0xF6, 0x7E, 0x79, 0x6C, +0x79, 0x5F, 0x5B, 0xEC, 0xE2, 0xEF, 0xED, 0xF1, 0xF7, 0xFE, 0x7C, 0xFE, 0x75, 0x6E, 0x75, 0x79, +0x7A, 0x72, 0x6E, 0x75, 0x7A, 0x7B, 0x77, 0x77, 0xFE, 0xF8, 0xF6, 0xF5, 0xEB, 0xE9, 0xEC, 0xE8, +0xEE, 0xEC, 0xED, 0x77, 0xFD, 0x61, 0x51, 0x66, 0xE7, 0xDC, 0xD8, 0xD3, 0xD3, 0x6C, 0x52, 0x63, +0x6F, 0x73, 0x7F, 0xFB, 0xF4, 0x79, 0x7B, 0xF1, 0xED, 0xEC, 0xFA, 0x76, 0x7A, 0x74, 0x6B, 0x6B, +0x75, 0x7C, 0x7C, 0x79, 0xFE, 0xF6, 0xFE, 0x7A, 0x71, 0x75, 0xFF, 0x70, 0x6D, 0x6E, 0x69, 0x66, +0x5E, 0x62, 0xFA, 0xEA, 0xE5, 0xE0, 0xE1, 0xE5, 0xEE, 0xF1, 0xE5, 0xE4, 0xEA, 0xE8, 0xE7, 0xE7, +0xE3, 0xE7, 0xE8, 0xE8, 0xEF, 0xF7, 0x78, 0x6E, 0x6D, 0x60, 0x5A, 0x57, 0x54, 0x53, 0x51, 0x50, +0x52, 0x54, 0x57, 0x59, 0x5D, 0x67, 0x70, 0x7B, 0xF5, 0xE5, 0xDA, 0xD5, 0xD2, 0xCD, 0xC4, 0xBE, +0xBB, 0xB7, 0xB5, 0xBB, 0xCB, 0xDE, 0xE9, 0x56, 0x3F, 0x3A, 0x39, 0x3B, 0x3B, 0x3A, 0x3F, 0x4E, +0x5D, 0x69, 0xF2, 0xDD, 0xD9, 0xE2, 0xF3, 0xF4, 0x72, 0x5C, 0x53, 0x4E, 0x4D, 0x4E, 0x4E, 0x4F, +0x58, 0x7E, 0xDA, 0xCB, 0xBF, 0xBA, 0xB7, 0xB4, 0xB0, 0xAE, 0xB2, 0xBE, 0xD7, 0x70, 0x4E, 0x3B, +0x32, 0x30, 0x33, 0x35, 0x35, 0x3A, 0x49, 0x5F, 0x7E, 0xEF, 0xE1, 0xD2, 0xD1, 0xE6, 0xEF, 0xF7, +0x5F, 0x4F, 0x48, 0x48, 0x4B, 0x48, 0x4B, 0x55, 0x72, 0xE1, 0xD2, 0xC2, 0xBA, 0xB6, 0xB3, 0xB0, +0xAD, 0xAE, 0xBA, 0xD0, 0x64, 0x4C, 0x3C, 0x30, 0x2E, 0x2F, 0x33, 0x35, 0x3A, 0x47, 0x6C, 0xE6, +0xEB, 0xD0, 0xC6, 0xCC, 0xD6, 0xE3, 0xEF, 0x69, 0x4E, 0x4B, 0x4B, 0x47, 0x46, 0x48, 0x4F, 0x61, +0xFE, 0xD1, 0xBE, 0xB8, 0xB5, 0xB2, 0xAF, 0xAD, 0xAE, 0xBA, 0xCD, 0x5F, 0x47, 0x3B, 0x2F, 0x2D, +0x2E, 0x30, 0x35, 0x3B, 0x47, 0x6C, 0xF4, 0xE2, 0xCB, 0xC7, 0xCD, 0xD7, 0xDD, 0xE3, 0x6E, 0x4E, +0x4A, 0x4B, 0x48, 0x47, 0x4A, 0x5B, 0xE4, 0xD3, 0xC0, 0xB7, 0xB3, 0xB0, 0xAF, 0xAC, 0xAC, 0xB3, +0xC4, 0x7D, 0x4C, 0x3E, 0x30, 0x2C, 0x2E, 0x31, 0x35, 0x3A, 0x45, 0x62, 0xFA, 0xEB, 0xCE, 0xCA, +0xD2, 0xDA, 0xE7, 0xE9, 0x6D, 0x4C, 0x49, 0x49, 0x47, 0x48, 0x4C, 0x68, 0xD7, 0xCA, 0xBC, 0xB5, +0xB2, 0xB0, 0xAE, 0xAC, 0xAE, 0xB9, 0xCE, 0x5D, 0x45, 0x39, 0x2F, 0x2D, 0x2E, 0x31, 0x36, 0x3B, +0x47, 0x5C, 0x6E, 0xE4, 0xD3, 0xD3, 0xD4, 0xDA, 0xDE, 0xEB, 0x5B, 0x4D, 0x4A, 0x47, 0x48, 0x49, +0x54, 0xEB, 0xCE, 0xBE, 0xB8, 0xB7, 0xB3, 0xB3, 0xB5, 0xB3, 0xBB, 0xC9, 0xC8, 0xED, 0x47, 0x42, +0x3A, 0x36, 0x37, 0x34, 0x39, 0x3E, 0x3F, 0x47, 0x4E, 0x65, 0xDE, 0xEC, 0xDC, 0xCE, 0xD9, 0xEB, +0x5F, 0x54, 0x51, 0x47, 0x46, 0x4C, 0x58, 0xFC, 0xD8, 0xC4, 0xBB, 0xBA, 0xB8, 0xB5, 0xB2, 0xAF, +0xB0, 0xB6, 0xBD, 0xCC, 0x66, 0x47, 0x3B, 0x34, 0x32, 0x32, 0x34, 0x38, 0x3B, 0x3F, 0x4B, 0x58, +0x69, 0xE9, 0xD9, 0xD4, 0xDB, 0x77, 0x5C, 0x59, 0x4F, 0x4A, 0x4B, 0x51, 0x69, 0xE0, 0xCE, 0xC2, +0xBD, 0xBC, 0xBA, 0xB8, 0xB7, 0xB4, 0xB2, 0xB7, 0xC3, 0xCE, 0xD4, 0x67, 0x44, 0x3D, 0x3C, 0x3B, +0x38, 0x38, 0x3B, 0x3F, 0x42, 0x46, 0x4E, 0x5F, 0x6A, 0x6B, 0xFD, 0xF7, 0x70, 0x5C, 0x54, 0x58, +0x58, 0x53, 0x5B, 0x73, 0xE5, 0xD2, 0xCA, 0xC6, 0xC2, 0xBF, 0xBE, 0xBE, 0xBD, 0xBB, 0xBC, 0xC3, +0xCA, 0xD0, 0xE2, 0x5F, 0x4E, 0x4A, 0x44, 0x3E, 0x3D, 0x3D, 0x3F, 0x42, 0x44, 0x4B, 0x55, 0x57, +0x5F, 0x69, 0x68, 0x63, 0x58, 0x56, 0x5B, 0x56, 0x57, 0x66, 0x79, 0xE8, 0xD9, 0xCF, 0xCB, 0xCB, +0xC8, 0xC4, 0xC5, 0xC6, 0xC9, 0xC9, 0xC6, 0xCD, 0xD4, 0xD8, 0xE2, 0xF1, 0x66, 0x5C, 0x57, 0x4C, +0x49, 0x49, 0x48, 0x49, 0x49, 0x4B, 0x51, 0x51, 0x4F, 0x53, 0x56, 0x58, 0x58, 0x54, 0x58, 0x5F, +0x5E, 0x5B, 0x63, 0xF2, 0xE5, 0xE5, 0xD7, 0xCF, 0xD2, 0xD6, 0xD1, 0xCF, 0xD6, 0xD6, 0xD2, 0xCF, +0xCE, 0xD0, 0xD8, 0xDB, 0xDB, 0xE5, 0x6D, 0x67, 0x65, 0x5C, 0x58, 0x54, 0x59, 0x5D, 0x57, 0x57, +0x5B, 0x5B, 0x59, 0x56, 0x57, 0x5A, 0x56, 0x52, 0x5A, 0x5C, 0x5D, 0x7D, 0xF1, 0xF3, 0xE7, 0xE3, +0xDF, 0xDB, 0xDA, 0xE7, 0xEC, 0xDE, 0xE5, 0xE9, 0xE6, 0xE4, 0xD6, 0xDF, 0xF8, 0xDE, 0xE9, 0x7C, +0xEE, 0xFB, 0x7A, 0x6B, 0x65, 0xFF, 0x79, 0x69, 0x6B, 0x63, 0x65, 0x62, 0x56, 0x5A, 0x60, 0x55, +0x58, 0x62, 0x5E, 0x64, 0x79, 0x7C, 0x78, 0xED, 0xE1, 0xEC, 0xF0, 0xE4, 0xF0, 0x6E, 0x7C, 0xED, +0xDD, 0xDB, 0xFE, 0x73, 0xED, 0xF0, 0xFF, 0xF9, 0xDE, 0xDC, 0x76, 0x6E, 0xFB, 0x7B, 0xFB, 0x6F, +0x6F, 0xEF, 0x7B, 0x6E, 0xF8, 0xE9, 0x7E, 0x5B, 0x5F, 0xF3, 0xFD, 0x67, 0x74, 0xEA, 0xEF, 0x77, +0x6D, 0x7C, 0xE8, 0xE2, 0xEE, 0xFB, 0xE6, 0xED, 0x66, 0x6C, 0x7B, 0x7C, 0xF4, 0xEF, 0xE2, 0xE6, +0x72, 0x70, 0xF0, 0xEE, 0x6E, 0x6B, 0xFB, 0xF5, 0xF6, 0x71, 0x6A, 0x6C, 0x65, 0x67, 0x5F, 0x5D, +0x6B, 0x62, 0x65, 0xFD, 0xED, 0xE9, 0xF2, 0xED, 0xE3, 0xE7, 0xE4, 0xE8, 0xED, 0xEF, 0x66, 0x5E, +0x79, 0x7E, 0x78, 0xF5, 0xFA, 0x79, 0x7A, 0xF5, 0xE7, 0xE2, 0xE4, 0xF2, 0xFF, 0x73, 0x66, 0x6B, +0x70, 0xFD, 0xEF, 0x6F, 0x67, 0x5F, 0x5C, 0x6B, 0x6E, 0x78, 0x77, 0x6D, 0xF1, 0xF4, 0xF8, 0xE5, +0xE9, 0xEB, 0xEC, 0xEF, 0xEF, 0xF0, 0xE7, 0xED, 0x6B, 0x6F, 0xF0, 0xFF, 0x6A, 0x6F, 0x7E, 0x6F, +0x69, 0xED, 0xDF, 0xFF, 0x7C, 0xEB, 0xF3, 0xF8, 0x7E, 0x7A, 0xFB, 0x6E, 0x5E, 0x60, 0x70, 0x7A, +0xFC, 0xF4, 0xFF, 0xEF, 0xF5, 0x72, 0xF1, 0xEC, 0xEA, 0xE1, 0xE9, 0xED, 0xF2, 0xFC, 0xE7, 0xF0, +0x68, 0x76, 0xEF, 0xF4, 0xF9, 0x77, 0x79, 0xFB, 0xFC, 0xF6, 0xEE, 0xE9, 0xF2, 0x6D, 0x70, 0x6F, +0x6F, 0xFE, 0x6A, 0x69, 0x7F, 0x6F, 0x6F, 0x79, 0x78, 0x77, 0x6E, 0xFE, 0xEE, 0xF0, 0xEF, 0x7E, +0xF4, 0xE9, 0xF8, 0xFD, 0x7C, 0x77, 0x7D, 0x78, 0x7D, 0xFE, 0x79, 0x72, 0x6E, 0x72, 0x7B, 0x73, +0x6B, 0x74, 0x76, 0x6C, 0x72, 0x70, 0x75, 0x6D, 0x5A, 0x5C, 0x6A, 0x77, 0xFE, 0x71, 0x7A, 0xF2, +0xE9, 0xE7, 0xEA, 0xDE, 0xE6, 0xF5, 0xEB, 0xF5, 0xEE, 0xEA, 0xF3, 0xEE, 0xF4, 0xEE, 0xF5, 0x73, +0xF4, 0xF6, 0x73, 0x7C, 0xEC, 0xE9, 0x72, 0x67, 0x6C, 0x70, 0x6E, 0x69, 0x6F, 0x68, 0x5D, 0x64, +0x71, 0x75, 0x6B, 0x6D, 0xF9, 0x79, 0x6F, 0xF4, 0xEA, 0xF5, 0x79, 0x7B, 0x7D, 0xFA, 0xF3, 0xF7, +0xF4, 0xF4, 0xF9, 0x7F, 0x77, 0x7F, 0xF5, 0xFD, 0x71, 0x71, 0x7B, 0x78, 0x7A, 0x73, 0x68, 0x71, +0x7A, 0x6B, 0x6C, 0x6E, 0x69, 0x6E, 0x71, 0x6C, 0x69, 0x6C, 0x7A, 0x7D, 0xF6, 0xEB, 0xF4, 0xF2, +0xF4, 0x78, 0xF8, 0xF1, 0xF6, 0xFE, 0x71, 0x75, 0x7C, 0x7B, 0x7D, 0x7E, 0xFB, 0x7E, 0x77, 0x76, +0xFF, 0xF7, 0x79, 0x70, 0x6E, 0x6C, 0x71, 0x6F, 0x6C, 0x6A, 0x70, 0x6E, 0x5F, 0x65, 0x6C, 0x66, +0x6D, 0x7A, 0xF1, 0x78, 0x6B, 0xED, 0xFB, 0x6C, 0x7C, 0x74, 0xF1, 0xEC, 0x76, 0xF9, 0xF8, 0x75, +0x71, 0x7A, 0xEC, 0xFA, 0x6C, 0x76, 0x7C, 0x7F, 0x6E, 0x6A, 0x76, 0x6C, 0x76, 0xF2, 0x7C, 0x76, +0x66, 0x62, 0x7D, 0xF9, 0x78, 0x69, 0x6A, 0xF8, 0x78, 0x6D, 0xFC, 0xF8, 0xF3, 0xF7, 0x7D, 0xEF, +0xF1, 0x7C, 0xF1, 0xE9, 0xEB, 0xEE, 0xF3, 0xFD, 0x73, 0x7D, 0xFA, 0x74, 0x78, 0x7A, 0x6E, 0x70, +0x76, 0x73, 0x6F, 0x6D, 0x6C, 0x68, 0x6D, 0x7D, 0x6E, 0x64, 0x6D, 0xFC, 0xFA, 0x71, 0x6F, 0xFF, +0x70, 0x70, 0xF0, 0xEE, 0xEF, 0xEB, 0xEC, 0xEC, 0xED, 0xF0, 0xEE, 0xE9, 0xEB, 0xF8, 0xFB, 0xED, +0xE9, 0xF7, 0xFF, 0xED, 0xEE, 0xEF, 0xF3, 0x6E, 0x70, 0xF3, 0xFF, 0x6F, 0x6F, 0x6F, 0x79, 0x7C, +0x79, 0x7E, 0x77, 0x6E, 0x6E, 0x7B, 0x7C, 0x6B, 0x72, 0xF6, 0xFF, 0x7D, 0x7D, 0x72, 0x78, 0xFB, +0xFD, 0xFB, 0xFA, 0x7D, 0x7A, 0x6D, 0x68, 0x74, 0x75, 0xF1, 0xE7, 0x7B, 0x76, 0x6B, 0x66, 0xFD, +0x73, 0x68, 0x6B, 0x73, 0x7C, 0x62, 0x64, 0x70, 0x64, 0x6D, 0x79, 0x70, 0x70, 0x74, 0xF8, 0x7C, +0x7C, 0xF8, 0x6B, 0x70, 0xF9, 0x7D, 0xF1, 0xF0, 0xFF, 0x7F, 0xF8, 0xED, 0xF2, 0xFC, 0xFF, 0x76, +0x7B, 0x7C, 0xFE, 0xFE, 0x6C, 0x7C, 0xED, 0x79, 0x77, 0x71, 0x69, 0x76, 0x7A, 0x76, 0x7A, 0x6F, +0x6E, 0x6E, 0x73, 0xFF, 0x78, 0x76, 0x7F, 0x7A, 0x6F, 0x78, 0xFE, 0x77, 0xFB, 0xEE, 0xEE, 0xF1, +0x7A, 0xFB, 0xEE, 0x75, 0x70, 0xFE, 0x7D, 0x72, 0x6D, 0x6F, 0x7B, 0xFB, 0xF9, 0x7C, 0x7E, 0x7A, +0x70, 0x76, 0x7B, 0xF7, 0xF5, 0x70, 0x74, 0xFF, 0x78, 0xFA, 0xFC, 0x79, 0x78, 0x6D, 0x7A, 0xFA, +0x77, 0xFC, 0xF4, 0xF1, 0xF1, 0xF7, 0xEB, 0xED, 0xFB, 0xF7, 0xEF, 0xF2, 0x78, 0x79, 0xF0, 0xF3, +0xFC, 0xFC, 0x7E, 0x77, 0xFF, 0xFC, 0x78, 0xF6, 0xF9, 0x6F, 0x7A, 0x78, 0x6F, 0xFF, 0xF9, 0x7E, +0x76, 0x72, 0x76, 0x78, 0x79, 0xFD, 0xFA, 0x7A, 0x7E, 0xF1, 0xFB, 0x7A, 0xF2, 0xEF, 0xFF, 0x74, +0x75, 0x7E, 0xFF, 0xF6, 0xE9, 0xF4, 0x71, 0x74, 0x74, 0x7C, 0xF8, 0x79, 0x75, 0x74, 0x73, 0xF9, +0xFE, 0xFF, 0xFA, 0x6A, 0x6C, 0xFE, 0x70, 0x72, 0x7C, 0x7D, 0x70, 0x67, 0x6F, 0x76, 0x7B, 0xF0, +0x7E, 0x6E, 0x6E, 0x76, 0xF1, 0xF2, 0x7A, 0x72, 0x7B, 0xFD, 0x79, 0x77, 0x6E, 0x6A, 0x6D, 0x6E, +0x74, 0x72, 0x77, 0xF5, 0x7C, 0x6D, 0x6C, 0x6D, 0x70, 0x76, 0xFD, 0xFC, 0xFF, 0xFE, 0xFE, 0xFA, +0x7D, 0x77, 0x74, 0x6F, 0xFB, 0xFA, 0x71, 0xFC, 0xF8, 0xFE, 0xEB, 0xE5, 0xEE, 0x7F, 0xF6, 0xED, +0xFA, 0x78, 0xF6, 0xF1, 0xF8, 0xF6, 0x79, 0x70, 0x7C, 0x75, 0x78, 0xF6, 0xFA, 0xFC, 0xFB, 0x7B, +0x7D, 0xF9, 0xF7, 0xF7, 0x7E, 0x6B, 0x68, 0xFA, 0xE6, 0xEE, 0x7B, 0x7B, 0x79, 0x7E, 0xFB, 0xF2, +0xEA, 0xEE, 0xF1, 0xF6, 0x79, 0xFB, 0xF0, 0xFB, 0xFF, 0xF0, 0xEE, 0xF4, 0xEF, 0xFB, 0x6F, 0x6C, +0x72, 0xFF, 0x71, 0x6C, 0x6A, 0x6D, 0xF4, 0xFB, 0x7C, 0xF3, 0xFA, 0xFC, 0x6F, 0x73, 0xFB, 0x72, +0x7D, 0x78, 0x76, 0xEF, 0xF3, 0x7C, 0x71, 0xFA, 0xF2, 0xFB, 0xEF, 0xF0, 0xEA, 0xFD, 0x6B, 0xED, +0xF2, 0x77, 0x6E, 0x6D, 0xFD, 0x64, 0xF3, 0xDF, 0x5C, 0x61, 0xED, 0xF2, 0x7E, 0x66, 0x73, 0x6E, +0x66, 0xFF, 0x6F, 0x72, 0x70, 0x66, 0xF3, 0xF7, 0x6F, 0x72, 0x75, 0xED, 0xEF, 0xF4, 0xED, 0xEF, +0xEF, 0x6E, 0x6F, 0xF7, 0x72, 0x7E, 0x78, 0x6F, 0xF9, 0x77, 0xFC, 0xF4, 0x6C, 0x66, 0x6A, 0x76, +0x65, 0x5C, 0x6D, 0xFF, 0xF8, 0xEA, 0xE2, 0xEF, 0x65, 0x70, 0xEB, 0xE8, 0xE2, 0xDF, 0xDA, 0xD9, +0xE3, 0xF0, 0xFA, 0xE6, 0xDD, 0xDF, 0xDF, 0xE0, 0xE4, 0xFC, 0x63, 0x60, 0x64, 0x63, 0x66, 0x78, +0x65, 0x57, 0x60, 0x67, 0x64, 0x67, 0x5F, 0x6E, 0xF3, 0x7F, 0x75, 0xFE, 0xEA, 0xF4, 0xF8, 0xE0, +0xE0, 0xE4, 0xE3, 0xE7, 0xEA, 0xFB, 0x6F, 0x6E, 0x75, 0x72, 0x68, 0x6E, 0x77, 0x74, 0x6D, 0x73, +0xF9, 0x74, 0xF2, 0xE2, 0xEF, 0xDE, 0xDD, 0x79, 0xFD, 0xF4, 0x6F, 0x6A, 0x6E, 0xFE, 0x7A, 0x68, +0x60, 0x63, 0x6B, 0x66, 0x67, 0x76, 0xFE, 0x78, 0x65, 0x63, 0x7A, 0xFF, 0x72, 0x72, 0x74, 0x7D, +0x7C, 0x6B, 0x72, 0xEF, 0xF6, 0x73, 0x74, 0x7C, 0x74, 0x68, 0x68, 0x73, 0xFA, 0xF6, 0x6F, 0x67, +0x6F, 0x6D, 0x6A, 0x69, 0x68, 0x74, 0x6D, 0x64, 0x6F, 0x75, 0x77, 0xFA, 0x7F, 0xF5, 0xEF, 0x78, +0x77, 0x7D, 0x7A, 0xFE, 0x77, 0x73, 0xF8, 0xF4, 0xFE, 0x6F, 0x71, 0xF7, 0x74, 0x79, 0xEF, 0x7B, +0xF9, 0xFA, 0x68, 0x71, 0x7F, 0x76, 0x73, 0x71, 0x7D, 0x7D, 0x65, 0x5D, 0x69, 0x6E, 0x5F, 0x67, +0x6F, 0x6D, 0xFF, 0x7F, 0x6E, 0x6F, 0x73, 0x77, 0xF2, 0xDE, 0xD4, 0xD0, 0xD0, 0xCF, 0xCE, 0xD0, +0xD2, 0xD6, 0xDA, 0xDB, 0xE7, 0x6D, 0x5B, 0x52, 0x4C, 0x47, 0x44, 0x43, 0x44, 0x47, 0x49, 0x4B, +0x4E, 0x52, 0x56, 0x5A, 0x5D, 0x64, 0x75, 0xE6, 0xCF, 0xC5, 0xBF, 0xBD, 0xBB, 0xB7, 0xB5, 0xB1, +0xAF, 0xB5, 0xC1, 0xDF, 0x51, 0x44, 0x3A, 0x33, 0x33, 0x37, 0x3D, 0x44, 0x48, 0x4D, 0x51, 0x54, +0x53, 0x4D, 0x49, 0x44, 0x43, 0x45, 0x46, 0x4C, 0x54, 0x65, 0xE4, 0xCF, 0xC4, 0xBB, 0xB4, 0xAF, +0xAD, 0xAC, 0xAA, 0xAB, 0xB5, 0xD1, 0x49, 0x3B, 0x35, 0x2F, 0x2D, 0x32, 0x3D, 0x4E, 0x57, 0x51, +0x4F, 0x50, 0x4C, 0x42, 0x3D, 0x3F, 0x46, 0x4A, 0x4F, 0x5E, 0xEC, 0xD9, 0xDA, 0xD2, 0xC8, 0xBE, +0xB7, 0xB0, 0xAD, 0xAB, 0xA9, 0xA8, 0xAD, 0xC4, 0x48, 0x36, 0x31, 0x2E, 0x2D, 0x30, 0x3E, 0x67, +0xE2, 0x63, 0x47, 0x43, 0x42, 0x39, 0x36, 0x3B, 0x46, 0x6B, 0xE1, 0xDB, 0xCC, 0xC8, 0xCC, 0xD7, +0xDD, 0xC6, 0xBA, 0xB2, 0xAC, 0xAA, 0xA7, 0xA7, 0xB0, 0x69, 0x32, 0x2D, 0x2D, 0x2C, 0x2D, 0x39, +0xF1, 0xC2, 0xCA, 0x5E, 0x3D, 0x38, 0x34, 0x2E, 0x2F, 0x3E, 0x69, 0xCC, 0xC3, 0xBD, 0xBD, 0xC2, +0xCD, 0xEC, 0xF4, 0xCD, 0xC0, 0xB7, 0xAC, 0xA7, 0xA4, 0xA4, 0xB7, 0x3A, 0x2A, 0x29, 0x2A, 0x2B, +0x30, 0x56, 0xBA, 0xB6, 0xCD, 0x4A, 0x33, 0x2C, 0x2C, 0x2B, 0x34, 0x65, 0xC3, 0xBB, 0xBB, 0xBC, +0xC1, 0xDA, 0x7F, 0x6A, 0x75, 0xD1, 0xC2, 0xB8, 0xAC, 0xA6, 0xA5, 0xA4, 0xB0, 0x35, 0x23, 0x25, +0x29, 0x2F, 0x38, 0x73, 0xB3, 0xAF, 0xC8, 0x3E, 0x2E, 0x29, 0x26, 0x2C, 0x3D, 0xDF, 0xB8, 0xB5, +0xBB, 0xC5, 0xE7, 0x5A, 0x53, 0x68, 0xD9, 0xC8, 0xBA, 0xB3, 0xAD, 0xA8, 0xA7, 0xA6, 0xAF, 0x34, +0x1F, 0x24, 0x2E, 0x3B, 0x48, 0xDA, 0xB3, 0xB0, 0xD6, 0x33, 0x29, 0x29, 0x29, 0x2F, 0x5B, 0xC3, +0xB9, 0xB8, 0xC1, 0xDB, 0x53, 0x46, 0x4E, 0xEE, 0xCB, 0xC5, 0xBF, 0xBA, 0xB6, 0xAE, 0xAA, 0xA8, +0xAA, 0xDB, 0x26, 0x20, 0x2B, 0x3E, 0x5E, 0xEE, 0xC1, 0xB6, 0xC1, 0x3F, 0x2A, 0x29, 0x2A, 0x2F, +0x4F, 0xCA, 0xC0, 0xBE, 0xC5, 0xDC, 0x51, 0x44, 0x4B, 0x7D, 0xCB, 0xC5, 0xC5, 0xC2, 0xBF, 0xBD, +0xB1, 0xA9, 0xA8, 0xAA, 0xCB, 0x28, 0x20, 0x2C, 0x44, 0x7E, 0xDE, 0xC8, 0xBB, 0xC6, 0x3F, 0x2B, +0x29, 0x2E, 0x35, 0x4C, 0xCB, 0xBF, 0xC3, 0xCA, 0xE6, 0x4E, 0x43, 0x44, 0x6A, 0xC8, 0xC3, 0xC3, +0xC8, 0xC8, 0xBE, 0xB5, 0xAB, 0xA7, 0xA8, 0xBC, 0x2D, 0x1F, 0x29, 0x42, 0xD7, 0xD0, 0xCD, 0xBF, +0xC5, 0x4C, 0x2E, 0x2B, 0x2F, 0x36, 0x4A, 0xD7, 0xBE, 0xBD, 0xD5, 0x74, 0x50, 0x42, 0x45, 0x53, +0xD1, 0xBE, 0xBE, 0xC5, 0xD2, 0xCD, 0xBC, 0xAE, 0xA7, 0xA7, 0xB5, 0x36, 0x21, 0x28, 0x41, 0xD1, +0xC9, 0xD4, 0xCB, 0xCB, 0x51, 0x31, 0x2B, 0x2F, 0x39, 0x47, 0xE9, 0xC5, 0xC0, 0xCD, 0xED, 0x50, +0x3F, 0x3F, 0x52, 0xCD, 0xBB, 0xBC, 0xC6, 0xDE, 0xE7, 0xCB, 0xB5, 0xA8, 0xA4, 0xA9, 0xCC, 0x28, +0x20, 0x2E, 0x6F, 0xC2, 0xCF, 0xF7, 0xDA, 0xEB, 0x3F, 0x2E, 0x2D, 0x34, 0x3E, 0x5D, 0xCD, 0xBF, +0xC7, 0x73, 0x53, 0x43, 0x3C, 0x49, 0xDD, 0xBC, 0xB7, 0xC2, 0xE4, 0x62, 0xEC, 0xBD, 0xAA, 0xA3, +0xA4, 0xB3, 0x32, 0x1F, 0x26, 0x42, 0xC3, 0xC0, 0xF2, 0x68, 0x73, 0x4D, 0x37, 0x2D, 0x2F, 0x39, +0x47, 0xDD, 0xC2, 0xBE, 0xD2, 0x4A, 0x3E, 0x3B, 0x42, 0xEB, 0xBE, 0xB5, 0xB9, 0xD5, 0x54, 0x54, +0xCB, 0xAD, 0xA3, 0xA2, 0xAC, 0x4D, 0x23, 0x21, 0x34, 0xCF, 0xBA, 0xD0, 0x5E, 0x73, 0x5D, 0x43, +0x34, 0x30, 0x38, 0x3C, 0x46, 0xCE, 0xB9, 0xBE, 0x5F, 0x3E, 0x3B, 0x3E, 0x62, 0xC0, 0xB5, 0xB6, +0xC9, 0x54, 0x48, 0xE3, 0xB1, 0xA4, 0xA0, 0xA6, 0xC3, 0x2B, 0x1E, 0x29, 0x5D, 0xB9, 0xBD, 0x72, +0x50, 0x5B, 0x50, 0x3C, 0x30, 0x30, 0x36, 0x3F, 0x7C, 0xC0, 0xBA, 0xD0, 0x45, 0x3A, 0x38, 0x46, +0xCB, 0xB7, 0xB5, 0xC4, 0x5A, 0x48, 0x62, 0xBA, 0xA8, 0xA1, 0xA3, 0xB0, 0x3C, 0x20, 0x20, 0x39, +0xBD, 0xB1, 0xC7, 0x4F, 0x4A, 0x4E, 0x48, 0x35, 0x2E, 0x31, 0x39, 0x56, 0xC0, 0xB8, 0xC2, 0x4D, +0x39, 0x37, 0x3E, 0xE2, 0xBC, 0xB6, 0xBB, 0xDC, 0x4B, 0x4A, 0xD3, 0xAE, 0xA3, 0xA0, 0xA8, 0xD5, +0x29, 0x1F, 0x2B, 0xE3, 0xB3, 0xBA, 0x65, 0x47, 0x4C, 0x4F, 0x3D, 0x2F, 0x2D, 0x30, 0x41, 0xCB, +0xB7, 0xBA, 0x76, 0x3D, 0x38, 0x39, 0x51, 0xC5, 0xB6, 0xB6, 0xCC, 0x50, 0x46, 0x7E, 0xB4, 0xA6, +0xA1, 0xA4, 0xB8, 0x35, 0x20, 0x25, 0x48, 0xB8, 0xB5, 0xDB, 0x47, 0x47, 0x52, 0x4A, 0x34, 0x2D, +0x2E, 0x39, 0xEC, 0xBA, 0xB6, 0xCF, 0x3F, 0x38, 0x37, 0x41, 0xD0, 0xB8, 0xB4, 0xBF, 0x6A, 0x4A, +0x5B, 0xBC, 0xA8, 0xA1, 0xA2, 0xAF, 0x3E, 0x22, 0x24, 0x3E, 0xBA, 0xB3, 0xD4, 0x45, 0x41, 0x4F, +0x52, 0x37, 0x2D, 0x2D, 0x36, 0x65, 0xBB, 0xB6, 0xC9, 0x46, 0x38, 0x35, 0x3D, 0xDC, 0xB7, 0xB0, +0xBA, 0xF0, 0x48, 0x4E, 0xC1, 0xAA, 0xA2, 0xA1, 0xAB, 0x5E, 0x27, 0x21, 0x32, 0xC7, 0xB4, 0xC8, +0x48, 0x3E, 0x4B, 0x58, 0x3D, 0x2E, 0x2C, 0x2F, 0x48, 0xBF, 0xB5, 0xBF, 0x4C, 0x36, 0x34, 0x3A, +0x67, 0xBC, 0xB2, 0xB7, 0xD6, 0x4C, 0x4A, 0xCE, 0xAD, 0xA3, 0xA0, 0xA7, 0xD8, 0x29, 0x20, 0x2F, +0xD2, 0xB5, 0xC4, 0x4C, 0x40, 0x4B, 0x64, 0x44, 0x2F, 0x2C, 0x2D, 0x3F, 0xC4, 0xB4, 0xB9, 0x5F, +0x39, 0x36, 0x39, 0x5D, 0xBE, 0xB3, 0xB4, 0xC8, 0x59, 0x4B, 0xDC, 0xAF, 0xA3, 0x9F, 0xA5, 0xC5, +0x2C, 0x21, 0x2C, 0xFB, 0xB9, 0xC1, 0x53, 0x42, 0x4A, 0x5F, 0x49, 0x31, 0x2C, 0x2C, 0x3A, 0xCF, +0xB6, 0xBA, 0xF7, 0x3E, 0x39, 0x3A, 0x4C, 0xCA, 0xB7, 0xB4, 0xBF, 0x79, 0x4D, 0xE5, 0xB1, 0xA4, +0x9F, 0xA4, 0xC6, 0x2B, 0x20, 0x2C, 0xEC, 0xB7, 0xC1, 0x57, 0x43, 0x49, 0x5C, 0x47, 0x31, 0x2C, +0x2C, 0x39, 0xD3, 0xB7, 0xBA, 0xDC, 0x46, 0x3C, 0x39, 0x47, 0xCE, 0xB9, 0xB5, 0xBD, 0xDE, 0x5E, +0xD3, 0xB0, 0xA4, 0xA0, 0xA6, 0xCF, 0x2A, 0x21, 0x2D, 0xF6, 0xBB, 0xC8, 0x55, 0x44, 0x48, 0x51, +0x3F, 0x2F, 0x2C, 0x2D, 0x3B, 0xD8, 0xBC, 0xBF, 0xE7, 0x4E, 0x45, 0x3C, 0x44, 0xEB, 0xBE, 0xB5, +0xBA, 0xCA, 0xE3, 0xC9, 0xAF, 0xA5, 0xA0, 0xA7, 0xE6, 0x28, 0x22, 0x2E, 0xEA, 0xBD, 0xC8, 0x5D, +0x46, 0x4A, 0x4D, 0x3B, 0x2F, 0x2D, 0x2F, 0x3F, 0xD0, 0xBE, 0xC3, 0xE6, 0x56, 0x4B, 0x43, 0x4C, +0xFA, 0xC8, 0xBB, 0xBB, 0xC3, 0xC8, 0xBD, 0xAE, 0xA7, 0xA3, 0xAA, 0x6C, 0x2A, 0x25, 0x30, 0x5A, +0xCD, 0xD3, 0x5F, 0x4D, 0x50, 0x4C, 0x3B, 0x2F, 0x2D, 0x2F, 0x3D, 0xE6, 0xCC, 0xD3, 0xDA, 0xDB, +0x79, 0x55, 0x56, 0x68, 0xE0, 0xCA, 0xC2, 0xC0, 0xBC, 0xB1, 0xAB, 0xA6, 0xA5, 0xAE, 0x53, 0x2C, +0x29, 0x30, 0x41, 0x59, 0x62, 0x53, 0x57, 0x7F, 0x5D, 0x40, 0x35, 0x2E, 0x2F, 0x3D, 0x58, 0x78, +0xE5, 0xCD, 0xC8, 0xCF, 0xDA, 0xEC, 0x7B, 0xE4, 0xD1, 0xCA, 0xC4, 0xBA, 0xB0, 0xAC, 0xAA, 0xAB, +0xBA, 0x4F, 0x39, 0x39, 0x3D, 0x3F, 0x42, 0x3D, 0x3C, 0x45, 0x51, 0x52, 0x4C, 0x42, 0x3B, 0x3E, +0x4A, 0x4C, 0x4D, 0x57, 0x69, 0xEE, 0xDE, 0xE4, 0xFD, 0xED, 0xDC, 0xD3, 0xCD, 0xCA, 0xC3, 0xBD, +0xB9, 0xB6, 0xB8, 0xC3, 0xCE, 0xC8, 0xC1, 0xC5, 0xCE, 0xF9, 0x4A, 0x3F, 0x3F, 0x41, 0x3F, 0x3D, +0x39, 0x38, 0x3B, 0x3C, 0x3A, 0x3C, 0x43, 0x4C, 0x52, 0x58, 0x5B, 0x59, 0x65, 0xDC, 0xCB, 0xC3, +0xBD, 0xB8, 0xB6, 0xB2, 0xAF, 0xB2, 0xB6, 0xB2, 0xB0, 0xB6, 0xBF, 0xD7, 0x4F, 0x40, 0x3F, 0x3D, +0x3A, 0x35, 0x2F, 0x2D, 0x2F, 0x32, 0x33, 0x34, 0x39, 0x3E, 0x46, 0x51, 0x59, 0x5C, 0x6F, 0xD8, +0xC6, 0xBD, 0xB8, 0xB4, 0xB2, 0xAF, 0xAC, 0xAD, 0xAF, 0xAE, 0xAE, 0xB2, 0xBC, 0xCF, 0x55, 0x42, +0x3E, 0x3B, 0x36, 0x31, 0x2D, 0x2A, 0x2B, 0x2F, 0x32, 0x33, 0x36, 0x3B, 0x40, 0x4A, 0x57, 0x69, +0xEE, 0xD6, 0xC8, 0xBF, 0xB9, 0xB3, 0xB1, 0xAF, 0xAC, 0xAB, 0xAE, 0xAF, 0xAF, 0xB1, 0xB9, 0xC6, +0x75, 0x46, 0x3D, 0x3A, 0x36, 0x30, 0x2D, 0x2B, 0x2A, 0x2D, 0x31, 0x34, 0x36, 0x39, 0x3E, 0x46, +0x56, 0x77, 0xE3, 0xD4, 0xCA, 0xC3, 0xBD, 0xB6, 0xB1, 0xAF, 0xAC, 0xAB, 0xAC, 0xAF, 0xAF, 0xB0, +0xB5, 0xBE, 0xDA, 0x4E, 0x3E, 0x3A, 0x36, 0x31, 0x2D, 0x2C, 0x2B, 0x2C, 0x2F, 0x32, 0x34, 0x38, +0x3D, 0x43, 0x4D, 0x66, 0xE7, 0xD6, 0xCB, 0xC5, 0xC0, 0xBA, 0xB3, 0xAF, 0xAD, 0xAB, 0xAC, 0xAE, +0xAF, 0xAF, 0xB3, 0xBB, 0xCD, 0x5A, 0x40, 0x3A, 0x36, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, 0x2F, 0x31, +0x32, 0x38, 0x3D, 0x41, 0x4B, 0x5C, 0xF8, 0xD8, 0xCA, 0xC3, 0xBF, 0xBA, 0xB4, 0xB0, 0xAD, 0xAB, +0xAB, 0xAE, 0xAF, 0xB0, 0xB3, 0xBA, 0xC9, 0x68, 0x46, 0x3C, 0x37, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, +0x2F, 0x30, 0x31, 0x36, 0x3C, 0x3F, 0x49, 0x58, 0x70, 0xDD, 0xCA, 0xC2, 0xBE, 0xB9, 0xB3, 0xB0, +0xAD, 0xAA, 0xAB, 0xAE, 0xAF, 0xAF, 0xB4, 0xBC, 0xCB, 0x61, 0x46, 0x3D, 0x36, 0x30, 0x2E, 0x2C, +0x2B, 0x2D, 0x2F, 0x2F, 0x31, 0x37, 0x3B, 0x3F, 0x4B, 0x5C, 0xFF, 0xD8, 0xC8, 0xC1, 0xBC, 0xB6, +0xB2, 0xAF, 0xAC, 0xAA, 0xAB, 0xAD, 0xAE, 0xAF, 0xB5, 0xBD, 0xCF, 0x5C, 0x45, 0x3C, 0x35, 0x2F, +0x2D, 0x2C, 0x2C, 0x2D, 0x2F, 0x2F, 0x32, 0x37, 0x3B, 0x3F, 0x4B, 0x5F, 0xEE, 0xD4, 0xC8, 0xC1, +0xBC, 0xB5, 0xB0, 0xAE, 0xAB, 0xAA, 0xAB, 0xAD, 0xAF, 0xB1, 0xB7, 0xC0, 0xD9, 0x53, 0x42, 0x3B, +0x34, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x30, 0x33, 0x37, 0x3C, 0x43, 0x4D, 0x5E, 0xEC, 0xD0, +0xC7, 0xC0, 0xBB, 0xB6, 0xB0, 0xAE, 0xAB, 0xAA, 0xAC, 0xAE, 0xAF, 0xB3, 0xB9, 0xC5, 0xE2, 0x4E, +0x3F, 0x39, 0x32, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x2F, 0x33, 0x39, 0x3D, 0x44, 0x4F, 0x65, +0xE3, 0xCE, 0xC5, 0xBF, 0xBA, 0xB4, 0xAF, 0xAD, 0xAA, 0xAA, 0xAC, 0xAE, 0xB0, 0xB5, 0xBB, 0xC8, +0xF8, 0x4C, 0x3E, 0x38, 0x31, 0x2E, 0x2C, 0x2B, 0x2C, 0x2E, 0x2F, 0x31, 0x35, 0x39, 0x3E, 0x4A, +0x5C, 0xF9, 0xD8, 0xCB, 0xC2, 0xBC, 0xB7, 0xB2, 0xAE, 0xAB, 0xA9, 0xAA, 0xAC, 0xAE, 0xB2, 0xB8, +0xBE, 0xCE, 0x72, 0x48, 0x3B, 0x34, 0x2F, 0x2E, 0x2C, 0x2B, 0x2C, 0x2D, 0x2F, 0x31, 0x36, 0x3A, +0x3E, 0x4A, 0x5F, 0xEA, 0xD0, 0xC9, 0xC1, 0xBB, 0xB5, 0xB0, 0xAE, 0xAB, 0xA9, 0xAB, 0xAC, 0xAE, +0xB4, 0xBB, 0xC4, 0xD6, 0x60, 0x45, 0x39, 0x30, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x32, +0x35, 0x3A, 0x43, 0x51, 0x6A, 0xDF, 0xCB, 0xC3, 0xBD, 0xB8, 0xB2, 0xAE, 0xAC, 0xAA, 0xAA, 0xAB, +0xAC, 0xAF, 0xB7, 0xBD, 0xCC, 0xF1, 0x51, 0x3F, 0x36, 0x2F, 0x2D, 0x2B, 0x2A, 0x2C, 0x2D, 0x2E, +0x2F, 0x33, 0x37, 0x3B, 0x45, 0x58, 0x77, 0xD5, 0xC8, 0xC0, 0xBB, 0xB6, 0xB1, 0xAE, 0xAB, 0xA9, +0xAA, 0xAB, 0xAC, 0xB1, 0xB9, 0xC0, 0xD3, 0x6A, 0x4A, 0x3C, 0x33, 0x2E, 0x2D, 0x2B, 0x2B, 0x2C, +0x2D, 0x2E, 0x31, 0x34, 0x38, 0x3F, 0x4C, 0x5D, 0xEA, 0xCE, 0xC6, 0xBE, 0xB8, 0xB4, 0xAF, 0xAD, +0xAB, 0xAA, 0xAA, 0xAB, 0xAD, 0xB2, 0xB9, 0xC3, 0xD8, 0x61, 0x47, 0x3A, 0x32, 0x2E, 0x2C, 0x2B, +0x2C, 0x2C, 0x2D, 0x2F, 0x31, 0x34, 0x38, 0x3F, 0x4D, 0x62, 0xDD, 0xCC, 0xC3, 0xBC, 0xB7, 0xB2, +0xAE, 0xAC, 0xAA, 0xAA, 0xAA, 0xAB, 0xAE, 0xB3, 0xBA, 0xC6, 0xE1, 0x55, 0x41, 0x37, 0x30, 0x2D, +0x2B, 0x2A, 0x2B, 0x2C, 0x2D, 0x2F, 0x31, 0x34, 0x39, 0x40, 0x4D, 0x6A, 0xD8, 0xC9, 0xC1, 0xBC, +0xB7, 0xB2, 0xAE, 0xAC, 0xAA, 0xAA, 0xAB, 0xAC, 0xAF, 0xB7, 0xBB, 0xC6, 0x79, 0x55, 0x44, 0x37, +0x30, 0x2D, 0x2C, 0x2B, 0x2C, 0x2D, 0x2D, 0x2F, 0x33, 0x35, 0x39, 0x42, 0x51, 0x6C, 0xDA, 0xCA, +0xC4, 0xBE, 0xBA, 0xB6, 0xB0, 0xAD, 0xAC, 0xAC, 0xAC, 0xAD, 0xAF, 0xB4, 0xB9, 0xC0, 0xD0, 0x65, +0x47, 0x3A, 0x32, 0x2F, 0x2C, 0x2B, 0x2B, 0x2C, 0x2D, 0x2E, 0x31, 0x36, 0x3A, 0x3F, 0x4A, 0x5E, +0xDC, 0xCC, 0xC4, 0xBE, 0xBA, 0xB6, 0xB2, 0xAF, 0xAE, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB8, 0xBE, +0xCA, 0xE6, 0x4F, 0x3F, 0x38, 0x31, 0x2E, 0x2C, 0x2C, 0x2C, 0x2D, 0x2F, 0x31, 0x35, 0x3A, 0x3F, +0x4B, 0x64, 0xDD, 0xCB, 0xC3, 0xBD, 0xBA, 0xB7, 0xB4, 0xB1, 0xAF, 0xAE, 0xAE, 0xB0, 0xB3, 0xB5, +0xB9, 0xBE, 0xC6, 0xD3, 0x74, 0x4E, 0x40, 0x3A, 0x35, 0x32, 0x30, 0x2F, 0x2F, 0x30, 0x33, 0x36, +0x3A, 0x3F, 0x48, 0x52, 0x6C, 0xDF, 0xCE, 0xC7, 0xC1, 0xBE, 0xBB, 0xB9, 0xB8, 0xB7, 0xB6, 0xB6, +0xB7, 0xB9, 0xBB, 0xBE, 0xC4, 0xCA, 0xD9, 0x6C, 0x50, 0x45, 0x3D, 0x3A, 0x37, 0x35, 0x35, 0x35, +0x36, 0x37, 0x39, 0x3C, 0x3F, 0x46, 0x4F, 0x5E, 0xF1, 0xD9, 0xCF, 0xCC, 0xC9, 0xC5, 0xC1, 0xBE, +0xBC, 0xBC, 0xBC, 0xBD, 0xBF, 0xC2, 0xC4, 0xC7, 0xCC, 0xD5, 0xE8, 0x64, 0x52, 0x4A, 0x45, 0x41, +0x3F, 0x3E, 0x3D, 0x3D, 0x3E, 0x41, 0x45, 0x49, 0x4D, 0x53, 0x5C, 0x71, 0xE9, 0xDD, 0xD6, 0xD1, +0xCE, 0xCB, 0xC9, 0xC8, 0xC8, 0xC7, 0xC7, 0xC8, 0xC9, 0xCC, 0xCF, 0xD4, 0xDA, 0xE4, 0xF7, 0x69, +0x5B, 0x53, 0x4F, 0x4E, 0x4D, 0x4D, 0x4D, 0x4E, 0x51, 0x58, 0x5F, 0x68, 0x6F, 0x77, 0xFC, 0xEE, +0xE8, 0xE5, 0xE1, 0xDD, 0xDE, 0xDE, 0xDE, 0xE2, 0xE6, 0xE6, 0xEB, 0xF0, 0xED, 0xEA, 0xEC, 0xEE, +0xF8, 0x6A, 0x5C, 0x57, 0x55, 0x56, 0x58, 0x59, 0x58, 0x58, 0x5B, 0x5E, 0x63, 0x71, 0xF7, 0xEE, +0xE9, 0xE3, 0xE4, 0xE8, 0xE7, 0xEA, 0xEE, 0xEE, 0xF2, 0xFB, 0xFF, 0x7B, 0x74, 0x6E, 0x6B, 0x65, +0x60, 0x65, 0x67, 0x61, 0x60, 0x61, 0x5E, 0x5E, 0x62, 0x69, 0x70, 0x7F, 0xF6, 0xF2, 0xEC, 0xE7, +0xE6, 0xE3, 0xDF, 0xDE, 0xDE, 0xDD, 0xDE, 0xE0, 0xE5, 0xEC, 0xF6, 0x7F, 0x78, 0x75, 0x70, 0x6B, +0x64, 0x5E, 0x5A, 0x58, 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5E, 0x61, 0x67, 0x6C, 0x75, 0xF8, 0xEC, +0xE6, 0xE0, 0xDD, 0xDD, 0xDE, 0xDF, 0xE0, 0xE2, 0xE2, 0xE4, 0xE6, 0xE9, 0xEE, 0xF9, 0x7D, 0x75, +0x6E, 0x6A, 0x65, 0x61, 0x5E, 0x5C, 0x5B, 0x5C, 0x5D, 0x5E, 0x60, 0x63, 0x66, 0x6C, 0x76, 0xFA, +0xEE, 0xE9, 0xE4, 0xE1, 0xDF, 0xDD, 0xDE, 0xDF, 0xE2, 0xE6, 0xEA, 0xEE, 0xF4, 0xFA, 0x7E, 0x7A, +0x75, 0x72, 0x74, 0x74, 0x71, 0x70, 0x6D, 0x6A, 0x6A, 0x6B, 0x6D, 0x70, 0x74, 0x78, 0x7A, 0x7D, +0xFA, 0xF0, 0xEA, 0xE5, 0xE3, 0xE2, 0xE0, 0xDF, 0xE1, 0xE3, 0xE4, 0xE8, 0xEB, 0xEE, 0xF4, 0xFB, +0x7E, 0x75, 0x6D, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x65, 0x64, 0x63, 0x64, 0x66, 0x69, 0x6D, 0x72, +0x77, 0x7B, 0xFE, 0xF7, 0xF0, 0xEB, 0xE8, 0xE7, 0xE6, 0xE6, 0xE6, 0xE7, 0xE7, 0xE8, 0xEA, 0xED, +0xF3, 0xFC, 0x79, 0x72, 0x6F, 0x6C, 0x6B, 0x6B, 0x69, 0x66, 0x64, 0x63, 0x62, 0x63, 0x67, 0x6C, +0x73, 0x7C, 0xFE, 0xFD, 0xFA, 0xF4, 0xEE, 0xEA, 0xE5, 0xE1, 0xE1, 0xE2, 0xE5, 0xE9, 0xED, 0xEF, +0xF1, 0xF2, 0xF4, 0xF8, 0xFF, 0x76, 0x6E, 0x6A, 0x68, 0x67, 0x66, 0x65, 0x64, 0x62, 0x61, 0x61, +0x63, 0x67, 0x6B, 0x72, 0x7E, 0xFA, 0xF5, 0xF1, 0xEE, 0xED, 0xEC, 0xE9, 0xE8, 0xE7, 0xE7, 0xE9, +0xEC, 0xF0, 0xF9, 0x7D, 0x77, 0x73, 0x70, 0x6F, 0x6E, 0x6C, 0x69, 0x67, 0x65, 0x66, 0x66, 0x68, +0x69, 0x69, 0x6A, 0x6C, 0x6E, 0x75, 0x7F, 0xF8, 0xF1, 0xED, 0xEB, 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, +0xEA, 0xE9, 0xEA, 0xEC, 0xEF, 0xF4, 0xFB, 0x7D, 0x77, 0x73, 0x71, 0x6F, 0x6D, 0x6B, 0x69, 0x67, +0x66, 0x67, 0x68, 0x69, 0x6B, 0x6D, 0x6F, 0x74, 0x79, 0x7F, 0xF9, 0xF3, 0xEF, 0xEE, 0xEE, 0xEE, +0xEE, 0xED, 0xED, 0xED, 0xEE, 0xEC, 0xEC, 0xF1, 0xF3, 0xF6, 0xFD, 0xFF, 0x7D, 0x78, 0x78, 0x76, +0x70, 0x6F, 0x6E, 0x6D, 0x6D, 0x6E, 0x6F, 0x71, 0x73, 0x77, 0x7B, 0x7D, 0xFF, 0xFB, 0xF8, 0xF8, +0xFA, 0xFB, 0xFE, 0x7E, 0x7D, 0x7A, 0x79, 0x7A, 0x76, 0x76, 0x76, 0x72, 0x70, 0x6F, 0x6D, 0x6E, +0x6D, 0x6B, 0x6E, 0x65, 0x66, 0x57, 0x41, 0x59, 0xC7, 0x62, 0x57, 0xCD, 0x64, 0x6B, 0xCC, 0x6D, +0xF6, 0xD1, 0x69, 0x6E, 0xDA, 0x7D, 0x61, 0xEE, 0xF1, 0xFD, 0xFF, 0x6E, 0xE7, 0x74, 0x66, 0xE9, +0x6A, 0xFC, 0xF2, 0x64, 0xEE, 0x6F, 0x6B, 0x7B, 0x69, 0xF2, 0x68, 0x74, 0xEC, 0x5F, 0xED, 0xFC, +0x5F, 0xDE, 0x72, 0x65, 0xDC, 0x51, 0x4C, 0xE8, 0x5F, 0xEF, 0xD7, 0x4E, 0xF3, 0xF9, 0x52, 0xC3, +0xE2, 0x56, 0xC9, 0x5B, 0x59, 0xE4, 0x50, 0x53, 0x47, 0x66, 0xF9, 0x47, 0xC9, 0xCB, 0x59, 0xD4, +0x55, 0x58, 0xD3, 0x5C, 0xF9, 0xCE, 0xD7, 0x6D, 0x61, 0xDB, 0xE4, 0xE8, 0x70, 0x79, 0xCD, 0x6B, +0x5D, 0xEC, 0x66, 0xDC, 0x6C, 0x5F, 0xD3, 0xF9, 0xFB, 0x66, 0x55, 0xDE, 0xFB, 0x64, 0xD7, 0xDA, +0xF1, 0xF1, 0xF1, 0xE5, 0xDB, 0xF4, 0x75, 0xDF, 0xE7, 0xFD, 0x79, 0xEC, 0xD9, 0xF0, 0x6E, 0xF5, +0xE4, 0xE5, 0x64, 0x74, 0xDF, 0x7D, 0x68, 0x75, 0xF0, 0xFD, 0x7B, 0xFC, 0x7B, 0xDE, 0xEF, 0x64, +0xDF, 0xE8, 0xFF, 0xE9, 0xFF, 0xE2, 0xE1, 0x76, 0xF6, 0xEF, 0xEC, 0xF9, 0x6D, 0x7C, 0x73, 0x6D, +0x69, 0x67, 0x76, 0x75, 0x73, 0x64, 0x66, 0xFD, 0x60, 0x5F, 0x77, 0x67, 0x70, 0x74, 0x60, 0x78, +0x7A, 0x5C, 0x67, 0x79, 0x6C, 0x77, 0x63, 0x63, 0xEF, 0x6C, 0x66, 0x73, 0x6D, 0xF8, 0x72, 0x74, +0xE6, 0xFB, 0x7B, 0xF3, 0xF6, 0xF1, 0xFE, 0x7B, 0xF5, 0xF1, 0x6D, 0x63, 0x75, 0x6E, 0x60, 0x64, +0x67, 0x67, 0x68, 0x67, 0x67, 0x6C, 0x64, 0x5B, 0x65, 0x6E, 0x69, 0x72, 0x76, 0x74, 0xFE, 0xFD, +0xFF, 0xF6, 0xF3, 0x7C, 0x7A, 0xFC, 0xFE, 0xFB, 0x7E, 0x75, 0xF5, 0xEE, 0xFC, 0xF7, 0xF3, 0xFF, +0xFE, 0x74, 0x6B, 0x6F, 0x6D, 0x6A, 0x6C, 0x6A, 0x7A, 0xF9, 0x71, 0x7C, 0xF5, 0x7C, 0x7B, 0x7F, +0xFE, 0x72, 0x6E, 0xFF, 0x6F, 0x66, 0x6B, 0x6A, 0x6E, 0x76, 0x71, 0x7C, 0x7A, 0x6E, 0x6C, 0x69, +0x6C, 0x6D, 0x63, 0x65, 0x6A, 0x66, 0x63, 0x65, 0x6C, 0x68, 0x64, 0x69, 0x6A, 0x6E, 0x79, 0x7B, +0x78, 0x6D, 0x6E, 0x79, 0x77, 0xFA, 0xED, 0xEF, 0xEF, 0xEC, 0xE8, 0xEF, 0xFB, 0xF6, 0xEF, 0xEE, +0xF7, 0xF9, 0xF3, 0xF7, 0xF1, 0xF3, 0xFD, 0xFD, 0x7A, 0x7B, 0xFE, 0x79, 0x7C, 0x7B, 0x6E, 0x72, +0x7A, 0x72, 0x71, 0x79, 0x79, 0x6F, 0x6F, 0x78, 0x74, 0x72, 0x7B, 0x72, 0x78, 0xF6, 0xF7, 0xF9, +0x78, 0x79, 0xEE, 0xF5, 0x74, 0x76, 0x7A, 0xFE, 0x7E, 0x75, 0x7A, 0x7E, 0x74, 0x70, 0x7D, 0xF8, +0xF8, 0x7D, 0x77, 0xF8, 0xF0, 0x7F, 0x7E, 0xF2, 0xED, 0xF0, 0xF4, 0xEB, 0xE9, 0xFE, 0x74, 0xEF, +0xE1, 0xE0, 0xDC, 0xD9, 0xD7, 0xD3, 0xD7, 0xDD, 0xD9, 0xD9, 0xDF, 0xE6, 0xEB, 0xF2, 0x78, 0x65, +0x61, 0x65, 0x5F, 0x5A, 0x5B, 0x5B, 0x5A, 0x5C, 0x5B, 0x5D, 0x5E, 0x5C, 0x5B, 0x5B, 0x5B, 0x5C, +0x5E, 0x6B, 0xEA, 0xD9, 0xD2, 0xD1, 0xCD, 0xC8, 0xC6, 0xC5, 0xC5, 0xC3, 0xC3, 0xC6, 0xCA, 0xD2, +0xE8, 0x67, 0x51, 0x49, 0x42, 0x3D, 0x3D, 0x3E, 0x3F, 0x41, 0x44, 0x49, 0x4E, 0x50, 0x55, 0x5A, +0x5F, 0x6F, 0xEF, 0xDA, 0xCD, 0xCA, 0xC8, 0xC4, 0xBF, 0xBD, 0xBB, 0xB9, 0xB7, 0xB6, 0xBA, 0xC2, +0xCC, 0xE2, 0x56, 0x43, 0x3B, 0x39, 0x37, 0x36, 0x37, 0x3B, 0x3E, 0x42, 0x47, 0x4B, 0x51, 0x5A, +0x5B, 0x5E, 0x67, 0x7A, 0xED, 0xE8, 0xDB, 0xCF, 0xCB, 0xC5, 0xBD, 0xB9, 0xB6, 0xB2, 0xB0, 0xB4, +0xB9, 0xBF, 0xCD, 0xFC, 0x49, 0x3B, 0x37, 0x33, 0x31, 0x32, 0x33, 0x38, 0x3E, 0x45, 0x4F, 0x5F, +0x74, 0xF0, 0xEF, 0xF1, 0xF4, 0xFF, 0x77, 0x72, 0xFB, 0xE4, 0xD9, 0xCE, 0xC3, 0xBA, 0xB6, 0xB2, +0xB0, 0xB2, 0xB6, 0xBB, 0xC8, 0xE4, 0x51, 0x3E, 0x38, 0x33, 0x2F, 0x2F, 0x31, 0x35, 0x3A, 0x3E, +0x49, 0x5D, 0xFE, 0xE4, 0xDD, 0xD9, 0xD9, 0xE1, 0xEB, 0xEE, 0xEE, 0xE7, 0xDD, 0xD2, 0xC7, 0xBD, +0xB9, 0xB5, 0xB2, 0xB5, 0xB8, 0xBB, 0xC6, 0xDA, 0x5F, 0x45, 0x3D, 0x37, 0x33, 0x31, 0x31, 0x35, +0x39, 0x3D, 0x45, 0x53, 0x6F, 0xE3, 0xD9, 0xD0, 0xCF, 0xD2, 0xD5, 0xD9, 0xD9, 0xD8, 0xD4, 0xCE, +0xC8, 0xC0, 0xBD, 0xB9, 0xB8, 0xBB, 0xBD, 0xC1, 0xCD, 0xDF, 0x5F, 0x4A, 0x41, 0x3B, 0x37, 0x36, +0x35, 0x36, 0x3A, 0x3D, 0x44, 0x4E, 0x5F, 0xEC, 0xDB, 0xD6, 0xD2, 0xD4, 0xD6, 0xDA, 0xDD, 0xDB, +0xD8, 0xD2, 0xCD, 0xC9, 0xC3, 0xBF, 0xBE, 0xBF, 0xC3, 0xC4, 0xCA, 0xD6, 0xED, 0x5E, 0x50, 0x48, +0x3F, 0x3C, 0x3B, 0x3A, 0x3A, 0x3D, 0x40, 0x4A, 0x55, 0x6A, 0xE6, 0xDC, 0xD8, 0xD6, 0xD8, 0xD8, +0xDB, 0xDE, 0xDF, 0xE2, 0xDE, 0xDC, 0xD9, 0xD0, 0xCB, 0xC8, 0xC8, 0xCC, 0xCD, 0xCD, 0xD1, 0xDB, +0xF2, 0x67, 0x5B, 0x51, 0x49, 0x44, 0x42, 0x41, 0x42, 0x44, 0x49, 0x4E, 0x55, 0x5C, 0x6A, 0x7E, +0xF3, 0xED, 0xED, 0xEF, 0xEC, 0xED, 0xF4, 0xF7, 0xF0, 0xEB, 0xE4, 0xDF, 0xDA, 0xD2, 0xCD, 0xCC, +0xCC, 0xCF, 0xCF, 0xCE, 0xD3, 0xDB, 0xE7, 0x7C, 0x69, 0x5E, 0x54, 0x4F, 0x4E, 0x4D, 0x4E, 0x4F, +0x52, 0x58, 0x5B, 0x5E, 0x63, 0x67, 0x6B, 0x6B, 0x6A, 0x6B, 0x6C, 0x6E, 0x6F, 0x73, 0x7D, 0xF3, +0xEA, 0xE1, 0xDC, 0xD8, 0xD3, 0xD1, 0xCF, 0xCE, 0xD1, 0xD2, 0xD2, 0xD6, 0xDB, 0xE2, 0xEF, 0xFD, +0x73, 0x66, 0x5F, 0x5C, 0x5A, 0x59, 0x58, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x5A, 0x5C, 0x5D, +0x61, 0x65, 0x6A, 0x74, 0x7E, 0xF4, 0xEA, 0xE2, 0xDD, 0xDA, 0xD7, 0xD5, 0xD2, 0xD1, 0xD0, 0xD1, +0xD3, 0xD3, 0xD4, 0xD7, 0xDB, 0xE0, 0xE8, 0xEF, 0x7B, 0x69, 0x5F, 0x5B, 0x57, 0x53, 0x50, 0x4F, +0x4F, 0x4F, 0x4F, 0x50, 0x52, 0x56, 0x59, 0x5C, 0x60, 0x68, 0x6E, 0x7A, 0xFB, 0xF1, 0xEB, 0xE7, +0xE2, 0xDE, 0xDC, 0xDA, 0xD7, 0xD5, 0xD3, 0xD3, 0xD3, 0xD5, 0xD5, 0xD8, 0xDC, 0xE4, 0xF2, 0x78, +0x6A, 0x5E, 0x59, 0x55, 0x52, 0x50, 0x4F, 0x4F, 0x50, 0x52, 0x55, 0x58, 0x5A, 0x5D, 0x61, 0x64, +0x69, 0x6E, 0x74, 0xFF, 0xF6, 0xEE, 0xE9, 0xE4, 0xDF, 0xDC, 0xD8, 0xD5, 0xD2, 0xD0, 0xD1, 0xD1, +0xD2, 0xD6, 0xD7, 0xDA, 0xDF, 0xE8, 0xF8, 0x71, 0x69, 0x60, 0x5C, 0x58, 0x56, 0x54, 0x53, 0x53, +0x53, 0x55, 0x56, 0x58, 0x5A, 0x5C, 0x5F, 0x63, 0x69, 0x71, 0xFF, 0xEF, 0xEA, 0xE6, 0xE1, 0xDF, +0xDE, 0xDB, 0xDA, 0xDA, 0xD7, 0xD4, 0xD1, 0xD1, 0xD2, 0xD4, 0xD7, 0xD8, 0xDB, 0xE1, 0xED, 0x78, +0x69, 0x61, 0x5A, 0x53, 0x50, 0x4F, 0x4E, 0x4F, 0x4F, 0x51, 0x55, 0x59, 0x5D, 0x60, 0x65, 0x6C, +0x6F, 0x76, 0x7E, 0xFC, 0xF5, 0xF2, 0xF2, 0xED, 0xE7, 0xE1, 0xDD, 0xD9, 0xD4, 0xCE, 0xCB, 0xCA, +0xC8, 0xCA, 0xCF, 0xD0, 0xD7, 0xE6, 0x7C, 0x5E, 0x53, 0x4F, 0x4C, 0x4A, 0x4A, 0x4A, 0x4C, 0x4E, +0x4F, 0x51, 0x57, 0x5D, 0x62, 0x66, 0x69, 0x6D, 0x6D, 0x67, 0x63, 0x65, 0x6B, 0x70, 0x75, 0xFE, +0xEA, 0xDC, 0xD3, 0xCE, 0xC9, 0xC2, 0xBE, 0xBC, 0xBC, 0xC1, 0xC8, 0xCB, 0xDC, 0x69, 0x50, 0x46, +0x42, 0x3F, 0x3D, 0x3D, 0x3F, 0x43, 0x4B, 0x4F, 0x55, 0x61, 0x6F, 0xFC, 0xF0, 0xFA, 0xFD, 0x7B, +0x63, 0x5A, 0x54, 0x52, 0x54, 0x58, 0x62, 0x7D, 0xDE, 0xCC, 0xC4, 0xBC, 0xB6, 0xB1, 0xAE, 0xB2, +0xBA, 0xC1, 0xDA, 0x5A, 0x45, 0x38, 0x33, 0x32, 0x33, 0x36, 0x3A, 0x3E, 0x4B, 0x66, 0xEA, 0xD6, +0xCE, 0xCF, 0xD3, 0xE0, 0x6E, 0x5C, 0x51, 0x4D, 0x4B, 0x4A, 0x4F, 0x5B, 0x7A, 0xD6, 0xC6, 0xBA, +0xB1, 0xAE, 0xAA, 0xAA, 0xAF, 0xBA, 0xD1, 0x4E, 0x3D, 0x31, 0x2B, 0x2B, 0x2C, 0x30, 0x38, 0x3E, +0x4E, 0xEA, 0xCD, 0xC7, 0xC8, 0xCB, 0xCE, 0xDD, 0x64, 0x4F, 0x48, 0x48, 0x47, 0x46, 0x4D, 0x62, +0xDD, 0xCA, 0xBD, 0xB1, 0xAC, 0xA9, 0xA7, 0xAA, 0xB2, 0xC4, 0x51, 0x3A, 0x2F, 0x29, 0x28, 0x2A, +0x2E, 0x39, 0x45, 0x5A, 0xDB, 0xC8, 0xC2, 0xC5, 0xCD, 0xD5, 0xE8, 0x5B, 0x4C, 0x46, 0x47, 0x4C, +0x4E, 0x59, 0xF3, 0xD3, 0xC6, 0xBE, 0xB5, 0xAD, 0xAA, 0xA6, 0xA8, 0xB2, 0xC5, 0x54, 0x38, 0x2F, +0x28, 0x26, 0x2A, 0x2F, 0x3A, 0x4B, 0x73, 0xCF, 0xC5, 0xC4, 0xC9, 0xD9, 0xF8, 0x5F, 0x4C, 0x47, +0x47, 0x48, 0x4F, 0x5A, 0x74, 0xD9, 0xCE, 0xC7, 0xBF, 0xBA, 0xB0, 0xAC, 0xAA, 0xA9, 0xB0, 0xC5, +0x5C, 0x3B, 0x30, 0x2B, 0x27, 0x29, 0x2E, 0x39, 0x49, 0x6C, 0xD2, 0xC7, 0xC5, 0xCA, 0xDA, 0x7A, +0x5E, 0x4D, 0x48, 0x49, 0x4B, 0x52, 0x5E, 0x70, 0xDC, 0xCE, 0xC9, 0xC4, 0xBE, 0xB5, 0xAE, 0xAC, +0xAA, 0xAD, 0xBB, 0xE1, 0x43, 0x35, 0x2E, 0x29, 0x28, 0x2B, 0x32, 0x3D, 0x4E, 0x7E, 0xD2, 0xC9, +0xC7, 0xCC, 0xDF, 0xFE, 0x61, 0x4F, 0x4C, 0x4B, 0x4C, 0x54, 0x5D, 0x72, 0xDA, 0xCE, 0xC7, 0xC0, +0xB9, 0xB0, 0xAD, 0xAA, 0xAA, 0xB1, 0xC5, 0x5D, 0x3D, 0x33, 0x2C, 0x29, 0x29, 0x2D, 0x35, 0x3F, +0x4F, 0x78, 0xD7, 0xCA, 0xC7, 0xCD, 0xD9, 0xE3, 0x71, 0x5C, 0x54, 0x4D, 0x4E, 0x55, 0x5A, 0x6E, +0xE3, 0xD3, 0xC8, 0xBE, 0xB6, 0xAF, 0xAC, 0xAA, 0xAC, 0xB7, 0xCE, 0x53, 0x3D, 0x34, 0x2D, 0x2A, +0x2A, 0x2E, 0x35, 0x3E, 0x4A, 0x5C, 0xE5, 0xCD, 0xC8, 0xCB, 0xCE, 0xD5, 0xE2, 0xF7, 0x66, 0x57, +0x54, 0x56, 0x5B, 0x6E, 0xE7, 0xD5, 0xC9, 0xBE, 0xB6, 0xB1, 0xAE, 0xAE, 0xB4, 0xBE, 0xD3, 0x5C, +0x46, 0x3C, 0x34, 0x30, 0x2F, 0x32, 0x38, 0x3E, 0x45, 0x4E, 0x69, 0xDC, 0xCF, 0xCD, 0xCF, 0xD3, +0xD9, 0xDF, 0xEF, 0x6F, 0x68, 0x67, 0x6F, 0xF7, 0xE7, 0xDC, 0xD2, 0xC8, 0xC1, 0xBE, 0xBC, 0xBD, +0xC3, 0xCB, 0xD5, 0xEA, 0x6A, 0x58, 0x4D, 0x47, 0x43, 0x43, 0x44, 0x47, 0x4A, 0x4D, 0x52, 0x5D, +0x6D, 0x78, 0x77, 0x78, 0x76, 0x73, 0x75, 0x72, 0x72, 0x78, 0x7E, 0xF6, 0xEB, 0xE3, 0xDC, 0xD6, +0xD2, 0xCF, 0xCE, 0xCE, 0xCD, 0xCF, 0xD2, 0xD4, 0xD7, 0xDA, 0xDD, 0xE3, 0xEF, 0x7A, 0x6C, 0x65, +0x5F, 0x5B, 0x57, 0x53, 0x4F, 0x4E, 0x4D, 0x4C, 0x4A, 0x4A, 0x4A, 0x4B, 0x4D, 0x4F, 0x53, 0x59, +0x5F, 0x6C, 0xFE, 0xEC, 0xE3, 0xDE, 0xDC, 0xDA, 0xD9, 0xD8, 0xD7, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, +0xD8, 0xDA, 0xDC, 0xDE, 0xE3, 0xEC, 0xFB, 0x6F, 0x63, 0x5B, 0x55, 0x4F, 0x4D, 0x4C, 0x4B, 0x4C, +0x4C, 0x4D, 0x4F, 0x53, 0x58, 0x5E, 0x67, 0x73, 0xFB, 0xEE, 0xE8, 0xE3, 0xDF, 0xDC, 0xDA, 0xD9, +0xD8, 0xD8, 0xD8, 0xD9, 0xDB, 0xDD, 0xDF, 0xE1, 0xE5, 0xE9, 0xEE, 0xF6, 0x7C, 0x6E, 0x66, 0x5F, +0x5C, 0x5A, 0x58, 0x56, 0x56, 0x57, 0x58, 0x5A, 0x5D, 0x60, 0x66, 0x6D, 0x74, 0x7C, 0xFB, 0xF4, +0xEE, 0xEA, 0xE7, 0xE5, 0xE4, 0xE4, 0xE4, 0xE7, 0xEA, 0xEC, 0xED, 0xED, 0xEC, 0xED, 0xEC, 0xED, +0xEE, 0xF1, 0xF9, 0x7F, 0x79, 0x75, 0x70, 0x6D, 0x6C, 0x6C, 0x6E, 0x73, 0x79, 0xFE, 0xF9, 0xF3, +0xEE, 0xEB, 0xE9, 0xE8, 0xE6, 0xE5, 0xE6, 0xE8, 0xEA, 0xED, 0xF1, 0xF8, 0xFD, 0x7E, 0x7E, 0xFE, +0xFC, 0xF9, 0xF5, 0xF5, 0xF6, 0xFB, 0x7C, 0x77, 0x71, 0x6E, 0x6C, 0x6A, 0x69, 0x69, 0x6B, 0x6E, +0x70, 0x75, 0x7A, 0xFE, 0xF6, 0xF1, 0xEE, 0xEC, 0xEB, 0xEB, 0xEC, 0xEE, 0xF1, 0xF5, 0xFB, 0x7D, +0x7B, 0x7A, 0x7C, 0xFE, 0xFA, 0xF4, 0xF1, 0xF0, 0xF0, 0xF3, 0xF7, 0xFB, 0xFD, 0xFF, 0xFF, 0x7F, +0x7F, 0xFE, 0xFE, 0xFE, 0xFF, 0x7F, 0xFD, 0xFC, 0xFA, 0xF5, 0xF4, 0xF1, 0xEF, 0xEF, 0xEF, 0xF0, +0xF4, 0xF8, 0xFD, 0x7D, 0x78, 0x77, 0x78, 0x7A, 0x7C, 0x7C, 0x7E, 0x7C, 0x7A, 0x79, 0x76, 0x77, +0x78, 0x77, 0x7B, 0x7E, 0xFF, 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0x7F, 0x7F, 0xFF, 0x7E, 0xFE, 0xFB, +0xFA, 0xF9, 0xFA, 0xFB, 0xFE, 0x7F, 0x7C, 0x79, 0x78, 0x77, 0x77, 0x7A, 0x7C, 0x7D, 0x7E, 0x7B, +0x77, 0x74, 0x71, 0x6F, 0x6E, 0x6E, 0x6F, 0x6F, 0x70, 0x71, 0x73, 0x74, 0x76, 0x76, 0x75, 0x76, +0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x77, 0x74, 0x72, 0x70, 0x6F, 0x6E, 0x6E, 0x6E, 0x70, 0x74, +0x78, 0x7B, 0x7D, 0x7D, 0x7C, 0x7C, 0x7A, 0x76, 0x72, 0x71, 0x70, 0x70, 0x70, 0x71, 0x72, 0x72, +0x74, 0x76, 0x78, 0x7B, 0x7F, 0xFE, 0xFC, 0xF9, 0xF6, 0xF5, 0xF7, 0xFC, 0xFF, 0x7C, 0x79, 0x78, +0x77, 0x77, 0x77, 0x7A, 0x7E, 0xFE, 0xFC, 0xFA, 0xF8, 0xF8, 0xFA, 0xFC, 0xFE, 0x7D, 0x7A, 0x76, +0x74, 0x74, 0x73, 0x75, 0x76, 0x76, 0x78, 0x7A, 0x7C, 0x7E, 0xFF, 0xFB, 0xF9, 0xF8, 0xF9, 0xFD, +0x7E, 0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x78, 0x7C, 0x7F, 0xFB, 0xF6, 0xF5, 0xF2, 0xF2, 0xF3, +0xF4, 0xF7, 0xF8, 0xFA, 0xFC, 0xFE, 0xFF, 0xFF, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xFA, +0xF7, 0xF6, 0xF8, 0xFC, 0x7F, 0x7C, 0x79, 0x72, 0x6F, 0x6E, 0x6E, 0x6E, 0x6F, 0x73, 0x77, 0x77, +0x7B, 0x7D, 0x7E, 0x7F, 0x7E, 0x7C, 0x7A, 0x77, 0x75, 0x71, 0x6F, 0x6E, 0x6D, 0x6E, 0x6F, 0x70, +0x73, 0x74, 0x77, 0x79, 0x7C, 0x7D, 0x7D, 0x7D, 0x7B, 0x7A, 0x79, 0x76, 0x73, 0x70, 0x6F, 0x71, +0x73, 0x78, 0x7B, 0x7F, 0xFB, 0xF8, 0xF5, 0xF3, 0xF5, 0xF6, 0xF6, 0xF8, 0xF9, 0xFC, 0xFE, 0xFF, +0x7F, 0xFF, 0xFD, 0xFC, 0xFC, 0xFB, 0xF7, 0xF6, 0xF6, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF7, 0xF9, +0xFA, 0xFC, 0xFF, 0xFF, 0x7F, 0x7F, 0xFE, 0xFD, 0xFE, 0xFD, 0xFB, 0xFB, 0xFC, 0xFE, 0x7E, 0x7C, +0x7A, 0x79, 0x77, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7C, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, +0x7D, 0x7E, 0x7C, 0x7E, 0x7F, 0x7E, 0x7E, 0xFF, 0xFD, 0xFC, 0xFB, 0xF8, 0xF8, 0xFA, 0xFA, 0xFC, +0xFE, 0x7D, 0x78, 0x75, 0x72, 0x70, 0x70, 0x73, 0x75, 0x76, 0x78, 0x79, 0x79, 0x7A, 0x79, 0x78, +0x77, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7D, 0x7F, 0xFC, 0xF8, 0xF6, +0xF4, 0xF2, 0xF3, 0xF7, 0xF9, 0xFB, 0x7E, 0x78, 0x75, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, +0x75, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x75, 0x76, 0x79, 0x7B, +0x7C, 0x7E, 0xFE, 0xFC, 0xF9, 0xF6, 0xF5, 0xF6, 0xF7, 0xF9, 0xFC, 0xFE, 0x7C, 0x79, 0x77, 0x76, +0x75, 0x74, 0x74, 0x75, 0x74, 0x76, 0x77, 0x78, 0x79, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x78, 0x78, +0x77, 0x76, 0x77, 0x77, 0x77, 0x78, 0x7A, 0x7C, 0xFF, 0xFD, 0xFA, 0xF8, 0xF6, 0xF7, 0xF8, 0xF7, +0xF8, 0xF8, 0xF8, 0xF9, 0xFA, 0xF9, 0xF9, 0xFA, 0xFB, 0xFB, 0xFB, 0xFD, 0xFD, 0xFC, 0xFD, 0xFE, +0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7B, 0x7A, 0x79, 0x79, 0x79, 0x78, 0x79, 0x7B, 0x7C, 0x7C, 0x7C, +0x7C, 0x7B, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x71, 0x70, 0x6F, 0x6F, 0x6E, +0x6D, 0x6C, 0x6C, 0x6D, 0x6E, 0x6E, 0x6E, 0x6F, 0x6E, 0x6F, 0x70, 0x70, 0x72, 0x75, 0x78, 0x7B, +0x7B, 0x7C, 0x7D, 0xFF, 0xFD, 0xFC, 0xFA, 0xFA, 0xF9, 0xF7, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF9, +0xFA, 0xFA, 0xFA, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFB, +0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFF, 0x7F, 0xFC, 0xFA, 0xFB, 0xFA, 0xFA, 0xF9, +0xFA, 0xFC, 0xFC, 0xFE, 0xFF, 0xFE, 0xFF, 0xFE, 0xFE, 0xFD, 0xFC, 0xFD, 0xFA, 0xFA, 0xF9, 0xF8, +0xFA, 0xF8, 0xFA, 0xFA, 0xFB, 0xFE, 0xFB, 0xFF, 0xFD, 0xFD, 0xFF, 0xFB, 0xFF, 0xFA, 0xFC, 0x7F, +0xFC, 0x70, 0x6A, 0x64, 0x61, 0x67, 0x6C, 0x73, 0x61, 0x60, 0x5A, 0x47, 0x53, 0xDF, 0x7D, 0x6F, +0x71, 0x69, 0x7F, 0x72, 0x70, 0x68, 0x5A, 0x5B, 0x59, 0x55, 0x5A, 0x5D, 0x4E, 0x46, 0x51, 0x77, +0xF6, 0xEC, 0xE8, 0xE6, 0xE5, 0xE4, 0xE1, 0xE5, 0xFD, 0x60, 0x65, 0xE6, 0xDB, 0xDD, 0xE1, 0xE4, +0xE2, 0xDC, 0xD4, 0xCF, 0xCF, 0xCF, 0xD1, 0xD2, 0xCF, 0xCD, 0xCC, 0xCD, 0xD0, 0xD4, 0xD7, 0xD5, +0xCE, 0xCD, 0xD3, 0xD9, 0xDB, 0xDA, 0xD9, 0xDC, 0xE2, 0xE5, 0xF1, 0xEE, 0xD7, 0xD2, 0xD9, 0xDC, +0xDD, 0xD9, 0xDC, 0xE7, 0xDF, 0xD9, 0xDD, 0x74, 0x62, 0xFC, 0xE9, 0xF2, 0x6C, 0x5D, 0x5D, 0x61, +0x6B, 0x6C, 0x5C, 0x5D, 0x70, 0x64, 0x5B, 0x6D, 0x78, 0x61, 0x57, 0x58, 0x65, 0x62, 0x53, 0x51, +0x69, 0xF5, 0x59, 0x53, 0x69, 0x68, 0x54, 0x4F, 0x67, 0xFA, 0x5B, 0x58, 0x5D, 0x60, 0x5D, 0x4E, +0x53, 0x61, 0x5A, 0x5F, 0x63, 0x61, 0x5E, 0x4C, 0x4C, 0x5A, 0x6B, 0xF7, 0x58, 0x47, 0x51, 0x6D, +0x68, 0x5A, 0x55, 0x53, 0x4A, 0x4E, 0xEE, 0xE1, 0x56, 0x46, 0x4D, 0x74, 0x70, 0x59, 0x53, 0x4C, +0x4E, 0x62, 0xF2, 0xF3, 0x5A, 0x4A, 0x4F, 0x6D, 0x6B, 0x57, 0x63, 0xED, 0x79, 0x69, 0x62, 0x5D, +0x6C, 0x67, 0x5E, 0xF5, 0xEA, 0x69, 0x63, 0x76, 0xFA, 0x6A, 0x59, 0x5D, 0xFB, 0xF6, 0x72, 0xFB, +0x71, 0x5D, 0x65, 0x7D, 0xFC, 0x79, 0xFB, 0xE9, 0xE2, 0xDD, 0xE3, 0xF9, 0xFA, 0xF3, 0xEA, 0xEC, +0x7D, 0xF1, 0xE5, 0xF2, 0x78, 0x6D, 0x6D, 0xED, 0xE4, 0xE5, 0xE4, 0xF6, 0x7A, 0xF8, 0xE5, 0xDC, +0xEA, 0xDF, 0xCF, 0xD3, 0xE7, 0x6C, 0x78, 0xCF, 0xC9, 0xD5, 0x7E, 0x64, 0x7E, 0xD7, 0xCF, 0xD7, +0xE0, 0xE8, 0xDC, 0xCB, 0xC5, 0xCC, 0xE6, 0x73, 0xE9, 0xD2, 0xC9, 0xCA, 0xD3, 0xED, 0x68, 0xF3, +0xD9, 0xDA, 0xDC, 0xDA, 0xD7, 0xDB, 0xE1, 0xE1, 0xEA, 0x69, 0x59, 0x60, 0xEE, 0xE0, 0xDC, 0xDF, +0xE5, 0xDD, 0xE1, 0xED, 0xED, 0xF4, 0xF6, 0xF2, 0xEE, 0xED, 0xFC, 0x6F, 0x64, 0x5C, 0x5C, 0x61, +0x76, 0xEA, 0xE1, 0xEB, 0x73, 0x66, 0x60, 0x69, 0xFB, 0x7E, 0x70, 0x76, 0xFF, 0x78, 0x73, 0xEB, +0xE2, 0x6F, 0x5C, 0x69, 0xE9, 0xDB, 0xDE, 0x73, 0x5E, 0x6D, 0xED, 0xEB, 0xF4, 0xFF, 0x77, 0xFD, +0xE7, 0xE2, 0xFB, 0x66, 0x69, 0xFE, 0xFA, 0x6B, 0x63, 0x69, 0x74, 0x74, 0x66, 0x63, 0x6F, 0xFB, +0xFD, 0x73, 0x71, 0x7B, 0xF4, 0xE8, 0xE2, 0xE8, 0xF2, 0xEB, 0xDE, 0xDC, 0xDE, 0xE2, 0xE7, 0xE5, +0xDF, 0xDF, 0xE8, 0xFC, 0x6D, 0x6A, 0x66, 0x5C, 0x53, 0x51, 0x56, 0x5B, 0x59, 0x56, 0x56, 0x5A, +0x5E, 0x5A, 0x53, 0x53, 0x59, 0x5D, 0x5F, 0x64, 0x74, 0xE9, 0xD6, 0xCB, 0xCB, 0xD3, 0xDC, 0xD4, +0xC8, 0xC1, 0xBF, 0xBE, 0xBE, 0xC5, 0xCE, 0xDC, 0xEA, 0x68, 0x4B, 0x3E, 0x3B, 0x3B, 0x3D, 0x3E, +0x41, 0x45, 0x47, 0x48, 0x4A, 0x4C, 0x4A, 0x47, 0x49, 0x4F, 0x5E, 0x6D, 0xF5, 0xDB, 0xCC, 0xC5, +0xC1, 0xBF, 0xBE, 0xBC, 0xBA, 0xB7, 0xB2, 0xAF, 0xAE, 0xB7, 0xDA, 0x43, 0x38, 0x35, 0x32, 0x31, +0x33, 0x3A, 0x46, 0x54, 0x5D, 0x56, 0x4A, 0x44, 0x43, 0x46, 0x44, 0x3F, 0x40, 0x4B, 0x61, 0x7B, +0xFD, 0xE7, 0xD4, 0xCA, 0xC5, 0xBF, 0xBB, 0xB6, 0xB1, 0xAF, 0xAD, 0xAC, 0xAC, 0xB4, 0xD8, 0x3C, +0x2D, 0x2B, 0x2D, 0x2F, 0x37, 0x41, 0x54, 0x76, 0xFF, 0x68, 0x54, 0x46, 0x40, 0x44, 0x49, 0x4A, +0x49, 0x4C, 0x5C, 0xFB, 0xE9, 0xE5, 0xDB, 0xCE, 0xC8, 0xC3, 0xBE, 0xBA, 0xB6, 0xB1, 0xAE, 0xAB, +0xA9, 0xAB, 0xBD, 0x3F, 0x2A, 0x26, 0x2A, 0x31, 0x3A, 0x43, 0x58, 0xE9, 0xDB, 0xE8, 0x5E, 0x46, +0x3C, 0x3D, 0x48, 0x55, 0x56, 0x55, 0x61, 0xF3, 0xE8, 0xE6, 0xDC, 0xCF, 0xC9, 0xC0, 0xB9, 0xB4, +0xB3, 0xB3, 0xAF, 0xAA, 0xA8, 0xAF, 0x75, 0x2C, 0x22, 0x24, 0x2D, 0x3F, 0x56, 0x72, 0xE0, 0xCF, +0xD4, 0x59, 0x3F, 0x38, 0x38, 0x3E, 0x4C, 0x68, 0xE8, 0xE3, 0xEA, 0x7E, 0x67, 0x64, 0x79, 0xDC, +0xCB, 0xBF, 0xB7, 0xB1, 0xAF, 0xAE, 0xAC, 0xAA, 0xB1, 0x56, 0x29, 0x1F, 0x20, 0x2B, 0x45, 0xD1, +0xC4, 0xC7, 0xCB, 0xD8, 0x4B, 0x33, 0x2E, 0x34, 0x42, 0x6D, 0xCD, 0xC5, 0xC8, 0xD1, 0xE0, 0x69, +0x52, 0x52, 0x6D, 0xD4, 0xC6, 0xBB, 0xB1, 0xAC, 0xAB, 0xAA, 0xA8, 0xAE, 0x68, 0x28, 0x1D, 0x1E, +0x2B, 0x53, 0xBC, 0xB6, 0xBD, 0xCA, 0xE1, 0x4E, 0x33, 0x2A, 0x2C, 0x3B, 0x7D, 0xBF, 0xBB, 0xC1, +0xD5, 0xED, 0x6A, 0x4F, 0x4C, 0x58, 0x7E, 0xD6, 0xC7, 0xBB, 0xB2, 0xAD, 0xA9, 0xA6, 0xA9, 0xC3, +0x2D, 0x1D, 0x1B, 0x23, 0x41, 0xBC, 0xAF, 0xB5, 0xC2, 0xDE, 0x4F, 0x3B, 0x2D, 0x27, 0x2D, 0x49, +0xC3, 0xB5, 0xB9, 0xCB, 0x64, 0x54, 0x56, 0x51, 0x58, 0x75, 0xE3, 0xD1, 0xCA, 0xC1, 0xB6, 0xAB, +0xA6, 0xA3, 0xA6, 0xC0, 0x2B, 0x1C, 0x1A, 0x24, 0x4D, 0xB0, 0xAA, 0xB0, 0xC3, 0xF0, 0x46, 0x38, +0x2D, 0x28, 0x2B, 0x4C, 0xBC, 0xB2, 0xB6, 0xD1, 0x4B, 0x46, 0x4F, 0x58, 0x61, 0xEE, 0xE1, 0xDB, +0xCF, 0xCB, 0xBD, 0xAE, 0xA7, 0xA3, 0xA2, 0xB6, 0x2C, 0x1B, 0x19, 0x21, 0x52, 0xAB, 0xA5, 0xAE, +0xC9, 0x4F, 0x3B, 0x37, 0x32, 0x2A, 0x2A, 0x3D, 0xC9, 0xB2, 0xB1, 0xCA, 0x44, 0x3D, 0x49, 0x5F, +0xDD, 0xD8, 0x77, 0x6E, 0xED, 0xDB, 0xC7, 0xB7, 0xAB, 0xA5, 0xA3, 0xA6, 0xC8, 0x26, 0x1A, 0x1A, +0x27, 0xC5, 0xA4, 0xA3, 0xAF, 0xE9, 0x3B, 0x33, 0x34, 0x31, 0x2D, 0x31, 0x57, 0xBF, 0xB3, 0xBA, +0x78, 0x41, 0x3E, 0x4E, 0xDC, 0xCE, 0xD4, 0x78, 0x5B, 0x67, 0xDC, 0xC4, 0xB7, 0xAC, 0xA6, 0xA5, +0xA5, 0xBA, 0x2C, 0x1B, 0x19, 0x23, 0xD8, 0xA3, 0x9F, 0xAB, 0xDA, 0x34, 0x2D, 0x30, 0x33, 0x33, +0x37, 0x54, 0xC1, 0xB7, 0xBD, 0x6E, 0x41, 0x3D, 0x4A, 0xD8, 0xCA, 0xD0, 0xEB, 0x56, 0x54, 0x74, +0xCE, 0xBD, 0xAF, 0xA8, 0xA6, 0xA5, 0xAE, 0x3B, 0x1E, 0x19, 0x1E, 0x43, 0xA8, 0x9E, 0xA6, 0xC8, +0x33, 0x29, 0x2C, 0x32, 0x39, 0x3D, 0x4E, 0xCD, 0xBE, 0xC2, 0xFF, 0x40, 0x3D, 0x48, 0xE0, 0xC4, +0xCB, 0xEA, 0x4F, 0x48, 0x59, 0xD7, 0xBE, 0xB5, 0xAD, 0xA9, 0xA9, 0xA7, 0xB3, 0x34, 0x1D, 0x19, +0x20, 0xEE, 0xA2, 0x9D, 0xA8, 0x60, 0x2A, 0x26, 0x2D, 0x3B, 0x4A, 0x4E, 0x64, 0xCE, 0xC6, 0xCF, +0x57, 0x42, 0x47, 0x67, 0xCB, 0xC3, 0xD4, 0x5C, 0x48, 0x47, 0x63, 0xCA, 0xBA, 0xB2, 0xAE, 0xAC, +0xAC, 0xAB, 0xB3, 0x3D, 0x1F, 0x1B, 0x20, 0x51, 0xA5, 0x9E, 0xA8, 0x6C, 0x2A, 0x24, 0x2B, 0x3E, +0x5E, 0x6C, 0x66, 0xFA, 0xE0, 0xE4, 0x60, 0x4B, 0x4E, 0x71, 0xD2, 0xC8, 0xD8, 0x5A, 0x4A, 0x49, +0x6E, 0xC6, 0xB9, 0xB3, 0xB1, 0xAF, 0xAE, 0xAC, 0xAF, 0x48, 0x21, 0x1B, 0x1F, 0x4C, 0xA5, 0x9D, +0xA7, 0x64, 0x28, 0x23, 0x2C, 0x4A, 0xD6, 0xD9, 0x61, 0x59, 0x6C, 0xEF, 0xF8, 0x5B, 0x5B, 0xEE, +0xD5, 0xCD, 0xDB, 0x5C, 0x4D, 0x4C, 0x6E, 0xC8, 0xBB, 0xB8, 0xB8, 0xB6, 0xB3, 0xAD, 0xA8, 0xBC, +0x2D, 0x1D, 0x1B, 0x2B, 0xB7, 0x9F, 0xA1, 0xB9, 0x33, 0x23, 0x28, 0x3A, 0xEB, 0xCF, 0x77, 0x50, +0x56, 0x6E, 0xE2, 0x73, 0x55, 0x5D, 0xE6, 0xCF, 0xD9, 0x5B, 0x4B, 0x47, 0x59, 0xD2, 0xC3, 0xBD, +0xBD, 0xBC, 0xB6, 0xAE, 0xA9, 0xAB, 0x68, 0x24, 0x1B, 0x1E, 0x3C, 0xAA, 0x9E, 0xA6, 0xDE, 0x2A, +0x23, 0x2C, 0x47, 0xD1, 0xCE, 0x72, 0x55, 0x58, 0x6A, 0x78, 0x5D, 0x5B, 0xF9, 0xDA, 0xD3, 0xDE, +0x5A, 0x49, 0x4A, 0x5F, 0xD1, 0xC0, 0xBD, 0xBC, 0xB9, 0xB3, 0xAD, 0xA9, 0xB1, 0x3C, 0x1F, 0x1C, +0x24, 0xE1, 0xA4, 0x9F, 0xAD, 0x44, 0x26, 0x25, 0x32, 0x6E, 0xC3, 0xCD, 0x64, 0x4F, 0x4F, 0x62, +0x70, 0x5C, 0x68, 0xE1, 0xD4, 0xD3, 0xF6, 0x4E, 0x45, 0x4B, 0x78, 0xCA, 0xBE, 0xBC, 0xBC, 0xB8, +0xB3, 0xAC, 0xA9, 0xBC, 0x2F, 0x1E, 0x1C, 0x2A, 0xBC, 0xA0, 0xA1, 0xB7, 0x35, 0x24, 0x28, 0x3B, +0xD8, 0xC4, 0xDC, 0x53, 0x4B, 0x4F, 0x67, 0x6D, 0x65, 0xEA, 0xDB, 0xD5, 0xDA, 0x5E, 0x4B, 0x48, +0x53, 0xDB, 0xC4, 0xBD, 0xBD, 0xBB, 0xB5, 0xAE, 0xA8, 0xAB, 0x75, 0x25, 0x1B, 0x1E, 0x3D, 0xAA, +0x9E, 0xA6, 0xDC, 0x2B, 0x25, 0x2E, 0x4E, 0xCC, 0xCC, 0x66, 0x4B, 0x4C, 0x5A, 0x74, 0x6C, 0x6D, +0xDF, 0xD6, 0xD6, 0xED, 0x4D, 0x43, 0x46, 0x59, 0xD0, 0xBF, 0xBC, 0xBB, 0xB8, 0xB3, 0xAD, 0xA9, +0xB3, 0x38, 0x1E, 0x1B, 0x24, 0xCF, 0xA2, 0x9F, 0xAF, 0x3E, 0x26, 0x27, 0x36, 0x6A, 0xCD, 0xE6, +0x4F, 0x4D, 0x55, 0x6E, 0xEF, 0x63, 0x7B, 0xDA, 0xDB, 0xDF, 0x5F, 0x49, 0x47, 0x4F, 0xE8, 0xC5, +0xBD, 0xBC, 0xBB, 0xB6, 0xAF, 0xAA, 0xAA, 0xCD, 0x29, 0x1C, 0x1D, 0x34, 0xAE, 0x9F, 0xA4, 0xC7, +0x2E, 0x25, 0x2C, 0x41, 0xDB, 0xD2, 0x75, 0x5B, 0x59, 0x60, 0x6E, 0x5B, 0x5C, 0xDF, 0xD0, 0xD8, +0x74, 0x4B, 0x43, 0x4B, 0x6E, 0xCC, 0xBF, 0xBD, 0xBE, 0xBC, 0xB5, 0xAD, 0xA8, 0xAD, 0x4B, 0x22, +0x1C, 0x22, 0x65, 0xA6, 0x9F, 0xAC, 0x4C, 0x2A, 0x28, 0x33, 0x50, 0xDE, 0xF2, 0x65, 0x7C, 0xF8, +0x79, 0x5A, 0x4B, 0x5E, 0xD7, 0xCF, 0xD6, 0x5F, 0x45, 0x43, 0x4C, 0xFB, 0xC9, 0xBF, 0xBD, 0xBC, +0xB8, 0xB2, 0xAD, 0xAA, 0xB7, 0x38, 0x20, 0x1D, 0x29, 0xC6, 0xA5, 0xA4, 0xB8, 0x3C, 0x2A, 0x2C, +0x39, 0x53, 0x7F, 0x6F, 0x79, 0xE8, 0xF9, 0x61, 0x4D, 0x4B, 0xFF, 0xD0, 0xD3, 0xEC, 0x4F, 0x45, +0x49, 0x58, 0xDF, 0xC7, 0xBF, 0xBD, 0xBB, 0xB5, 0xAF, 0xA9, 0xAA, 0xCA, 0x2C, 0x1D, 0x1E, 0x36, +0xB1, 0xA2, 0xA8, 0xCE, 0x33, 0x2B, 0x30, 0x3E, 0x4F, 0x5A, 0x6D, 0xD8, 0xD2, 0xF5, 0x4F, 0x46, +0x54, 0xD4, 0xCA, 0xD7, 0x65, 0x48, 0x43, 0x4C, 0x61, 0xD7, 0xC4, 0xBF, 0xBD, 0xB7, 0xB1, 0xAD, +0xAA, 0xB0, 0x48, 0x23, 0x1D, 0x24, 0x5D, 0xAA, 0xA4, 0xB0, 0x56, 0x30, 0x2E, 0x34, 0x3E, 0x47, +0x52, 0xE3, 0xC9, 0xCE, 0x65, 0x45, 0x43, 0x6A, 0xCE, 0xCD, 0xDE, 0x58, 0x49, 0x49, 0x4F, 0x6D, +0xD1, 0xC0, 0xBB, 0xB6, 0xAF, 0xAE, 0xAA, 0xAB, 0xCF, 0x2B, 0x1D, 0x1E, 0x36, 0xB2, 0xA4, 0xA9, +0xC7, 0x3B, 0x2F, 0x31, 0x37, 0x3D, 0x46, 0x6E, 0xC7, 0xC5, 0xE5, 0x4C, 0x41, 0x50, 0xD5, 0xCB, +0xDF, 0x58, 0x4C, 0x49, 0x4E, 0x62, 0xE4, 0xC8, 0xBD, 0xB9, 0xB4, 0xAF, 0xAD, 0xA9, 0xB2, 0x41, +0x22, 0x1D, 0x26, 0xEB, 0xAA, 0xA6, 0xB3, 0x5D, 0x38, 0x32, 0x32, 0x34, 0x39, 0x4D, 0xCC, 0xBD, +0xC7, 0x60, 0x44, 0x47, 0x6D, 0xDC, 0xE2, 0xEF, 0x63, 0x58, 0x50, 0x4D, 0x5A, 0xDB, 0xC3, 0xBA, +0xB3, 0xAF, 0xAD, 0xAC, 0xAE, 0xD3, 0x2D, 0x1F, 0x20, 0x38, 0xB9, 0xA9, 0xAD, 0xC4, 0x4C, 0x39, +0x33, 0x30, 0x32, 0x3C, 0xFA, 0xBE, 0xBE, 0xD5, 0x51, 0x46, 0x4F, 0x6F, 0x7B, 0x65, 0x68, 0x76, +0x60, 0x54, 0x52, 0x61, 0xCF, 0xBF, 0xB7, 0xAE, 0xAC, 0xAB, 0xAB, 0xBC, 0x39, 0x22, 0x1E, 0x2B, +0xE7, 0xAF, 0xAC, 0xB6, 0xD1, 0x4E, 0x3A, 0x2F, 0x2D, 0x31, 0x45, 0xCC, 0xBC, 0xC2, 0xDA, 0x58, +0x4D, 0x55, 0x52, 0x52, 0x68, 0xED, 0xF4, 0x66, 0x55, 0x59, 0xEF, 0xCE, 0xBF, 0xB5, 0xAD, 0xAB, +0xAB, 0xAE, 0xCC, 0x31, 0x22, 0x22, 0x2F, 0xE8, 0xB6, 0xB1, 0xB8, 0xC4, 0x73, 0x3D, 0x2F, 0x2B, +0x2F, 0x3F, 0xDD, 0xC0, 0xBF, 0xC7, 0xD8, 0x73, 0x55, 0x46, 0x44, 0x53, 0x7B, 0xEE, 0xED, 0xF2, +0xED, 0xDC, 0xCF, 0xC1, 0xB3, 0xAC, 0xA9, 0xA9, 0xB2, 0x58, 0x2C, 0x24, 0x28, 0x36, 0x5C, 0xC7, +0xBA, 0xB6, 0xB7, 0xCA, 0x49, 0x34, 0x2D, 0x2E, 0x37, 0x49, 0xE0, 0xC4, 0xBD, 0xBE, 0xC7, 0xEA, +0x4C, 0x42, 0x44, 0x49, 0x50, 0x69, 0xDD, 0xD0, 0xCB, 0xC6, 0xBD, 0xB3, 0xAD, 0xAB, 0xAB, 0xBA, +0x49, 0x2F, 0x2B, 0x2D, 0x32, 0x3A, 0x4B, 0xD6, 0xBC, 0xB6, 0xBD, 0xD7, 0x51, 0x3D, 0x36, 0x34, +0x37, 0x3E, 0x52, 0xDE, 0xC8, 0xC3, 0xC7, 0xCE, 0xDE, 0x72, 0x56, 0x4F, 0x53, 0x5D, 0xFF, 0xDA, +0xC9, 0xBD, 0xB7, 0xB4, 0xB2, 0xB6, 0xC6, 0x62, 0x47, 0x3F, 0x3D, 0x3B, 0x3B, 0x40, 0x4E, 0x6F, +0xEC, 0x7B, 0x67, 0x5E, 0x5B, 0x59, 0x55, 0x5A, 0x65, 0x5E, 0x5A, 0x5F, 0x61, 0x5E, 0x63, 0x65, +0x61, 0x6D, 0xF5, 0xFA, 0x7A, 0x77, 0x77, 0xFF, 0xEB, 0xDC, 0xD5, 0xCE, 0xCA, 0xC8, 0xC8, 0xCD, +0xD9, 0xEC, 0x76, 0x70, 0xFD, 0xED, 0xEA, 0xEE, 0x7D, 0x66, 0x59, 0x53, 0x50, 0x4F, 0x50, 0x54, +0x56, 0x58, 0x59, 0x5A, 0x5A, 0x5C, 0x5F, 0x6B, 0xF6, 0xE5, 0xE1, 0xE7, 0xEF, 0xF5, 0xF2, 0xEA, +0xDF, 0xD8, 0xCE, 0xC8, 0xC4, 0xC5, 0xCB, 0xD4, 0xDF, 0xE9, 0xE7, 0xE1, 0xDD, 0xDB, 0xDE, 0xEE, +0x68, 0x57, 0x4F, 0x4D, 0x4D, 0x4E, 0x4F, 0x4F, 0x52, 0x54, 0x53, 0x51, 0x53, 0x57, 0x5E, 0x6F, +0xFA, 0xEF, 0xEF, 0xF3, 0xF1, 0xF1, 0xEE, 0xE6, 0xDE, 0xD6, 0xCF, 0xCD, 0xCE, 0xD3, 0xDA, 0xDC, +0xDF, 0xDF, 0xD9, 0xD5, 0xD4, 0xD7, 0xE0, 0xFE, 0x6B, 0x5F, 0x5A, 0x58, 0x56, 0x54, 0x54, 0x53, +0x53, 0x50, 0x4E, 0x4F, 0x52, 0x56, 0x5C, 0x64, 0x67, 0x66, 0x69, 0x6C, 0x6D, 0x74, 0xFA, 0xEC, +0xDF, 0xD7, 0xD6, 0xDD, 0xE6, 0xF3, 0x7B, 0xF7, 0xE8, 0xDC, 0xD3, 0xD0, 0xD2, 0xD9, 0xE1, 0xE7, +0xEB, 0xF6, 0x7B, 0x74, 0x6F, 0x6B, 0x66, 0x5E, 0x59, 0x55, 0x53, 0x52, 0x56, 0x59, 0x5C, 0x61, +0x5F, 0x64, 0x65, 0x62, 0x6F, 0x7B, 0xFC, 0xE4, 0xDC, 0xD9, 0xE2, 0x7E, 0xFF, 0xFE, 0xFF, 0xEE, +0xDF, 0xD8, 0xD6, 0xD7, 0xDB, 0xDD, 0xDD, 0xE8, 0xE7, 0xE3, 0xEA, 0xE7, 0xF9, 0x72, 0x7C, 0x5F, +0x56, 0x58, 0x58, 0x56, 0x57, 0x57, 0x53, 0x54, 0x4A, 0x42, 0x4F, 0x67, 0x6A, 0xE0, 0xD4, 0xD8, +0xD7, 0xDD, 0xFD, 0xFE, 0xE4, 0x7B, 0xFF, 0xD9, 0xDF, 0xDE, 0xD7, 0xDA, 0xCF, 0xCF, 0xD3, 0xCD, +0xD3, 0xDF, 0xDD, 0xDE, 0xF3, 0x6D, 0x5F, 0x55, 0x54, 0x55, 0x51, 0x51, 0x50, 0x4F, 0x51, 0x53, +0x57, 0x59, 0x60, 0x73, 0xFB, 0xE7, 0xE1, 0xEA, 0xF4, 0x7D, 0x6D, 0x6F, 0x7F, 0x78, 0xF5, 0xE7, +0xEA, 0xE0, 0xDE, 0xD9, 0xCD, 0xCB, 0xC5, 0xC2, 0xC5, 0xCB, 0xDB, 0xDD, 0xEC, 0x53, 0x4C, 0x45, +0x42, 0x49, 0x48, 0x49, 0x4D, 0x51, 0x5A, 0x55, 0x55, 0x5D, 0x64, 0xF4, 0xED, 0xF5, 0xEB, 0xF2, +0x7A, 0x6D, 0x60, 0x5E, 0x6E, 0xF3, 0xF7, 0xE9, 0xDF, 0xDD, 0xD4, 0xCD, 0xC8, 0xC1, 0xBC, 0xB8, +0xB5, 0xB8, 0xC7, 0xF5, 0x52, 0x3E, 0x38, 0x37, 0x36, 0x3D, 0x4B, 0x59, 0xFD, 0xDF, 0xE3, 0xFE, +0x5C, 0x54, 0x52, 0x4E, 0x50, 0x55, 0x5D, 0xFF, 0xF2, 0xF1, 0xE9, 0xFB, 0xFD, 0x74, 0x5E, 0x62, +0x7A, 0xE3, 0xD2, 0xCA, 0xC0, 0xB9, 0xB1, 0xAD, 0xAE, 0xBC, 0x68, 0x3E, 0x31, 0x2D, 0x2E, 0x30, +0x3B, 0x5B, 0xD4, 0xC7, 0xC9, 0xD6, 0x65, 0x4A, 0x46, 0x3E, 0x3D, 0x47, 0x51, 0x7F, 0xD5, 0xD0, +0xCE, 0xD2, 0xE2, 0x6E, 0x57, 0x55, 0x61, 0xEA, 0xCD, 0xBE, 0xB7, 0xB2, 0xAD, 0xAB, 0xB0, 0xCE, +0x40, 0x2F, 0x2B, 0x2D, 0x2F, 0x38, 0x59, 0xCA, 0xBD, 0xBE, 0xCF, 0x70, 0x45, 0x39, 0x3A, 0x3B, +0x3F, 0x5D, 0xD9, 0xCB, 0xC4, 0xC5, 0xCF, 0xEA, 0x62, 0x52, 0x50, 0x5C, 0x7E, 0xD1, 0xBE, 0xB5, +0xAF, 0xAE, 0xAB, 0xAC, 0xC2, 0x44, 0x2F, 0x2A, 0x2D, 0x32, 0x38, 0x55, 0xC6, 0xBA, 0xBC, 0xCF, +0x5B, 0x40, 0x36, 0x34, 0x38, 0x40, 0x66, 0xCD, 0xC4, 0xC2, 0xC6, 0xD1, 0xFE, 0x52, 0x4C, 0x4F, +0x5C, 0xEF, 0xCF, 0xC1, 0xB7, 0xAF, 0xAD, 0xAB, 0xAD, 0xC9, 0x3C, 0x2D, 0x29, 0x2D, 0x35, 0x3D, +0xF1, 0xBD, 0xB8, 0xBF, 0xE1, 0x4C, 0x3C, 0x32, 0x31, 0x39, 0x47, 0xF7, 0xCB, 0xC4, 0xC2, 0xC7, +0xD9, 0x6F, 0x54, 0x4D, 0x4F, 0x5D, 0xEF, 0xCF, 0xC1, 0xB8, 0xAF, 0xAD, 0xAB, 0xAC, 0xC9, 0x3A, +0x2C, 0x29, 0x2D, 0x37, 0x44, 0xD8, 0xB9, 0xB7, 0xC4, 0x6C, 0x44, 0x38, 0x31, 0x30, 0x39, 0x4E, +0xDF, 0xCA, 0xC5, 0xC6, 0xCD, 0xEF, 0x5E, 0x5A, 0x53, 0x55, 0x64, 0xE8, 0xCD, 0xC4, 0xBB, 0xB0, +0xAC, 0xAA, 0xAC, 0xD0, 0x36, 0x2C, 0x2B, 0x2E, 0x39, 0x4A, 0xCB, 0xB6, 0xB7, 0xC8, 0x5D, 0x43, +0x39, 0x31, 0x32, 0x3D, 0x58, 0xD9, 0xCD, 0xCA, 0xC9, 0xD6, 0x73, 0x62, 0x63, 0x62, 0x68, 0x72, +0xE9, 0xCE, 0xC6, 0xBB, 0xAF, 0xAD, 0xAB, 0xAE, 0xD7, 0x38, 0x2D, 0x2C, 0x2F, 0x3B, 0x4F, 0xCA, +0xB6, 0xB8, 0xCB, 0x5D, 0x41, 0x39, 0x32, 0x33, 0x3E, 0x59, 0xDC, 0xCF, 0xCD, 0xCB, 0xD8, 0x63, +0x53, 0x5A, 0x5E, 0x61, 0x6F, 0xEA, 0xCF, 0xC6, 0xBC, 0xB0, 0xAD, 0xAB, 0xAE, 0xEE, 0x32, 0x2C, +0x2C, 0x30, 0x3B, 0x50, 0xC9, 0xB6, 0xB9, 0xCF, 0x5D, 0x47, 0x3A, 0x32, 0x33, 0x3F, 0x63, 0xDB, +0xD5, 0xCC, 0xC8, 0xD7, 0x66, 0x56, 0x58, 0x5C, 0x5A, 0x5B, 0x7E, 0xCE, 0xC4, 0xBB, 0xB0, 0xAD, +0xAB, 0xAF, 0x7B, 0x2F, 0x2C, 0x2E, 0x31, 0x39, 0x52, 0xC6, 0xB6, 0xBA, 0xD1, 0x5C, 0x4E, 0x3E, +0x32, 0x33, 0x3F, 0x64, 0xEA, 0xFD, 0xCE, 0xC2, 0xD0, 0x6C, 0x57, 0x5D, 0x64, 0x56, 0x53, 0x6C, +0xCE, 0xC4, 0xBD, 0xB1, 0xAD, 0xAA, 0xAE, 0x6F, 0x31, 0x2F, 0x31, 0x31, 0x37, 0x4F, 0xC5, 0xB6, +0xBA, 0xD2, 0xFC, 0x60, 0x45, 0x36, 0x35, 0x41, 0x56, 0xF8, 0xF2, 0xE4, 0xC6, 0xC8, 0x7C, 0x5A, +0x6A, 0x6A, 0x57, 0x52, 0x5B, 0xDA, 0xC6, 0xC0, 0xB6, 0xAE, 0xAA, 0xAC, 0xDD, 0x33, 0x30, 0x35, +0x31, 0x30, 0x42, 0xCE, 0xBA, 0xBA, 0xCC, 0xD9, 0xD9, 0x53, 0x3A, 0x35, 0x3E, 0x4D, 0x52, 0x60, +0xD6, 0xC5, 0xD2, 0x71, 0xE7, 0x7C, 0x55, 0x53, 0x51, 0x5B, 0xEE, 0xDC, 0xD3, 0xBE, 0xB2, 0xB0, +0xAD, 0xAE, 0x67, 0x31, 0x38, 0x39, 0x2F, 0x32, 0x49, 0xD5, 0xBE, 0xBF, 0xCF, 0xCD, 0xCA, 0x5C, +0x3D, 0x3C, 0x41, 0x41, 0x47, 0x5D, 0xE1, 0xC9, 0xC7, 0xD4, 0xDD, 0xFC, 0x51, 0x4C, 0x4C, 0x4C, +0x5F, 0xE2, 0xDC, 0xCA, 0xBF, 0xBD, 0xB9, 0xB5, 0xAF, 0xBA, 0x43, 0x35, 0x44, 0x3E, 0x2F, 0x36, +0x53, 0xD4, 0xC8, 0xCC, 0xD1, 0xC3, 0xC5, 0x5E, 0x41, 0x45, 0x49, 0x42, 0x44, 0x55, 0xE9, 0xD0, +0xD1, 0xDA, 0xD6, 0xD7, 0xFD, 0x5A, 0x58, 0x5B, 0x5A, 0x5B, 0x5F, 0x6C, 0x7A, 0xE1, 0xD3, 0xD2, +0xCC, 0xC8, 0xC4, 0xBF, 0xBD, 0xBA, 0xC2, 0x49, 0x3C, 0x4C, 0x41, 0x35, 0x3B, 0x52, 0xF3, 0xD6, +0xD1, 0xCE, 0xC3, 0xC6, 0x7A, 0x53, 0x57, 0x4E, 0x44, 0x46, 0x4F, 0x64, 0xE8, 0xDF, 0xDD, 0xD4, +0xD6, 0xEC, 0x56, 0x49, 0x54, 0x5E, 0x4F, 0x57, 0xFA, 0xE1, 0xDC, 0xE0, 0xE3, 0xD6, 0xD0, 0xDC, +0xD9, 0xC9, 0xC2, 0xBD, 0xC5, 0x58, 0x50, 0xE6, 0x4B, 0x37, 0x3F, 0x4F, 0x4D, 0x52, 0x6D, 0xDD, +0xC8, 0xC8, 0xDC, 0xDC, 0xD1, 0x72, 0x4A, 0x4A, 0x4E, 0x4B, 0x4E, 0x57, 0x6A, 0xDF, 0xD7, 0xDB, +0xD5, 0xCF, 0xDA, 0xF4, 0x74, 0x67, 0x5E, 0x5E, 0x5E, 0x66, 0xF9, 0xED, 0xEC, 0xE8, 0xE4, 0xE8, +0xF4, 0xF7, 0x60, 0x52, 0x6D, 0xF3, 0x5B, 0x66, 0xE7, 0xE1, 0xE0, 0xDF, 0xDF, 0xD8, 0xD1, 0xEA, +0x6B, 0xD9, 0xD1, 0xE5, 0xE6, 0xCC, 0xC4, 0xE7, 0x52, 0xEA, 0xE4, 0x4C, 0x48, 0x59, 0x5D, 0x59, +0x5D, 0x60, 0xF7, 0xDF, 0x79, 0x6A, 0xDF, 0xDC, 0xFE, 0xF8, 0xE2, 0xF0, 0x6F, 0x6B, 0x61, 0x5F, +0x62, 0x5D, 0x5E, 0x6C, 0x76, 0x70, 0xF7, 0xE5, 0xE6, 0xE7, 0xE5, 0xEA, 0xF4, 0x7D, 0x6C, 0x66, +0x68, 0x66, 0x66, 0x73, 0xF8, 0xF3, 0xF4, 0xF6, 0xFB, 0x7E, 0x7A, 0x7E, 0xF6, 0xEF, 0xED, 0xE9, +0xE9, 0xEF, 0xFB, 0x78, 0x6E, 0x69, 0x64, 0x63, 0x68, 0x6E, 0x74, 0x7B, 0xFA, 0xF6, 0xF3, 0xFF, +0x6B, 0x69, 0x69, 0x60, 0x5F, 0x65, 0x6C, 0x73, 0x7C, 0xF3, 0xEB, 0xE9, 0xEA, 0xE8, 0xE6, 0xE6, +0xE7, 0xE4, 0xDE, 0xDD, 0xE2, 0xE2, 0xE1, 0xE9, 0xF8, 0x77, 0x6B, 0x62, 0x5D, 0x5B, 0x5A, 0x59, +0x5A, 0x5B, 0x5D, 0x5E, 0x5E, 0x5E, 0x5F, 0x62, 0x67, 0x6D, 0x78, 0xFA, 0xF2, 0xEE, 0xEF, 0xF3, +0xF7, 0xF8, 0xFA, 0xFE, 0xFA, 0xF3, 0xF1, 0xEF, 0xEA, 0xE7, 0xE5, 0xE6, 0xE9, 0xEF, 0xFB, 0x79, +0x70, 0x6C, 0x6A, 0x6C, 0x6F, 0x77, 0x7C, 0xFD, 0xFB, 0x7F, 0x73, 0x6C, 0x69, 0x69, 0x6C, 0x73, +0xFA, 0xED, 0xE9, 0xE5, 0xE1, 0xE4, 0xE8, 0xE8, 0xE7, 0xE7, 0xE5, 0xE2, 0xE0, 0xDD, 0xDC, 0xE1, +0xE3, 0xE2, 0xEC, 0x7C, 0x6C, 0x63, 0x5D, 0x5B, 0x59, 0x58, 0x5A, 0x5B, 0x5B, 0x5C, 0x5F, 0x60, +0x5F, 0x60, 0x65, 0x6A, 0x75, 0xF8, 0xEC, 0xE7, 0xE6, 0xE7, 0xEA, 0xF0, 0xF8, 0xF9, 0xF4, 0xED, +0xE9, 0xE5, 0xE3, 0xE3, 0xE6, 0xEB, 0xF6, 0x76, 0x6C, 0x67, 0x62, 0x5F, 0x61, 0x64, 0x69, 0x6F, +0x73, 0x73, 0x75, 0x75, 0x70, 0x6E, 0x6F, 0x6E, 0x6E, 0x75, 0xFE, 0xF3, 0xEC, 0xE9, 0xE9, 0xE9, +0xED, 0xFA, 0x7A, 0x74, 0x71, 0x72, 0x73, 0x74, 0x7A, 0xFF, 0xFF, 0x7B, 0x72, 0x6E, 0x6D, 0x6C, +0x6C, 0x6E, 0x73, 0x7C, 0xFC, 0xF7, 0xF0, 0xEB, 0xE6, 0xE0, 0xDD, 0xDB, 0xDB, 0xDB, 0xDC, 0xDF, +0xE2, 0xE3, 0xE8, 0xF2, 0x7D, 0x6C, 0x61, 0x5D, 0x5A, 0x58, 0x59, 0x5C, 0x5E, 0x61, 0x66, 0x69, +0x6A, 0x6B, 0x6C, 0x6B, 0x6C, 0x75, 0xFE, 0xF7, 0xEE, 0xEA, 0xE8, 0xE6, 0xE9, 0xEC, 0xEB, 0xEB, +0xEE, 0xF0, 0xF2, 0xF6, 0xF9, 0xFD, 0x7F, 0xFF, 0x7C, 0x74, 0x6D, 0x69, 0x66, 0x64, 0x64, 0x68, +0x6B, 0x6D, 0x75, 0x7D, 0xFC, 0xF8, 0xFA, 0xFC, 0xFA, 0xF7, 0xF5, 0xF0, 0xEB, 0xE6, 0xE4, 0xE5, +0xE9, 0xED, 0xF2, 0xFC, 0x7A, 0x74, 0x6E, 0x6C, 0x6A, 0x69, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6E, +0x6D, 0x6E, 0x70, 0x71, 0x74, 0x79, 0x7B, 0x7E, 0xFB, 0xF6, 0xF8, 0xF9, 0xF6, 0xF5, 0xF8, 0xFA, +0xF7, 0xF0, 0xEE, 0xF0, 0xF7, 0xFC, 0x7D, 0x73, 0x6C, 0x6B, 0x6B, 0x6A, 0x6B, 0x6B, 0x6B, 0x6B, +0x6C, 0x6D, 0x6D, 0x6E, 0x71, 0x71, 0x71, 0x72, 0x77, 0x7D, 0xFC, 0xF7, 0xF3, 0xED, 0xEB, 0xEB, +0xEE, 0xF4, 0xF9, 0xFE, 0x79, 0x77, 0x7B, 0x7F, 0x7F, 0xFF, 0xFF, 0x7B, 0x77, 0x76, 0x77, 0x79, +0x79, 0x7A, 0x7C, 0xFF, 0xFC, 0xFC, 0xFA, 0xF8, 0xF9, 0xF9, 0xFA, 0xFD, 0xFE, 0xFD, 0xFA, 0xF8, +0xF5, 0xF2, 0xF1, 0xF2, 0xF4, 0xF8, 0xFE, 0x7C, 0x79, 0x77, 0x77, 0x7A, 0x7E, 0x7F, 0x7C, 0x79, +0x78, 0x75, 0x73, 0x72, 0x71, 0x73, 0x75, 0x76, 0x78, 0x7D, 0xFD, 0xFB, 0xFC, 0xFF, 0x7D, 0x79, +0x76, 0x76, 0x77, 0x7C, 0xFB, 0xF5, 0xF3, 0xF3, 0xF3, 0xF7, 0x7D, 0x74, 0x6F, 0x6D, 0x6B, 0x6C, +0x6E, 0x73, 0x77, 0x77, 0x77, 0x7A, 0x7A, 0x76, 0x73, 0x72, 0x6F, 0x6D, 0x6B, 0x6C, 0x6F, 0x76, +0x7A, 0x7D, 0xFE, 0xFC, 0x7E, 0x7A, 0x75, 0x71, 0x6E, 0x6D, 0x6E, 0x71, 0x77, 0x7D, 0xFE, 0xFC, +0xFC, 0xFE, 0xFF, 0x7D, 0x7B, 0x7C, 0x7E, 0xFF, 0xFF, 0xFC, 0xF9, 0xF7, 0xF6, 0xF8, 0xFA, 0xFC, +0xFF, 0x7E, 0x7F, 0xFF, 0xFD, 0xFB, 0xF7, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFD, 0x7D, 0x7A, 0x7A, +0x7D, 0x7E, 0x7F, 0xFF, 0xFE, 0xFE, 0x7E, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0xFF, 0xFD, 0xFD, 0xFD, +0xFB, 0xF8, 0xF7, 0xF9, 0xFD, 0x7C, 0x79, 0x78, 0x78, 0x77, 0x77, 0x76, 0x75, 0x75, 0x75, 0x75, +0x75, 0x74, 0x76, 0x78, 0x79, 0x7B, 0x7D, 0x7F, 0xFD, 0xFB, 0xFF, 0x7A, 0x79, 0x7D, 0xFE, 0xFD, +0xFD, 0xFC, 0xFD, 0xFA, 0xF5, 0xF2, 0xF3, 0xF6, 0xF8, 0xF9, 0xFC, 0xFF, 0xFD, 0xF8, 0xF5, 0xF5, +0xF6, 0xFA, 0xFC, 0xFD, 0x7F, 0x7A, 0x78, 0x76, 0x75, 0x75, 0x77, 0x7B, 0x7E, 0x7E, 0x7E, 0x7F, +0x7E, 0x7C, 0x79, 0x76, 0x76, 0x78, 0x79, 0x78, 0x7B, 0x7E, 0xFF, 0x7F, 0x7C, 0x7A, 0x78, 0x75, +0x73, 0x73, 0x74, 0x76, 0x77, 0x78, 0x7B, 0x7B, 0x79, 0x79, 0x78, 0x77, 0x78, 0x74, 0x71, 0x72, +0x73, 0x76, 0x77, 0x77, 0x79, 0x79, 0x77, 0x76, 0x75, 0x76, 0x78, 0x7B, 0x7F, 0xFC, 0xFB, 0xFB, +0xFA, 0xFB, 0xFE, 0x7C, 0x79, 0x79, 0x78, 0x78, 0x7B, 0xFF, 0xFD, 0xFD, 0xFC, 0xFC, 0xFE, 0x7E, +0x7A, 0x78, 0x77, 0x75, 0x75, 0x76, 0x78, 0x79, 0x7A, 0x7C, 0x7C, 0x7C, 0x7B, 0x77, 0x78, 0x7A, +0x7A, 0x7A, 0x7C, 0x7E, 0xFF, 0x7F, 0x7F, 0xFF, 0xFF, 0x7F, 0x7E, 0x7F, 0x7E, 0x7C, 0x7A, 0x7A, +0x79, 0x79, 0x7B, 0x7E, 0x7E, 0x7F, 0xFD, 0xFC, 0xFD, 0xFD, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, +0xFF, 0x7E, 0x7D, 0x7F, 0xFF, 0xFF, 0xFE, 0xFC, 0xFB, 0xFC, 0xFC, 0xFE, 0x7E, 0x7F, 0x7E, 0x7B, +0x7C, 0x7D, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7A, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x77, 0x7A, +0x7C, 0x7D, 0x7E, 0x7E, 0x7C, 0x79, 0x76, 0x77, 0x79, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0x7D, +0x7D, 0x7C, 0x7A, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x7C, 0x7E, 0x7D, 0x7E, 0x7E, 0x7C, 0x7B, 0x7C, +0x7C, 0x7C, 0x7D, 0xFF, 0xFC, 0xFB, 0xFB, 0xFC, 0xFF, 0x7C, 0x79, 0x77, 0x74, 0x75, 0x77, 0x7A, +0x7D, 0x7E, 0xFF, 0xFD, 0xFD, 0xFE, 0x7E, 0x7D, 0x7D, 0x7B, 0x7A, 0x7B, 0x7D, 0x7E, 0xFE, 0xFD, +0xFF, 0x7F, 0x7D, 0x7B, 0x7A, 0x78, 0x76, 0x76, 0x79, 0x7C, 0x7E, 0xFF, 0xFF, 0x7F, 0x7E, 0x7C, +0x7A, 0x79, 0x78, 0x78, 0x77, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0x7F, 0x7E, 0x7D, 0x7B, 0x7A, +0x7B, 0x7C, 0x7D, 0xFE, 0xFC, 0xFA, 0xF9, 0xFA, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFA, 0xF8, 0xF7, +0xF6, 0xF7, 0xF9, 0xFB, 0xFE, 0x7E, 0x7C, 0x7A, 0x79, 0x79, 0x7B, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, +0x7E, 0x7C, 0x7B, 0x79, 0x7A, 0x7C, 0x7C, 0x7E, 0x7E, 0x7F, 0xFF, 0x7F, 0x7E, 0x7C, 0x7B, 0x79, +0x77, 0x76, 0x76, 0x78, 0x7B, 0x7B, 0x7B, 0x7A, 0x7A, 0x7A, 0x77, 0x77, 0x78, 0x78, 0x79, 0x7B, +0x7D, 0x79, 0x79, 0x7E, 0x79, 0x78, 0x79, 0x78, 0x7A, 0x78, 0x7D, 0x7D, 0x7C, 0xFF, 0x7D, 0x7F, +0x7E, 0x7B, 0x7A, 0x76, 0x79, 0x76, 0x78, 0x7B, 0x79, 0xFF, 0x7D, 0xFB, 0xFD, 0x7D, 0xF9, 0x7B, +0xFF, 0x79, 0x75, 0xFF, 0x6E, 0x7F, 0x71, 0x73, 0x79, 0x51, 0x60, 0xE2, 0x6F, 0x7D, 0xF7, 0xF5, +0x77, 0x72, 0xE4, 0x50, 0x4C, 0xDE, 0xFB, 0x66, 0xE5, 0xF6, 0x6F, 0x6C, 0xE7, 0xDC, 0x6E, 0xFD, +0xE6, 0x7E, 0xE9, 0x77, 0x62, 0xE3, 0xE9, 0x6C, 0x71, 0xEA, 0xDE, 0x75, 0x7E, 0xE8, 0x75, 0xF8, +0x7A, 0xFC, 0xF2, 0x65, 0xF8, 0xEE, 0xF9, 0xF4, 0x73, 0xE4, 0xF9, 0x6E, 0xE5, 0x75, 0x67, 0x5A, +0x50, 0x57, 0x5A, 0x7D, 0x6C, 0x64, 0xDA, 0xED, 0x64, 0xEA, 0xE9, 0xF5, 0x7E, 0x6F, 0xFC, 0xF2, +0x66, 0x63, 0xF7, 0x7D, 0x78, 0xF6, 0xF8, 0xE1, 0xE2, 0xF9, 0xEB, 0xE4, 0xED, 0xFE, 0xFA, 0xF6, +0xF1, 0xF2, 0x6F, 0xFE, 0xE8, 0xFF, 0x7F, 0xEA, 0xE8, 0xED, 0xEE, 0xEA, 0xEB, 0xED, 0xF8, 0xEF, +0xE8, 0x7F, 0xF5, 0xE6, 0xF7, 0xF2, 0xF3, 0xF2, 0xDF, 0xEB, 0xF5, 0xE3, 0xEC, 0xF2, 0xEF, 0xFC, +0xED, 0xEF, 0xFD, 0xED, 0xF0, 0x7C, 0x77, 0xFE, 0xF1, 0x77, 0x79, 0xEF, 0xF6, 0xF8, 0xFB, 0x72, +0x75, 0x79, 0x78, 0x70, 0x6E, 0x7C, 0x7D, 0x74, 0x79, 0x77, 0x6E, 0x71, 0x7D, 0x6F, 0x6B, 0x7D, +0xFE, 0x76, 0x7A, 0x7D, 0x7F, 0x75, 0x6C, 0x7B, 0xF7, 0x7A, 0x7B, 0x7E, 0x74, 0x79, 0x75, 0x70, +0x7C, 0x79, 0xFD, 0xF6, 0x6E, 0x6E, 0x7B, 0x6B, 0x67, 0x6D, 0x6E, 0x6A, 0x67, 0x6A, 0x6D, 0x6F, +0x6B, 0x67, 0x6D, 0x6C, 0x65, 0x63, 0x5E, 0x65, 0x6A, 0x5F, 0x68, 0x6C, 0x60, 0x6C, 0x7D, 0x6D, +0x6E, 0x7D, 0x7C, 0xFF, 0xEE, 0xEB, 0xEC, 0xE3, 0xDE, 0xE1, 0xE4, 0xE0, 0xE8, 0xF8, 0xEE, 0xFA, +0x6D, 0x69, 0x5C, 0x58, 0x59, 0x53, 0x50, 0x4E, 0x4D, 0x4E, 0x4F, 0x4F, 0x53, 0x51, 0x51, 0x54, +0x55, 0x56, 0x5A, 0x5E, 0x69, 0xF7, 0xE2, 0xD8, 0xCF, 0xCE, 0xCD, 0xCC, 0xCE, 0xCE, 0xCA, 0xC7, +0xC2, 0xBF, 0xBE, 0xBD, 0xC2, 0xD5, 0xF1, 0x62, 0x4B, 0x3F, 0x3D, 0x3D, 0x3E, 0x40, 0x42, 0x4A, +0x51, 0x51, 0x51, 0x55, 0x56, 0x4F, 0x4D, 0x4E, 0x50, 0x52, 0x55, 0x5C, 0x69, 0xFA, 0xE4, 0xD9, +0xCD, 0xC9, 0xC5, 0xC1, 0xBF, 0xBB, 0xBB, 0xBD, 0xB9, 0xB7, 0xB5, 0xB7, 0xC8, 0xDD, 0x61, 0x43, +0x3C, 0x38, 0x38, 0x3D, 0x40, 0x46, 0x4E, 0x5A, 0x60, 0x5D, 0x5B, 0x5B, 0x5A, 0x58, 0x56, 0x58, +0x5C, 0x5E, 0x5E, 0x64, 0x6B, 0x6D, 0xF9, 0xED, 0xE5, 0xDC, 0xD9, 0xD2, 0xCC, 0xC5, 0xBF, 0xBF, +0xBA, 0xB7, 0xB6, 0xB1, 0xB7, 0xCB, 0xFA, 0x49, 0x3A, 0x35, 0x31, 0x33, 0x3A, 0x42, 0x4C, 0x5C, +0xFD, 0xE1, 0xEE, 0x68, 0x66, 0x5C, 0x51, 0x4F, 0x4D, 0x55, 0x5F, 0x5D, 0x64, 0x71, 0xFA, 0xED, +0xEF, 0xEB, 0xDE, 0xD3, 0xCC, 0xC3, 0xBE, 0xBD, 0xB9, 0xB8, 0xB5, 0xAF, 0xB7, 0xCC, 0x60, 0x3F, +0x39, 0x34, 0x2F, 0x31, 0x3A, 0x47, 0x56, 0x6F, 0xE3, 0xDA, 0xD5, 0xEC, 0x56, 0x50, 0x4E, 0x4B, +0x4B, 0x4C, 0x57, 0x7B, 0xE7, 0xE0, 0xDC, 0xD5, 0xD6, 0xDE, 0xEC, 0xEF, 0xDE, 0xD7, 0xCC, 0xC1, +0xBD, 0xB8, 0xB5, 0xB4, 0xB0, 0xB6, 0xCB, 0x58, 0x3E, 0x38, 0x34, 0x2F, 0x2F, 0x38, 0x45, 0x59, +0x7D, 0xDD, 0xD1, 0xCE, 0xDD, 0x63, 0x53, 0x4E, 0x4C, 0x4A, 0x4B, 0x53, 0x69, 0xE7, 0xDB, 0xD5, +0xD0, 0xCE, 0xD3, 0xDC, 0xE4, 0xEA, 0xE8, 0xE2, 0xD5, 0xC8, 0xC0, 0xBB, 0xB8, 0xB5, 0xB2, 0xB9, +0xD1, 0x54, 0x40, 0x3A, 0x34, 0x2F, 0x2F, 0x36, 0x3F, 0x4C, 0x5B, 0x7E, 0xDE, 0xD4, 0xDB, 0xFF, +0x62, 0x58, 0x55, 0x53, 0x4F, 0x52, 0x5D, 0x6F, 0xF0, 0xE4, 0xDE, 0xDA, 0xD8, 0xDC, 0xE1, 0xE5, +0xDF, 0xDC, 0xD6, 0xCC, 0xC6, 0xC1, 0xBE, 0xBB, 0xB8, 0xBC, 0xCE, 0x67, 0x4B, 0x44, 0x3E, 0x38, +0x35, 0x37, 0x3D, 0x45, 0x4B, 0x53, 0x61, 0xFA, 0xE4, 0xEC, 0x7F, 0x79, 0x78, 0x79, 0x70, 0x68, +0x68, 0x70, 0x7B, 0x7D, 0x7D, 0xF9, 0xEE, 0xEA, 0xE8, 0xE6, 0xE1, 0xDB, 0xD6, 0xCF, 0xCB, 0xC8, +0xC5, 0xC1, 0xBE, 0xBF, 0xC7, 0xD5, 0xF9, 0x5F, 0x55, 0x4A, 0x42, 0x3E, 0x3E, 0x41, 0x45, 0x48, +0x4C, 0x56, 0x5F, 0x6F, 0xF8, 0xEF, 0xE7, 0xE4, 0xE6, 0xE2, 0xEA, 0xF5, 0xFD, 0x75, 0x75, 0x79, +0x75, 0x76, 0x7E, 0xFA, 0xF1, 0xE9, 0xE0, 0xDA, 0xD3, 0xCF, 0xCC, 0xCA, 0xC7, 0xC4, 0xC5, 0xCC, +0xD3, 0xDF, 0xFF, 0x69, 0x58, 0x4C, 0x47, 0x43, 0x42, 0x42, 0x43, 0x46, 0x4C, 0x55, 0x59, 0x62, +0x77, 0xFD, 0xEE, 0xEC, 0xF3, 0xEC, 0xF2, 0x76, 0x76, 0x6F, 0x6E, 0x79, 0x79, 0x7F, 0xF3, 0xED, +0xE4, 0xDD, 0xDB, 0xD7, 0xD3, 0xD0, 0xCE, 0xCC, 0xCB, 0xCA, 0xCC, 0xD1, 0xD6, 0xDD, 0xEA, 0x7E, +0x62, 0x56, 0x4F, 0x4C, 0x49, 0x48, 0x49, 0x4C, 0x50, 0x56, 0x58, 0x5C, 0x67, 0x6F, 0x6C, 0x6E, +0x6D, 0x6A, 0x6F, 0x6D, 0x6B, 0x6E, 0x6D, 0x76, 0xFA, 0xF9, 0xF1, 0xEB, 0xE7, 0xE1, 0xDE, 0xDD, +0xDB, 0xD8, 0xD7, 0xD4, 0xD2, 0xD0, 0xCF, 0xD4, 0xD8, 0xDA, 0xDF, 0xEA, 0xF8, 0x6D, 0x60, 0x5C, +0x58, 0x56, 0x56, 0x56, 0x57, 0x59, 0x5B, 0x5B, 0x5A, 0x5C, 0x5F, 0x5F, 0x5F, 0x63, 0x66, 0x6B, +0x72, 0x77, 0x7E, 0xF7, 0xF0, 0xEC, 0xE9, 0xE9, 0xE8, 0xE8, 0xE8, 0xE8, 0xEA, 0xE7, 0xE6, 0xE5, +0xE3, 0xE1, 0xDD, 0xDA, 0xD9, 0xD8, 0xDD, 0xDF, 0xDD, 0xE0, 0xE7, 0xEE, 0xFE, 0x74, 0x6C, 0x62, +0x5C, 0x59, 0x56, 0x54, 0x52, 0x51, 0x51, 0x52, 0x55, 0x58, 0x59, 0x5D, 0x62, 0x68, 0x70, 0x75, +0x7D, 0xF9, 0xF8, 0xF4, 0xF5, 0xF9, 0xF5, 0xF3, 0xF3, 0xF2, 0xF2, 0xEF, 0xED, 0xEB, 0xEA, 0xE6, +0xE3, 0xE0, 0xDC, 0xDA, 0xD7, 0xD8, 0xDB, 0xDB, 0xDA, 0xDC, 0xDF, 0xE8, 0xF6, 0x7F, 0x6E, 0x60, +0x5B, 0x58, 0x56, 0x54, 0x53, 0x52, 0x53, 0x59, 0x5C, 0x5E, 0x63, 0x68, 0x6F, 0x7B, 0x7C, 0xFF, +0xFC, 0xFC, 0xFB, 0xFC, 0xFD, 0xF8, 0xF7, 0xF6, 0xF4, 0xF5, 0xF3, 0xF0, 0xEF, 0xED, 0xEB, 0xE8, +0xE4, 0xE0, 0xDD, 0xDA, 0xD9, 0xDA, 0xDC, 0xDC, 0xDC, 0xE0, 0xE9, 0xF8, 0x76, 0x6B, 0x61, 0x5C, +0x5A, 0x5A, 0x5A, 0x5B, 0x5C, 0x5E, 0x62, 0x67, 0x6B, 0x6D, 0x6F, 0x72, 0x75, 0x76, 0x76, 0x75, +0x74, 0x79, 0x7E, 0x7B, 0x78, 0x7D, 0xFB, 0xFB, 0xFD, 0xFA, 0xF6, 0xF5, 0xF2, 0xEF, 0xEC, 0xE9, +0xE4, 0xDF, 0xDE, 0xDE, 0xE0, 0xE7, 0xEA, 0xEC, 0xF2, 0xFE, 0x76, 0x6F, 0x6F, 0x6D, 0x6A, 0x6A, +0x6B, 0x6C, 0x6C, 0x69, 0x67, 0x67, 0x66, 0x65, 0x64, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6B, 0x6E, +0x71, 0x76, 0x7A, 0x7D, 0xFE, 0xFC, 0xFA, 0xF8, 0xF4, 0xF0, 0xEE, 0xEC, 0xEA, 0xE9, 0xE8, 0xE9, +0xEB, 0xEB, 0xEC, 0xED, 0xEE, 0xED, 0xEB, 0xE9, 0xEA, 0xE9, 0xE9, 0xEA, 0xEC, 0xF0, 0xF6, 0xFD, +0x78, 0x71, 0x6D, 0x69, 0x67, 0x66, 0x65, 0x65, 0x66, 0x67, 0x66, 0x66, 0x67, 0x67, 0x66, 0x66, +0x69, 0x6B, 0x6D, 0x73, 0x7A, 0xFE, 0xF7, 0xF3, 0xEF, 0xEE, 0xEE, 0xEC, 0xEB, 0xEA, 0xE8, 0xE7, +0xE5, 0xE3, 0xE1, 0xE1, 0xE1, 0xE3, 0xE6, 0xE8, 0xEB, 0xEF, 0xF8, 0x7E, 0x75, 0x6F, 0x6B, 0x69, +0x67, 0x66, 0x65, 0x65, 0x66, 0x67, 0x67, 0x68, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, +0x70, 0x6F, 0x6F, 0x6F, 0x72, 0x75, 0x79, 0xFF, 0xFB, 0xF6, 0xF2, 0xEF, 0xEE, 0xED, 0xEE, 0xF0, +0xF3, 0xF6, 0xF8, 0xFC, 0xFF, 0x7D, 0x79, 0x76, 0x72, 0x6E, 0x6D, 0x6B, 0x6B, 0x6C, 0x6C, 0x6D, +0x6E, 0x71, 0x76, 0x7B, 0xFF, 0xFE, 0xFD, 0xFC, 0xFD, 0x7F, 0x7B, 0x78, 0x75, 0x74, 0x75, 0x77, +0x7A, 0x7E, 0xFC, 0xF9, 0xF6, 0xF5, 0xF4, 0xF4, 0xF5, 0xF7, 0xF8, 0xF8, 0xF7, 0xF6, 0xF5, 0xF5, +0xF6, 0xF8, 0xFA, 0xFC, 0x7F, 0x7B, 0x79, 0x78, 0x77, 0x77, 0x79, 0x7D, 0xFD, 0xF9, 0xF4, 0xF2, +0xF1, 0xF1, 0xF3, 0xF5, 0xFA, 0xFE, 0x7F, 0xFF, 0xFD, 0xFC, 0xFB, 0xF7, 0xF5, 0xF4, 0xF4, 0xF6, +0xF8, 0xFB, 0xFD, 0xFF, 0x7E, 0x7E, 0x7E, 0xFF, 0x7F, 0x7D, 0x7D, 0x7E, 0x7E, 0x7B, 0x79, 0x77, +0x76, 0x75, 0x74, 0x74, 0x75, 0x78, 0x7C, 0x7F, 0xFE, 0xFD, 0xFE, 0xFF, 0x7E, 0x7C, 0x7B, 0x79, +0x79, 0x7A, 0x7D, 0xFE, 0xFC, 0xFA, 0xF8, 0xF8, 0xF9, 0xFB, 0xFD, 0x7F, 0x7B, 0x78, 0x76, 0x75, +0x74, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x75, 0x76, 0x76, 0x77, 0x7A, 0x7C, +0x7E, 0xFF, 0xFF, 0xFF, 0x7F, 0x7D, 0x7C, 0x7A, 0x78, 0x77, 0x77, 0x76, 0x79, 0x7B, 0x7E, 0xFF, +0xFE, 0xFD, 0xFD, 0xFF, 0x7E, 0x7C, 0x7C, 0x7B, 0x79, 0x78, 0x78, 0x78, 0x77, 0x75, 0x74, 0x74, +0x74, 0x74, 0x75, 0x76, 0x79, 0x7C, 0x7E, 0xFF, 0xFC, 0xF8, 0xF7, 0xF6, 0xF7, 0xF7, 0xF7, 0xF9, +0xFC, 0xFF, 0x7E, 0x7D, 0x7C, 0x7D, 0x7F, 0xFF, 0xFC, 0xFB, 0xFA, 0xF8, 0xF8, 0xF8, 0xF6, 0xF5, +0xF5, 0xF4, 0xF4, 0xF5, 0xF7, 0xF8, 0xFA, 0xFD, 0x7F, 0x7E, 0x7D, 0x7C, 0x7C, 0x7D, 0x7E, 0xFE, +0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF9, 0xF9, 0xFA, 0xFB, 0xFD, 0xFF, 0x7E, 0x7D, 0x79, 0x77, 0x75, +0x72, 0x71, 0x70, 0x70, 0x70, 0x71, 0x71, 0x70, 0x71, 0x72, 0x71, 0x72, 0x71, 0x72, 0x73, 0x72, +0x72, 0x71, 0x71, 0x71, 0x72, 0x74, 0x74, 0x76, 0x77, 0x77, 0x77, 0x78, 0x77, 0x78, 0x78, 0x78, +0x7A, 0x7C, 0x7C, 0x7D, 0x7E, 0x7F, 0xFF, 0xFF, 0xFE, 0xFD, 0xFF, 0x7E, 0x7D, 0x7B, 0x7C, 0x7B, +0x7B, 0x7B, 0x7B, 0x7B, 0x7C, 0x7B, 0x7A, 0x7B, 0x7B, 0x7A, 0x7B, 0x7B, 0x7C, 0x7E, 0xFF, 0xFD, +0xFB, 0xFB, 0xFB, 0xFB, 0xFC, 0xFE, 0xFF, 0x7F, 0x7D, 0x7C, 0x7B, 0x7A, 0x7A, 0x7B, 0x7B, 0x7D, +0x7F, 0x7F, 0xFF, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, +0xFF, 0xFF, 0xFF, 0xFD, 0xFA, 0xF9, 0xF7, 0xF5, 0xF4, 0xF3, 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, +0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xFA, 0xFC, 0xFE, 0xFE, 0xFF, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, +0x7F, 0x7D, 0x7C, 0x7D, 0x7B, 0x7A, 0x7D, 0x7B, 0x7B, 0x7C, 0x7B, 0x7B, 0x7B, 0x79, 0x78, 0x77, +0x77, 0x76, 0x75, 0x76, 0x75, 0x74, 0x74, 0x75, 0x74, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73, 0x74, +0x72, 0x70, 0x70, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x71, 0x72, 0x73, 0x73, 0x76, +0x79, 0x79, 0x79, 0x7A, 0x7B, 0x7C, 0x7B, 0x7D, 0x7E, 0x7D, 0x7F, 0x7D, 0x7C, 0x7B, 0x7B, 0x7C, +0x7B, 0x7B, 0x7A, 0x78, 0x7A, 0x7B, 0x7D, 0x7E, 0x7E, 0xFF, 0x7D, 0x7E, 0x7C, 0x7C, 0x7B, 0x78, +0x7C, 0x7A, 0x7C, 0x7D, 0x7B, 0x7E, 0x7C, 0x7F, 0x7D, 0x7A, 0x7E, 0x78, 0x7B, 0x6F, 0x68, 0x5C, +0x4C, 0x58, 0xDD, 0xE1, 0xEB, 0xE1, 0xE9, 0xEF, 0xF8, 0xE9, 0xE1, 0xED, 0xF9, 0xFC, 0xF2, 0xED, +0x7D, 0x76, 0xFB, 0xF9, 0x7C, 0x70, 0x6F, 0x78, 0x79, 0x6D, 0x6D, 0x76, 0x7D, 0xFE, 0x7A, 0x79, +0xFC, 0xFD, 0xFD, 0xFA, 0xFB, 0xFA, 0xFC, 0xFF, 0xFC, 0xFC, 0xFE, 0xFD, 0xFE, 0xFB, 0xFB, 0xFE, +0xFE, 0x7E, 0x7D, 0x7C, 0x7C, 0x7B, 0x78, 0x7D, 0x7D, 0xFF, 0xFA, 0xFF, 0xF9, 0xF9, 0xFA, 0xF7, +0x7F, 0xF9, 0x7A, 0x7A, 0x6F, 0x51, 0x52, 0x6E, 0x71, 0xF1, 0xD8, 0xD3, 0xDB, 0xEF, 0xE2, 0xDB, +0xED, 0xF6, 0xF3, 0xEF, 0xF4, 0x6A, 0x74, 0x73, 0x57, 0x5E, 0x77, 0x6E, 0xFD, 0xF4, 0xFC, 0x7D, +0x73, 0xE9, 0xDE, 0xE2, 0xDE, 0xE3, 0xE5, 0xE8, 0xFA, 0xF7, 0xFA, 0x6F, 0x6C, 0x6A, 0x6B, 0x6A, +0x66, 0x6B, 0x75, 0x70, 0x74, 0xFA, 0xFB, 0xFD, 0xF8, 0xF3, 0xF2, 0xFB, 0xF5, 0xED, 0xEF, 0xEB, +0xE5, 0xDF, 0xDA, 0xD7, 0xD5, 0xD3, 0xD3, 0xD4, 0xD8, 0xE0, 0xEE, 0x76, 0x5D, 0x53, 0x4D, 0x49, +0x46, 0x43, 0x42, 0x43, 0x43, 0x45, 0x48, 0x4B, 0x4F, 0x57, 0x60, 0x6D, 0xF7, 0xE3, 0xDB, 0xD4, +0xCF, 0xCB, 0xC8, 0xC4, 0xBE, 0xBC, 0xB9, 0xB4, 0xB6, 0xBC, 0xC1, 0xC3, 0xD5, 0x4F, 0x4B, 0x43, +0x36, 0x33, 0x34, 0x32, 0x31, 0x36, 0x3B, 0x3F, 0x48, 0x60, 0xDF, 0xD2, 0xC9, 0xC1, 0xC3, 0xC6, +0xC7, 0xCF, 0xE3, 0x67, 0x56, 0x47, 0x3E, 0x3F, 0x3C, 0x3B, 0x43, 0x48, 0x4F, 0xFA, 0xD5, 0xC5, +0xBD, 0xB7, 0xB1, 0xAE, 0xAC, 0xAE, 0xB1, 0xB5, 0xC0, 0xD7, 0x5D, 0x40, 0x38, 0x31, 0x2E, 0x2D, +0x2C, 0x2E, 0x32, 0x37, 0x3F, 0x4F, 0xF8, 0xD0, 0xC4, 0xBC, 0xBB, 0xBB, 0xBB, 0xBE, 0xC7, 0xD0, +0xF1, 0x56, 0x48, 0x40, 0x3D, 0x3B, 0x3D, 0x42, 0x49, 0x63, 0xDA, 0xCB, 0xBC, 0xB6, 0xB0, 0xAE, +0xAF, 0xAF, 0xB4, 0xBC, 0xC6, 0xFE, 0x4C, 0x3E, 0x34, 0x30, 0x2E, 0x2D, 0x2E, 0x30, 0x35, 0x3C, +0x46, 0x62, 0xDE, 0xCA, 0xBE, 0xBD, 0xBB, 0xBA, 0xBD, 0xC3, 0xCB, 0xDC, 0x6B, 0x59, 0x51, 0x52, +0x60, 0xFF, 0xD5, 0xC4, 0xBE, 0xBC, 0xBA, 0xB9, 0xBB, 0xC3, 0xC8, 0xD6, 0x5A, 0x4C, 0x42, 0x39, +0x36, 0x35, 0x32, 0x34, 0x36, 0x39, 0x41, 0x47, 0x58, 0xE0, 0xDA, 0xC9, 0xC1, 0xC4, 0xC0, 0xC0, +0xC6, 0xCA, 0xD1, 0xDC, 0xF3, 0x6E, 0xFC, 0xE8, 0xDB, 0xCB, 0xC2, 0xBE, 0xBD, 0xBE, 0xBD, 0xC0, +0xCD, 0xCE, 0xEC, 0x4E, 0x4C, 0x40, 0x38, 0x39, 0x37, 0x35, 0x38, 0x38, 0x3B, 0x43, 0x49, 0x54, +0xEA, 0xDB, 0xCE, 0xC5, 0xC5, 0xC3, 0xC1, 0xC7, 0xCA, 0xCF, 0xDB, 0xE9, 0xFD, 0xF7, 0xE9, 0xDD, +0xCE, 0xC6, 0xC1, 0xBF, 0xC0, 0xBF, 0xC3, 0xCF, 0xD0, 0xE6, 0x51, 0x4E, 0x43, 0x3A, 0x3B, 0x38, +0x35, 0x38, 0x38, 0x3A, 0x3F, 0x44, 0x4E, 0x5F, 0xEF, 0xD7, 0xCD, 0xC8, 0xC6, 0xC4, 0xC6, 0xC9, +0xCC, 0xD4, 0xDD, 0xE6, 0xE1, 0xDA, 0xD7, 0xCA, 0xC3, 0xC4, 0xC4, 0xC1, 0xC3, 0xCC, 0xCF, 0xD8, +0x60, 0x54, 0x4E, 0x3F, 0x3D, 0x3D, 0x39, 0x3A, 0x3C, 0x3B, 0x3D, 0x47, 0x48, 0x51, 0x79, 0xFA, +0xDD, 0xCD, 0xCF, 0xCC, 0xC8, 0xCD, 0xCE, 0xCE, 0xD7, 0xDC, 0xDC, 0xD7, 0xD4, 0xCC, 0xC3, 0xC1, +0xBF, 0xBF, 0xC2, 0xC1, 0xCE, 0xDB, 0xDD, 0x54, 0x4C, 0x49, 0x3C, 0x3B, 0x3B, 0x38, 0x3A, 0x3B, +0x3C, 0x3E, 0x48, 0x4C, 0x55, 0xF3, 0xEC, 0xDB, 0xCD, 0xD1, 0xCD, 0xCB, 0xD2, 0xD1, 0xD6, 0xDD, +0xE1, 0xE2, 0xD7, 0xD3, 0xCA, 0xC0, 0xBE, 0xBE, 0xBF, 0xBE, 0xC1, 0xCF, 0xD0, 0xED, 0x4E, 0x4D, +0x41, 0x3A, 0x3A, 0x37, 0x35, 0x38, 0x3A, 0x3A, 0x3F, 0x49, 0x4A, 0x62, 0xE7, 0xEA, 0xCE, 0xCB, +0xCF, 0xC8, 0xCB, 0xD1, 0xCF, 0xD7, 0xE2, 0xE5, 0xE5, 0xDF, 0xD5, 0xCC, 0xC5, 0xBE, 0xBE, 0xC0, +0xBC, 0xC0, 0xCD, 0xC8, 0xDC, 0x58, 0x5B, 0x47, 0x3C, 0x3D, 0x39, 0x36, 0x39, 0x3A, 0x39, 0x3E, +0x47, 0x49, 0x59, 0xEA, 0xEC, 0xD0, 0xC9, 0xCD, 0xC7, 0xC8, 0xCE, 0xCD, 0xD2, 0xDC, 0xDF, 0xDF, +0xDD, 0xD6, 0xCB, 0xC6, 0xBF, 0xBF, 0xC4, 0xBD, 0xC4, 0xD1, 0xC9, 0xEF, 0x55, 0x5D, 0x43, 0x3D, +0x3E, 0x38, 0x37, 0x3A, 0x3A, 0x3A, 0x3E, 0x45, 0x48, 0x56, 0x74, 0xF8, 0xD8, 0xCF, 0xD0, 0xCB, +0xCB, 0xCE, 0xCE, 0xD2, 0xD9, 0xDC, 0xDC, 0xD7, 0xD3, 0xCA, 0xC4, 0xC0, 0xBF, 0xC2, 0xBE, 0xC3, +0xCF, 0xCB, 0xE5, 0x58, 0x5C, 0x45, 0x3D, 0x3E, 0x39, 0x37, 0x39, 0x3A, 0x3A, 0x3D, 0x45, 0x46, +0x52, 0x79, 0x73, 0xD7, 0xCD, 0xD1, 0xC8, 0xC8, 0xCD, 0xCA, 0xCF, 0xD5, 0xD7, 0xDC, 0xDA, 0xD4, +0xCD, 0xC7, 0xC1, 0xC0, 0xC5, 0xBF, 0xC2, 0xD1, 0xCA, 0xDA, 0x5A, 0x68, 0x4C, 0x3E, 0x42, 0x3B, +0x38, 0x3B, 0x3A, 0x3A, 0x3D, 0x42, 0x44, 0x4B, 0x62, 0x66, 0xF1, 0xD0, 0xD6, 0xCD, 0xC8, 0xCE, +0xCA, 0xCB, 0xD1, 0xCF, 0xD2, 0xD2, 0xCE, 0xC9, 0xC5, 0xC1, 0xBF, 0xC5, 0xC1, 0xC0, 0xD3, 0xCE, +0xD6, 0x57, 0x5F, 0x4E, 0x3E, 0x41, 0x3D, 0x39, 0x3B, 0x3B, 0x3A, 0x3D, 0x42, 0x44, 0x4C, 0x5A, +0x5E, 0xEC, 0xDD, 0xDC, 0xCE, 0xD0, 0xD1, 0xCD, 0xD4, 0xD4, 0xD4, 0xDA, 0xD3, 0xCE, 0xCB, 0xC4, +0xBF, 0xBE, 0xC2, 0xBE, 0xBF, 0xCD, 0xCB, 0xD5, 0x5B, 0x5F, 0x4D, 0x3E, 0x3F, 0x3B, 0x37, 0x39, +0x3A, 0x39, 0x3C, 0x3F, 0x42, 0x4B, 0x59, 0x61, 0xEA, 0xDA, 0xD6, 0xCD, 0xCD, 0xCE, 0xCD, 0xCF, +0xD3, 0xD6, 0xDA, 0xD7, 0xD2, 0xCE, 0xC7, 0xC2, 0xBF, 0xC0, 0xC1, 0xBE, 0xC8, 0xCE, 0xCB, 0x79, +0x5A, 0x5C, 0x41, 0x3F, 0x3E, 0x38, 0x39, 0x3A, 0x39, 0x3A, 0x3E, 0x42, 0x45, 0x51, 0x62, 0x65, +0xDD, 0xD5, 0xD7, 0xCA, 0xCC, 0xCE, 0xCA, 0xCE, 0xD0, 0xCF, 0xCF, 0xCD, 0xC9, 0xC4, 0xBF, 0xBD, +0xBE, 0xBF, 0xBD, 0xC5, 0xCE, 0xCB, 0xF8, 0x58, 0x5B, 0x43, 0x3E, 0x3E, 0x39, 0x38, 0x3A, 0x39, +0x3A, 0x3E, 0x44, 0x45, 0x51, 0x6E, 0x69, 0xDC, 0xCF, 0xD7, 0xCA, 0xCB, 0xD0, 0xCC, 0xD1, 0xD5, +0xD5, 0xD5, 0xCF, 0xCB, 0xC5, 0xBF, 0xBC, 0xBD, 0xBF, 0xBB, 0xC3, 0xCC, 0xC8, 0xEF, 0x5B, 0x5D, +0x41, 0x3D, 0x3D, 0x37, 0x37, 0x38, 0x37, 0x38, 0x3B, 0x41, 0x43, 0x4E, 0x6B, 0x67, 0xDC, 0xCE, +0xD4, 0xC9, 0xC8, 0xCE, 0xCA, 0xCE, 0xD5, 0xD4, 0xD5, 0xD3, 0xCE, 0xC7, 0xC3, 0xBE, 0xBE, 0xC3, +0xBD, 0xC2, 0xD0, 0xC9, 0xDE, 0x57, 0x61, 0x47, 0x3D, 0x3F, 0x39, 0x36, 0x38, 0x38, 0x38, 0x3A, +0x41, 0x40, 0x48, 0x6A, 0x5C, 0xF7, 0xCD, 0xDB, 0xCD, 0xC6, 0xD1, 0xCC, 0xCC, 0xD6, 0xD5, 0xD3, +0xCF, 0xCE, 0xC6, 0xC0, 0xBF, 0xBE, 0xBF, 0xBE, 0xC0, 0xCC, 0xCB, 0xDB, 0x5D, 0x5B, 0x49, 0x3E, +0x3E, 0x39, 0x37, 0x38, 0x38, 0x38, 0x3B, 0x40, 0x42, 0x4A, 0x63, 0x66, 0xE5, 0xCE, 0xD0, 0xCA, +0xC7, 0xCA, 0xCA, 0xCC, 0xCE, 0xD1, 0xCF, 0xCC, 0xCC, 0xC4, 0xBF, 0xBF, 0xBE, 0xC0, 0xBE, 0xC2, +0xCE, 0xCC, 0xE2, 0x58, 0x59, 0x47, 0x3D, 0x3D, 0x39, 0x37, 0x39, 0x39, 0x39, 0x3C, 0x40, 0x44, +0x4D, 0x5D, 0x6F, 0xE0, 0xD4, 0xCF, 0xCC, 0xCB, 0xCB, 0xCD, 0xCF, 0xCF, 0xD4, 0xD1, 0xCC, 0xCA, +0xC4, 0xBF, 0xBD, 0xBF, 0xBF, 0xBE, 0xC7, 0xCF, 0xCE, 0x79, 0x52, 0x51, 0x41, 0x3C, 0x3B, 0x38, +0x36, 0x38, 0x39, 0x38, 0x3D, 0x44, 0x44, 0x55, 0x70, 0x76, 0xD5, 0xCF, 0xCF, 0xC9, 0xCB, 0xCB, +0xCD, 0xD1, 0xD1, 0xD9, 0xD2, 0xCD, 0xCD, 0xC4, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xC9, 0xCF, 0xD0, +0x6A, 0x53, 0x4F, 0x3F, 0x3C, 0x3B, 0x38, 0x37, 0x38, 0x39, 0x3A, 0x3E, 0x44, 0x4A, 0x56, 0x75, +0xE7, 0xD7, 0xCD, 0xCB, 0xCA, 0xC9, 0xCA, 0xCD, 0xCE, 0xCF, 0xD3, 0xCE, 0xCA, 0xC7, 0xC0, 0xBE, +0xBE, 0xBF, 0xBF, 0xC1, 0xCD, 0xD2, 0xDB, 0x5C, 0x4F, 0x4A, 0x3E, 0x3C, 0x3B, 0x39, 0x38, 0x3A, +0x3A, 0x3C, 0x43, 0x46, 0x4E, 0x71, 0x7A, 0xDD, 0xCE, 0xD0, 0xCB, 0xCA, 0xCD, 0xCC, 0xD1, 0xD2, +0xD5, 0xD7, 0xCC, 0xCC, 0xC7, 0xBE, 0xBF, 0xBF, 0xBE, 0xC0, 0xC6, 0xCD, 0xD5, 0xEE, 0x54, 0x4D, +0x45, 0x3C, 0x3B, 0x39, 0x37, 0x38, 0x39, 0x3A, 0x3E, 0x44, 0x4A, 0x59, 0x71, 0xE8, 0xD4, 0xCE, +0xCC, 0xC9, 0xCB, 0xCB, 0xCE, 0xD2, 0xD4, 0xD7, 0xD2, 0xCD, 0xCB, 0xC4, 0xBF, 0xBF, 0xC0, 0xC0, +0xC0, 0xC9, 0xD1, 0xD8, 0x73, 0x52, 0x4B, 0x42, 0x3C, 0x3A, 0x39, 0x38, 0x38, 0x39, 0x3C, 0x3F, +0x41, 0x4E, 0x5D, 0x63, 0xDF, 0xD3, 0xD1, 0xCD, 0xCB, 0xCC, 0xD1, 0xD1, 0xD3, 0xDE, 0xDA, 0xD1, +0xCF, 0xCC, 0xC4, 0xBF, 0xC2, 0xC2, 0xBF, 0xC6, 0xCD, 0xD2, 0xE3, 0x63, 0x4F, 0x4A, 0x42, 0x3C, +0x3B, 0x3A, 0x39, 0x3A, 0x3B, 0x3F, 0x42, 0x47, 0x5A, 0x62, 0x7C, 0xD5, 0xD2, 0xCF, 0xCC, 0xCD, +0xCE, 0xD5, 0xD6, 0xD9, 0xE0, 0xD9, 0xD2, 0xCE, 0xCB, 0xC4, 0xBF, 0xC2, 0xC2, 0xBF, 0xC6, 0xCD, +0xD4, 0xE2, 0x67, 0x4F, 0x4B, 0x43, 0x3D, 0x3C, 0x3B, 0x3B, 0x3B, 0x3C, 0x42, 0x43, 0x49, 0x60, +0x6B, 0xF5, 0xD4, 0xD2, 0xD0, 0xD2, 0xD2, 0xD4, 0xDF, 0xDD, 0xDF, 0xEA, 0xDC, 0xD5, 0xD0, 0xCB, +0xC4, 0xC0, 0xC2, 0xBF, 0xC0, 0xC7, 0xC9, 0xD0, 0xDD, 0x7A, 0x57, 0x52, 0x48, 0x3F, 0x3F, 0x3D, +0x3C, 0x3C, 0x3D, 0x42, 0x44, 0x49, 0x5B, 0x64, 0x7C, 0xDE, 0xDB, 0xDB, 0xDC, 0xDA, 0xDF, 0xEE, +0xE9, 0xE6, 0xE8, 0xE3, 0xDB, 0xD0, 0xCD, 0xCC, 0xC5, 0xC3, 0xC5, 0xC2, 0xC3, 0xC8, 0xCD, 0xD1, +0xDE, 0x6F, 0x5B, 0x50, 0x4A, 0x44, 0x40, 0x3F, 0x3E, 0x3E, 0x42, 0x43, 0x47, 0x4F, 0x58, 0x5F, +0x69, 0xF6, 0xED, 0xF7, 0xEB, 0xE8, 0xEA, 0xEC, 0xE8, 0xE0, 0xE0, 0xDD, 0xD7, 0xD0, 0xCE, 0xCC, +0xC8, 0xC7, 0xC6, 0xC4, 0xC8, 0xC9, 0xCB, 0xD2, 0xDA, 0xEF, 0x71, 0x5B, 0x4F, 0x4E, 0x49, 0x45, +0x46, 0x45, 0x47, 0x47, 0x4A, 0x4E, 0x4E, 0x54, 0x5A, 0x5D, 0x62, 0x65, 0x70, 0x6C, 0x69, 0xFA, +0x7A, 0x7A, 0xE6, 0xE2, 0xDF, 0xDA, 0xD5, 0xCF, 0xD1, 0xD1, 0xCB, 0xCE, 0xD4, 0xCE, 0xD1, 0xD9, +0xDB, 0xE0, 0xE1, 0xEE, 0x6A, 0x74, 0x6C, 0x5A, 0x5B, 0x5A, 0x56, 0x56, 0x53, 0x56, 0x57, 0x53, +0x57, 0x5B, 0x59, 0x59, 0x5D, 0x65, 0x60, 0x61, 0x6F, 0x73, 0xF7, 0xEF, 0xEA, 0xDD, 0xDF, 0xDC, +0xD5, 0xD8, 0xDC, 0xDC, 0xDA, 0xDF, 0xE5, 0xE1, 0xEB, 0xED, 0xED, 0xFC, 0xFF, 0x70, 0x6C, 0x6C, +0x66, 0x5F, 0x5F, 0x62, 0x5F, 0x60, 0x60, 0x5A, 0x5F, 0x64, 0x5C, 0x64, 0x6E, 0x5F, 0x5E, 0x69, +0x6B, 0x7B, 0xF0, 0xFA, 0xE9, 0xE4, 0xE8, 0xDF, 0xE6, 0xEB, 0xE1, 0xE2, 0xE6, 0xE3, 0xE8, 0xED, +0xE5, 0xFC, 0x71, 0xE9, 0xFE, 0x7A, 0xEC, 0x73, 0x7E, 0x77, 0x64, 0xFD, 0x74, 0x66, 0x7B, 0x6C, +0x6B, 0x72, 0x6A, 0x79, 0x73, 0x71, 0xF4, 0x79, 0xFC, 0xEF, 0xF9, 0xEB, 0xF1, 0xF0, 0xE2, 0xE3, +0xE0, 0xE2, 0xE3, 0xEB, 0xFC, 0xEA, 0xF8, 0x6F, 0x70, 0x69, 0x77, 0x6C, 0x6D, 0xEF, 0x6B, 0x67, +0x6D, 0x65, 0x76, 0x75, 0x6F, 0x7E, 0x69, 0x67, 0x6F, 0x68, 0x6F, 0x73, 0x68, 0x69, 0x68, 0x69, +0x75, 0xFA, 0xEE, 0xF2, 0xEA, 0xDE, 0xE2, 0xE7, 0xE5, 0xEB, 0xF3, 0xED, 0xE8, 0xF7, 0x7F, 0xFA, +0x74, 0x6A, 0x68, 0x65, 0x66, 0x68, 0x64, 0x65, 0x68, 0x64, 0x6D, 0x77, 0x72, 0x70, 0x69, 0x77, +0x78, 0x64, 0x6B, 0x68, 0x60, 0x66, 0x67, 0x67, 0x61, 0x6D, 0xEB, 0xE8, 0xEC, 0xEB, 0xEA, 0xF7, +0xF5, 0xE2, 0xE5, 0xF6, 0xF8, 0xF0, 0x7E, 0x77, 0xFA, 0x76, 0x77, 0x7D, 0x6E, 0x74, 0x74, 0x72, +0x72, 0x6D, 0x75, 0x74, 0x74, 0x75, 0x76, 0xEF, 0xEE, 0xEF, 0xEA, 0xFA, 0x7F, 0xF2, 0xF6, 0xF7, +0xEF, 0xEA, 0xE4, 0xE5, 0xE7, 0xE3, 0xE9, 0xEC, 0xE8, 0xEB, 0xF0, 0xF8, 0xFC, 0x7F, 0x73, 0x73, +0x70, 0x72, 0x75, 0x69, 0x67, 0x6A, 0x6C, 0x6D, 0x6C, 0x70, 0x6D, 0x6D, 0x78, 0x72, 0x6F, 0x6E, +0x6C, 0x6F, 0x77, 0xF7, 0xEF, 0xF1, 0xF6, 0xF4, 0xF1, 0xFC, 0xF8, 0xEE, 0xF0, 0xEE, 0xEF, 0xEF, +0xEC, 0xEE, 0xF3, 0xF4, 0x76, 0x69, 0x77, 0xFA, 0x70, 0x75, 0x7E, 0x6E, 0x6D, 0x6E, 0x6E, 0x6E, +0x6D, 0x70, 0x74, 0x79, 0xFE, 0x7D, 0x78, 0x7C, 0x7A, 0x75, 0x78, 0x75, 0x70, 0x7C, 0xFC, 0xFB, +0xF4, 0xF3, 0xED, 0xEC, 0xF6, 0xF1, 0xEF, 0xF6, 0xF0, 0xFB, 0x7A, 0x7C, 0x74, 0x79, 0x74, 0x6C, +0x6C, 0x63, 0x67, 0x6C, 0x62, 0x66, 0x67, 0x68, 0x6C, 0x6A, 0x7D, 0x78, 0x6B, 0x7B, 0x71, 0x75, +0xFB, 0x75, 0x76, 0x7E, 0xEE, 0xED, 0xFA, 0xE8, 0xEE, 0x7F, 0xE4, 0xE9, 0xED, 0xE1, 0xEC, 0xEE, +0xE6, 0xF6, 0xFE, 0xF7, 0xFF, 0x7B, 0x72, 0x7C, 0x7F, 0x6B, 0x6C, 0x66, 0x67, 0x71, 0x66, 0x72, +0xFF, 0x69, 0x7B, 0xF7, 0xFF, 0xF3, 0xF6, 0xF3, 0xF2, 0xEE, 0xED, 0xFF, 0xF6, 0xED, 0xFB, 0xF2, +0xE9, 0xF0, 0xEC, 0xE6, 0xF4, 0xF2, 0xF5, 0x7C, 0xED, 0x7E, 0x6B, 0x7B, 0x77, 0xFE, 0x7A, 0x69, +0x68, 0x60, 0x65, 0x66, 0x61, 0x71, 0x74, 0x74, 0xFC, 0x7E, 0xFA, 0xFF, 0x7E, 0xF9, 0xFB, 0xEE, +0xED, 0xEF, 0xEF, 0xF4, 0xEC, 0xEC, 0xF2, 0xF0, 0xEF, 0xED, 0xF4, 0xF6, 0xEF, 0xFD, 0xF8, 0xF1, +0x77, 0x74, 0x7A, 0x70, 0x6F, 0x79, 0x76, 0x6A, 0x68, 0x6C, 0x6C, 0x69, 0x65, 0x66, 0x6E, 0x73, +0x6C, 0x6D, 0x7A, 0x79, 0x7A, 0xFE, 0x73, 0x72, 0x7A, 0x7E, 0xF3, 0xEF, 0xEE, 0xF1, 0xF6, 0xEC, +0xEF, 0xFA, 0xEE, 0xF5, 0xFE, 0xF2, 0xF0, 0xF7, 0xFA, 0xF9, 0xFB, 0xFB, 0x7A, 0x6B, 0x6B, 0x72, +0x6C, 0x6A, 0x76, 0x74, 0x6E, 0x72, 0x6C, 0x6B, 0x6F, 0x6B, 0x6E, 0x71, 0x6D, 0x75, 0x76, 0x70, +0x78, 0x7C, 0xFA, 0xF2, 0xF7, 0xF1, 0xED, 0xF3, 0xF4, 0xF6, 0xFA, 0xF0, 0xEF, 0xFD, 0x7B, 0xFF, +0x78, 0x6C, 0x70, 0x72, 0x6E, 0x73, 0x6D, 0x6D, 0x6D, 0x65, 0x65, 0x69, 0x6F, 0x70, 0x6B, 0x6E, +0x71, 0x6E, 0x6E, 0x6F, 0x7A, 0x7D, 0x7E, 0xEF, 0xF4, 0x7D, 0xFB, 0xF3, 0xEC, 0xEB, 0xF0, 0xEF, +0xEE, 0xEE, 0xF3, 0xF0, 0xED, 0xFF, 0xFF, 0xF3, 0x7E, 0xFB, 0xFF, 0x73, 0x7E, 0x7A, 0x76, 0x6F, +0x6C, 0x7A, 0x74, 0x6F, 0xFF, 0x7B, 0x79, 0xF7, 0xF5, 0xFB, 0xF6, 0xF3, 0x7E, 0x7D, 0xFA, 0xFD, +0xF6, 0xF5, 0x7D, 0x7B, 0x7A, 0xFF, 0xFB, 0x7D, 0x75, 0x76, 0xF3, 0xF3, 0x78, 0xFE, 0x76, 0x6B, +0x7B, 0xFB, 0x75, 0x69, 0x6C, 0xF6, 0xF6, 0x7B, 0x6F, 0x69, 0x6E, 0x72, 0x70, 0x74, 0x78, 0xFF, +0x7F, 0xFD, 0xF5, 0xF8, 0xF5, 0xF9, 0x75, 0x74, 0x7D, 0xF7, 0xFB, 0x70, 0x7E, 0xE9, 0xEF, 0xF7, +0xE6, 0xED, 0x74, 0x7A, 0xF7, 0x7D, 0x71, 0x77, 0xFE, 0xF6, 0xFC, 0x6B, 0x6B, 0x72, 0x69, 0x6D, +0x7B, 0x7C, 0xFD, 0x6F, 0x6B, 0xFC, 0x7F, 0x73, 0xF9, 0xF5, 0x70, 0x6E, 0xFD, 0xFF, 0x7C, 0xFB, +0x70, 0x76, 0xEF, 0x7D, 0x75, 0xFB, 0xF6, 0xEF, 0xF6, 0x7C, 0x79, 0x76, 0xFE, 0x7D, 0x73, 0xFD, +0xFE, 0x76, 0x6E, 0x66, 0x6B, 0x75, 0x6D, 0x7D, 0xF2, 0x6D, 0x75, 0xED, 0x7A, 0x6D, 0x7E, 0xF9, +0xFE, 0x6E, 0x78, 0xF4, 0x6E, 0x73, 0xF8, 0x74, 0xFF, 0xFE, 0x77, 0xF6, 0x7C, 0x71, 0x7F, 0x7E, +0x7E, 0x79, 0x78, 0x7C, 0x6E, 0x6F, 0x70, 0x6D, 0xFD, 0xFA, 0x6C, 0x6B, 0x71, 0x70, 0x7B, 0x7A, +0x7C, 0xFD, 0x6D, 0x75, 0xED, 0xF8, 0xFC, 0xF7, 0xFB, 0xEE, 0xEF, 0x79, 0xFF, 0xED, 0xF8, 0x7A, +0xF1, 0xED, 0xF7, 0xFC, 0xF8, 0xF1, 0xF8, 0x79, 0x7D, 0xF6, 0x78, 0x6E, 0xFD, 0xFB, 0x72, 0x6E, +0x6C, 0x74, 0xFE, 0xFF, 0xF7, 0xFE, 0x6D, 0x75, 0x79, 0x6F, 0x7C, 0x7D, 0x76, 0x78, 0x7A, 0x7F, +0x75, 0x7D, 0xF7, 0xF8, 0xEF, 0x7B, 0x7A, 0xF3, 0xFF, 0xEF, 0xF8, 0xFE, 0xF6, 0x6E, 0xF4, 0xED, +0x6F, 0x7C, 0x74, 0x75, 0xF2, 0x7C, 0x75, 0xF9, 0xEE, 0xFF, 0x70, 0x7C, 0x7F, 0xFD, 0xFD, 0xFA, +0x79, 0x6C, 0x7C, 0x7F, 0xFD, 0xF3, 0x78, 0xFE, 0xF7, 0xFC, 0xED, 0xF1, 0xFD, 0xFE, 0x7D, 0xF4, +0xED, 0xF4, 0xFA, 0xFD, 0x70, 0x73, 0xF6, 0xFF, 0x7D, 0xF7, 0x79, 0x72, 0x78, 0x7D, 0x77, 0x6E, +0x71, 0x6C, 0x6A, 0x7D, 0x74, 0x71, 0x7D, 0x6E, 0x79, 0xF8, 0x70, 0x7C, 0xFE, 0x6D, 0x6F, 0x6E, +0x6D, 0x7D, 0xFD, 0xFB, 0xFA, 0x7C, 0xFD, 0xFA, 0xF7, 0xF4, 0xFD, 0x7B, 0x76, 0x7D, 0xF3, 0xF5, +0xFD, 0xF5, 0xED, 0x7A, 0x6D, 0xF5, 0x7C, 0x76, 0xEF, 0x77, 0x6E, 0xFF, 0x74, 0x79, 0xFD, 0x76, +0x7A, 0x7E, 0x7B, 0x7D, 0x78, 0x73, 0x7A, 0xFB, 0xFB, 0x7E, 0xFB, 0xF2, 0xF8, 0xF9, 0xFB, 0xFE, +0xF5, 0xF6, 0xF9, 0x7E, 0x73, 0xF7, 0xFA, 0x74, 0xFC, 0x7B, 0x70, 0xFF, 0xFC, 0x7E, 0x7C, 0xFE, +0xFF, 0x7C, 0xFC, 0x7E, 0x79, 0xFF, 0x7C, 0x79, 0x79, 0x79, 0x7A, 0x79, 0x7A, 0x7C, 0x7A, 0x75, +0x72, 0x7C, 0xFC, 0xFE, 0xFE, 0xFC, 0xF9, 0xFE, 0xFE, 0xFA, 0x7C, 0xFD, 0xFC, 0x77, 0x7B, 0x7A, +0x73, 0x78, 0x7A, 0x78, 0x7B, 0x77, 0x6E, 0x70, 0x7B, 0x7A, 0x72, 0x74, 0x76, 0x75, 0x77, 0x75, +0x70, 0x6F, 0x6F, 0x6F, 0x74, 0x77, 0x72, 0x6F, 0x70, 0x79, 0x79, 0x6F, 0x7E, 0xFA, 0x72, 0x79, +0x79, 0x78, 0xFE, 0x78, 0xFF, 0xFE, 0x76, 0xFF, 0xFF, 0x7D, 0xFF, 0x7E, 0x7B, 0x78, 0x7C, 0x75, +0x75, 0xFF, 0xFF, 0xF8, 0xF6, 0xFD, 0xF5, 0xF4, 0xF6, 0xFC, 0x7C, 0x7C, 0x7B, 0xFC, 0xFD, 0xFD, +0xFD, 0x77, 0x7A, 0x7F, 0x7E, 0xFC, 0xFA, 0xF7, 0xFF, 0xFE, 0xF1, 0xFD, 0xFD, 0xF0, 0xF9, 0xF8, +0xEE, 0xEF, 0xF8, 0x7E, 0x79, 0x77, 0x6C, 0x66, 0x6A, 0x68, 0x67, 0x71, 0x74, 0x77, 0x7E, 0x7B, +0xFD, 0xFD, 0x7F, 0xFF, 0x79, 0xFE, 0xFE, 0x75, 0x78, 0x7A, 0x74, 0x70, 0x76, 0x77, 0x75, 0x7C, +0x7C, 0x79, 0x78, 0x77, 0x78, 0x7C, 0x7E, 0x77, 0x74, 0x79, 0x77, 0x78, 0x78, 0x77, 0x7B, 0x78, +0x77, 0x77, 0x7A, 0xFE, 0x7D, 0xFE, 0xF6, 0xFB, 0xFC, 0xF8, 0xF6, 0xFA, 0xFD, 0xFB, 0xFC, 0x7D, +0x7B, 0xFB, 0xF5, 0xFC, 0xFF, 0xFD, 0xFE, 0xFF, 0x7F, 0xFC, 0xF8, 0xFF, 0x7F, 0xF7, 0xF9, 0xFA, +0xF9, 0xFB, 0xFA, 0xFA, 0xFA, 0xF8, 0xF8, 0xFD, 0x7E, 0xF8, 0xF7, 0xEF, 0xE0, 0xE1, 0xF7, 0x6E, +0x69, 0x65, 0x5C, 0x5B, 0x61, 0x69, 0x6E, 0x76, 0xF8, 0xEF, 0xF2, 0xEB, 0xE3, 0xDE, 0xE2, 0xFA, +0x66, 0x5B, 0x5F, 0x6E, 0x6E, 0xFB, 0xED, 0xED, 0xEC, 0xF8, 0x7E, 0x7B, 0x6E, 0x67, 0x60, 0x65, +0x6E, 0x6F, 0x78, 0xFB, 0x7E, 0x7D, 0xFA, 0xF9, 0xF7, 0xF5, 0xF7, 0xEE, 0xEB, 0xF3, 0xFA, 0x7A, +0x6D, 0x69, 0x6A, 0x69, 0x64, 0x69, 0x6E, 0x6F, 0x78, 0xFB, 0xFB, 0x7C, 0xF8, 0xF1, 0xFB, 0xF4, +0xF9, 0x7D, 0xF8, 0x7D, 0xFD, 0xF3, 0x7C, 0xFD, 0xF4, 0x7A, 0x6F, 0x79, 0xFF, 0x75, 0x78, 0xFA, +0xFB, 0xFE, 0xFB, 0xF9, 0xFE, 0xFF, 0xFF, 0xFC, 0xF5, 0xFD, 0x79, 0xFF, 0xF9, 0xFA, 0xFF, 0xFF, +0x7B, 0x74, 0x75, 0x6F, 0x71, 0x7D, 0x74, 0x75, 0x79, 0x71, 0x77, 0x7E, 0x7E, 0x7C, 0x74, 0x71, +0x77, 0x7A, 0x7F, 0xFB, 0x72, 0x69, 0x74, 0x74, 0x6A, 0x74, 0x7E, 0x79, 0x76, 0x74, 0x7F, 0x7C, +0x76, 0xF8, 0xF8, 0x7E, 0x7D, 0x7E, 0xFE, 0x77, 0x7B, 0xF8, 0x7B, 0xFF, 0xF3, 0xFC, 0xFF, 0xFE, +0xFD, 0xF5, 0xF6, 0xF3, 0xF2, 0xFA, 0xF8, 0xF3, 0xFB, 0x7E, 0xFA, 0xFA, 0x7E, 0xFE, 0xFC, 0x7C, +0x78, 0x7D, 0xFB, 0xF3, 0xFD, 0x74, 0xF7, 0xF5, 0x76, 0xF9, 0xF8, 0xFF, 0xF5, 0x76, 0x7B, 0xFA, +0x77, 0xFD, 0x7C, 0x77, 0x7D, 0x6F, 0x7D, 0xF7, 0xFC, 0xFD, 0x7B, 0xF5, 0xF8, 0x7A, 0xF4, 0xFB, +0x77, 0x7B, 0x76, 0x74, 0x7D, 0x7E, 0x72, 0x71, 0x70, 0x70, 0x77, 0x70, 0x7B, 0xFD, 0x6F, 0x72, +0x7D, 0x7A, 0x71, 0x79, 0xF8, 0x77, 0x6F, 0x74, 0x7A, 0x78, 0x7C, 0xF6, 0x7C, 0xFB, 0x7D, 0x6C, +0xEF, 0xFC, 0x6D, 0xF1, 0xF5, 0x7D, 0x79, 0xFA, 0xF5, 0x75, 0xF4, 0x7C, 0xFC, 0xE6, 0x68, 0x78, +0xE4, 0x6E, 0x77, 0xF2, 0x7E, 0x70, 0x69, 0xF9, 0xF7, 0x6C, 0x74, 0xF3, 0xEE, 0x79, 0x7E, 0xFB, +0x7A, 0xF6, 0x6C, 0x6B, 0xED, 0x77, 0x6A, 0x70, 0x6F, 0xFC, 0x7E, 0x79, 0xF2, 0xEE, 0xF8, 0x7D, +0xEF, 0xEB, 0x7E, 0x72, 0x7D, 0x74, 0x6B, 0xFA, 0xE5, 0xE7, 0xE4, 0xEB, 0xF8, 0xEC, 0xEA, 0xF3, +0xFB, 0xFA, 0xEF, 0xF6, 0x7C, 0xFF, 0x7B, 0x72, 0x78, 0x7C, 0x6F, 0x6E, 0xFF, 0xFF, 0x75, 0x74, +0x74, 0x76, 0x6C, 0x6A, 0x7F, 0x78, 0x6D, 0x74, 0x6E, 0x76, 0x7B, 0x69, 0x6B, 0x79, 0x72, 0x6A, +0x6D, 0x77, 0xFD, 0xFC, 0x6F, 0x7C, 0xEE, 0x76, 0x69, 0x74, 0xFB, 0x74, 0x6A, 0x7D, 0xF0, 0xFF, +0x6B, 0x71, 0xEF, 0x7D, 0x74, 0xF8, 0x75, 0x74, 0x77, 0x6C, 0x6E, 0x71, 0x73, 0x72, 0x70, 0xF4, +0xF0, 0x79, 0x7B, 0xFB, 0xF3, 0xF4, 0x78, 0x79, 0xF7, 0xFC, 0x6E, 0x70, 0xF8, 0xF8, 0x79, 0x6D, +0x70, 0xFB, 0x6E, 0x64, 0x6B, 0x72, 0x6F, 0x65, 0x71, 0xFC, 0x71, 0x76, 0x6E, 0x71, 0xF9, 0xFF, +0xFD, 0x73, 0x7A, 0xFF, 0x66, 0x70, 0xFE, 0x79, 0xFD, 0x7D, 0xF1, 0xF6, 0x76, 0x79, 0x6D, 0x79, +0xFF, 0x72, 0x7F, 0xF8, 0xF0, 0xFF, 0x71, 0xEC, 0xE9, 0x7C, 0x7C, 0xF1, 0xF7, 0xF7, 0xF5, 0xFA, +0xF1, 0x7C, 0x70, 0x7D, 0xFB, 0xF4, 0x7C, 0x7D, 0xF6, 0xFD, 0xEF, 0xF6, 0xEE, 0xE1, 0xEE, 0xF4, +0xF3, 0xEE, 0xF4, 0x78, 0xEC, 0xF7, 0x72, 0x74, 0x6E, 0xF5, 0x6A, 0x7B, 0xDF, 0x69, 0x7F, 0xE7, +0x6F, 0x7C, 0x68, 0xF4, 0xEE, 0x5C, 0x72, 0x6B, 0x6D, 0xEC, 0x60, 0x7E, 0xEB, 0x66, 0x6D, 0x6A, +0x7A, 0xFF, 0x6A, 0x6E, 0x74, 0xED, 0x79, 0x6B, 0xED, 0xFA, 0xFC, 0x70, 0x65, 0xF6, 0x75, 0x67, +0x78, 0x78, 0xF4, 0xFF, 0x5F, 0xF9, 0xE3, 0x6D, 0xF1, 0x7A, 0x70, 0xDB, 0x6A, 0xF9, 0xDC, 0x66, +0xDB, 0xF8, 0x65, 0xD6, 0x6A, 0xF2, 0xE6, 0x5E, 0xE1, 0x76, 0x6F, 0xF5, 0x65, 0xEF, 0x5F, 0x66, +0x6F, 0x5A, 0xFB, 0x5E, 0x65, 0x7E, 0x60, 0xF2, 0x5D, 0x72, 0xE8, 0x5A, 0xEA, 0x6E, 0x62, 0xE4, +0x5E, 0x6F, 0x74, 0x67, 0xEA, 0x64, 0x77, 0xF3, 0x69, 0xF1, 0x6B, 0x6E, 0xEB, 0x74, 0x74, 0x74, +0xF6, 0xF5, 0x66, 0xF5, 0xF7, 0x6C, 0xE9, 0x70, 0x6F, 0xE4, 0x6E, 0xF0, 0xF4, 0x63, 0xE1, 0xFE, +0x6D, 0xE4, 0x6D, 0xF2, 0xEF, 0x6C, 0xE8, 0x7B, 0xFC, 0xED, 0x74, 0xEB, 0xFE, 0xFC, 0xEF, 0x6D, +0xEC, 0xFB, 0x71, 0xEB, 0x77, 0xF3, 0xF8, 0x6F, 0xE9, 0xFE, 0xFC, 0xEE, 0x6F, 0xEB, 0xED, 0x7A, +0xEE, 0xF4, 0xF3, 0xF8, 0xF1, 0xEE, 0x79, 0xF4, 0xF3, 0xFC, 0xF1, 0x7C, 0xF4, 0xF9, 0x76, 0xE8, +0xF8, 0x75, 0xE3, 0x7B, 0x6E, 0xE0, 0x75, 0x72, 0xE3, 0x6C, 0xF8, 0xE7, 0x6D, 0xEA, 0xF4, 0x75, +0xEA, 0x71, 0xFA, 0xED, 0x6A, 0xF2, 0xFB, 0x70, 0xEB, 0x6F, 0x71, 0xEE, 0x6C, 0xF6, 0xF2, 0x68, +0xF3, 0xF8, 0x6D, 0x7A, 0xFC, 0x75, 0x6D, 0xF3, 0x6E, 0x6E, 0xEE, 0x61, 0x7C, 0xFE, 0x60, 0xF2, +0x6D, 0x78, 0x7C, 0x63, 0xEB, 0x64, 0x71, 0xED, 0x5C, 0xEB, 0x6F, 0x69, 0xEA, 0x5D, 0xE7, 0xF8, +0x5E, 0xE6, 0x6F, 0xFA, 0x79, 0x72, 0xE8, 0x5E, 0xE9, 0xFB, 0x5F, 0xDE, 0x61, 0xFA, 0xE3, 0x5A, +0xE3, 0x79, 0x62, 0xDF, 0x64, 0x76, 0xE4, 0x63, 0xFE, 0xE9, 0x64, 0xF8, 0xE6, 0x5F, 0xF2, 0xE8, +0x62, 0xE7, 0xFB, 0x6A, 0xF0, 0x77, 0xF9, 0x77, 0xE9, 0x78, 0x59, 0xE3, 0x71, 0x6C, 0xDF, 0x5F, +0xEF, 0xE9, 0x5F, 0xFA, 0x76, 0xF9, 0x7D, 0x67, 0xEE, 0x7B, 0x6F, 0x7E, 0x6B, 0x6D, 0xF7, 0x6E, +0x6B, 0xF0, 0x63, 0xF0, 0x75, 0x57, 0xD4, 0x59, 0x57, 0xCD, 0x4F, 0xEE, 0xDE, 0x4B, 0xCF, 0x68, +0x5B, 0xD4, 0x50, 0xE0, 0xEF, 0x54, 0xD5, 0x57, 0x6A, 0xD3, 0x54, 0x79, 0xDF, 0x5E, 0xFC, 0xE6, +0x5F, 0x71, 0xE0, 0x64, 0x76, 0xFC, 0x5D, 0xEA, 0xF8, 0x58, 0x79, 0xDB, 0x68, 0x59, 0xDF, 0x76, +0x64, 0xDA, 0x63, 0x5A, 0xD9, 0xE0, 0x51, 0xF3, 0xD3, 0x4D, 0xDE, 0xCF, 0x3F, 0xDA, 0xC2, 0x41, +0x6A, 0xC3, 0x50, 0x55, 0xC6, 0x5A, 0x4B, 0xC2, 0x7A, 0x46, 0xCA, 0xDF, 0x4C, 0xD8, 0xDE, 0x4F, +0xE2, 0xD2, 0x4D, 0x6B, 0xCD, 0x5C, 0x56, 0xD8, 0xEB, 0x54, 0xEF, 0xDE, 0x4F, 0x78, 0xD7, 0x54, +0x5B, 0xDA, 0xFA, 0x56, 0xF6, 0xE9, 0x58, 0xF1, 0xE5, 0x59, 0x6D, 0xE8, 0x7B, 0x64, 0x7E, 0xE2, +0x60, 0x6D, 0xDC, 0x63, 0x67, 0xDC, 0x6F, 0x62, 0xE2, 0x7B, 0x60, 0xEC, 0xF3, 0x67, 0x77, 0xF1, +0x7C, 0x75, 0xF0, 0x79, 0x6F, 0xED, 0x76, 0x6B, 0xF3, 0xFF, 0x74, 0xF4, 0xF8, 0x6B, 0x6C, 0xE6, +0xE7, 0x61, 0x79, 0xDD, 0x6F, 0x77, 0xDE, 0x6D, 0x6E, 0xE4, 0x7E, 0xF9, 0xE8, 0x6D, 0x6F, 0xDE, +0xEF, 0x5C, 0xEF, 0xDB, 0x64, 0x6B, 0xDF, 0xF9, 0x6C, 0xF4, 0xF5, 0x72, 0xF5, 0xF7, 0x66, 0x7D, +0xE9, 0x7D, 0x70, 0x79, 0xF6, 0x7B, 0x6C, 0xF3, 0xF2, 0x6A, 0x76, 0xED, 0x79, 0x6B, 0xF2, 0xF1, +0x6B, 0x78, 0xEF, 0x73, 0x74, 0xED, 0x73, 0x6A, 0xEB, 0xF2, 0x64, 0x6F, 0xE2, 0xF8, 0x5E, 0xF3, +0xE8, 0x64, 0x74, 0xEF, 0x7B, 0x77, 0x74, 0x78, 0x6D, 0xF8, 0xEA, 0x63, 0x68, 0xEC, 0xEF, 0x6E, +0x63, 0xEE, 0xFA, 0x5F, 0xE5, 0xEB, 0x58, 0x73, 0xD1, 0xF3, 0x4D, 0xF2, 0xCD, 0x5D, 0x54, 0xDF, +0xDD, 0x61, 0x5B, 0xD9, 0xDF, 0x50, 0xF0, 0xD3, 0x5F, 0x5D, 0xE4, 0xDF, 0x6E, 0x5B, 0xED, 0xD8, +0x68, 0x56, 0xEA, 0xD3, 0x70, 0x52, 0xF0, 0xD3, 0x74, 0x57, 0xF5, 0xD8, 0x6A, 0x58, 0xE4, 0xE2, +0x5C, 0x7A, 0xD8, 0x77, 0x5A, 0xE8, 0xD9, 0x73, 0x5F, 0x7D, 0xE3, 0xEC, 0x73, 0x72, 0x6E, 0xF6, +0xDF, 0xF7, 0x62, 0x6B, 0xE5, 0xDD, 0x6B, 0x58, 0xF7, 0xDB, 0x73, 0x5E, 0x75, 0x7E, 0xF6, 0xFE, +0x66, 0x71, 0x7B, 0x7E, 0xEE, 0x6C, 0x6B, 0xEB, 0x76, 0x6C, 0xEA, 0x7A, 0x67, 0xE5, 0xE8, 0x5F, +0x75, 0xDE, 0xEE, 0x6F, 0x7A, 0xED, 0xE8, 0xF8, 0xFB, 0xF4, 0x78, 0xF1, 0xE4, 0x6E, 0x62, 0xEB, +0xEC, 0x65, 0x6D, 0x7E, 0x6B, 0x69, 0x6E, 0x72, 0x78, 0x68, 0x5E, 0x74, 0xE9, 0x6F, 0x5E, 0x72, +0xEB, 0x7A, 0x6F, 0xF1, 0x78, 0x75, 0xE5, 0xE6, 0xE2, 0xDD, 0xE0, 0xD6, 0xD1, 0xD5, 0xD1, 0xD3, +0xDE, 0xE0, 0xDD, 0xE9, 0x68, 0x57, 0x52, 0x50, 0x4B, 0x48, 0x48, 0x48, 0x48, 0x4B, 0x51, 0x56, +0x56, 0x5D, 0x68, 0x6A, 0x69, 0x7C, 0xE8, 0xED, 0xED, 0xDC, 0xD5, 0xCD, 0xCB, 0xCD, 0xC5, 0xBE, +0xBE, 0xBC, 0xBC, 0xBF, 0xC5, 0xD2, 0x72, 0x52, 0x48, 0x40, 0x3C, 0x39, 0x39, 0x3B, 0x3D, 0x40, +0x4A, 0x5A, 0x6C, 0x7E, 0xDF, 0xCF, 0xCE, 0xDB, 0x6F, 0x63, 0x6E, 0x60, 0x4D, 0x47, 0x4D, 0x5E, +0x7C, 0xFA, 0xE4, 0xCD, 0xC1, 0xBD, 0xBC, 0xBA, 0xB7, 0xB4, 0xB5, 0xBE, 0xD7, 0xEB, 0xF2, 0x4E, +0x3B, 0x36, 0x37, 0x39, 0x38, 0x39, 0x3D, 0x48, 0x58, 0xFE, 0xDA, 0xD6, 0xD8, 0xCF, 0xC8, 0xCD, +0xF3, 0x5A, 0x59, 0x58, 0x4E, 0x47, 0x48, 0x4F, 0x5F, 0xF2, 0xD9, 0xCE, 0xC6, 0xBF, 0xBB, 0xBA, +0xB9, 0xB7, 0xB5, 0xB7, 0xC0, 0xD9, 0x68, 0x57, 0x49, 0x3B, 0x35, 0x35, 0x38, 0x3A, 0x3B, 0x3F, +0x4B, 0x60, 0xE7, 0xD8, 0xD5, 0xD4, 0xCE, 0xCA, 0xCF, 0xF9, 0x59, 0x51, 0x4E, 0x4C, 0x48, 0x46, +0x49, 0x56, 0xFB, 0xD9, 0xD1, 0xC9, 0xBE, 0xB8, 0xB6, 0xB5, 0xB3, 0xB2, 0xB6, 0xC3, 0xE5, 0x60, +0x4E, 0x3F, 0x37, 0x32, 0x34, 0x37, 0x39, 0x3C, 0x41, 0x4E, 0x6F, 0xDA, 0xD2, 0xD4, 0xD1, 0xCA, +0xC9, 0xD7, 0x6F, 0x59, 0x4D, 0x47, 0x47, 0x48, 0x45, 0x46, 0x52, 0xEE, 0xD7, 0xD0, 0xC7, 0xBC, +0xB5, 0xB3, 0xB3, 0xB1, 0xB0, 0xB7, 0xCA, 0x68, 0x4F, 0x45, 0x3B, 0x32, 0x2E, 0x30, 0x35, 0x39, +0x3D, 0x44, 0x52, 0xEC, 0xD0, 0xCF, 0xD3, 0xD0, 0xCD, 0xCF, 0xE3, 0x63, 0x5B, 0x59, 0x52, 0x4D, +0x4C, 0x4F, 0x5A, 0x6D, 0xE5, 0xD2, 0xC8, 0xBE, 0xB9, 0xB5, 0xB3, 0xB1, 0xAF, 0xB1, 0xBD, 0xE3, +0x53, 0x4B, 0x40, 0x35, 0x2E, 0x2F, 0x34, 0x39, 0x3B, 0x3F, 0x4C, 0x75, 0xDA, 0xD6, 0xD2, 0xCE, +0xCE, 0xD0, 0xD9, 0xEF, 0x62, 0x56, 0x55, 0x55, 0x4F, 0x4E, 0x52, 0x61, 0xEF, 0xDB, 0xCC, 0xBF, +0xB9, 0xB5, 0xB3, 0xB0, 0xAE, 0xB4, 0xC8, 0x63, 0x4D, 0x45, 0x39, 0x2E, 0x2C, 0x2F, 0x35, 0x38, +0x3B, 0x43, 0x5A, 0xDD, 0xCE, 0xCD, 0xCC, 0xCB, 0xCD, 0xD2, 0xDE, 0x76, 0x5A, 0x52, 0x53, 0x51, +0x4E, 0x4F, 0x5C, 0x7C, 0xE2, 0xD2, 0xC5, 0xBB, 0xB5, 0xB2, 0xB0, 0xAE, 0xAE, 0xB6, 0xCF, 0x55, +0x48, 0x3F, 0x34, 0x2C, 0x2C, 0x2F, 0x36, 0x39, 0x3D, 0x4A, 0x7D, 0xCE, 0xCA, 0xCB, 0xCB, 0xCB, +0xCD, 0xD9, 0x76, 0x59, 0x4F, 0x4C, 0x4C, 0x4A, 0x4C, 0x54, 0x68, 0xEC, 0xD8, 0xCB, 0xBF, 0xB8, +0xB3, 0xB0, 0xAE, 0xAD, 0xAE, 0xBC, 0xF5, 0x4C, 0x43, 0x39, 0x2E, 0x2A, 0x2D, 0x32, 0x37, 0x3B, +0x44, 0x5F, 0xD5, 0xC8, 0xC7, 0xC9, 0xCB, 0xCE, 0xD3, 0xE9, 0x5A, 0x4D, 0x4D, 0x4D, 0x4B, 0x4B, +0x50, 0x63, 0xF6, 0xDE, 0xCE, 0xC5, 0xBD, 0xB7, 0xB2, 0xB0, 0xAF, 0xAD, 0xAF, 0xBF, 0x5E, 0x45, +0x40, 0x37, 0x2C, 0x29, 0x2D, 0x34, 0x38, 0x3C, 0x48, 0x77, 0xCD, 0xC6, 0xC7, 0xCB, 0xCB, 0xCF, +0xE9, 0x59, 0x4E, 0x4B, 0x47, 0x44, 0x47, 0x4D, 0x57, 0x69, 0xEB, 0xD7, 0xCA, 0xBF, 0xB9, 0xB3, +0xAF, 0xAE, 0xAD, 0xAC, 0xB5, 0xDE, 0x49, 0x43, 0x3B, 0x2D, 0x28, 0x2A, 0x30, 0x36, 0x3A, 0x44, +0x6A, 0xCD, 0xC2, 0xC2, 0xC6, 0xCA, 0xCC, 0xD8, 0x60, 0x4C, 0x48, 0x46, 0x44, 0x43, 0x49, 0x54, +0x68, 0xEC, 0xD8, 0xCB, 0xC2, 0xBC, 0xB8, 0xB2, 0xAF, 0xAE, 0xAE, 0xAE, 0xBA, 0x74, 0x45, 0x3F, +0x36, 0x2C, 0x29, 0x2C, 0x32, 0x37, 0x3E, 0x4E, 0xE3, 0xC7, 0xC2, 0xC5, 0xC6, 0xC8, 0xD2, 0x71, +0x52, 0x4D, 0x49, 0x42, 0x41, 0x47, 0x51, 0x60, 0x7B, 0xDE, 0xCE, 0xC6, 0xC0, 0xBE, 0xB9, 0xB2, +0xAF, 0xAF, 0xAE, 0xAE, 0xBC, 0x6B, 0x47, 0x3F, 0x34, 0x2C, 0x2A, 0x2D, 0x32, 0x39, 0x3F, 0x4F, +0xDF, 0xC5, 0xC4, 0xCD, 0xCA, 0xC7, 0xDB, 0x5A, 0x4E, 0x4D, 0x48, 0x42, 0x40, 0x45, 0x54, 0x6F, +0x74, 0xEC, 0xCD, 0xC4, 0xC4, 0xC1, 0xBB, 0xB3, 0xAF, 0xB0, 0xAE, 0xAE, 0xBC, 0x6F, 0x4A, 0x3F, +0x34, 0x2C, 0x2B, 0x2E, 0x34, 0x3B, 0x42, 0x56, 0xCF, 0xBF, 0xC2, 0xCB, 0xC6, 0xC6, 0xE6, 0x52, +0x4B, 0x47, 0x45, 0x3F, 0x3D, 0x45, 0x5E, 0x7A, 0x72, 0xDB, 0xC7, 0xC3, 0xC5, 0xC2, 0xBC, 0xB5, +0xB1, 0xB3, 0xB0, 0xAE, 0xB9, 0xF0, 0x4C, 0x43, 0x38, 0x2E, 0x2B, 0x2D, 0x34, 0x3A, 0x3E, 0x4F, +0xD3, 0xC1, 0xC4, 0xCD, 0xCC, 0xC8, 0xDE, 0x4D, 0x45, 0x47, 0x47, 0x41, 0x3D, 0x47, 0x6D, 0xF7, +0x79, 0xDA, 0xC9, 0xC6, 0xC8, 0xC9, 0xC0, 0xB8, 0xB4, 0xB5, 0xB0, 0xAC, 0xB1, 0xCF, 0x5A, 0x4E, +0x3E, 0x30, 0x2B, 0x2D, 0x33, 0x38, 0x3B, 0x48, 0xDC, 0xC4, 0xC5, 0xCA, 0xCB, 0xCB, 0xD9, 0x50, +0x46, 0x4B, 0x46, 0x3E, 0x3F, 0x48, 0x55, 0x76, 0x7E, 0xE3, 0xCA, 0xC9, 0xCE, 0xCB, 0xC6, 0xBE, +0xBA, 0xB8, 0xB4, 0xAE, 0xAE, 0xBD, 0xEA, 0x62, 0x48, 0x35, 0x2D, 0x2C, 0x30, 0x35, 0x37, 0x3F, +0x6F, 0xCB, 0xCA, 0xC9, 0xC7, 0xCE, 0xD9, 0x60, 0x46, 0x46, 0x48, 0x40, 0x40, 0x49, 0x52, 0x69, +0xED, 0xE1, 0xD1, 0xCC, 0xD0, 0xD2, 0xD0, 0xCD, 0xC2, 0xBD, 0xB9, 0xB2, 0xAE, 0xAF, 0xBA, 0xE0, +0x67, 0x4C, 0x34, 0x2D, 0x2E, 0x30, 0x34, 0x37, 0x41, 0xF4, 0xCD, 0xCC, 0xC7, 0xC5, 0xD0, 0xED, +0x64, 0x4D, 0x45, 0x47, 0x43, 0x44, 0x4F, 0x51, 0x69, 0xD9, 0xDD, 0xD1, 0xCB, 0xD1, 0xCF, 0xD2, +0xCD, 0xBF, 0xBC, 0xB8, 0xB0, 0xAD, 0xAE, 0xBC, 0xD9, 0x76, 0x48, 0x32, 0x2D, 0x2F, 0x30, 0x32, +0x38, 0x49, 0xE6, 0xD1, 0xCB, 0xC1, 0xC1, 0xD2, 0x7A, 0x6F, 0x51, 0x42, 0x43, 0x45, 0x4A, 0x4D, +0x4E, 0x72, 0xD7, 0xDB, 0xD8, 0xCE, 0xCF, 0xD7, 0xDD, 0xD3, 0xC6, 0xBF, 0xBB, 0xB3, 0xAD, 0xAE, +0xB8, 0xCD, 0xE2, 0x52, 0x35, 0x2E, 0x2F, 0x2F, 0x2F, 0x35, 0x43, 0x62, 0xE5, 0xCF, 0xC1, 0xC0, +0xD1, 0xE1, 0xDB, 0x5E, 0x46, 0x49, 0x4D, 0x4A, 0x49, 0x51, 0x6A, 0xEE, 0xEB, 0xDE, 0xD0, 0xD4, +0xDF, 0xDC, 0xD7, 0xCF, 0xC5, 0xBE, 0xB7, 0xB1, 0xAE, 0xAF, 0xBC, 0xD3, 0xE7, 0x48, 0x31, 0x2E, +0x2F, 0x2E, 0x2F, 0x36, 0x44, 0x5B, 0xF4, 0xCC, 0xBF, 0xC2, 0xD4, 0xD1, 0xCF, 0x59, 0x4B, 0x51, +0x4B, 0x46, 0x44, 0x4C, 0x56, 0x51, 0x66, 0xE5, 0xE6, 0xE0, 0xDF, 0xD6, 0xD1, 0xCD, 0xC0, 0xBB, +0xB7, 0xB0, 0xAD, 0xB0, 0xBD, 0xCE, 0xEF, 0x44, 0x31, 0x2F, 0x30, 0x2E, 0x2E, 0x39, 0x46, 0x56, +0xF0, 0xC7, 0xBD, 0xC2, 0xC9, 0xC8, 0xCC, 0x7A, 0x50, 0x57, 0x4F, 0x42, 0x42, 0x4A, 0x4C, 0x4C, +0x5D, 0xEF, 0xEE, 0xE3, 0xD6, 0xD1, 0xD2, 0xCC, 0xC0, 0xBC, 0xBA, 0xB3, 0xAE, 0xAF, 0xBA, 0xC9, +0xD6, 0x4F, 0x36, 0x30, 0x30, 0x2E, 0x2D, 0x34, 0x3E, 0x45, 0x5C, 0xCF, 0xC1, 0xC0, 0xC1, 0xC0, +0xC9, 0xD9, 0xF5, 0x54, 0x4A, 0x47, 0x40, 0x41, 0x42, 0x45, 0x4E, 0x53, 0x68, 0xE8, 0xE1, 0xD1, +0xCD, 0xCC, 0xC5, 0xBF, 0xBB, 0xB8, 0xB4, 0xAF, 0xB0, 0xBD, 0xCB, 0xD8, 0x4B, 0x36, 0x34, 0x33, +0x2E, 0x2E, 0x37, 0x3D, 0x44, 0x62, 0xCD, 0xC4, 0xC0, 0xBE, 0xBF, 0xC5, 0xCF, 0xEE, 0x66, 0x4F, +0x45, 0x43, 0x40, 0x41, 0x44, 0x47, 0x51, 0x5B, 0x71, 0xDD, 0xD8, 0xCE, 0xC8, 0xC6, 0xC1, 0xBD, +0xB9, 0xB7, 0xB2, 0xAF, 0xB9, 0xC3, 0xCC, 0x71, 0x40, 0x37, 0x36, 0x31, 0x2E, 0x33, 0x3A, 0x3D, +0x4A, 0xE6, 0xCF, 0xC7, 0xBE, 0xBF, 0xC2, 0xCA, 0xD3, 0xE6, 0x50, 0x4C, 0x4B, 0x3E, 0x3E, 0x43, +0x41, 0x47, 0x4D, 0x59, 0x75, 0xE4, 0xD0, 0xCC, 0xC9, 0xC3, 0xBF, 0xBD, 0xBB, 0xB8, 0xB3, 0xB3, +0xBB, 0xC3, 0xCD, 0x6A, 0x42, 0x3A, 0x38, 0x31, 0x30, 0x36, 0x39, 0x3C, 0x4B, 0x7A, 0xDB, 0xCB, +0xC1, 0xC3, 0xC5, 0xC5, 0xD5, 0xE5, 0x6B, 0x4E, 0x4C, 0x43, 0x40, 0x45, 0x42, 0x48, 0x50, 0x55, +0x6C, 0xE8, 0xD7, 0xCD, 0xCC, 0xC7, 0xC3, 0xC0, 0xBD, 0xBC, 0xB8, 0xB2, 0xB5, 0xBD, 0xC2, 0xD0, +0x5D, 0x45, 0x3C, 0x38, 0x32, 0x32, 0x37, 0x37, 0x3C, 0x4C, 0x5E, 0xEE, 0xCD, 0xC5, 0xC8, 0xC6, +0xC5, 0xD0, 0xE2, 0xF9, 0x5D, 0x4D, 0x47, 0x46, 0x42, 0x41, 0x47, 0x4B, 0x4E, 0x63, 0xEA, 0xE3, +0xD3, 0xC9, 0xCB, 0xC8, 0xC0, 0xBF, 0xBD, 0xBA, 0xB5, 0xB6, 0xBC, 0xC1, 0xCC, 0x7E, 0x4B, 0x3F, +0x3B, 0x35, 0x32, 0x37, 0x37, 0x3A, 0x45, 0x50, 0x6D, 0xD7, 0xC8, 0xC6, 0xC7, 0xC2, 0xCA, 0xD7, +0xDB, 0x6D, 0x59, 0x4F, 0x48, 0x48, 0x45, 0x46, 0x4D, 0x4F, 0x5E, 0xFF, 0xE6, 0xD7, 0xD4, 0xCF, +0xD1, 0xD5, 0xD0, 0xD3, 0xCD, 0xC6, 0xC1, 0xBA, 0xB8, 0xBB, 0xC2, 0xC4, 0xCD, 0x58, 0x4C, 0x48, +0x39, 0x36, 0x39, 0x36, 0x37, 0x3E, 0x44, 0x4B, 0x66, 0xDC, 0xD4, 0xCA, 0xC3, 0xC5, 0xC7, 0xCA, +0xCE, 0xDD, 0x6D, 0x5F, 0x4F, 0x46, 0x47, 0x46, 0x43, 0x49, 0x4E, 0x53, 0x65, 0xF1, 0xE4, 0xD9, +0xCF, 0xCE, 0xCD, 0xC6, 0xC3, 0xC0, 0xBA, 0xB7, 0xB7, 0xBD, 0xC4, 0xC5, 0xFD, 0x4A, 0x4C, 0x3B, +0x33, 0x37, 0x34, 0x32, 0x3A, 0x3F, 0x47, 0x5B, 0xDC, 0xCB, 0xC8, 0xBE, 0xBC, 0xC3, 0xC0, 0xC7, +0xDE, 0xEC, 0x5B, 0x49, 0x45, 0x3F, 0x3E, 0x3F, 0x40, 0x49, 0x4E, 0x5B, 0xEF, 0xDF, 0xD4, 0xCC, +0xCA, 0xC7, 0xC5, 0xC3, 0xBF, 0xBD, 0xBB, 0xB8, 0xB8, 0xC0, 0xCB, 0xCA, 0x68, 0x45, 0x4D, 0x3D, +0x35, 0x3C, 0x3A, 0x38, 0x41, 0x49, 0x4D, 0x69, 0xDB, 0xD3, 0xCD, 0xC5, 0xC6, 0xCC, 0xCB, 0xD0, +0xEB, 0x76, 0x5C, 0x4C, 0x48, 0x44, 0x41, 0x41, 0x44, 0x49, 0x4E, 0x5D, 0x7E, 0xE6, 0xD4, 0xCE, +0xCE, 0xCB, 0xCB, 0xCE, 0xCE, 0xCA, 0xC9, 0xC6, 0xBE, 0xBC, 0xC6, 0xCA, 0xC4, 0xE0, 0x58, 0x77, +0x4A, 0x3D, 0x45, 0x3D, 0x39, 0x3F, 0x41, 0x40, 0x4C, 0x61, 0x6D, 0xE7, 0xCE, 0xCC, 0xCC, 0xC9, +0xCA, 0xD1, 0xDB, 0xE2, 0x66, 0x54, 0x50, 0x48, 0x45, 0x47, 0x47, 0x4B, 0x51, 0x5A, 0x71, 0xEB, +0xDD, 0xD5, 0xD2, 0xCF, 0xCC, 0xCC, 0xCA, 0xC4, 0xC3, 0xBF, 0xB9, 0xBD, 0xCB, 0xC0, 0xC9, 0x56, +0x71, 0x5A, 0x3A, 0x3F, 0x3E, 0x34, 0x3A, 0x3E, 0x3C, 0x42, 0x54, 0x62, 0x73, 0xCF, 0xC8, 0xCC, +0xC3, 0xC3, 0xCD, 0xCF, 0xDD, 0x6D, 0x56, 0x4D, 0x48, 0x42, 0x42, 0x44, 0x45, 0x4D, 0x57, 0x61, +0xED, 0xDB, 0xD5, 0xCD, 0xCD, 0xCD, 0xCD, 0xD0, 0xCD, 0xD1, 0xCA, 0xC4, 0xC7, 0xBA, 0xC2, 0xD8, +0xBB, 0xD7, 0x53, 0xCC, 0x4E, 0x3E, 0x57, 0x3E, 0x3B, 0x43, 0x3F, 0x3E, 0x46, 0x52, 0x50, 0x60, +0xD6, 0xD9, 0xD4, 0xC6, 0xCA, 0xCF, 0xCB, 0xD5, 0xF4, 0xFB, 0x5D, 0x4E, 0x4C, 0x4B, 0x46, 0x45, +0x4F, 0x4E, 0x4D, 0x7E, 0x6F, 0x71, 0xD4, 0xE1, 0xDF, 0xCE, 0xD9, 0xD5, 0xCD, 0xCD, 0xC5, 0xBF, +0xB9, 0xBA, 0xC6, 0xBA, 0xBF, 0x6C, 0xCE, 0xFB, 0x3D, 0x4D, 0x40, 0x35, 0x3C, 0x3B, 0x38, 0x3E, +0x47, 0x4B, 0x52, 0xDF, 0xD8, 0xD6, 0xC3, 0xC6, 0xCB, 0xC5, 0xCD, 0xDD, 0xE4, 0x6B, 0x50, 0x4D, +0x49, 0x44, 0x45, 0x47, 0x48, 0x49, 0x50, 0x5D, 0x5C, 0xEE, 0xDD, 0xE7, 0xD1, 0xD5, 0xDC, 0xD0, +0xDA, 0xD8, 0xD1, 0xCD, 0xC6, 0xBF, 0xBA, 0xC1, 0xC4, 0xBA, 0xD3, 0xE1, 0xCC, 0x4D, 0x49, 0x4F, +0x3B, 0x3B, 0x3E, 0x3A, 0x3C, 0x42, 0x4A, 0x4C, 0x6D, 0xD9, 0xDC, 0xC9, 0xC4, 0xCA, 0xC6, 0xC8, +0xD0, 0xD8, 0xE5, 0x68, 0x58, 0x53, 0x4C, 0x4A, 0x4B, 0x4C, 0x4E, 0x56, 0x5F, 0x69, 0xEA, 0xE0, +0xE8, 0xD5, 0xDD, 0xE7, 0xD9, 0xFB, 0xF9, 0xF5, 0x64, 0x75, 0x6D, 0xF5, 0xE5, 0xD8, 0xC8, 0xC4, +0xBB, 0xBF, 0xC4, 0xB7, 0xCC, 0xD6, 0xC3, 0x56, 0x52, 0x5F, 0x3D, 0x3E, 0x3E, 0x39, 0x3A, 0x3D, +0x41, 0x41, 0x4F, 0x6B, 0x63, 0xD6, 0xCD, 0xD1, 0xC7, 0xC8, 0xCE, 0xCE, 0xD6, 0xE8, 0x71, 0x67, +0x55, 0x4F, 0x52, 0x4D, 0x4F, 0x56, 0x56, 0x5E, 0x6D, 0x7E, 0xF5, 0xDF, 0xE3, 0xEE, 0xDC, 0x7B, +0x73, 0xED, 0x5C, 0x6A, 0x69, 0x5B, 0x70, 0x6D, 0xEF, 0xE1, 0xCF, 0xC8, 0xC4, 0xB9, 0xC5, 0xC2, +0xB6, 0xDC, 0xCD, 0xC3, 0x49, 0x60, 0x57, 0x3A, 0x40, 0x3D, 0x38, 0x3A, 0x3E, 0x3F, 0x3E, 0x53, +0x58, 0x59, 0xD3, 0xD7, 0xD2, 0xC4, 0xC9, 0xCA, 0xC8, 0xCD, 0xD8, 0xDE, 0xEE, 0x5F, 0x5D, 0x59, +0x4F, 0x54, 0x56, 0x54, 0x5D, 0x69, 0x6D, 0xF2, 0xE1, 0xDF, 0xDB, 0xD8, 0xDD, 0xE8, 0xEB, 0x71, +0x5D, 0x66, 0x56, 0x52, 0x62, 0x52, 0x5C, 0x74, 0x63, 0xE2, 0xDD, 0xD4, 0xCA, 0xC9, 0xBF, 0xC0, +0xBB, 0xBB, 0xCC, 0xBB, 0xC8, 0x68, 0xC8, 0x58, 0x44, 0x5D, 0x3C, 0x3B, 0x40, 0x3A, 0x3B, 0x3F, +0x44, 0x43, 0x52, 0x7A, 0x62, 0xD4, 0xCB, 0xD1, 0xC3, 0xC4, 0xC8, 0xC5, 0xCA, 0xD0, 0xD9, 0xE1, +0x6C, 0x5C, 0x5B, 0x4E, 0x4D, 0x50, 0x4C, 0x50, 0x58, 0x58, 0x63, 0x79, 0xFE, 0xED, 0xE1, 0xE7, +0xEE, 0xE6, 0xFB, 0x6D, 0x7A, 0x61, 0x5D, 0x62, 0x59, 0x5B, 0x5E, 0x5C, 0x64, 0x69, 0x72, 0xFE, +0xF1, 0xE6, 0xE2, 0xDB, 0xD9, 0xD6, 0xD3, 0xD3, 0xD0, 0xD0, 0xCF, 0xCE, 0xCD, 0xCD, 0xDA, 0xDB, +0xDA, 0x64, 0x69, 0x63, 0x4C, 0x4F, 0x4D, 0x46, 0x4A, 0x4A, 0x48, 0x4D, 0x52, 0x52, 0x5C, 0x70, +0x71, 0xEB, 0xDC, 0xDE, 0xD7, 0xD4, 0xD8, 0xD5, 0xD7, 0xDD, 0xDF, 0xE7, 0xFD, 0x71, 0x69, 0x5D, +0x5A, 0x5A, 0x57, 0x56, 0x5B, 0x59, 0x5A, 0x69, 0x62, 0x6A, 0xF5, 0x73, 0xF1, 0xE7, 0xF4, 0xE6, +0xE6, 0xEE, 0xEA, 0xED, 0xF5, 0xF1, 0xED, 0xF0, 0xEA, 0xE4, 0xE7, 0xDF, 0xDE, 0xDF, 0xDC, 0xDE, +0xDF, 0xE1, 0xE8, 0xEE, 0xFD, 0x77, 0x6B, 0x64, 0x61, 0x5C, 0x5C, 0x5C, 0x5B, 0x5F, 0x61, 0x67, +0x6E, 0x78, 0xF8, 0xF1, 0xEA, 0xE5, 0xE4, 0xE2, 0xE1, 0xE5, 0xEA, 0xED, 0xFA, 0x77, 0x6E, 0x66, +0x62, 0x5D, 0x5C, 0x5A, 0x59, 0x59, 0x59, 0x5B, 0x5C, 0x5D, 0x64, 0x64, 0x6C, 0x77, 0x7C, 0xEE, +0xEB, 0xE0, 0xDB, 0xD7, 0xCF, 0xCF, 0xCA, 0xC8, 0xC5, 0xC4, 0xCD, 0xC7, 0xCB, 0xE8, 0xD3, 0xFD, +0x55, 0x67, 0x4B, 0x45, 0x48, 0x40, 0x3F, 0x42, 0x43, 0x43, 0x4A, 0x50, 0x50, 0x6C, 0xF5, 0xF2, +0xD4, 0xD2, 0xD1, 0xCB, 0xCC, 0xCE, 0xCE, 0xD0, 0xDA, 0xDC, 0xDF, 0xFD, 0x7D, 0x6F, 0x5E, 0x5F, +0x5D, 0x59, 0x5A, 0x5C, 0x5C, 0x5F, 0x68, 0x68, 0x6F, 0xFC, 0xFC, 0xEF, 0xE9, 0xEB, 0xE9, 0xE9, +0xED, 0xEF, 0xF2, 0xF8, 0xFE, 0xFE, 0x7C, 0x7C, 0x7E, 0x79, 0xFE, 0xFB, 0xFE, 0xF7, 0xF6, 0xF9, +0xF6, 0xF8, 0xFD, 0xFF, 0x7C, 0x73, 0x70, 0x6E, 0x6A, 0x6A, 0x69, 0x68, 0x6A, 0x6B, 0x6C, 0x6F, +0x74, 0x79, 0xFF, 0xFA, 0xF8, 0xF2, 0xF4, 0xF6, 0xF3, 0xFE, 0xFB, 0x74, 0x62, 0x69, 0x5F, 0x5A, +0x66, 0x5B, 0x5D, 0x70, 0x61, 0x78, 0xED, 0xF4, 0xDB, 0xD7, 0xD0, 0xCB, 0xC9, 0xC3, 0xCC, 0xC9, +0xC4, 0xDD, 0xD2, 0xD7, 0x59, 0x6E, 0x57, 0x45, 0x4B, 0x45, 0x3F, 0x43, 0x44, 0x43, 0x49, 0x51, +0x4F, 0x5E, 0xFB, 0x70, 0xDE, 0xD8, 0xDC, 0xD1, 0xD2, 0xD7, 0xD4, 0xD6, 0xDD, 0xDF, 0xDF, 0xF1, +0xF2, 0xF2, 0x6F, 0x73, 0x72, 0x69, 0x6D, 0x6F, 0x6D, 0x72, 0x7B, 0x79, 0x7E, 0xF8, 0xFD, 0xF9, +0xF6, 0xFD, 0xFA, 0xFA, 0xFD, 0xFB, 0xFB, 0xFD, 0xFA, 0xF6, 0xF8, 0xF3, 0xF2, 0xF4, 0xEF, 0xF1, +0xF4, 0xF2, 0xF6, 0xF9, 0xF8, 0xF9, 0xFD, 0xFD, 0xFC, 0x7F, 0x7E, 0x7D, 0x79, 0x76, 0x74, 0x71, +0x6F, 0x6E, 0x6C, 0x6C, 0x6D, 0x6B, 0x6C, 0x6D, 0x6C, 0x71, 0x71, 0x70, 0x7E, 0x79, 0x7C, 0xFA, +0x7B, 0xFD, 0xFC, 0x7A, 0xFE, 0x7C, 0x78, 0x7B, 0x76, 0x76, 0x78, 0x77, 0x77, 0x7C, 0x7E, 0xFF, +0xF2, 0xF3, 0xED, 0xE7, 0xE8, 0xE0, 0xDE, 0xDC, 0xD7, 0xD8, 0xD3, 0xD4, 0xDA, 0xD7, 0xDF, 0xEB, +0xED, 0x6A, 0x60, 0x5C, 0x52, 0x4F, 0x4D, 0x4B, 0x4A, 0x4B, 0x4B, 0x4D, 0x50, 0x54, 0x5B, 0x66, +0x6F, 0xF1, 0xE6, 0xDF, 0xDA, 0xD8, 0xD8, 0xD7, 0xD9, 0xDB, 0xDE, 0xE2, 0xEA, 0xF1, 0xFA, 0x78, +0x70, 0x6D, 0x69, 0x68, 0x66, 0x65, 0x65, 0x66, 0x66, 0x67, 0x6A, 0x6B, 0x6C, 0x70, 0x74, 0x79, +0xFB, 0xF5, 0xEF, 0xEB, 0xE9, 0xE6, 0xE3, 0xE2, 0xE1, 0xE0, 0xE0, 0xE0, 0xE1, 0xE3, 0xE3, 0xE6, +0xE9, 0xEB, 0xEF, 0xF7, 0x7F, 0x75, 0x6E, 0x6A, 0x66, 0x62, 0x61, 0x5F, 0x5F, 0x60, 0x5F, 0x62, +0x65, 0x66, 0x6C, 0x6E, 0x72, 0x7D, 0xFE, 0xF6, 0xEF, 0xED, 0xE9, 0xE7, 0xE4, 0xE3, 0xE0, 0xDF, +0xE1, 0xDF, 0xE1, 0xE3, 0xE3, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xED, 0xF5, 0xF6, 0xF9, 0x75, +0x76, 0x6E, 0x66, 0x65, 0x5E, 0x5B, 0x5A, 0x56, 0x55, 0x54, 0x53, 0x54, 0x55, 0x57, 0x59, 0x5D, +0x60, 0x66, 0x70, 0x79, 0xFA, 0xF0, 0xEE, 0xEC, 0xED, 0xED, 0xF0, 0xF5, 0xF8, 0xFF, 0xFD, 0x7E, +0x7D, 0xFE, 0x7E, 0xFD, 0xF8, 0xF6, 0xEF, 0xED, 0xEB, 0xE8, 0xE4, 0xE3, 0xE0, 0xDF, 0xDE, 0xDC, +0xDD, 0xDC, 0xDD, 0xE1, 0xE2, 0xE9, 0xF3, 0x7A, 0x65, 0x61, 0x5B, 0x56, 0x56, 0x51, 0x50, 0x52, +0x50, 0x55, 0x58, 0x59, 0x5F, 0x68, 0x70, 0xFC, 0xEE, 0xE9, 0xE4, 0xE1, 0xE4, 0xE4, 0xE7, 0xED, +0xEE, 0xF8, 0xFF, 0x7D, 0x76, 0x76, 0x7A, 0x7B, 0xFF, 0xF9, 0xF7, 0xF1, 0xED, 0xED, 0xEB, 0xE9, +0xEA, 0xEA, 0xEC, 0xED, 0xEE, 0xF0, 0xF1, 0xF2, 0xF2, 0xF3, 0xF0, 0xF1, 0xF3, 0xEF, 0xF3, 0xF5, +0xF4, 0xFB, 0xFC, 0xFC, 0x7C, 0x7A, 0x76, 0x70, 0x6F, 0x6F, 0x6C, 0x6C, 0x6C, 0x68, 0x6B, 0x6B, +0x68, 0x6D, 0x6B, 0x6B, 0x6F, 0x6E, 0x70, 0x77, 0x76, 0x7A, 0x7F, 0xFF, 0xFD, 0xF6, 0xF7, 0xF5, +0xEF, 0xF4, 0xF1, 0xEF, 0xF2, 0xEE, 0xF0, 0xF1, 0xEE, 0xF0, 0xF1, 0xF1, 0xF2, 0xF6, 0xF9, 0xFA, +0x7F, 0x7E, 0x7A, 0x76, 0x7A, 0x73, 0x72, 0x74, 0x6F, 0x73, 0x75, 0x73, 0x75, 0x74, 0x76, 0x73, +0x77, 0x7A, 0x76, 0x7E, 0x78, 0x76, 0x7E, 0x76, 0x7A, 0x79, 0x74, 0x7D, 0x77, 0x77, 0x79, 0x74, +0x76, 0x77, 0x7A, 0x79, 0x7C, 0xFF, 0x79, 0xFC, 0xFA, 0x7E, 0xF4, 0xF9, 0xFC, 0xF6, 0x7E, 0xFF, +0xFF, 0x7B, 0x7C, 0x77, 0x75, 0x76, 0x78, 0x76, 0x74, 0x7B, 0x74, 0x75, 0x7E, 0x74, 0x7B, 0x7C, +0x72, 0x7A, 0x77, 0x74, 0x7A, 0x75, 0x72, 0x73, 0x72, 0x6E, 0x6E, 0x70, 0x6D, 0x70, 0x71, 0x6E, +0x75, 0x73, 0x72, 0x79, 0x78, 0x7B, 0xFF, 0xFF, 0xFD, 0xFA, 0xFC, 0xFB, 0xF7, 0xFD, 0xFE, 0xFA, +0x7D, 0x7D, 0xFE, 0x79, 0x7B, 0x7C, 0x7B, 0x7E, 0x7E, 0xFD, 0xFA, 0xFA, 0xF7, 0xF8, 0xF9, 0xF9, +0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x7D, 0x7B, 0x77, 0x78, 0x74, 0x71, 0x74, 0x6F, 0x6F, 0x71, 0x6D, +0x6F, 0x71, 0x6F, 0x73, 0x74, 0x77, 0x7B, 0x7D, 0x7F, 0xFF, 0xFC, 0xFE, 0xFB, 0xF8, 0xFB, 0xF7, +0xF9, 0xFE, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0x7E, 0x7C, 0x7E, 0x7B, 0x7B, 0x7E, 0x7C, 0xFF, 0xFE, +0xFE, 0xFB, 0xFE, 0xFF, 0xFD, 0xFE, 0x7E, 0x7F, 0x7A, 0x78, 0x79, 0x75, 0x74, 0x75, 0x73, 0x75, +0x77, 0x77, 0x79, 0x7B, 0x7D, 0xFF, 0xFA, 0xF8, 0xF4, 0xF2, 0xF5, 0xF1, 0xF2, 0xF6, 0xF3, 0xF6, +0xFA, 0xFB, 0xFC, 0x7D, 0x7A, 0x7A, 0x74, 0x77, 0x78, 0x74, 0x7A, 0x77, 0x7A, 0xFF, 0x7F, 0xF9, +0xFB, 0xFB, 0xF9, 0xFF, 0x7F, 0x7C, 0x7A, 0x77, 0x72, 0x73, 0x6E, 0x6E, 0x6E, 0x6D, 0x70, 0x70, +0x75, 0x7D, 0x7B, 0xFE, 0xFD, 0xFF, 0xFC, 0xFF, 0x7E, 0xFF, 0x7E, 0x7A, 0x79, 0x76, 0x6F, 0x72, +0x72, 0x6F, 0x73, 0x6F, 0x6E, 0x74, 0x72, 0x74, 0x7C, 0x7C, 0xFF, 0xF9, 0xFA, 0xF9, 0xF5, 0xF7, +0xF7, 0xF5, 0xFA, 0xFA, 0xF7, 0xFA, 0xF9, 0xF8, 0xFC, 0xF9, 0xF8, 0xFA, 0xF6, 0xF9, 0xFC, 0xFA, +0xFD, 0xFE, 0xFD, 0xFF, 0x7E, 0x7E, 0x7D, 0x7A, 0x7C, 0x7B, 0x79, 0x7C, 0x7B, 0x7B, 0xFF, 0x7E, +0xFF, 0xFC, 0xFE, 0xFE, 0xFB, 0xFD, 0x7C, 0x7F, 0x7F, 0x76, 0x78, 0x78, 0x74, 0x78, 0x78, 0x78, +0x7B, 0x7A, 0x7A, 0x79, 0x77, 0x78, 0x79, 0x78, 0x7A, 0x7B, 0x7A, 0x7C, 0x7F, 0x7D, 0xFF, 0xFC, +0xFD, 0xFA, 0xFB, 0xFD, 0xFE, 0xFF, 0x7F, 0x7D, 0x7C, 0x7A, 0x7B, 0x7D, 0x7D, 0x7E, 0x7E, 0x7D, +0x7D, 0x7C, 0x7C, 0x7C, 0x7C, 0x7D, 0x7C, 0x7B, 0x7C, 0x7D, 0x7F, 0xFF, 0xFE, 0xFC, 0xFC, 0xFB, +0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xFB, 0xFB, 0xFD, 0xFF, 0x7D, 0x7B, 0x7B, 0x7A, 0x77, 0x77, 0x78, +0x77, 0x77, 0x79, 0x7A, 0x7B, 0x7B, 0x7D, 0x7E, 0xFF, 0xFE, 0xFE, 0xFD, 0xFC, 0xFC, 0xFC, 0xFC, +0xFE, 0xFF, 0xFF, 0x7E, 0x7B, 0x78, 0x77, 0x76, 0x74, 0x73, 0x73, 0x71, 0x72, 0x73, 0x73, 0x74, +0x75, 0x76, 0x77, 0x77, 0x78, 0x78, 0x7A, 0x7D, 0x7D, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0x7F, 0x7E, 0x7D, 0x7D, 0x7C, 0x7A, 0x79, 0x79, 0x78, 0x77, 0x78, 0x79, 0x7A, 0x7A, 0x7B, 0x7A, +0x79, 0x7B, 0x7B, 0x7B, 0x7C, 0x7A, 0x7A, 0x79, 0x78, 0x78, 0x76, 0x76, 0x75, 0x73, 0x73, 0x73, +0x74, 0x77, 0x79, 0x7A, 0x7D, 0x7F, 0xFE, 0xFD, 0xFD, 0xFD, 0xFC, 0xFC, 0xFD, 0xFD, 0xFE, 0xFF, +0xFF, 0xFF, 0x7F, 0x7E, 0x7E, 0x7D, 0x7C, 0x7C, 0x7C, 0x7B, 0x7B, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4C, 0x49, 0x53, 0x54, 0x4A, 0x00, +0x00, 0x00, 0x49, 0x4E, 0x46, 0x4F, 0x49, 0x53, 0x46, 0x54, 0x3E, 0x00, 0x00, 0x00, 0x46, 0x69, +0x6C, 0x65, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x6F, +0x6C, 0x64, 0x57, 0x61, 0x76, 0x65, 0x2E, 0x20, 0x20, 0x47, 0x6F, 0x6C, 0x64, 0x57, 0x61, 0x76, +0x65, 0x20, 0x63, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x43, 0x29, 0x20, +0x43, 0x68, 0x72, 0x69, 0x73, 0x20, 0x43, 0x72, 0x61, 0x69, 0x67, 0x00 + +}; + +static const uint8_t shaun_png[] PROGMEM = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x57, 0x08, 0x06, 0x00, 0x00, 0x00, 0xF2, 0x0C, 0xE0, + 0x57, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4B, 0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0, + 0xBD, 0xA7, 0x93, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x42, 0x8A, 0x00, + 0x00, 0x42, 0x8A, 0x01, 0x34, 0xA8, 0x6C, 0x25, 0x00, 0x00, 0x00, 0x09, 0x76, 0x70, 0x41, 0x67, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x57, 0x00, 0x73, 0x4D, 0x3B, 0xD6, 0x00, 0x00, 0x1B, + 0x47, 0x49, 0x44, 0x41, 0x54, 0x78, 0xDA, 0xED, 0x9D, 0x79, 0x74, 0x14, 0x55, 0xBE, 0xC7, 0x3F, + 0x55, 0xDD, 0x49, 0x67, 0x5F, 0x3A, 0x7B, 0x42, 0x82, 0x61, 0x49, 0x02, 0x81, 0xB0, 0x29, 0x32, + 0x22, 0x3C, 0x16, 0x41, 0x45, 0x10, 0x15, 0x7D, 0x13, 0x65, 0xD0, 0x81, 0xE3, 0x7B, 0xCC, 0xD3, + 0x51, 0x04, 0xF5, 0xE1, 0xB8, 0xCE, 0xE6, 0x28, 0x22, 0x23, 0x33, 0x2C, 0x2A, 0x22, 0xEE, 0x02, + 0x22, 0x0C, 0x2A, 0x83, 0x28, 0x7B, 0x20, 0xC8, 0x92, 0x10, 0xD9, 0x97, 0x40, 0x08, 0x81, 0x90, + 0x3D, 0x64, 0x21, 0xE9, 0x4E, 0x3A, 0x5D, 0xF7, 0xFD, 0x71, 0xBB, 0x93, 0x0E, 0x10, 0xD2, 0x59, + 0x3A, 0x01, 0xCF, 0xFB, 0x9E, 0xD3, 0xE7, 0xA4, 0x6E, 0xA5, 0x6E, 0xDD, 0xFA, 0xFD, 0xEA, 0xFE, + 0xEE, 0xEF, 0xFE, 0xB6, 0x52, 0xB8, 0xFE, 0xA1, 0x03, 0x7A, 0x01, 0x43, 0x81, 0x9B, 0x80, 0x6A, + 0x60, 0x3F, 0xA0, 0x02, 0x8F, 0x00, 0xB7, 0x03, 0xA1, 0x80, 0x00, 0x72, 0x81, 0xAD, 0xC0, 0xC7, + 0xC0, 0x6E, 0xA0, 0xAE, 0xB3, 0x07, 0xFF, 0x4B, 0x43, 0x30, 0xF0, 0x67, 0x20, 0x1B, 0xB0, 0x20, + 0x89, 0xAE, 0x01, 0x95, 0x40, 0xB9, 0xED, 0xF8, 0x6A, 0xBF, 0x3C, 0xDB, 0x75, 0x81, 0xCD, 0xF4, + 0xAF, 0x03, 0x8C, 0x40, 0x2C, 0xD0, 0x13, 0x88, 0x00, 0x0C, 0x9D, 0xF9, 0xC0, 0x4A, 0x27, 0xDD, + 0xD7, 0x13, 0x88, 0x07, 0xFA, 0x03, 0x51, 0x36, 0x22, 0xE4, 0x03, 0x87, 0x80, 0x83, 0x48, 0x62, + 0x1B, 0x81, 0x85, 0x40, 0x72, 0x2B, 0xC7, 0xA9, 0x01, 0x5F, 0x00, 0x2F, 0x03, 0x35, 0xB6, 0xE3, + 0x0A, 0xDB, 0xDF, 0xDE, 0xC0, 0x48, 0x60, 0x22, 0x30, 0x08, 0xC9, 0x78, 0x3D, 0x92, 0xD1, 0x99, + 0xC0, 0x0F, 0xC0, 0x5A, 0xE0, 0x5C, 0x47, 0x13, 0xA6, 0xA3, 0x19, 0xA2, 0x07, 0x46, 0x00, 0x4F, + 0x22, 0x45, 0x4D, 0xD0, 0x65, 0x63, 0xB8, 0x84, 0x14, 0x47, 0xEF, 0x03, 0x09, 0xC0, 0x4B, 0x48, + 0xD1, 0x44, 0x40, 0x40, 0x00, 0x31, 0x31, 0x31, 0x54, 0x56, 0x56, 0x92, 0x93, 0x93, 0x83, 0xD5, + 0x6A, 0x25, 0x3A, 0x3A, 0x9A, 0x89, 0x13, 0x27, 0x32, 0x60, 0xC0, 0x00, 0xAC, 0x56, 0x2B, 0xBB, + 0x77, 0xEF, 0x66, 0xDD, 0xBA, 0x75, 0x14, 0x16, 0x16, 0xDA, 0xFB, 0xAB, 0x03, 0x4E, 0x23, 0x67, + 0x4D, 0x9D, 0x8D, 0xC0, 0xFB, 0x90, 0x22, 0xF0, 0x1E, 0xC0, 0xAB, 0x89, 0x71, 0x6A, 0xC0, 0x11, + 0xE0, 0x0D, 0xE0, 0x6B, 0xE4, 0xEC, 0xFC, 0xC5, 0xC1, 0x07, 0x78, 0x0D, 0x28, 0xA5, 0x69, 0x51, + 0x63, 0xFF, 0x99, 0x80, 0x2A, 0xFB, 0xF1, 0xC0, 0x81, 0x03, 0xC5, 0xA6, 0x4D, 0x9B, 0x44, 0x49, + 0x49, 0x89, 0xC8, 0xCA, 0xCA, 0x12, 0xAF, 0xBF, 0xFE, 0xBA, 0x78, 0xFC, 0xF1, 0xC7, 0x45, 0x5A, + 0x5A, 0x9A, 0xD0, 0x34, 0x4D, 0xD8, 0x51, 0x57, 0x57, 0x27, 0xB6, 0x6E, 0xDD, 0x2A, 0xFA, 0xF7, + 0xEF, 0xDF, 0x5C, 0xFF, 0x8D, 0x7E, 0x8A, 0xA2, 0x08, 0x55, 0x55, 0xAF, 0x76, 0xAE, 0x02, 0x78, + 0x0E, 0xF9, 0x22, 0x75, 0x08, 0x3A, 0x6A, 0x86, 0x78, 0x02, 0x7F, 0x05, 0x9E, 0x02, 0xDC, 0x00, + 0x14, 0x45, 0x21, 0x24, 0x24, 0x84, 0xE8, 0xE8, 0x68, 0xDC, 0xDD, 0xDD, 0xB9, 0x70, 0xE1, 0x02, + 0xB9, 0xB9, 0xB9, 0xD4, 0xD5, 0x35, 0x5E, 0x87, 0xBD, 0xBC, 0xBC, 0x58, 0xB1, 0x62, 0x05, 0x13, + 0x26, 0x4C, 0xA8, 0x6F, 0x13, 0x42, 0x20, 0x84, 0x40, 0x55, 0xD5, 0xAB, 0xDE, 0x6C, 0xD7, 0xAE, + 0x5D, 0x3C, 0xFC, 0xF0, 0xC3, 0xE4, 0xE4, 0xE4, 0x34, 0xFD, 0xE0, 0x8A, 0x42, 0x7C, 0x7C, 0x3C, + 0xF7, 0xDC, 0x73, 0x0F, 0xFD, 0xFA, 0xF5, 0xC3, 0xC3, 0xC3, 0x83, 0xEC, 0xEC, 0x6C, 0x36, 0x6C, + 0xD8, 0x40, 0x6A, 0x6A, 0x2A, 0x35, 0x35, 0x35, 0xF6, 0x7F, 0xAD, 0xB4, 0x8D, 0xFB, 0x73, 0xC0, + 0xDA, 0x41, 0xF4, 0x72, 0x39, 0x7E, 0x8F, 0x7C, 0xEB, 0x05, 0x20, 0xC2, 0xC2, 0xC2, 0xC4, 0x2B, + 0xAF, 0xBC, 0x22, 0x0E, 0x1E, 0x3C, 0x28, 0x2E, 0x5E, 0xBC, 0x28, 0x2A, 0x2A, 0x2A, 0x44, 0x56, + 0x56, 0x96, 0x58, 0xBC, 0x78, 0xB1, 0x48, 0x48, 0x48, 0x68, 0xF4, 0x96, 0xC6, 0xC4, 0xC4, 0x88, + 0x33, 0x67, 0xCE, 0x88, 0x96, 0xE2, 0xE3, 0x8F, 0x3F, 0x16, 0x77, 0xDE, 0x79, 0xA7, 0x78, 0xFE, + 0xF9, 0xE7, 0xC5, 0xBB, 0xEF, 0xBE, 0x2B, 0xDE, 0x7E, 0xFB, 0x6D, 0xF1, 0xE0, 0x83, 0x0F, 0x0A, + 0xA3, 0xD1, 0x28, 0xDC, 0xDC, 0xDC, 0xC4, 0xD4, 0xA9, 0x53, 0xC5, 0xE9, 0xD3, 0xA7, 0xAF, 0xB8, + 0xAE, 0xA2, 0xA2, 0x42, 0x2C, 0x58, 0xB0, 0x40, 0x04, 0x07, 0x07, 0x3B, 0x8E, 0xA3, 0x00, 0x58, + 0x0D, 0xFC, 0x0E, 0x08, 0xEF, 0x6C, 0x62, 0xB6, 0x15, 0x7D, 0x80, 0x33, 0xF6, 0x87, 0x8B, 0x8D, + 0x8D, 0x15, 0xEB, 0xD7, 0xAF, 0x6F, 0x24, 0x6A, 0x1C, 0x91, 0x91, 0x91, 0x21, 0x06, 0x0F, 0x1E, + 0x2C, 0x00, 0x61, 0x30, 0x18, 0xC4, 0xAF, 0x7F, 0xFD, 0x6B, 0x51, 0x51, 0x51, 0xD1, 0x62, 0x86, + 0x58, 0xAD, 0x56, 0x61, 0x36, 0x9B, 0x1B, 0xDD, 0xA7, 0xA6, 0xA6, 0x46, 0xEC, 0xD8, 0xB1, 0x43, + 0xAC, 0x5A, 0xB5, 0x4A, 0x94, 0x97, 0x97, 0x37, 0x79, 0xAD, 0xA6, 0x69, 0x62, 0xF1, 0xE2, 0xC5, + 0xC2, 0xC3, 0xC3, 0xE3, 0x72, 0x11, 0x66, 0x05, 0x76, 0x02, 0x43, 0x3A, 0x9B, 0xA8, 0x6D, 0xC1, + 0xDB, 0xF6, 0x07, 0xF2, 0xF5, 0xF5, 0x15, 0x2B, 0x56, 0xAC, 0x68, 0x96, 0x98, 0xC7, 0x8E, 0x1D, + 0x13, 0xF3, 0xE7, 0xCF, 0x17, 0x1B, 0x36, 0x6C, 0x10, 0xA5, 0xA5, 0xA5, 0x2D, 0x66, 0x46, 0x7B, + 0xA0, 0xB2, 0xB2, 0x52, 0x4C, 0x98, 0x30, 0xA1, 0xA9, 0x75, 0xE7, 0x00, 0x52, 0x31, 0x68, 0x77, + 0xB8, 0x7A, 0x0D, 0x89, 0x02, 0x36, 0xDA, 0x07, 0x3F, 0x79, 0xF2, 0x64, 0x3E, 0xFC, 0xF0, 0x43, + 0x0C, 0x86, 0x4E, 0x55, 0xF5, 0x9D, 0xC6, 0xC1, 0x83, 0x07, 0x59, 0xBB, 0x76, 0x2D, 0x16, 0x8B, + 0x85, 0x94, 0x94, 0x14, 0x52, 0x53, 0x53, 0xB1, 0x5A, 0xEB, 0x97, 0x91, 0xF7, 0x91, 0xDA, 0xE2, + 0x0D, 0xB5, 0xAE, 0x8C, 0x07, 0xCC, 0x80, 0xF0, 0xF4, 0xF4, 0x14, 0xEB, 0xD6, 0xAD, 0xEB, 0x94, + 0xB7, 0xBD, 0x3D, 0x50, 0x54, 0x54, 0x24, 0x92, 0x93, 0x93, 0x1D, 0x67, 0x49, 0x36, 0xD0, 0xBD, + 0xB3, 0x09, 0xDC, 0x12, 0x84, 0x00, 0xAB, 0xEC, 0x0F, 0x10, 0x1F, 0x1F, 0x2F, 0x72, 0x73, 0x73, + 0x3B, 0x9B, 0xAE, 0x6D, 0xC2, 0x96, 0x2D, 0x5B, 0x84, 0x8F, 0x8F, 0x8F, 0xA3, 0x6A, 0x7E, 0x47, + 0x7B, 0x13, 0x4D, 0x6D, 0x7B, 0x17, 0x57, 0x85, 0x37, 0x72, 0x53, 0x35, 0xC9, 0xDE, 0xD0, 0xAD, + 0x5B, 0x37, 0x8C, 0x46, 0xA3, 0x8B, 0x6E, 0xD7, 0x31, 0xF0, 0xF5, 0xF5, 0x45, 0xAF, 0xAF, 0xDF, + 0x92, 0xA8, 0x80, 0x47, 0x7B, 0xDF, 0xC3, 0x55, 0x0C, 0xF9, 0x4F, 0xE0, 0x37, 0xD8, 0xD6, 0xA8, + 0x84, 0x84, 0x04, 0x9E, 0x7E, 0xFA, 0x69, 0x3C, 0x3C, 0xDA, 0x7D, 0xFC, 0x1D, 0x8A, 0x5D, 0xBB, + 0x76, 0x51, 0x56, 0x56, 0x66, 0x3F, 0xAC, 0x42, 0xDA, 0xCC, 0xDA, 0x15, 0xAE, 0xD8, 0x81, 0x1A, + 0x81, 0xC7, 0xB1, 0x19, 0xE9, 0x12, 0x12, 0x12, 0xF8, 0xEC, 0xB3, 0xCF, 0xB8, 0xF9, 0xE6, 0x9B, + 0x5D, 0x44, 0xA6, 0x8E, 0x43, 0x5E, 0x5E, 0x23, 0xFA, 0x0B, 0x5C, 0xF7, 0x42, 0xB7, 0x2B, 0x46, + 0x21, 0x6D, 0x52, 0x42, 0xAF, 0xD7, 0x8B, 0x25, 0x4B, 0x96, 0x74, 0xB6, 0xE8, 0x6F, 0x37, 0xEC, + 0xDD, 0xBB, 0x57, 0x84, 0x86, 0x86, 0x3A, 0x2E, 0xEC, 0xB3, 0xDB, 0x9B, 0x78, 0xAE, 0xE0, 0x70, + 0x12, 0x72, 0x0D, 0xA1, 0x6B, 0xD7, 0xAE, 0x8C, 0x1D, 0x3B, 0xD6, 0x85, 0xBC, 0xEF, 0x58, 0x24, + 0x25, 0x25, 0x31, 0x64, 0x48, 0xA3, 0x3D, 0xE1, 0x2D, 0xB4, 0xB3, 0x94, 0x71, 0x05, 0x43, 0x22, + 0xED, 0x7F, 0x44, 0x47, 0x47, 0x13, 0x12, 0x12, 0xE2, 0x1A, 0xEA, 0x74, 0x02, 0x0C, 0x06, 0x03, + 0x89, 0x89, 0x89, 0x8E, 0x4D, 0x51, 0x48, 0x3B, 0x5D, 0xBB, 0xC1, 0x15, 0x0C, 0xA9, 0xEF, 0x53, + 0xA7, 0xD3, 0x35, 0x69, 0x00, 0xBC, 0x51, 0xE1, 0xEB, 0xEB, 0xEB, 0x78, 0x68, 0xE0, 0x06, 0x98, + 0x21, 0xF5, 0xCE, 0x88, 0xBC, 0xBC, 0x3C, 0x47, 0xAD, 0xE4, 0x17, 0x81, 0xD2, 0xD2, 0x52, 0xC7, + 0xC3, 0x6A, 0xDA, 0xD9, 0x57, 0xE2, 0x0A, 0x86, 0x1C, 0x46, 0xEE, 0xCE, 0xC9, 0xCA, 0xCA, 0x22, + 0x35, 0x35, 0xD5, 0x65, 0xC4, 0xE9, 0x68, 0x54, 0x55, 0x55, 0x91, 0x91, 0x91, 0xE1, 0xD8, 0x94, + 0x8D, 0x64, 0xCA, 0x75, 0x8D, 0x70, 0xE0, 0x67, 0x6C, 0x9A, 0xC8, 0xD0, 0xA1, 0x43, 0x45, 0x76, + 0x76, 0x76, 0x67, 0x2B, 0x48, 0xED, 0x82, 0x1F, 0x7E, 0xF8, 0x41, 0xF8, 0xF9, 0xF9, 0x39, 0x6A, + 0x59, 0x4F, 0x74, 0x36, 0xB1, 0x9D, 0xC5, 0x73, 0x48, 0xA3, 0x9B, 0x00, 0xC4, 0xC8, 0x91, 0x23, + 0xC5, 0x8F, 0x3F, 0xFE, 0x28, 0xCC, 0x66, 0xB3, 0xCB, 0x88, 0x65, 0xB5, 0x5A, 0x5D, 0xCA, 0x8C, + 0xAC, 0xAC, 0x2C, 0x31, 0x6C, 0xD8, 0x30, 0x47, 0x66, 0x64, 0x01, 0x71, 0x9D, 0x4D, 0x68, 0x67, + 0x61, 0x04, 0xD6, 0x39, 0x0C, 0x5E, 0xF8, 0xF8, 0xF8, 0x88, 0x05, 0x0B, 0x16, 0xB8, 0x84, 0x58, + 0x99, 0x99, 0x99, 0x62, 0xFA, 0xF4, 0xE9, 0x62, 0xD9, 0xB2, 0x65, 0xC2, 0x64, 0x32, 0x5D, 0x71, + 0x5E, 0xD3, 0x34, 0x71, 0xEE, 0xDC, 0x39, 0x91, 0x97, 0x97, 0xD7, 0xAA, 0xFE, 0x4F, 0x9E, 0x3C, + 0x29, 0x46, 0x8C, 0x18, 0x71, 0xB9, 0x09, 0xFE, 0xF5, 0xCE, 0x26, 0xB2, 0xB3, 0x08, 0x46, 0x5A, + 0x79, 0x1B, 0x31, 0x04, 0x10, 0x49, 0x49, 0x49, 0x22, 0x27, 0x27, 0xA7, 0x5D, 0x99, 0x61, 0xB5, + 0x5A, 0xC5, 0x8C, 0x19, 0x33, 0x04, 0x20, 0xBC, 0xBC, 0xBC, 0xC4, 0xA3, 0x8F, 0x3E, 0x2A, 0x36, + 0x6F, 0xDE, 0x2C, 0xCE, 0x9F, 0x3F, 0x2F, 0x0A, 0x0B, 0x0B, 0xC5, 0xE1, 0xC3, 0x87, 0xC5, 0xDC, + 0xB9, 0x73, 0x45, 0x42, 0x42, 0x82, 0x18, 0x33, 0x66, 0x8C, 0x28, 0x28, 0x28, 0x68, 0xF1, 0x3D, + 0x96, 0x2E, 0x5D, 0x7A, 0x39, 0x33, 0x34, 0x60, 0x3B, 0xF0, 0xDF, 0x40, 0x37, 0x64, 0x38, 0xD1, + 0x75, 0x87, 0x28, 0xA4, 0xEF, 0x79, 0x2F, 0x36, 0x93, 0x3B, 0x57, 0x09, 0x26, 0x98, 0x35, 0x6B, + 0x56, 0xBB, 0x8A, 0xAE, 0x6D, 0xDB, 0xB6, 0x89, 0xD0, 0xD0, 0x50, 0xE1, 0xED, 0x69, 0x10, 0xE1, + 0xC1, 0x01, 0x02, 0x10, 0x9E, 0x5E, 0x5E, 0xA2, 0x5B, 0xB7, 0xEE, 0xA2, 0x57, 0xAF, 0x5E, 0x22, + 0x38, 0x24, 0x44, 0x28, 0x8A, 0x22, 0x00, 0xE1, 0xE6, 0xE6, 0x26, 0x3E, 0xFA, 0xE8, 0xA3, 0x16, + 0xDF, 0x63, 0xCD, 0x9A, 0x35, 0x42, 0xAF, 0xD7, 0x5F, 0xCD, 0x51, 0x55, 0x87, 0x14, 0x5D, 0x0B, + 0x80, 0x5B, 0x01, 0xF7, 0xB6, 0x12, 0xB1, 0x3D, 0x38, 0x1B, 0x0A, 0x4C, 0x07, 0xE6, 0x21, 0x0D, + 0x8A, 0x5D, 0x70, 0xD0, 0xCD, 0x75, 0x3A, 0x1D, 0xE1, 0xE1, 0xE1, 0x24, 0x25, 0x25, 0x61, 0x36, + 0x9B, 0x49, 0x4D, 0x4D, 0xC5, 0x64, 0x32, 0xD1, 0xB7, 0x6F, 0x5F, 0x7C, 0x7C, 0x7C, 0x00, 0x19, + 0xB4, 0x50, 0x50, 0x50, 0x40, 0x59, 0x59, 0x19, 0xBE, 0xBE, 0xBE, 0x28, 0x8A, 0x73, 0x7E, 0xB3, + 0xEC, 0xEC, 0x6C, 0x9E, 0x7E, 0xFA, 0x69, 0x8E, 0x1D, 0x3B, 0xC6, 0x8C, 0x87, 0xC7, 0x31, 0x77, + 0xC6, 0x14, 0x02, 0xFD, 0x7C, 0xA8, 0xAA, 0x36, 0x51, 0x5A, 0x5A, 0x42, 0x65, 0x45, 0x39, 0x81, + 0x3E, 0x06, 0xEE, 0xFC, 0x55, 0x7F, 0x86, 0x0D, 0x48, 0x20, 0xFD, 0xE8, 0x69, 0xB2, 0xB3, 0xCF, + 0x72, 0xC7, 0x1D, 0x77, 0xB4, 0xC8, 0xF2, 0xBC, 0x7E, 0xFD, 0x7A, 0x36, 0x6C, 0xD8, 0x80, 0x9F, + 0x9F, 0x1F, 0x3A, 0x9D, 0x0E, 0x8B, 0xA5, 0x5E, 0xD3, 0x55, 0x91, 0xC1, 0x78, 0x83, 0x81, 0xFB, + 0x81, 0xDE, 0x40, 0x11, 0xD2, 0xE8, 0xA8, 0xB5, 0x03, 0x6D, 0x5B, 0x04, 0x37, 0xA4, 0x68, 0x4A, + 0x45, 0xBE, 0x29, 0x8D, 0x66, 0x42, 0x97, 0x2E, 0x5D, 0xC4, 0x23, 0x8F, 0x3C, 0x22, 0x3E, 0xF9, + 0xE4, 0x13, 0x71, 0xEC, 0xD8, 0x31, 0x51, 0x55, 0x55, 0x25, 0x5E, 0x7A, 0xE9, 0x25, 0x01, 0x08, + 0x9D, 0x4E, 0x27, 0x06, 0x0E, 0x1A, 0x24, 0x66, 0xCF, 0x9E, 0x2D, 0xE6, 0xCF, 0x9F, 0x2F, 0x66, + 0xCE, 0x9C, 0x29, 0xFA, 0xF4, 0xE9, 0x23, 0x7A, 0xF7, 0xEE, 0x2D, 0xD6, 0xAC, 0x59, 0xE3, 0xD4, + 0x02, 0x9D, 0x99, 0x99, 0x29, 0xC6, 0x8D, 0x1B, 0x27, 0x95, 0x86, 0x9B, 0x13, 0x45, 0xEE, 0x86, + 0x25, 0x42, 0x64, 0xAC, 0x16, 0x5A, 0xFA, 0x2A, 0x51, 0xB6, 0xED, 0x63, 0x71, 0xFA, 0x9B, 0x05, + 0xE2, 0xF8, 0xD7, 0xF3, 0xC5, 0x85, 0x0D, 0xEF, 0x0B, 0xCB, 0xDE, 0x15, 0xA2, 0x74, 0xFB, 0x27, + 0x62, 0xFC, 0xB0, 0x41, 0x02, 0x10, 0x77, 0xDF, 0x7D, 0xB7, 0x38, 0x7A, 0xF4, 0x68, 0xA3, 0xFE, + 0x34, 0x4D, 0x13, 0xFB, 0xF7, 0xEF, 0x17, 0x6F, 0xBD, 0xF5, 0x96, 0xD8, 0xBD, 0x7B, 0xB7, 0xB0, + 0x58, 0x2C, 0xC2, 0x62, 0xB1, 0x88, 0x6D, 0xDB, 0xB6, 0x89, 0xB8, 0xB8, 0x38, 0xE1, 0xEE, 0xEE, + 0x2E, 0xDE, 0x7B, 0xEF, 0x3D, 0xB1, 0x69, 0xD3, 0x26, 0xF1, 0xDC, 0x73, 0xCF, 0x89, 0x7E, 0xFD, + 0xFA, 0x09, 0x77, 0x77, 0xF7, 0xAB, 0xCD, 0x9A, 0x12, 0xE0, 0x03, 0x64, 0x10, 0x60, 0x87, 0xC5, + 0xBD, 0x45, 0x20, 0x67, 0x44, 0x99, 0xE3, 0x60, 0x74, 0x3A, 0x9D, 0x48, 0x4A, 0x4A, 0x12, 0x6F, + 0xBE, 0xF9, 0xA6, 0x38, 0x76, 0xEC, 0x98, 0xB0, 0x58, 0x2C, 0xF5, 0x0F, 0x6C, 0x32, 0x99, 0xC4, + 0xA4, 0x49, 0x93, 0x04, 0x20, 0xBA, 0x84, 0x1A, 0x85, 0xA7, 0xC1, 0xAD, 0xD1, 0x83, 0x78, 0xB8, + 0xBB, 0x09, 0x9D, 0xAA, 0x8A, 0xA0, 0xA0, 0x20, 0xF1, 0xDA, 0x6B, 0xAF, 0x89, 0xB3, 0x67, 0xCF, + 0x5E, 0x35, 0x10, 0xA2, 0xA2, 0xA2, 0x42, 0xAC, 0x5C, 0xB9, 0x52, 0x0C, 0x18, 0x30, 0x40, 0x00, + 0xE2, 0x96, 0xDE, 0xDD, 0xC5, 0xC1, 0x95, 0x6F, 0x0B, 0xB1, 0xFF, 0x6B, 0x21, 0xD2, 0xBE, 0x92, + 0xBF, 0xF4, 0x55, 0x42, 0xEC, 0x5F, 0x25, 0xDB, 0xD2, 0x57, 0xC9, 0xB6, 0xFD, 0x5F, 0x8B, 0xC3, + 0x5F, 0xFD, 0x5D, 0x0C, 0x4E, 0xEC, 0x21, 0x00, 0xD1, 0xA3, 0x47, 0x0F, 0xF1, 0x87, 0x3F, 0xFC, + 0x41, 0xAC, 0x5A, 0xB5, 0x4A, 0xAC, 0x5C, 0xB9, 0x52, 0xCC, 0x9A, 0x35, 0x4B, 0xC4, 0xC4, 0xC4, + 0x08, 0x40, 0x84, 0x87, 0x87, 0x8B, 0xFB, 0xEE, 0xBB, 0x4F, 0x4C, 0x9C, 0x38, 0xB1, 0xDE, 0x98, + 0x38, 0x79, 0xF2, 0xE4, 0xFA, 0x60, 0x0B, 0x4D, 0xD3, 0x44, 0x7E, 0x7E, 0xBE, 0x58, 0xBE, 0x7C, + 0xB9, 0x18, 0x3F, 0x7E, 0xBC, 0xF0, 0xF5, 0xF5, 0xBD, 0x1A, 0x63, 0xCE, 0x21, 0x8D, 0x8F, 0xC1, + 0x2D, 0x21, 0x6C, 0x4B, 0x39, 0xA8, 0x20, 0x83, 0x9E, 0x5F, 0x07, 0x86, 0x39, 0x5E, 0x1F, 0x17, + 0x17, 0xC7, 0xF4, 0xE9, 0xD3, 0x49, 0x4E, 0x4E, 0x26, 0x32, 0x32, 0xF2, 0x8A, 0x0B, 0x77, 0xEC, + 0xD8, 0xC1, 0x84, 0x09, 0x13, 0xF0, 0xD4, 0x2B, 0x2C, 0xFF, 0xDB, 0x33, 0x58, 0xEA, 0xEA, 0x48, + 0x3B, 0x7A, 0x9A, 0xD2, 0x8A, 0x4B, 0x04, 0x07, 0xF8, 0x31, 0xA8, 0x57, 0x37, 0x52, 0x7F, 0x3E, + 0xCE, 0x3F, 0x96, 0xAF, 0xA7, 0xEC, 0x52, 0x35, 0x71, 0xF1, 0xF1, 0xDC, 0x39, 0x76, 0x2C, 0x03, + 0x07, 0x0E, 0x24, 0x28, 0x28, 0x88, 0xAA, 0xAA, 0x2A, 0x4E, 0x9C, 0x38, 0xC1, 0x96, 0x2D, 0x5B, + 0xD8, 0xB3, 0x67, 0x0F, 0x96, 0xDA, 0x5A, 0xEE, 0xBA, 0xAD, 0x3F, 0x73, 0x9F, 0x99, 0x42, 0xAF, + 0x6E, 0xD1, 0xA0, 0x39, 0x21, 0x21, 0x54, 0x95, 0x13, 0x67, 0xCE, 0xF3, 0xA7, 0x25, 0xAB, 0xF8, + 0x76, 0x7B, 0x1A, 0x55, 0xE6, 0x1A, 0xDB, 0x23, 0x08, 0x00, 0x02, 0x7C, 0xBD, 0x49, 0xEA, 0x19, + 0xC3, 0xD1, 0xAC, 0xF3, 0x14, 0x97, 0x55, 0xA2, 0x28, 0x0A, 0xE1, 0xE1, 0xE1, 0x24, 0x27, 0x27, + 0x33, 0x7B, 0xF6, 0x6C, 0xC2, 0xC2, 0xC2, 0xAE, 0xE8, 0xB2, 0xBA, 0xBA, 0x9A, 0xD4, 0xD4, 0x54, + 0x96, 0x2E, 0x5D, 0xCA, 0xF7, 0xDF, 0x7F, 0x4F, 0x65, 0x65, 0xA5, 0xE3, 0x69, 0x2B, 0xB0, 0x03, + 0xF8, 0x13, 0x90, 0x82, 0x13, 0x62, 0xAC, 0x25, 0x0C, 0x71, 0x03, 0x26, 0x03, 0x7F, 0x41, 0xAE, + 0x13, 0x80, 0xB4, 0xED, 0x4C, 0x99, 0x32, 0x85, 0x99, 0x33, 0x67, 0xD2, 0xA3, 0x47, 0x8F, 0xAB, + 0x5E, 0x28, 0x84, 0x60, 0xC6, 0x8C, 0x19, 0x2C, 0x58, 0xB0, 0x80, 0xA9, 0xF7, 0x8E, 0x64, 0xC9, + 0x2B, 0xBF, 0xB3, 0x79, 0xDE, 0x84, 0xA4, 0x85, 0x22, 0x87, 0x52, 0x67, 0xA9, 0x63, 0xEB, 0xDE, + 0x43, 0xFC, 0x73, 0xE5, 0xF7, 0x6C, 0x4F, 0x3F, 0x42, 0x65, 0xB5, 0x59, 0x0E, 0x52, 0x51, 0x11, + 0x42, 0x3E, 0x8B, 0x5E, 0xA7, 0x92, 0xD8, 0x2D, 0x9A, 0x69, 0x13, 0x47, 0x32, 0xE5, 0x9E, 0xFF, + 0x20, 0xD0, 0xDF, 0xD7, 0x39, 0x66, 0x38, 0x30, 0xA5, 0xDA, 0x64, 0x66, 0xD7, 0x81, 0x13, 0x6C, + 0xD9, 0x77, 0x98, 0xAC, 0xDC, 0x02, 0x54, 0x45, 0xA1, 0x67, 0x4C, 0x04, 0x63, 0x6E, 0x4D, 0x62, + 0x50, 0xAF, 0x6E, 0x7C, 0xBA, 0x6E, 0x3B, 0x4F, 0xCE, 0x59, 0x4A, 0x78, 0x44, 0x24, 0x5F, 0x7E, + 0xF9, 0x25, 0x43, 0x87, 0x0E, 0x45, 0xA7, 0xBB, 0xF6, 0x72, 0x6B, 0x36, 0x9B, 0xD9, 0xB6, 0x6D, + 0x1B, 0x0B, 0x17, 0x2E, 0x64, 0xD3, 0xA6, 0x4D, 0x8E, 0x81, 0x76, 0x20, 0xE3, 0xBA, 0xDE, 0x04, + 0x96, 0xD0, 0xCC, 0xCE, 0xDE, 0x59, 0x86, 0xF8, 0x02, 0xFF, 0x0B, 0x3C, 0x83, 0x0C, 0x09, 0x05, + 0x20, 0x31, 0x31, 0x91, 0x3F, 0xFE, 0xF1, 0x8F, 0xDC, 0x7B, 0xEF, 0xBD, 0xB8, 0xBB, 0x37, 0xAD, + 0x60, 0x9C, 0x39, 0x73, 0x86, 0x31, 0x63, 0xC7, 0x92, 0x9B, 0x73, 0x96, 0x7F, 0xCD, 0x7B, 0x9E, + 0xBB, 0x6E, 0x1F, 0x08, 0xD6, 0x26, 0x88, 0xA8, 0x53, 0xA9, 0xAA, 0x32, 0xF1, 0xF3, 0xF1, 0x33, + 0xEC, 0x3C, 0x70, 0x82, 0xE3, 0xD9, 0xB9, 0x54, 0x5C, 0xAA, 0xC6, 0xD3, 0xC3, 0x40, 0x4C, 0x78, + 0x30, 0x83, 0x13, 0xBB, 0x33, 0xA4, 0x6F, 0x1C, 0xE1, 0x21, 0x81, 0x36, 0xE1, 0x20, 0x9C, 0x67, + 0x86, 0xE3, 0x53, 0xAB, 0x2A, 0x08, 0xD0, 0xEA, 0xAC, 0xA0, 0x80, 0xAA, 0xD3, 0xD5, 0x4F, 0x96, + 0xBC, 0xA2, 0x52, 0xEE, 0x7A, 0xF2, 0xAF, 0x1C, 0x3D, 0x9B, 0xC7, 0x8A, 0xE5, 0xCB, 0x99, 0x34, + 0x69, 0x92, 0xD3, 0x5D, 0x57, 0x56, 0x56, 0xB2, 0x62, 0xC5, 0x0A, 0xE6, 0xCD, 0x9B, 0xC7, 0x89, + 0x13, 0x27, 0x1C, 0x4F, 0xD5, 0x00, 0xCB, 0x80, 0x57, 0x81, 0xE2, 0xB6, 0x30, 0x24, 0x10, 0x29, + 0xA2, 0xFE, 0x0B, 0x9B, 0xF6, 0xA4, 0xD7, 0xEB, 0x79, 0xE0, 0x81, 0x07, 0xF8, 0xF3, 0x9F, 0xFF, + 0x4C, 0x7C, 0x7C, 0x7C, 0xB3, 0x1D, 0x2C, 0x59, 0xB2, 0x84, 0xE9, 0xD3, 0xA7, 0x33, 0x6C, 0x40, + 0x02, 0xDF, 0xBE, 0xF3, 0x02, 0x01, 0xBE, 0xDE, 0xD7, 0x26, 0xA4, 0x9D, 0x60, 0x80, 0xB0, 0x6A, + 0x68, 0x9A, 0x86, 0xAA, 0x28, 0x28, 0x3A, 0x1D, 0x28, 0x8A, 0x9C, 0x11, 0xAD, 0x61, 0x84, 0xB3, + 0x50, 0x14, 0x5E, 0x5A, 0xB4, 0x9C, 0xBF, 0x2D, 0x5B, 0x43, 0x72, 0x72, 0x32, 0x9F, 0x7E, 0xFA, + 0x29, 0x6E, 0x6E, 0x6E, 0x2D, 0xEA, 0x22, 0x33, 0x33, 0x93, 0xD7, 0x5F, 0x7F, 0x9D, 0x15, 0x2B, + 0x56, 0x38, 0xCE, 0x16, 0x0D, 0x19, 0x01, 0x39, 0x13, 0x99, 0xCB, 0x72, 0x05, 0x9A, 0x33, 0x2E, + 0x86, 0x00, 0xFF, 0x40, 0xAA, 0xB5, 0x7A, 0x90, 0x22, 0xEA, 0x85, 0x17, 0x5E, 0x60, 0xC9, 0x92, + 0x25, 0x4E, 0x31, 0xC3, 0x6C, 0x36, 0xB3, 0x6E, 0xDD, 0x3A, 0x00, 0x26, 0x0C, 0xBF, 0x99, 0x00, + 0x7F, 0x9F, 0xE6, 0x89, 0x29, 0x90, 0x33, 0xC8, 0xAA, 0xA1, 0x00, 0x3A, 0x55, 0x95, 0xAA, 0xB0, + 0xA6, 0x81, 0xD5, 0xEA, 0x5A, 0x66, 0x00, 0xA8, 0x0A, 0x13, 0x86, 0x0F, 0x22, 0xC0, 0xD7, 0x8B, + 0x94, 0x94, 0x14, 0x32, 0x33, 0x33, 0x5B, 0xDC, 0x45, 0xCF, 0x9E, 0x3D, 0x59, 0xBC, 0x78, 0x31, + 0x73, 0xE6, 0xCC, 0x71, 0xF4, 0x09, 0xA9, 0xC0, 0x43, 0xC8, 0x7D, 0x4B, 0xC4, 0x55, 0x6F, 0x7D, + 0x8D, 0x3E, 0x8D, 0x34, 0xEC, 0x2D, 0x54, 0x80, 0x90, 0x90, 0x10, 0xDE, 0x79, 0xE7, 0x1D, 0x5E, + 0x7D, 0xF5, 0x55, 0xFC, 0xFD, 0xFD, 0x9D, 0x1A, 0xD8, 0xF1, 0xE3, 0xC7, 0xF9, 0x69, 0xF7, 0x6E, + 0x42, 0x02, 0xFD, 0x18, 0x3B, 0xA4, 0x9F, 0x7D, 0xFD, 0xBC, 0xBE, 0xA1, 0x69, 0xF4, 0xED, 0x11, + 0xC3, 0x2D, 0x89, 0x3D, 0xB8, 0x70, 0xE1, 0x02, 0x5B, 0xB7, 0x6E, 0x6D, 0x55, 0x37, 0x5E, 0x5E, + 0x5E, 0x3C, 0xF5, 0xD4, 0x53, 0x7C, 0xF0, 0xC1, 0x07, 0xC4, 0xC6, 0xC6, 0x3A, 0x9E, 0xBA, 0x1F, + 0x98, 0x03, 0x5C, 0x41, 0xC4, 0xA6, 0x18, 0xE2, 0x89, 0x4C, 0x1D, 0x98, 0x8C, 0x4D, 0xAC, 0x45, + 0x45, 0x45, 0xB1, 0x68, 0xD1, 0x22, 0xA6, 0x4D, 0x9B, 0xD6, 0xA2, 0xE9, 0xBB, 0x7D, 0xFB, 0x76, + 0x8A, 0x8B, 0x8A, 0xB8, 0xB5, 0x4F, 0x4F, 0xE2, 0xBB, 0x46, 0xB6, 0x6C, 0x01, 0xEE, 0x2C, 0x08, + 0xF0, 0xF6, 0xF6, 0x64, 0xDC, 0xD0, 0x01, 0x00, 0x6C, 0xD8, 0xB0, 0x01, 0xB3, 0xD9, 0xDC, 0xAA, + 0xAE, 0x54, 0x55, 0x65, 0xE2, 0xC4, 0x89, 0x2C, 0x5D, 0xBA, 0xF4, 0x72, 0xA5, 0xE7, 0x11, 0xE4, + 0xBA, 0xDC, 0xC8, 0xC1, 0x75, 0x35, 0x86, 0x28, 0xC0, 0xFF, 0x20, 0xC5, 0x94, 0x0A, 0x92, 0x19, + 0xEF, 0xBE, 0xFB, 0x2E, 0x0F, 0x3D, 0xF4, 0x90, 0xD3, 0xBB, 0x68, 0x90, 0xE2, 0x6A, 0xD3, 0xA6, + 0x4D, 0x00, 0x8C, 0x19, 0x92, 0x84, 0x87, 0xE7, 0x8D, 0x11, 0x42, 0x0A, 0x80, 0x80, 0x11, 0x83, + 0x12, 0x09, 0xF2, 0xF7, 0x21, 0x2D, 0x2D, 0x9D, 0xAC, 0xAC, 0xAC, 0x36, 0x75, 0x37, 0x6A, 0xD4, + 0x28, 0x16, 0x2D, 0x5A, 0x44, 0x54, 0x54, 0x94, 0xBD, 0x49, 0x87, 0xCC, 0x0A, 0xB8, 0xDF, 0xF1, + 0xFF, 0xAE, 0xC6, 0x90, 0x31, 0xC8, 0x0D, 0x8D, 0x01, 0xC0, 0x68, 0x34, 0x32, 0x6F, 0xDE, 0xBC, + 0x46, 0xF9, 0x19, 0xCE, 0x22, 0x3B, 0x3B, 0x9B, 0xF4, 0xFD, 0xFB, 0x09, 0xF2, 0xF7, 0x61, 0xF8, + 0x80, 0x5E, 0x37, 0x86, 0xB8, 0xB2, 0x43, 0x68, 0xC4, 0xC5, 0x44, 0x30, 0x20, 0x3E, 0x96, 0xFC, + 0xFC, 0x3C, 0x76, 0xED, 0xDA, 0xD5, 0xE6, 0x2E, 0xC7, 0x8E, 0x1D, 0xCB, 0x1B, 0x6F, 0xBC, 0xE1, + 0xE8, 0x06, 0xF6, 0x43, 0x66, 0x89, 0xDD, 0x64, 0x6F, 0xB8, 0x9C, 0x21, 0x91, 0x48, 0x51, 0x15, + 0x0A, 0xD2, 0xA9, 0xFF, 0xF2, 0xCB, 0x2F, 0xF3, 0xD0, 0x43, 0x0F, 0xB5, 0x6A, 0x00, 0xE9, 0xE9, + 0xE9, 0xE4, 0x5D, 0xC8, 0xA3, 0x4F, 0xF7, 0x18, 0x7A, 0x44, 0x87, 0x3B, 0xBF, 0x18, 0xAB, 0x2A, + 0xA8, 0xAA, 0x4C, 0xCC, 0x01, 0xD0, 0xA9, 0x52, 0xBB, 0x6A, 0x2D, 0x54, 0x05, 0x54, 0x15, 0xAB, + 0xA6, 0x61, 0xD5, 0xB4, 0xFA, 0xFE, 0xAF, 0x09, 0x01, 0x5E, 0x5E, 0x9E, 0x0C, 0x1F, 0xD8, 0x1B, + 0x80, 0x9D, 0x3B, 0x77, 0xA2, 0xB5, 0x83, 0xB8, 0x4D, 0x4E, 0x4E, 0x66, 0xFA, 0xF4, 0xE9, 0x8E, + 0x4D, 0xFD, 0x90, 0x41, 0xDB, 0x2A, 0x34, 0x96, 0x5F, 0x0A, 0x32, 0x21, 0xE5, 0x36, 0x7B, 0xC3, + 0x23, 0x8F, 0x3C, 0xC2, 0xF4, 0xE9, 0xD3, 0x5B, 0x1D, 0xA8, 0x20, 0xDD, 0xB7, 0x82, 0xDB, 0xFA, + 0xC5, 0xE3, 0xE3, 0xED, 0x09, 0x5A, 0x33, 0x0C, 0x51, 0x14, 0xAC, 0x9A, 0x46, 0xFA, 0xA1, 0x93, + 0xFC, 0x7B, 0xE7, 0x7E, 0x4E, 0x9D, 0xCB, 0xC7, 0xDB, 0xD3, 0xC0, 0x6D, 0x49, 0xF1, 0x8C, 0xBB, + 0x7D, 0x20, 0xA1, 0x41, 0x01, 0x2D, 0x5F, 0x83, 0x14, 0x85, 0x53, 0x39, 0x79, 0xFC, 0x6B, 0xCB, + 0x5E, 0xD2, 0x8F, 0x67, 0x61, 0xB5, 0x6A, 0x24, 0x76, 0x8F, 0xE6, 0xFE, 0x11, 0xB7, 0xD0, 0x37, + 0xEE, 0xA6, 0x6B, 0xAB, 0x99, 0x8A, 0xC2, 0xAD, 0x7D, 0x7B, 0xE2, 0xAE, 0xD7, 0x91, 0x91, 0x91, + 0x41, 0x49, 0x49, 0x49, 0x9B, 0xA3, 0x68, 0xDC, 0xDC, 0xDC, 0x78, 0xE6, 0x99, 0x67, 0x48, 0x49, + 0x49, 0x61, 0xEF, 0xDE, 0xBD, 0xF6, 0xE6, 0xC9, 0xC0, 0x72, 0x60, 0xBF, 0x23, 0x43, 0xFA, 0x03, + 0x53, 0xED, 0x07, 0x7D, 0xFA, 0xF4, 0xE1, 0xC5, 0x17, 0x5F, 0xC4, 0xCB, 0xCB, 0xCB, 0xE9, 0x9B, + 0x39, 0xA2, 0xAC, 0xAC, 0x8C, 0xFD, 0xFB, 0xF7, 0xA3, 0x53, 0x15, 0x86, 0xF4, 0xED, 0x09, 0x8A, + 0x4A, 0x73, 0x91, 0xFB, 0xB5, 0x96, 0x3A, 0x16, 0xAE, 0xFC, 0x9E, 0x39, 0x1F, 0x7F, 0x43, 0xE1, + 0xC5, 0xF2, 0xFA, 0xF6, 0x65, 0xDF, 0x6C, 0x65, 0xD8, 0x80, 0x04, 0xDE, 0x79, 0x76, 0x2A, 0xFD, + 0x13, 0x62, 0x9D, 0x67, 0x8A, 0xA2, 0xF0, 0x7D, 0xEA, 0x7E, 0x9E, 0x7D, 0xE7, 0x53, 0x8E, 0x9D, + 0x69, 0x50, 0xFB, 0xBF, 0xDE, 0xBC, 0x9B, 0x0F, 0xD7, 0x6E, 0xE6, 0x2F, 0xFF, 0x93, 0xCC, 0xA3, + 0xE3, 0xFF, 0x03, 0xB5, 0xA9, 0xD9, 0xA7, 0x69, 0xF4, 0x8E, 0xED, 0x42, 0xD7, 0x88, 0x10, 0x4E, + 0x67, 0x65, 0x71, 0xF2, 0xE4, 0xC9, 0x76, 0x09, 0x6B, 0x8A, 0x8A, 0x8A, 0x62, 0xE6, 0xCC, 0x99, + 0x4C, 0x9D, 0x3A, 0xD5, 0xAE, 0x2C, 0x44, 0x00, 0x8F, 0x02, 0x19, 0xF6, 0x17, 0x44, 0x05, 0xA6, + 0x61, 0x33, 0x89, 0xB8, 0xBB, 0xBB, 0x33, 0x6B, 0xD6, 0xAC, 0x26, 0x4D, 0x21, 0xCE, 0xE0, 0xEC, + 0xD9, 0xB3, 0x64, 0x9E, 0x3A, 0x45, 0x44, 0x70, 0x20, 0xBD, 0xBB, 0x75, 0x01, 0xD1, 0x0C, 0x11, + 0x55, 0x95, 0x55, 0x9B, 0x7E, 0xE2, 0xD5, 0xF7, 0xBE, 0x6A, 0xC4, 0x0C, 0x2F, 0x2F, 0x2F, 0xFC, + 0xFC, 0xFD, 0xD9, 0x96, 0x7E, 0x94, 0x67, 0xDE, 0xFE, 0x88, 0x82, 0xE2, 0x8B, 0xCE, 0x89, 0x2F, + 0x55, 0xE5, 0xF0, 0xE9, 0x1C, 0x66, 0xBC, 0xFD, 0x71, 0x23, 0x66, 0x18, 0x0C, 0x06, 0xC2, 0xC2, + 0xC2, 0x28, 0x2C, 0xAB, 0xE2, 0xF9, 0x7F, 0x7C, 0xCE, 0x96, 0x7D, 0x87, 0x9B, 0x16, 0x5F, 0x42, + 0x10, 0x1E, 0xE4, 0x4F, 0xBF, 0xB8, 0x9B, 0xA8, 0xBA, 0x74, 0x89, 0xB4, 0xB4, 0xB4, 0x36, 0x33, + 0xC3, 0x8E, 0x71, 0xE3, 0xC6, 0x31, 0x7C, 0xF8, 0x70, 0xC7, 0xA6, 0x7B, 0x80, 0x04, 0xFB, 0x48, + 0x12, 0x80, 0xFB, 0xEC, 0x67, 0x46, 0x8C, 0x18, 0xC1, 0x03, 0x0F, 0x3C, 0xD0, 0xA6, 0x1B, 0x1E, + 0x3D, 0x7A, 0x94, 0xD2, 0x92, 0x12, 0xE2, 0xBB, 0x46, 0x12, 0x19, 0x62, 0xBC, 0xB6, 0xB8, 0x52, + 0x14, 0xCA, 0x2B, 0x2E, 0xF1, 0xFE, 0xEA, 0x8D, 0x54, 0x99, 0x1A, 0xD4, 0xCB, 0xBE, 0x7D, 0xFB, + 0xB2, 0x72, 0xE5, 0x4A, 0x36, 0x6F, 0xDE, 0xCC, 0x13, 0x4F, 0x3C, 0xC1, 0x4F, 0x87, 0x32, 0xF9, + 0x2E, 0x25, 0x4D, 0xAE, 0x09, 0xCD, 0x41, 0x08, 0xBE, 0x58, 0xBF, 0x83, 0xCC, 0x9C, 0x86, 0x78, + 0x5C, 0xA3, 0xD1, 0xC8, 0xFC, 0xF9, 0xF3, 0x49, 0x49, 0x49, 0xE1, 0xBD, 0xF7, 0xDE, 0x45, 0xE8, + 0xDD, 0xF9, 0x60, 0xCD, 0x26, 0x2C, 0xB5, 0x4D, 0x47, 0xF2, 0xE8, 0xDD, 0xDD, 0xE4, 0x0C, 0x07, + 0xF6, 0xEC, 0xD9, 0xE3, 0x98, 0xB0, 0xD3, 0x26, 0xF8, 0xF9, 0xF9, 0x31, 0x79, 0xF2, 0x64, 0xC7, + 0x68, 0xFA, 0x58, 0x60, 0xBC, 0x9D, 0x21, 0xE3, 0xB1, 0xCD, 0x0E, 0x83, 0xC1, 0xC0, 0xB4, 0x69, + 0xD3, 0x9C, 0xDE, 0xF8, 0x35, 0x85, 0x43, 0x87, 0x0E, 0x01, 0x90, 0xD8, 0x3D, 0x06, 0x2F, 0x8F, + 0x66, 0xD4, 0x5D, 0x45, 0xE1, 0x6C, 0x5E, 0x11, 0xC7, 0xCE, 0x9C, 0x6F, 0xD4, 0xFC, 0xE4, 0x93, + 0x4F, 0x32, 0x7E, 0xFC, 0x78, 0x06, 0x0C, 0x18, 0xC0, 0x8B, 0x2F, 0xBE, 0x48, 0x74, 0xD7, 0x9B, + 0x48, 0xFD, 0xF9, 0x78, 0xD3, 0x76, 0x30, 0x07, 0x98, 0xCC, 0x35, 0xEC, 0x3D, 0x72, 0xAA, 0x51, + 0xDB, 0x98, 0x31, 0x63, 0x78, 0xFC, 0xF1, 0xC7, 0x89, 0x8B, 0x8B, 0xE3, 0xB1, 0xC7, 0x1E, 0x63, + 0xC2, 0x84, 0x09, 0xA4, 0x1F, 0x3B, 0x4D, 0x71, 0x59, 0xE5, 0x35, 0x66, 0x9D, 0x42, 0xBF, 0xB8, + 0x9B, 0x70, 0xD7, 0xEB, 0x38, 0x7E, 0xFC, 0x38, 0xE5, 0xE5, 0xE5, 0xCD, 0xDE, 0xDB, 0x59, 0x8C, + 0x1A, 0x35, 0x8A, 0xEE, 0xDD, 0xEB, 0x73, 0x7E, 0x74, 0xC0, 0x44, 0x15, 0xB9, 0x5B, 0xBC, 0xDB, + 0xDE, 0xDA, 0xB7, 0x6F, 0x5F, 0x46, 0x8F, 0x1E, 0xDD, 0xA6, 0x1B, 0x59, 0x2C, 0x16, 0x8E, 0x1E, + 0x3D, 0x2A, 0xFB, 0xEB, 0x11, 0xD3, 0xBC, 0x46, 0xA3, 0x80, 0xB9, 0xD6, 0x42, 0xAD, 0xA5, 0xF1, + 0xDB, 0x27, 0x1C, 0xB4, 0x32, 0x21, 0x04, 0x08, 0x41, 0xB5, 0xB9, 0x06, 0xAD, 0x39, 0x6D, 0x4D, + 0x01, 0xAB, 0x55, 0xC3, 0x5C, 0xD3, 0xF8, 0xCD, 0xB7, 0x58, 0x2C, 0xF5, 0x9A, 0x92, 0xA6, 0x69, + 0xD4, 0xD6, 0xD6, 0x52, 0x6B, 0xA9, 0xA3, 0xCE, 0x6A, 0x6D, 0xDA, 0xAA, 0x27, 0x34, 0x62, 0x23, + 0x43, 0x09, 0x35, 0xFA, 0x93, 0x9D, 0x9D, 0x4D, 0x4A, 0x4A, 0x0A, 0x15, 0x15, 0x15, 0x8D, 0xC6, + 0xD6, 0x52, 0x54, 0x57, 0x57, 0x93, 0x9E, 0x9E, 0xCE, 0xFB, 0xEF, 0xBF, 0x7F, 0x79, 0xE0, 0x5D, + 0x92, 0x1E, 0x48, 0x44, 0x66, 0xCA, 0x02, 0x70, 0xF7, 0xDD, 0x77, 0x13, 0x1C, 0xDC, 0x22, 0x9F, + 0xCA, 0x15, 0xA8, 0xA8, 0xA8, 0xE0, 0xCC, 0x99, 0x33, 0x78, 0xB8, 0xEB, 0xE9, 0x19, 0x13, 0x4E, + 0xB3, 0x1B, 0x10, 0x21, 0x08, 0x0F, 0x0A, 0x20, 0xD4, 0xE8, 0x47, 0x45, 0x55, 0x83, 0x75, 0x7A, + 0xD1, 0xA2, 0x45, 0x44, 0x44, 0x44, 0x10, 0x15, 0x15, 0xC5, 0x87, 0x1F, 0x7E, 0xC8, 0xE9, 0xAC, + 0xD3, 0x3C, 0x3C, 0xA2, 0x9F, 0xB4, 0xCC, 0x5E, 0x6B, 0x61, 0x17, 0xE0, 0xE5, 0x61, 0xA0, 0x47, + 0x74, 0x38, 0xBB, 0x0E, 0x36, 0x58, 0x5C, 0x37, 0x6E, 0xDC, 0xC8, 0xDC, 0xB9, 0x73, 0x19, 0x33, + 0x66, 0x0C, 0x3B, 0x76, 0xEC, 0xE0, 0xBB, 0xEF, 0xD6, 0x31, 0xA0, 0x47, 0x24, 0x81, 0xBE, 0xDE, + 0x4D, 0x0F, 0x51, 0x40, 0xA8, 0xD1, 0x9F, 0xAE, 0x11, 0x21, 0xA4, 0x1E, 0x38, 0xC1, 0x6F, 0x7F, + 0xFB, 0x5B, 0x12, 0x12, 0x12, 0x18, 0x32, 0x64, 0x08, 0x83, 0x07, 0x0F, 0xA6, 0x7B, 0xF7, 0xEE, + 0x44, 0x45, 0x45, 0x11, 0x18, 0x18, 0x88, 0xC1, 0x60, 0x40, 0xA7, 0xD3, 0xD5, 0x6F, 0x9E, 0x35, + 0x4D, 0xC3, 0x62, 0xB1, 0x50, 0x5D, 0x5D, 0x4D, 0x71, 0x71, 0x31, 0xA7, 0x4F, 0x9F, 0x26, 0x2D, + 0x2D, 0x8D, 0x94, 0x94, 0x14, 0x32, 0x32, 0x32, 0x28, 0x2E, 0xBE, 0xC2, 0xE8, 0x9B, 0xAB, 0x47, + 0xAA, 0xB9, 0x46, 0x00, 0x6F, 0x6F, 0x6F, 0x46, 0x8C, 0x18, 0xD1, 0x26, 0x66, 0x00, 0x14, 0x14, + 0x14, 0x90, 0x97, 0x9F, 0x4F, 0x90, 0xBF, 0x2F, 0x51, 0xA1, 0xC6, 0xE6, 0x37, 0x84, 0x9A, 0xA0, + 0x4B, 0x58, 0x10, 0xE3, 0x6E, 0x1F, 0xC8, 0x3F, 0x97, 0xAF, 0xAF, 0x6F, 0x3E, 0x7C, 0xF8, 0x30, + 0x0F, 0x3F, 0xFC, 0x30, 0xEE, 0xEE, 0xEE, 0x94, 0x57, 0x54, 0x10, 0x66, 0xF4, 0x63, 0xC2, 0xF0, + 0x41, 0x4E, 0x8D, 0x41, 0x75, 0xD3, 0x31, 0x69, 0xF4, 0xAD, 0xAC, 0xD9, 0xBA, 0x87, 0x4B, 0x36, + 0xBF, 0x4A, 0x65, 0x65, 0x25, 0xAF, 0xBD, 0xF6, 0x1A, 0x73, 0xE6, 0xCC, 0xA1, 0xBA, 0xBA, 0x1A, + 0x10, 0x3C, 0x74, 0xC7, 0x6D, 0xF8, 0xF8, 0x78, 0x35, 0xCD, 0x60, 0x21, 0xF0, 0xF1, 0xF2, 0x20, + 0xBE, 0x6B, 0x24, 0xA9, 0x07, 0x4E, 0x50, 0x5E, 0x5E, 0xCE, 0x9E, 0x3D, 0x7B, 0xD8, 0xB3, 0x67, + 0x0F, 0x3A, 0x9D, 0x0E, 0x1F, 0x1F, 0x1F, 0x42, 0x42, 0x42, 0x88, 0x88, 0x88, 0x20, 0x28, 0x28, + 0x08, 0x5F, 0x5F, 0x5F, 0x0C, 0x06, 0x03, 0x9A, 0xA6, 0x51, 0x5D, 0x5D, 0x4D, 0x59, 0x59, 0x19, + 0x85, 0x85, 0x85, 0x14, 0x14, 0x14, 0x50, 0x52, 0x52, 0xD2, 0x94, 0x09, 0x46, 0x43, 0x66, 0xF6, + 0xBE, 0xAA, 0x47, 0x3A, 0xE8, 0x55, 0x80, 0x2E, 0x5D, 0xBA, 0x90, 0x90, 0x90, 0xD0, 0x6A, 0x46, + 0x98, 0xCD, 0x66, 0x32, 0x32, 0x32, 0x58, 0xB8, 0x70, 0x21, 0x45, 0x85, 0x45, 0x0C, 0x4C, 0x88, + 0x25, 0xC8, 0xDF, 0xD7, 0xA9, 0x0D, 0xA1, 0xAA, 0x53, 0x99, 0xF9, 0xC8, 0x3D, 0x1C, 0x3C, 0x79, + 0x96, 0x6D, 0xE9, 0x47, 0xEA, 0xDB, 0x4D, 0x26, 0x13, 0x26, 0x93, 0x09, 0x1F, 0x4F, 0x0F, 0x66, + 0x3F, 0x76, 0x1F, 0x37, 0xF7, 0xEE, 0xEE, 0x9C, 0xDA, 0x6B, 0xD5, 0xB8, 0xEB, 0xB6, 0xFE, 0x3C, + 0x9D, 0x7C, 0x37, 0xF3, 0x3E, 0x5F, 0x47, 0x8D, 0x6D, 0xE1, 0xB6, 0x5A, 0xAD, 0x54, 0x56, 0x56, + 0xA2, 0x53, 0x55, 0x7E, 0x33, 0x6E, 0x38, 0x53, 0xC6, 0x0D, 0x6B, 0x76, 0x7C, 0x8A, 0x4E, 0x27, + 0x35, 0xC5, 0xCB, 0x6F, 0x61, 0xB5, 0x52, 0x5E, 0x5E, 0x4E, 0x79, 0x79, 0x39, 0xA7, 0x4E, 0x9D, + 0xA2, 0x15, 0xA8, 0x46, 0x46, 0x79, 0xAE, 0x04, 0xD6, 0x00, 0xE7, 0xF5, 0xC8, 0x48, 0x09, 0x40, + 0x9A, 0x8C, 0x5B, 0x2A, 0xAE, 0xEA, 0xEA, 0xEA, 0x38, 0x7F, 0xFE, 0x3C, 0x5B, 0xB7, 0x6E, 0x65, + 0xCD, 0x9A, 0x35, 0xEC, 0xDA, 0xB5, 0xAB, 0x5E, 0x2E, 0x46, 0x04, 0x07, 0xE0, 0xED, 0x61, 0x70, + 0x6E, 0x87, 0xAE, 0x09, 0x6E, 0x8A, 0x0A, 0xE5, 0xE3, 0x3F, 0x3D, 0xC9, 0x3F, 0x97, 0xAF, 0x67, + 0xDD, 0xCE, 0x74, 0x8A, 0x4A, 0x2B, 0x70, 0x73, 0xD3, 0xD3, 0x3B, 0xB6, 0x0B, 0xBF, 0x7B, 0x70, + 0x0C, 0xF7, 0x8F, 0xBA, 0x15, 0x55, 0x55, 0x9C, 0x36, 0xC1, 0xB8, 0xBB, 0xB9, 0xF1, 0xF2, 0xE3, + 0x0F, 0xD2, 0xA3, 0x4B, 0x38, 0x1F, 0x7D, 0xB7, 0x8D, 0x53, 0xE7, 0xF2, 0xD1, 0x34, 0x8D, 0xE8, + 0xB0, 0x20, 0x92, 0xEF, 0x1C, 0xCA, 0xB4, 0x89, 0xA3, 0xF1, 0x6F, 0xCE, 0x37, 0x63, 0x43, 0xD7, + 0x88, 0x10, 0x74, 0x3A, 0x15, 0xAB, 0x54, 0x28, 0x34, 0xA4, 0x93, 0xC9, 0x1B, 0x59, 0xC0, 0xC6, + 0x59, 0x33, 0x42, 0x1D, 0x32, 0x0E, 0xE1, 0x14, 0x32, 0x38, 0xE4, 0x47, 0x64, 0xD8, 0x54, 0x99, + 0xFD, 0x1F, 0xF4, 0x38, 0xD8, 0xE5, 0x2D, 0x16, 0x0B, 0x07, 0x0F, 0x1E, 0x24, 0x2A, 0x2A, 0x0A, + 0x3F, 0x3F, 0x3F, 0x0C, 0x06, 0x03, 0xAA, 0xCD, 0x17, 0xA1, 0x69, 0x1A, 0x75, 0x75, 0x75, 0x98, + 0x4C, 0x26, 0x4A, 0x4B, 0x4B, 0xC9, 0xCE, 0xCE, 0xE6, 0xC0, 0x81, 0x03, 0xEC, 0xDE, 0xBD, 0x9B, + 0x7D, 0xFB, 0xF6, 0x71, 0xEE, 0xDC, 0xB9, 0x2B, 0xEA, 0x94, 0x44, 0x86, 0x04, 0xE2, 0xEE, 0xD6, + 0x82, 0x68, 0x7D, 0x4D, 0xD0, 0x35, 0x32, 0x84, 0xB7, 0x9E, 0x99, 0xC2, 0xAC, 0xC9, 0xE3, 0x29, + 0xBC, 0x58, 0x8E, 0xC1, 0xDD, 0x8D, 0xE8, 0xB0, 0x20, 0x7C, 0x7D, 0xBC, 0x6D, 0x8E, 0x29, 0xE7, + 0xBB, 0x43, 0x08, 0x3C, 0x0D, 0x6E, 0x4C, 0xBD, 0x6F, 0x34, 0x93, 0x46, 0x0F, 0x21, 0xBF, 0xF8, + 0x22, 0x56, 0x4D, 0x10, 0x16, 0xE4, 0x4F, 0xA0, 0xBF, 0xAF, 0xA4, 0xA2, 0x53, 0x8B, 0xB3, 0x5C, + 0xE3, 0x3C, 0xDD, 0xDD, 0xB9, 0x24, 0xD5, 0xF2, 0x3A, 0xE0, 0x0F, 0xC8, 0x52, 0x4E, 0x7D, 0x80, + 0x18, 0x64, 0x5C, 0x5A, 0x28, 0x32, 0x11, 0x54, 0x8F, 0xD4, 0x9A, 0xAA, 0x6D, 0xC4, 0x2E, 0x45, + 0xC6, 0x6F, 0x1D, 0x47, 0x56, 0x27, 0x3A, 0x8B, 0x2C, 0x6C, 0x73, 0xC5, 0xCD, 0xF5, 0x38, 0x64, + 0x92, 0x6E, 0xDC, 0xB8, 0x91, 0x3D, 0x7B, 0xF6, 0x10, 0x1A, 0x1A, 0x4A, 0x68, 0x68, 0x28, 0x46, + 0xA3, 0x11, 0x2F, 0x2F, 0x2F, 0x54, 0x55, 0xA5, 0xB6, 0xB6, 0x96, 0xCA, 0xCA, 0x4A, 0x8A, 0x8B, + 0x8B, 0x29, 0x2C, 0x2C, 0xA4, 0xA4, 0xA4, 0x04, 0x93, 0xC9, 0x74, 0x4D, 0x6D, 0x23, 0x24, 0xD0, + 0x5F, 0x6A, 0x58, 0x2D, 0x31, 0x77, 0x68, 0x02, 0x9D, 0xA2, 0x10, 0x15, 0x16, 0x44, 0x54, 0x78, + 0x70, 0x3D, 0x61, 0x5B, 0x6D, 0xB6, 0x17, 0x80, 0xD0, 0xF0, 0xF3, 0xF1, 0xC2, 0xCF, 0xD7, 0xBB, + 0xA1, 0xBF, 0x96, 0x68, 0x49, 0x02, 0x42, 0x02, 0xFD, 0xF0, 0xF5, 0xF6, 0xB0, 0x33, 0xC4, 0x1D, + 0x39, 0x4B, 0x76, 0xD8, 0x7E, 0x20, 0x67, 0x89, 0x3B, 0x52, 0xFC, 0xEB, 0x6C, 0xC7, 0x16, 0x1B, + 0xF3, 0x9C, 0xAE, 0x6C, 0xA7, 0x07, 0x7E, 0x02, 0x46, 0x83, 0xD4, 0x0A, 0xCA, 0xCA, 0xCA, 0x28, + 0x2B, 0x2B, 0xE3, 0xE4, 0xC9, 0x93, 0x2D, 0x7D, 0xF4, 0x3A, 0xE0, 0x02, 0xD2, 0xCB, 0xE8, 0x09, + 0x10, 0xE4, 0xEF, 0xD3, 0x7A, 0xA3, 0x60, 0x4B, 0x89, 0xE6, 0xCA, 0xFE, 0x84, 0x20, 0xD0, 0xD7, + 0x9B, 0x40, 0x3F, 0x1F, 0xF2, 0x8A, 0xCB, 0xEC, 0xAD, 0x51, 0x97, 0xFF, 0x17, 0xD2, 0x6F, 0xDE, + 0x26, 0xE8, 0x91, 0x36, 0xF9, 0x67, 0x80, 0xE1, 0xC8, 0xCD, 0xA1, 0x0F, 0xCE, 0xC9, 0xC4, 0x3A, + 0xE4, 0xB4, 0xCB, 0x46, 0xCA, 0xC1, 0x6D, 0xC0, 0x79, 0x64, 0x15, 0xB7, 0xAE, 0x00, 0x7E, 0xDE, + 0xED, 0x9A, 0xED, 0xD5, 0x89, 0x10, 0x78, 0x7B, 0x7A, 0x60, 0xF4, 0xF3, 0x71, 0x6C, 0x0C, 0x72, + 0xC5, 0x9D, 0xF4, 0x48, 0xB9, 0xF6, 0x7B, 0x64, 0x40, 0x57, 0x37, 0xE4, 0xBE, 0xA4, 0x2B, 0xD2, + 0x14, 0x1F, 0x8C, 0x9C, 0x86, 0x3A, 0xA4, 0x65, 0xB0, 0x0C, 0x29, 0x0F, 0xCF, 0x03, 0x27, 0x69, + 0x90, 0x87, 0x17, 0x91, 0x6F, 0x48, 0x4F, 0x1C, 0xEA, 0x61, 0x79, 0x7A, 0x18, 0x3A, 0xAF, 0x88, + 0x60, 0x7B, 0x42, 0x80, 0x9B, 0x5E, 0x87, 0xBF, 0x4F, 0x23, 0x43, 0x6B, 0xDB, 0x4C, 0x19, 0x4D, + 0xC0, 0xBE, 0xE2, 0xD6, 0x21, 0x6B, 0x1E, 0xE6, 0x03, 0x76, 0x4F, 0x8C, 0x62, 0x3B, 0xEF, 0xB8, + 0xCD, 0xAE, 0xE3, 0xDA, 0x26, 0x5B, 0x9D, 0xFD, 0xFF, 0x55, 0x45, 0xC1, 0x5D, 0xAF, 0xBB, 0xB1, + 0x9C, 0x52, 0xD7, 0x22, 0x94, 0x5E, 0x87, 0x6F, 0xE3, 0x19, 0xEF, 0x47, 0xC3, 0x8B, 0xDA, 0x7E, + 0xF7, 0xB9, 0xC6, 0x39, 0xC1, 0x2F, 0xB4, 0xD6, 0x60, 0x6B, 0xA0, 0x2A, 0x0A, 0x9E, 0x86, 0x46, + 0xB1, 0x67, 0x9E, 0xB8, 0x80, 0x21, 0xED, 0x9D, 0x63, 0x58, 0x3F, 0x1F, 0x84, 0x10, 0xD2, 0x3B, + 0xF7, 0x4B, 0x10, 0x59, 0x00, 0x8A, 0x82, 0xA1, 0xB1, 0x0A, 0x6F, 0xD7, 0xA4, 0xDA, 0x15, 0xED, + 0xCD, 0x90, 0x1A, 0xA0, 0x16, 0x40, 0x13, 0x82, 0x6A, 0x73, 0xED, 0x2F, 0x46, 0x64, 0x01, 0x97, + 0x07, 0x78, 0xDC, 0x30, 0x0C, 0x31, 0xD9, 0x0F, 0x2A, 0xAA, 0x4C, 0x6D, 0xE8, 0xEA, 0x3A, 0x83, + 0x10, 0xD2, 0x2A, 0xDC, 0x00, 0x0D, 0x17, 0xBC, 0x6E, 0xED, 0xCD, 0x10, 0x13, 0xB2, 0xCE, 0x09, + 0x00, 0x45, 0xA5, 0xE5, 0xAE, 0x8F, 0x32, 0xEC, 0x20, 0x08, 0x21, 0x30, 0x35, 0x36, 0xE7, 0x9B, + 0x70, 0x41, 0x35, 0x39, 0x57, 0x30, 0xA4, 0xBE, 0x70, 0xC0, 0x85, 0xE2, 0x8B, 0x88, 0x1B, 0x21, + 0x30, 0xCE, 0x09, 0x58, 0x35, 0x8D, 0x4B, 0xD5, 0x8D, 0x66, 0xFC, 0x0D, 0xC1, 0x90, 0x1A, 0x1C, + 0x82, 0x88, 0xCF, 0xE6, 0x15, 0x61, 0x32, 0xB7, 0x79, 0xF3, 0xDA, 0xF9, 0x50, 0xA0, 0xA6, 0xB6, + 0x8E, 0x92, 0xF2, 0x4B, 0x8E, 0xAD, 0xC5, 0xDC, 0x00, 0x22, 0x0B, 0xE4, 0x66, 0x11, 0x80, 0x9C, + 0xFC, 0x62, 0xF9, 0x10, 0x6D, 0x89, 0xA9, 0xBA, 0x2E, 0xA0, 0x70, 0xC9, 0x64, 0x96, 0xAE, 0xDE, + 0x06, 0xB4, 0x7B, 0xF1, 0x32, 0x70, 0x5D, 0x69, 0x8D, 0x5A, 0x80, 0xFC, 0x92, 0x32, 0x4E, 0x9D, + 0xCB, 0x77, 0x2E, 0x28, 0xE1, 0x7A, 0x86, 0xA2, 0x50, 0x50, 0x5A, 0x4E, 0x51, 0x43, 0x34, 0x8C, + 0x40, 0x5A, 0x2B, 0xDA, 0x1D, 0xAE, 0x60, 0xC8, 0x49, 0x64, 0x26, 0x2A, 0x55, 0xA6, 0x2B, 0x03, + 0x0D, 0x6E, 0x48, 0x28, 0x0A, 0xA7, 0xCE, 0xE5, 0x53, 0x7E, 0xA9, 0xDE, 0xBD, 0x5C, 0x89, 0xF4, + 0x69, 0xB4, 0x3B, 0x5C, 0xC1, 0x90, 0x73, 0xC8, 0xCF, 0x4E, 0x00, 0xB0, 0x65, 0xDF, 0x61, 0xAA, + 0xAB, 0xCD, 0x9D, 0xBF, 0x41, 0x54, 0x14, 0x19, 0x92, 0xDA, 0x9A, 0x28, 0x4C, 0x21, 0xD8, 0x77, + 0xE4, 0x14, 0x96, 0xBA, 0xFA, 0x35, 0x3C, 0x1F, 0x69, 0xC3, 0x6B, 0x77, 0xB8, 0x82, 0x21, 0x26, + 0xE4, 0x57, 0x6E, 0x00, 0x48, 0x3F, 0x96, 0xC5, 0xE1, 0x53, 0x39, 0xAD, 0x23, 0x84, 0x1D, 0x8A, + 0xD2, 0x40, 0xD0, 0x96, 0xAE, 0x47, 0x0A, 0xA0, 0xD3, 0x51, 0x71, 0xA9, 0x9A, 0x9D, 0xE9, 0x47, + 0x39, 0x9E, 0xD5, 0xC2, 0x4F, 0x82, 0x28, 0x0A, 0xE5, 0x95, 0x97, 0xD8, 0x91, 0x71, 0xDC, 0xB1, + 0xF5, 0x20, 0x36, 0x29, 0xD0, 0xDE, 0x70, 0xD5, 0x67, 0x18, 0x36, 0xDB, 0x06, 0x1C, 0x52, 0x52, + 0x5E, 0xC9, 0xAA, 0x4D, 0xBB, 0x19, 0xDC, 0xA7, 0xF5, 0x51, 0x90, 0xCB, 0x37, 0xEC, 0x64, 0xF7, + 0xA1, 0x4C, 0x46, 0xDF, 0xD2, 0x87, 0x61, 0x03, 0x7B, 0x39, 0x9F, 0xE8, 0xA9, 0x28, 0x54, 0x9B, + 0x6B, 0xF8, 0xF1, 0xA7, 0x03, 0x2C, 0x59, 0xB3, 0x91, 0xED, 0xFB, 0x8F, 0xD2, 0x3B, 0x36, 0x9A, + 0xB5, 0xF3, 0x9E, 0x27, 0x2A, 0x2C, 0xC8, 0xB9, 0x3D, 0x92, 0xAA, 0xB0, 0xF7, 0xC8, 0x69, 0x0E, + 0x64, 0x66, 0xDB, 0x5B, 0x84, 0xED, 0xF9, 0x5C, 0x62, 0xE7, 0x73, 0x55, 0x8D, 0x8E, 0x12, 0x64, + 0xAC, 0x70, 0x1F, 0x80, 0x0B, 0xC5, 0xA5, 0x8C, 0x1D, 0xD2, 0x8F, 0x90, 0xA0, 0x80, 0x96, 0x6D, + 0x14, 0x6D, 0x8B, 0xE9, 0xF4, 0xD7, 0xDF, 0xE7, 0xDB, 0x94, 0x34, 0xD6, 0x6E, 0xDF, 0xC7, 0xB6, + 0xB4, 0x23, 0x18, 0xFD, 0x7C, 0xE8, 0xD9, 0x35, 0xB2, 0xE9, 0x98, 0x5C, 0xDB, 0xB5, 0x85, 0x17, + 0xCB, 0xF9, 0xDF, 0x7F, 0x7C, 0xC6, 0x6B, 0xEF, 0x7F, 0xC5, 0xB1, 0xEC, 0x5C, 0x2C, 0x75, 0x56, + 0xAA, 0xCC, 0x35, 0xDC, 0x3F, 0x62, 0x30, 0x51, 0xE1, 0xCE, 0x31, 0xA4, 0xCE, 0x6A, 0xE5, 0x8D, + 0x65, 0xFF, 0x62, 0xEF, 0xE1, 0xFA, 0x25, 0xE3, 0x3C, 0x32, 0x13, 0xB9, 0xB8, 0xD9, 0x8B, 0x5B, + 0x01, 0x57, 0xD5, 0xDF, 0xAB, 0x45, 0x3A, 0xAA, 0xAA, 0x01, 0xB2, 0x2F, 0x14, 0xB1, 0x74, 0xED, + 0x16, 0xB4, 0x56, 0x84, 0x61, 0x6A, 0x9A, 0x46, 0x8D, 0x45, 0x7A, 0x40, 0xCD, 0x35, 0xB5, 0xA4, + 0x1E, 0x38, 0xC1, 0xB4, 0x3F, 0x2D, 0xE6, 0x93, 0xEF, 0xB6, 0x35, 0xBD, 0x2E, 0xD9, 0x66, 0xC6, + 0x4B, 0x0B, 0x97, 0xB3, 0x74, 0xED, 0x16, 0xCC, 0x0E, 0xA1, 0xA2, 0x31, 0xE1, 0xC1, 0x44, 0x85, + 0x19, 0x9B, 0x8F, 0xC4, 0x07, 0xD0, 0xA9, 0xEC, 0x3B, 0x72, 0x8A, 0x75, 0x3B, 0xD2, 0x1D, 0x5B, + 0xBF, 0x47, 0xFA, 0xD2, 0x5D, 0x02, 0x57, 0x16, 0x44, 0xDC, 0x82, 0x8C, 0xAA, 0x00, 0xE0, 0xCB, + 0xEF, 0x77, 0xB0, 0xEB, 0xE0, 0x49, 0xB9, 0x0E, 0x38, 0x0B, 0x21, 0x08, 0x33, 0x06, 0x70, 0xD7, + 0x6D, 0xFD, 0xEB, 0x9B, 0xBC, 0x3D, 0x0D, 0x18, 0xDC, 0xDD, 0x78, 0xE5, 0xDD, 0x15, 0xEC, 0xFC, + 0xF9, 0xC4, 0xD5, 0xD7, 0x26, 0x45, 0x61, 0xD5, 0xC6, 0x9F, 0xF8, 0xF4, 0xDF, 0xDB, 0x19, 0x79, + 0x73, 0x62, 0xFD, 0xF5, 0xC1, 0x01, 0xBE, 0x3C, 0x3F, 0xE5, 0x5E, 0x19, 0x6B, 0xEC, 0x44, 0xF4, + 0xA3, 0xD9, 0x5C, 0xC3, 0xA2, 0xAF, 0x7E, 0xA0, 0xE8, 0x62, 0x85, 0xBD, 0xB5, 0x14, 0x17, 0x7F, + 0xD8, 0xC5, 0x95, 0x65, 0x85, 0x2C, 0x48, 0xD1, 0x75, 0x2F, 0xE0, 0x51, 0x65, 0xAA, 0xA1, 0xE8, + 0x62, 0x05, 0xF7, 0x0C, 0x1D, 0x88, 0x87, 0xC1, 0xF9, 0xA2, 0x39, 0x8A, 0xAA, 0x92, 0xD4, 0xB3, + 0x2B, 0x25, 0x65, 0x95, 0x14, 0x94, 0x94, 0x73, 0xEF, 0xF0, 0x9B, 0x99, 0xFD, 0xD8, 0x44, 0xBE, + 0x4D, 0x49, 0x27, 0x33, 0x27, 0x8F, 0x7B, 0x87, 0x0D, 0xC2, 0xE0, 0xD8, 0x9F, 0xA2, 0x90, 0x5B, + 0x58, 0xC2, 0xEF, 0xDF, 0x5A, 0x86, 0x5E, 0xA7, 0x63, 0xD9, 0x1F, 0x9F, 0xE0, 0x81, 0x91, 0xB7, + 0x12, 0xDF, 0x35, 0x82, 0x19, 0x0F, 0x8F, 0x63, 0xDC, 0xED, 0x03, 0x9D, 0xDB, 0x16, 0xE9, 0x54, + 0x56, 0x6F, 0xDA, 0xCD, 0x9C, 0x8F, 0xBF, 0x71, 0xD4, 0xAE, 0xBE, 0x44, 0x7E, 0x15, 0xC1, 0x65, + 0xF6, 0x20, 0x57, 0xD7, 0x79, 0x3A, 0x87, 0x0C, 0x33, 0x1A, 0x0C, 0x70, 0xE6, 0x42, 0x21, 0x46, + 0x3F, 0x6F, 0x7E, 0x95, 0x14, 0xD7, 0x22, 0x2D, 0xD8, 0xD7, 0xDB, 0x8B, 0x3B, 0x6F, 0xEB, 0xCF, + 0x83, 0xA3, 0x87, 0x30, 0x69, 0xF4, 0x10, 0x92, 0xE2, 0x63, 0x11, 0x42, 0xE3, 0x93, 0x75, 0xDB, + 0xE9, 0xD3, 0x3D, 0x9A, 0xC4, 0x9E, 0x31, 0x0D, 0x6F, 0xBC, 0x4E, 0xE5, 0x8B, 0x7F, 0xA7, 0xF0, + 0xD9, 0xFA, 0x14, 0x5E, 0xFD, 0xAF, 0x87, 0xB8, 0x7F, 0xD4, 0xAD, 0x04, 0xFA, 0x7B, 0x73, 0x4B, + 0xDF, 0x38, 0x62, 0x22, 0x42, 0x9C, 0x13, 0x09, 0xAA, 0xCA, 0x89, 0xEC, 0x5C, 0x9E, 0x7A, 0x6B, + 0x19, 0xB9, 0x85, 0xF5, 0xB1, 0xB7, 0x39, 0xC0, 0xB3, 0x34, 0x91, 0x5F, 0xDE, 0x5E, 0x70, 0x35, + 0x43, 0x34, 0xE4, 0x46, 0x71, 0x14, 0x10, 0xAA, 0x69, 0x82, 0x03, 0x27, 0xCF, 0xD2, 0x3F, 0x3E, + 0x96, 0xEE, 0x31, 0x11, 0x2D, 0x5A, 0xE0, 0xDD, 0x74, 0x3A, 0x8C, 0x81, 0x7E, 0x78, 0xB8, 0xCB, + 0x0C, 0xE0, 0xB8, 0xAE, 0x91, 0x6C, 0xDE, 0x7B, 0x88, 0xFC, 0x92, 0x8B, 0xDC, 0x3F, 0xE2, 0x96, + 0xFA, 0x05, 0xBE, 0xB6, 0xD6, 0xC2, 0x5F, 0x96, 0x7E, 0x8D, 0x97, 0x87, 0x81, 0x37, 0x9F, 0xFE, + 0x0D, 0x3E, 0x9E, 0x86, 0x86, 0x88, 0x13, 0x67, 0xEE, 0xA7, 0x28, 0x94, 0x55, 0x56, 0xF1, 0xEC, + 0xDF, 0x3F, 0x61, 0x6B, 0x5A, 0x7D, 0x04, 0xA5, 0x15, 0xF9, 0x71, 0x81, 0xD5, 0x2E, 0xA6, 0x57, + 0x87, 0xD4, 0x2E, 0x3F, 0x8D, 0xAC, 0x04, 0x51, 0x09, 0x50, 0x50, 0x2A, 0x35, 0x9F, 0xA3, 0xA7, + 0x72, 0x5A, 0xB6, 0x9E, 0x40, 0x43, 0x05, 0x07, 0x21, 0x08, 0x31, 0xFA, 0xF3, 0xDB, 0x09, 0x23, + 0x38, 0x73, 0xA1, 0x88, 0xCA, 0x2A, 0x53, 0xFD, 0x5E, 0xA5, 0xFC, 0x52, 0x35, 0x39, 0xF9, 0xC5, + 0xFC, 0xE7, 0xD8, 0xDB, 0x08, 0x0B, 0x0E, 0x68, 0xB1, 0x56, 0x67, 0xAE, 0xAD, 0xE5, 0xAF, 0x4B, + 0x57, 0xB3, 0x7A, 0xF3, 0x1E, 0xC7, 0x33, 0xDF, 0x21, 0x4B, 0x2E, 0xB9, 0x1C, 0x1D, 0x55, 0xE5, + 0x78, 0x35, 0xF0, 0x1E, 0x36, 0xEB, 0xE8, 0xCF, 0x27, 0xB2, 0x99, 0x31, 0xF7, 0x23, 0x72, 0x72, + 0x0B, 0x5B, 0xBF, 0x61, 0x14, 0x82, 0x31, 0x43, 0xFA, 0xD1, 0x2D, 0x2A, 0x94, 0x3A, 0x87, 0x7C, + 0x91, 0x3A, 0xAB, 0x95, 0x40, 0x3F, 0x1F, 0xC6, 0xDE, 0x9A, 0xD4, 0x32, 0x5B, 0xAC, 0xA2, 0x60, + 0xAE, 0xB5, 0x30, 0xE7, 0xA3, 0xB5, 0x2C, 0xFC, 0x6A, 0x83, 0x74, 0x3F, 0x4B, 0x1C, 0x01, 0x5E, + 0xC1, 0x21, 0xDC, 0xD3, 0x95, 0xE8, 0xA8, 0x5A, 0x81, 0x1A, 0x90, 0x81, 0x0C, 0x13, 0xEA, 0x05, + 0x90, 0x95, 0x5B, 0xC8, 0xC9, 0xB3, 0x17, 0xB8, 0xBD, 0x7F, 0x82, 0x73, 0xE5, 0x36, 0x2E, 0x87, + 0x00, 0x7F, 0x1F, 0x4F, 0x06, 0x27, 0xF6, 0x20, 0xD4, 0xE8, 0x57, 0x2F, 0xB2, 0xF4, 0x3A, 0x1D, + 0x91, 0x21, 0x46, 0x6E, 0xE9, 0xDD, 0x1D, 0x37, 0x9D, 0x93, 0x8F, 0xA7, 0xAA, 0x54, 0x56, 0x9B, + 0xF9, 0xDB, 0xD2, 0xD5, 0xCC, 0xFD, 0xFC, 0xBB, 0xFA, 0xC0, 0x6C, 0x64, 0xE0, 0xDF, 0x13, 0xC8, + 0x60, 0xC2, 0x0E, 0x41, 0x47, 0x16, 0x6F, 0xAC, 0x46, 0x7E, 0x65, 0x73, 0x10, 0x32, 0x16, 0x96, + 0xCC, 0x73, 0xF9, 0x1C, 0x3A, 0x95, 0xC3, 0xA0, 0x84, 0x6E, 0x84, 0xB6, 0x54, 0xBC, 0x20, 0x23, + 0x41, 0x02, 0xFC, 0x7D, 0x1A, 0x6D, 0x10, 0xDD, 0xF4, 0x3A, 0xE2, 0x6E, 0x8A, 0x72, 0x9E, 0x19, + 0x3A, 0x95, 0xF3, 0xF9, 0xC5, 0xBC, 0xF0, 0xCF, 0xCF, 0x79, 0x77, 0xF5, 0x8F, 0xD4, 0x5A, 0xEA, + 0xA3, 0x3E, 0x8B, 0x90, 0x45, 0x62, 0xBE, 0xE9, 0x40, 0x1A, 0x75, 0x78, 0x35, 0xCD, 0x8B, 0x48, + 0xA6, 0x0C, 0xC4, 0x96, 0x42, 0x77, 0x26, 0xB7, 0x90, 0x9D, 0x3F, 0x1F, 0x27, 0x36, 0x3C, 0x84, + 0xD8, 0xE8, 0xF0, 0x6B, 0xEF, 0xBE, 0xAF, 0x86, 0xAB, 0xF1, 0xD0, 0x49, 0x93, 0x88, 0x26, 0x20, + 0x25, 0xED, 0x08, 0x4F, 0xCE, 0x59, 0xCA, 0xB7, 0xDB, 0xD3, 0xB0, 0x36, 0x6C, 0x16, 0x0B, 0x90, + 0xCC, 0x58, 0xD1, 0xC1, 0xF4, 0xE9, 0x94, 0xF2, 0xA6, 0x85, 0xC8, 0x4F, 0x6B, 0xF7, 0xC5, 0x16, + 0x72, 0x5A, 0x50, 0x5A, 0xCE, 0x86, 0x9F, 0x7E, 0xA6, 0xA6, 0xA6, 0x96, 0x5E, 0x37, 0x45, 0xC9, + 0x04, 0x1A, 0x57, 0xC1, 0x66, 0xA4, 0xCC, 0x2D, 0x28, 0xE1, 0xEF, 0x9F, 0x7F, 0xC7, 0xEC, 0x05, + 0x5F, 0x34, 0xCA, 0xD2, 0x45, 0x2A, 0x21, 0x4F, 0x22, 0xF3, 0x35, 0x3A, 0x3C, 0x20, 0xA0, 0xB3, + 0xEA, 0xCD, 0x16, 0x21, 0x2D, 0xC2, 0x5D, 0x90, 0x5F, 0x8D, 0x56, 0x4D, 0xE6, 0x5A, 0x76, 0x64, + 0x1C, 0x27, 0xF5, 0xE7, 0xE3, 0xF8, 0x79, 0x79, 0x10, 0x13, 0x1E, 0x8C, 0xA1, 0xB9, 0x64, 0xD1, + 0x96, 0x40, 0x95, 0x96, 0xE2, 0xC2, 0xD2, 0x32, 0xBE, 0xF8, 0xF7, 0x0E, 0x9E, 0x7D, 0xE7, 0x13, + 0x56, 0x6D, 0xFC, 0xC9, 0x1E, 0xCD, 0x0E, 0x92, 0xF8, 0xDB, 0x91, 0xC5, 0x13, 0x5A, 0x57, 0xFE, + 0xA7, 0x1D, 0xD0, 0xD9, 0x5E, 0x8A, 0x40, 0xA4, 0x68, 0xF8, 0x3D, 0x0E, 0xDF, 0x3E, 0xF7, 0x34, + 0xB8, 0x33, 0x6C, 0x40, 0x2F, 0xA6, 0x8C, 0x1B, 0xCE, 0xE8, 0xC1, 0x7D, 0x09, 0x0F, 0x09, 0x40, + 0x51, 0x75, 0x36, 0x95, 0xD7, 0xC9, 0x1C, 0x11, 0x45, 0xB1, 0x79, 0x2A, 0x15, 0x6A, 0x6B, 0x6A, + 0x38, 0x95, 0x93, 0xCF, 0xBA, 0x9D, 0xE9, 0x7C, 0xB5, 0xF1, 0x27, 0x0E, 0x9C, 0x3C, 0x7B, 0x79, + 0x48, 0x4F, 0x39, 0xF0, 0x21, 0xF2, 0x23, 0x98, 0x2E, 0x71, 0xCD, 0x3A, 0x8B, 0xCE, 0x66, 0x08, + 0x48, 0x17, 0xC0, 0x9D, 0xC0, 0x8B, 0xC8, 0x62, 0xC4, 0xF5, 0xB3, 0xD6, 0x4D, 0xAF, 0x23, 0xBE, + 0x6B, 0x24, 0x23, 0x6F, 0xEE, 0xC3, 0xA8, 0x5B, 0x12, 0xE9, 0xD3, 0x3D, 0x86, 0x88, 0xE0, 0x40, + 0xBC, 0x3C, 0xDC, 0x1B, 0xAA, 0xCB, 0x35, 0x82, 0x00, 0x4D, 0x50, 0x6B, 0xB1, 0x50, 0x56, 0x51, + 0xC5, 0x99, 0x0B, 0x85, 0xEC, 0x3B, 0x7A, 0x9A, 0x2D, 0xFB, 0x0E, 0xB3, 0xFB, 0x50, 0x26, 0xF9, + 0x25, 0x65, 0x97, 0xE7, 0xB3, 0xD4, 0x21, 0x3F, 0xA5, 0x3A, 0x17, 0xF9, 0x01, 0xCC, 0x4E, 0x0F, + 0x9D, 0xBD, 0x1E, 0x18, 0x62, 0x47, 0x28, 0xB2, 0xB4, 0xC7, 0x34, 0xA4, 0x7A, 0xDC, 0x68, 0x6C, + 0xEE, 0x6E, 0x7A, 0x42, 0x8D, 0xFE, 0x74, 0x8B, 0x0C, 0x25, 0x36, 0x2A, 0x8C, 0x2E, 0xA1, 0x46, + 0x82, 0xFC, 0x7D, 0xF0, 0xF2, 0x34, 0xA0, 0x2A, 0x2A, 0xE6, 0x5A, 0x0B, 0x15, 0x97, 0xAA, 0xB9, + 0x50, 0x7C, 0x91, 0x9C, 0xFC, 0x62, 0xCE, 0xE4, 0x16, 0x72, 0xBE, 0xB0, 0x84, 0x8A, 0xAA, 0xAB, + 0x26, 0x15, 0xD5, 0x21, 0x93, 0x2C, 0x97, 0x02, 0x5F, 0x21, 0x8D, 0x86, 0xFF, 0x8F, 0xAB, 0x40, + 0x41, 0xA6, 0x44, 0xBC, 0x88, 0xDC, 0xB7, 0xD4, 0xD0, 0x82, 0xEF, 0xA2, 0x3B, 0xF1, 0x2B, 0x03, + 0x7E, 0x40, 0x32, 0x3D, 0xB4, 0xB3, 0x1F, 0xB6, 0x29, 0x02, 0x5C, 0xAF, 0x08, 0x45, 0xD6, 0x06, + 0xBE, 0x0B, 0xF8, 0x15, 0x72, 0xEF, 0xE2, 0x6C, 0x32, 0x91, 0x1D, 0x16, 0xA4, 0x23, 0xE9, 0x38, + 0x32, 0xA1, 0x68, 0x13, 0x72, 0x66, 0x54, 0x75, 0xF6, 0xC3, 0x35, 0x85, 0xEB, 0x99, 0x21, 0x76, + 0xE8, 0x90, 0x16, 0xE3, 0x3E, 0x48, 0xAB, 0x71, 0x5F, 0xA0, 0x07, 0x92, 0x61, 0x01, 0x34, 0xE4, + 0xF5, 0xD5, 0x22, 0x09, 0x5D, 0x8C, 0xF4, 0xEA, 0x1D, 0x45, 0xA6, 0x1C, 0x67, 0x20, 0x23, 0x44, + 0x2A, 0x5B, 0x76, 0xDB, 0xCE, 0xC1, 0xFF, 0x01, 0xCE, 0x34, 0xF5, 0xEC, 0x2D, 0xA9, 0x9C, 0xA8, + 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x00, 0x32, 0x30, 0x31, 0x32, 0x2D, 0x30, 0x31, 0x2D, 0x33, 0x31, 0x54, 0x31, + 0x33, 0x3A, 0x34, 0x31, 0x3A, 0x31, 0x38, 0x2D, 0x30, 0x38, 0x3A, 0x30, 0x30, 0xED, 0x4F, 0xCC, + 0x0D, 0x00, 0x00, 0x00, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3A, 0x6D, 0x6F, + 0x64, 0x69, 0x66, 0x79, 0x00, 0x32, 0x30, 0x31, 0x32, 0x2D, 0x30, 0x31, 0x2D, 0x33, 0x31, 0x54, + 0x31, 0x33, 0x3A, 0x34, 0x31, 0x3A, 0x31, 0x38, 0x2D, 0x30, 0x38, 0x3A, 0x30, 0x30, 0x9C, 0x12, + 0x74, 0xB1, 0x00, 0x00, 0x00, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6F, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x00, 0x77, 0x77, 0x77, 0x2E, 0x69, 0x6E, 0x6B, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2E, + 0x6F, 0x72, 0x67, 0x9B, 0xEE, 0x3C, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, + 0x42, 0x60, 0x82}; \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_RFC822_Attachment/Send_RFC822_Attachment.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_RFC822_Attachment/Send_RFC822_Attachment.ino new file mode 100644 index 000000000..49a98ed09 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_RFC822_Attachment/Send_RFC822_Attachment.ino @@ -0,0 +1,360 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send Email message with attachment + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +/* This is for attachment data */ +#include "image.h" + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending Email with rfc822 attachment"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + message.text.content = F("This is simple plain text message with rfc822 attachment"); + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + SMTP_Message rfc822; + rfc822.messageID = F("1234@local.machine.example"); + rfc822.from.name = F("rob"); + rfc822.from.email = F("rob@example.com"); + rfc822.sender.name = F("steve"); + rfc822.sender.email = F("steve@example.com"); + + // This date field will set by default if the device time was already set or set date field manually + rfc822.date = MailClient.Time.getDateTimeString(); + + rfc822.subject = F("Test rfc822 message"); + rfc822.comments = F("This is comment"); + rfc822.addRecipient(F("joe"), F("joe@example.com")); + rfc822.response.reply_to = F("rob@example.com"); + rfc822.text.charSet = F("utf-8"); + rfc822.text.content = F("This is rfc822 text message"); + rfc822.text.transfer_encoding = Content_Transfer_Encoding::enc_qp; + + rfc822.html.charSet = F("utf-8"); + rfc822.html.content = F("This is rfc822 html message"); + rfc822.html.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* The attachment data item */ + SMTP_Attachment att[2]; + int attIndex = 0; + + /** Set the attachment info e.g. + * file name, MIME type, BLOB data, BLOB data size, + * and transfer encoding + */ + att[attIndex].descr.filename = F("firebase_logo.png"); + att[attIndex].descr.mime = F("image/png"); + att[attIndex].blob.data = firebase_png; + att[attIndex].blob.size = sizeof(firebase_png); + att[attIndex].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; + + /* Add the attachment to the rfc822 message */ +#if defined(ESP32) || defined(ESP8266) + rfc822.addAttachment(att[attIndex]); // Required more stack and may fail on SAMD +#endif + /* Prepare other attachment data */ + uint8_t *a = new uint8_t[512]; + int j = 0; + + for (int i = 0; i < 512; i++) + { + a[i] = j; + j++; + if (j > 255) + j = 0; + } + + /** Set the attachment info e.g. + * file name, MIME type, BLOB data, BLOB data size. + * The default transfer encoding is base64. + */ + attIndex++; + att[attIndex].descr.filename = F("test.dat"); + att[attIndex].descr.mime = F("application/octet-stream"); + att[attIndex].blob.data = a; + att[attIndex].blob.size = 512; + + /* Add this attachment to the message */ + message.addAttachment(att[attIndex]); + + /* Add rfc822 message in the message */ + message.addMessage(rfc822); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (!smtp.isLoggedIn()) + { + Serial.println("\nNot yet logged in."); + } + else + { + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + } + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/lib_mail/examples/Send_Attachment_Blob/image.h b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_RFC822_Attachment/image.h similarity index 99% rename from lib/libesp32/lib_mail/examples/Send_Attachment_Blob/image.h rename to lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_RFC822_Attachment/image.h index 80ce0a0e7..5ddd6829b 100644 --- a/lib/libesp32/lib_mail/examples/Send_Attachment_Blob/image.h +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_RFC822_Attachment/image.h @@ -1,1851 +1,1851 @@ -#include - -static const uint8_t firebase_png[] PROGMEM = { - 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, - 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x58, 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x76, 0x82, - 0x70, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, - 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, - 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, - 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x55, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5E, 0xED, 0xDD, 0x59, - 0x90, 0x1D, 0xF5, 0x81, 0xE7, 0x7B, 0x3F, 0xF4, 0xC3, 0x84, 0x91, 0x40, 0x6E, 0xEF, 0xC6, 0x8B, - 0x30, 0x92, 0x4A, 0x1B, 0x58, 0x98, 0xCD, 0xA0, 0xA5, 0x4A, 0x12, 0x20, 0x6C, 0x9A, 0xB6, 0xBA, - 0x01, 0x63, 0x4F, 0x3F, 0x8C, 0x1E, 0x26, 0xC2, 0xF7, 0xE5, 0xC6, 0x25, 0xE2, 0xDE, 0x97, 0x3B, - 0x7D, 0x67, 0xAC, 0x6E, 0x63, 0x63, 0x83, 0x8D, 0xBC, 0xB1, 0x99, 0xA5, 0x10, 0x08, 0xED, 0x52, - 0x69, 0xAD, 0x92, 0xA0, 0xBB, 0xAB, 0xA7, 0xED, 0x6E, 0x77, 0xB7, 0x81, 0x42, 0x9B, 0x99, 0x89, - 0x89, 0xDB, 0x9A, 0xB9, 0x0E, 0x2F, 0x2C, 0x76, 0x61, 0x16, 0x49, 0x85, 0xA4, 0xFC, 0xDF, 0xFF, - 0x3F, 0x4F, 0xE6, 0xA9, 0x3C, 0x79, 0x7E, 0xE7, 0x9C, 0xCC, 0x3C, 0x99, 0x75, 0xCE, 0xC9, 0xFA, - 0x7E, 0x22, 0x7E, 0xA1, 0x6E, 0x2F, 0x42, 0xC2, 0x94, 0xE2, 0xFF, 0x8D, 0x7F, 0x65, 0x9E, 0xF7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x82, 0x79, 0x6E, 0xCD, 0x80, 0xBF, 0xC3, 0x5F, 0x58, 0x12, 0xFC, - 0x4B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1F, 0x73, 0x78, 0xCD, 0x3A, 0xEF, 0xB9, 0x35, 0x63, 0xE6, - 0xB9, 0x9B, 0x4D, 0x75, 0xCF, 0xAE, 0xF1, 0xE7, 0x3D, 0x7B, 0xD3, 0xA0, 0x0B, 0x92, 0xE0, 0x3F, - 0x0A, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x98, 0x91, 0x35, 0xB3, 0xEB, 0xC2, 0x23, 0x12, 0x1F, 0xD1, - 0x79, 0x87, 0xD7, 0x6C, 0x08, 0xFE, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x8E, 0xFB, 0x16, 0x2B, - 0xEF, 0xD9, 0x35, 0xE3, 0x95, 0xE0, 0xB8, 0xD1, 0x98, 0x03, 0x57, 0x19, 0xB3, 0x7B, 0xAE, 0x31, - 0x3B, 0x3E, 0x65, 0xCC, 0xB6, 0x8F, 0x1A, 0xB3, 0xF3, 0xD3, 0xC6, 0x0C, 0x2D, 0x34, 0x66, 0x78, - 0xD9, 0x64, 0x84, 0x3C, 0x7B, 0xD3, 0x60, 0xF0, 0x5F, 0x07, 0x00, 0x00, 0x00, 0x80, 0xE4, 0xAA, - 0x37, 0x1F, 0x2E, 0x3C, 0x76, 0x7C, 0xC2, 0x98, 0xED, 0x1F, 0xAB, 0x84, 0x87, 0xDA, 0x2E, 0x1B, - 0x26, 0x87, 0x6F, 0xA8, 0x84, 0xC8, 0xA1, 0x9B, 0xD6, 0x06, 0x3F, 0x05, 0x00, 0x00, 0x00, 0x00, - 0xB4, 0xE6, 0x9E, 0xF9, 0xF0, 0xE3, 0x63, 0xCF, 0xA2, 0x4A, 0x78, 0x34, 0x8B, 0x8F, 0x70, 0xDB, - 0x3F, 0x6E, 0xCC, 0xC8, 0x0A, 0xF7, 0xAD, 0x58, 0xE3, 0x66, 0xB4, 0x7F, 0x56, 0xF0, 0x53, 0x01, - 0x00, 0x00, 0x00, 0x40, 0x73, 0xDE, 0x73, 0x37, 0x9F, 0x34, 0xFB, 0xAF, 0x48, 0x1E, 0x1F, 0xE1, - 0x76, 0x5E, 0x62, 0xCC, 0xE1, 0xD5, 0x76, 0x37, 0xAE, 0x0F, 0x7E, 0x2A, 0x00, 0x00, 0x00, 0x00, - 0x68, 0xCC, 0x3D, 0x78, 0x6E, 0x0E, 0xAF, 0x4A, 0x1F, 0x1F, 0xFE, 0x3E, 0x62, 0xCC, 0xBE, 0xCF, - 0x18, 0xEF, 0xF0, 0x4D, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x68, 0xCD, 0xFF, 0x8C, 0x8F, 0xBD, - 0x97, 0x67, 0x8B, 0x0F, 0xB7, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x20, 0x19, 0x1B, - 0x20, 0xEB, 0xCD, 0xAE, 0x4F, 0xC7, 0xE2, 0xA2, 0xD5, 0x82, 0xF8, 0x08, 0xB7, 0x67, 0xB1, 0x31, - 0xCF, 0xDE, 0x64, 0xDC, 0x6D, 0x4A, 0xF0, 0xD3, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3D, 0xEF, 0xB9, - 0x9B, 0x07, 0x75, 0x64, 0x34, 0x5A, 0x2C, 0x3E, 0xC2, 0x1D, 0x1A, 0xE0, 0xB5, 0xBC, 0x00, 0x00, - 0x00, 0x00, 0x9A, 0xF3, 0x0E, 0x2E, 0x1B, 0xD5, 0xA1, 0xA1, 0x26, 0xC2, 0x23, 0xDC, 0xD0, 0x02, - 0x6E, 0x41, 0x00, 0x00, 0x00, 0x00, 0x34, 0xE7, 0x1D, 0xB8, 0x76, 0x5C, 0xC7, 0x46, 0x7C, 0x22, - 0x3A, 0xE2, 0x1B, 0x59, 0x6E, 0xBC, 0xC3, 0x37, 0x8E, 0x06, 0x3F, 0x35, 0x00, 0x00, 0x00, 0x00, - 0x4C, 0x72, 0x6F, 0xAE, 0x32, 0xFB, 0x96, 0xD8, 0x78, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x0D, 0xB5, - 0x5D, 0x73, 0x2A, 0xB7, 0x20, 0xCF, 0xAD, 0x19, 0x08, 0xFE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x50, - 0xE1, 0xBF, 0x01, 0x6B, 0x77, 0x9F, 0x8D, 0x07, 0x15, 0x1D, 0xE1, 0x44, 0x68, 0x34, 0xDB, 0xF0, - 0xF5, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xE7, 0x7F, 0x02, 0xFA, 0xAE, 0xB9, 0x36, 0x1C, - 0x54, 0x78, 0xB8, 0x89, 0xC0, 0x68, 0xB5, 0x5D, 0x97, 0x1A, 0xF3, 0xEC, 0x8D, 0xC6, 0x3C, 0xB7, - 0x9A, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x93, 0x6C, 0x80, 0xAC, 0xD7, 0xE1, 0xE1, 0x26, 0xE2, - 0xA2, 0xE5, 0x3E, 0x5C, 0xD9, 0x81, 0xAB, 0x8C, 0xF7, 0xEC, 0x0D, 0x27, 0x83, 0xBF, 0x0C, 0x00, - 0x00, 0x00, 0x00, 0xBC, 0xE7, 0x3D, 0xDE, 0xF0, 0x8A, 0x06, 0x6F, 0xC0, 0x52, 0x71, 0xD1, 0x6A, - 0x41, 0x7C, 0xB8, 0xED, 0xF8, 0x44, 0xE5, 0x16, 0xE4, 0xF0, 0x8D, 0xEB, 0x82, 0xBF, 0x14, 0x00, - 0x00, 0x00, 0x80, 0xE9, 0xCE, 0x3B, 0x70, 0xFD, 0xC9, 0xDC, 0xE3, 0x23, 0x1C, 0xB7, 0x20, 0x00, - 0x00, 0x00, 0x00, 0xA2, 0xCC, 0xFE, 0x2B, 0x6D, 0x2C, 0x14, 0x10, 0x1F, 0x6E, 0xEE, 0x16, 0xE4, - 0xF0, 0x2A, 0x77, 0x0B, 0xB2, 0x3E, 0xF8, 0xCB, 0x01, 0x00, 0x00, 0x00, 0x98, 0xAE, 0x6C, 0x18, - 0x2C, 0x31, 0x7B, 0x2E, 0xB3, 0xB1, 0x50, 0x40, 0x7C, 0x84, 0xDB, 0x77, 0xB9, 0x7B, 0x23, 0xD6, - 0xB8, 0x7B, 0xDD, 0x6F, 0xF0, 0x97, 0x05, 0x00, 0x00, 0x00, 0x30, 0x1D, 0x99, 0x43, 0x37, 0xAD, - 0x9D, 0x7C, 0x03, 0x96, 0x8A, 0x8B, 0x56, 0x13, 0xC1, 0x11, 0xDF, 0xF6, 0x8F, 0x71, 0x0B, 0x02, - 0x00, 0x00, 0x00, 0x20, 0x78, 0x03, 0xD6, 0xF6, 0x8F, 0xDB, 0x50, 0x50, 0x71, 0xD1, 0x6A, 0x22, - 0x36, 0x1A, 0x8D, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB3, 0x37, 0x0D, 0xEA, 0xB8, 0x68, - 0x35, 0x11, 0x19, 0xAD, 0x76, 0xA8, 0xDF, 0x3D, 0x90, 0x3E, 0x18, 0xFC, 0xA5, 0x01, 0x00, 0x00, - 0x00, 0x4C, 0x37, 0xDE, 0x81, 0x6B, 0x46, 0x75, 0x60, 0x34, 0x9B, 0x88, 0x8B, 0x56, 0xDB, 0xFA, - 0x21, 0x63, 0x86, 0xE6, 0x57, 0x5E, 0xCB, 0x3B, 0xB2, 0x66, 0x76, 0xF0, 0x97, 0x07, 0x00, 0x00, - 0x00, 0x30, 0x9D, 0x98, 0x03, 0x57, 0xDB, 0x40, 0x50, 0x91, 0xD1, 0x68, 0x22, 0x2E, 0x5A, 0xCD, - 0xC5, 0x47, 0x38, 0x6E, 0x41, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC9, 0xDD, 0x44, 0x98, 0x7D, 0x9F, - 0xB1, 0x91, 0xA0, 0x42, 0x43, 0x4D, 0xC4, 0x45, 0xAB, 0x45, 0xE3, 0xC3, 0x6D, 0xF7, 0xDC, 0xCA, - 0x2D, 0xC8, 0x73, 0xAB, 0x07, 0x82, 0x5F, 0x06, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC0, 0x3C, 0xB7, - 0x66, 0xC0, 0xEC, 0x9E, 0x67, 0x43, 0x41, 0xC5, 0x46, 0x7C, 0x22, 0x2E, 0x5A, 0x2D, 0x1E, 0x1F, - 0xE1, 0x86, 0xAF, 0x73, 0x0F, 0xA4, 0x8F, 0x06, 0xBF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x81, - 0xF7, 0xEC, 0x4D, 0x77, 0x99, 0x9D, 0x97, 0xD8, 0x58, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x8B, 0x56, - 0x53, 0xE1, 0x11, 0x6E, 0xD7, 0xA7, 0xB9, 0x05, 0x01, 0x00, 0x00, 0x00, 0xA6, 0x1B, 0xEF, 0xF0, - 0x8D, 0x1B, 0x74, 0x70, 0x44, 0x27, 0xE2, 0xA2, 0xD5, 0x54, 0x74, 0xC4, 0xC7, 0x2D, 0x08, 0x00, - 0x00, 0x00, 0x30, 0xBD, 0x78, 0x07, 0xAF, 0x6F, 0xF1, 0x06, 0x2C, 0x11, 0x17, 0xAD, 0xA6, 0x62, - 0x43, 0xCD, 0x7D, 0xF6, 0x88, 0xBB, 0x05, 0x39, 0x7C, 0xE3, 0xBA, 0xE0, 0x97, 0x03, 0x00, 0x00, - 0x00, 0xA0, 0xCC, 0xBC, 0x03, 0xD7, 0x9D, 0xD4, 0xE1, 0xE1, 0x26, 0xE2, 0xA2, 0xD5, 0x54, 0x68, - 0x34, 0xDB, 0xFE, 0x2B, 0xDD, 0x1B, 0xB1, 0x4E, 0x06, 0xBF, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x65, - 0xD6, 0xF8, 0x0D, 0x58, 0x22, 0x2E, 0x5A, 0x4D, 0x05, 0x46, 0xAB, 0xB9, 0x5B, 0x90, 0xC3, 0x37, - 0x70, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x94, 0x9D, 0xFF, 0x06, 0xAC, 0xA1, 0x05, 0x36, 0x1E, 0x3A, - 0x14, 0x1F, 0xFE, 0x3E, 0x68, 0x5C, 0x04, 0x79, 0x87, 0x6E, 0x18, 0x37, 0xA3, 0xFD, 0xB3, 0x82, - 0x5F, 0x1A, 0x00, 0x00, 0x00, 0x80, 0xB2, 0x71, 0xB7, 0x0E, 0x66, 0xD7, 0x1C, 0x1B, 0x10, 0x1D, - 0x8C, 0x0F, 0x37, 0xF7, 0xD7, 0x3D, 0xB4, 0xD2, 0x98, 0xC3, 0xAB, 0xD7, 0x07, 0xBF, 0x34, 0x00, - 0x00, 0x00, 0x00, 0x65, 0x63, 0x03, 0x64, 0xBD, 0xD9, 0x7E, 0x71, 0x25, 0x00, 0x3A, 0x15, 0x1F, - 0xE1, 0xF6, 0x5E, 0xC6, 0x2D, 0x08, 0x00, 0x00, 0x00, 0x50, 0x66, 0xDE, 0xC8, 0xCA, 0xA1, 0xAE, - 0x88, 0x0F, 0xB7, 0xE0, 0x16, 0xC4, 0x3B, 0xBC, 0x7A, 0x43, 0xF0, 0xCB, 0x03, 0x00, 0x00, 0x00, - 0x50, 0x26, 0xDE, 0xC1, 0x6B, 0xC7, 0xBA, 0x22, 0x3E, 0xC2, 0xED, 0xEE, 0xAB, 0x3C, 0x90, 0x3E, - 0xB2, 0x66, 0x76, 0xF0, 0x4B, 0x04, 0x00, 0x00, 0x00, 0x50, 0x16, 0x66, 0xFF, 0x67, 0x75, 0x5C, - 0xB4, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0xD1, 0x11, 0xDF, 0xC8, 0x0A, 0xE3, 0x1D, 0x5A, 0x3D, 0x18, - 0xFC, 0x12, 0x01, 0x00, 0x00, 0x00, 0x94, 0x81, 0xBB, 0x65, 0x30, 0xFB, 0x2E, 0xD7, 0x81, 0xD1, - 0x6C, 0x32, 0x2C, 0x92, 0x4C, 0xC4, 0x86, 0x1A, 0xB7, 0x20, 0x00, 0x00, 0x00, 0x40, 0xF9, 0x98, - 0xE7, 0x56, 0x0F, 0x98, 0x5D, 0x97, 0xEA, 0xC8, 0x68, 0x34, 0x19, 0x16, 0x49, 0x26, 0x42, 0xA3, - 0xD9, 0x0E, 0x7E, 0xCE, 0x78, 0x87, 0x6F, 0x18, 0x0D, 0x7E, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x7A, - 0x9D, 0xFF, 0x06, 0xAC, 0x1D, 0x9F, 0xD0, 0xA1, 0xA1, 0x26, 0xC3, 0x22, 0xC9, 0x44, 0x60, 0xB4, - 0xDA, 0xCE, 0x4B, 0x82, 0x5B, 0x90, 0xD5, 0x03, 0xC1, 0x2F, 0x17, 0x00, 0x00, 0x00, 0x40, 0x2F, - 0xF3, 0x9E, 0xBD, 0x61, 0x50, 0x86, 0x86, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0x71, 0x91, 0x74, 0x07, - 0xAF, 0x35, 0xDE, 0xE1, 0x55, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x65, 0xE0, 0x1D, 0xBC, 0x6E, - 0x54, 0xC6, 0x46, 0x7C, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, 0x6D, 0xF9, 0x80, 0x31, 0x3B, - 0x67, 0xBB, 0x0F, 0x26, 0x34, 0xE6, 0xD0, 0xAA, 0xB5, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, 0x40, - 0xAF, 0xF2, 0x0E, 0x5C, 0x33, 0x2E, 0x83, 0x23, 0x3A, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, - 0x5C, 0x7C, 0x84, 0xDB, 0x77, 0x85, 0xFB, 0x5C, 0x90, 0x93, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, - 0x40, 0x2F, 0x72, 0x9F, 0x36, 0xDE, 0xF2, 0x0D, 0x58, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, - 0x45, 0xE3, 0xC3, 0x6D, 0xDB, 0xC7, 0x2A, 0xB7, 0x20, 0x87, 0x57, 0xAD, 0x0B, 0x7E, 0xE9, 0x00, - 0x00, 0x00, 0x00, 0x7A, 0x8D, 0xFF, 0x06, 0xAC, 0xDD, 0x73, 0xEB, 0xA3, 0x23, 0x9C, 0x0C, 0x8B, - 0x24, 0x13, 0x51, 0x91, 0x74, 0xF1, 0xF8, 0x08, 0xC7, 0x2D, 0x08, 0x00, 0x00, 0x00, 0xD0, 0xDB, - 0xCC, 0xE1, 0x1B, 0xD7, 0x35, 0x7C, 0x05, 0xAF, 0x0C, 0x8B, 0x24, 0x13, 0x51, 0x91, 0x74, 0x2A, - 0x3C, 0xC2, 0x6D, 0xB5, 0xBF, 0xA6, 0x43, 0x03, 0xEE, 0x26, 0x64, 0x7D, 0xF0, 0xCB, 0x07, 0x00, - 0x00, 0x00, 0xD0, 0x4B, 0xFC, 0x57, 0xF0, 0xF6, 0x42, 0x7C, 0x84, 0xDB, 0xB3, 0xD8, 0x7D, 0x3A, - 0xFA, 0xB8, 0xFB, 0xD6, 0xB1, 0xE0, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x57, 0x78, 0xC3, 0xCB, - 0xEB, 0xDF, 0x80, 0x25, 0xC3, 0x22, 0xC9, 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x0D, 0x35, 0x6E, 0x41, - 0x00, 0x00, 0x00, 0x80, 0xDE, 0xE5, 0x1D, 0xBC, 0x76, 0xAC, 0x67, 0xE2, 0x23, 0xDC, 0x9E, 0x45, - 0xC6, 0x3B, 0xB4, 0x6A, 0xDC, 0x8C, 0xF4, 0xCF, 0x0E, 0x7E, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x7A, - 0x81, 0xD9, 0x7F, 0x45, 0x6F, 0xC5, 0x87, 0xBF, 0xF7, 0x1B, 0x33, 0xB2, 0xCC, 0x46, 0xC8, 0xCA, - 0xC1, 0xE0, 0xB7, 0x01, 0x00, 0x00, 0x00, 0xA0, 0xDB, 0x99, 0xC3, 0x37, 0x2E, 0x71, 0xB7, 0x09, - 0x3D, 0x17, 0x1F, 0x6E, 0xEE, 0xCD, 0x5D, 0x87, 0x57, 0xD9, 0x10, 0xE9, 0xCD, 0x5B, 0x10, 0xF7, - 0xEB, 0xB6, 0x1B, 0x08, 0xC6, 0x4D, 0x0E, 0x00, 0x00, 0x00, 0xCA, 0xCF, 0x1C, 0xBA, 0x69, 0xAD, - 0xFF, 0x06, 0x2C, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x5A, 0x10, 0x1F, - 0xE1, 0x7A, 0xEC, 0x16, 0xC4, 0xFF, 0xCC, 0x95, 0x91, 0xFE, 0xF5, 0xDE, 0xA1, 0x81, 0x93, 0xFE, - 0x73, 0x2C, 0x91, 0xF9, 0xFF, 0x9A, 0xFD, 0xF7, 0x78, 0xB8, 0x1E, 0x00, 0x00, 0x00, 0xA5, 0x55, - 0x79, 0x03, 0xD6, 0x47, 0x6D, 0x10, 0xA8, 0xB8, 0x68, 0x35, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, - 0xD5, 0x62, 0xF1, 0xE1, 0xB6, 0xF3, 0x53, 0xC1, 0x2D, 0xC8, 0xEA, 0x81, 0xE0, 0xB7, 0xD4, 0xB5, - 0xCC, 0xA1, 0xFE, 0xB5, 0xDE, 0xC8, 0xC0, 0x78, 0x3C, 0x3C, 0xE2, 0xAB, 0xFC, 0x67, 0xFA, 0xD7, - 0x06, 0xFF, 0x35, 0x00, 0x00, 0x00, 0xA0, 0x3C, 0xBC, 0x67, 0x6F, 0x18, 0xD4, 0x71, 0xD1, 0x6A, - 0x22, 0x2A, 0x92, 0x4E, 0xC6, 0x45, 0xAB, 0x89, 0xF8, 0x08, 0x77, 0xF0, 0x1A, 0xE3, 0x1D, 0x5E, - 0x39, 0x1A, 0xFC, 0x96, 0xBA, 0x92, 0x19, 0xE9, 0x5F, 0x57, 0x8D, 0x8C, 0x91, 0xE5, 0xFE, 0x43, - 0xF4, 0x66, 0xC7, 0xC7, 0x6B, 0xE7, 0xFE, 0x35, 0xF7, 0xEF, 0xF9, 0xFF, 0x99, 0x7E, 0x37, 0x3E, - 0xF1, 0x1D, 0x00, 0x00, 0x00, 0xE5, 0xE2, 0x1D, 0xB8, 0x7A, 0x54, 0x07, 0x46, 0xB3, 0x89, 0xA8, - 0x48, 0x3A, 0x19, 0x17, 0xAD, 0x26, 0xA2, 0x23, 0xBA, 0x2E, 0xBF, 0x05, 0xB1, 0x21, 0x31, 0xBB, - 0x7A, 0xF3, 0x31, 0x34, 0xBF, 0xF2, 0x6B, 0xDE, 0x3C, 0x4B, 0xCF, 0xFD, 0x7B, 0x43, 0x7D, 0x7E, - 0x80, 0x78, 0x23, 0x2B, 0x78, 0xCB, 0x17, 0x00, 0x00, 0x00, 0xCA, 0xC5, 0xEC, 0xBF, 0xD2, 0x86, - 0x81, 0x8A, 0x8C, 0x46, 0x13, 0x51, 0x91, 0x74, 0x32, 0x2E, 0x5A, 0x2D, 0x12, 0x1A, 0xCD, 0xE6, - 0x6E, 0x41, 0x0E, 0xAD, 0x1A, 0x0B, 0x7E, 0x5B, 0x5D, 0xC5, 0xC6, 0xC7, 0x90, 0x1F, 0x1F, 0xBB, - 0x3E, 0xAD, 0xA3, 0xA3, 0x66, 0x17, 0x55, 0xB6, 0xF3, 0x92, 0x4A, 0x84, 0x0C, 0xAF, 0xE8, 0xEA, - 0x9B, 0x1D, 0x00, 0x00, 0x00, 0x20, 0x31, 0xFF, 0x81, 0xE8, 0xBD, 0x97, 0xDB, 0x38, 0x50, 0xA1, - 0xA1, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x9A, 0x08, 0x8D, 0x46, 0x73, 0xCF, 0xB1, 0xB8, - 0x5B, 0x90, 0xC3, 0xAB, 0xBA, 0xEA, 0xDB, 0x96, 0x6C, 0x44, 0x0C, 0xF8, 0xF1, 0xE1, 0xDE, 0xD8, - 0x25, 0x83, 0x23, 0xBA, 0x20, 0x3E, 0x62, 0x11, 0xE2, 0x7E, 0x8E, 0xE0, 0xA7, 0x03, 0x00, 0x00, - 0x00, 0x7A, 0x97, 0x79, 0x6E, 0xF5, 0x80, 0x7F, 0x30, 0x96, 0xB1, 0x11, 0x9F, 0x88, 0x8A, 0xA4, - 0x93, 0x71, 0xD1, 0x6A, 0x22, 0x32, 0x5A, 0x6D, 0xDF, 0x12, 0xE3, 0x1D, 0x5E, 0x75, 0x32, 0xF8, - 0xED, 0x75, 0x05, 0xEF, 0xD0, 0xC0, 0xA8, 0x39, 0x70, 0x55, 0x10, 0x18, 0xCD, 0x16, 0x8B, 0x8F, - 0x70, 0xFB, 0xAF, 0xE4, 0x16, 0x04, 0x00, 0x00, 0x00, 0xE5, 0xE0, 0x3D, 0x7B, 0xC3, 0x5D, 0x66, - 0xC7, 0xA7, 0x6C, 0x24, 0xA8, 0xE0, 0x88, 0x4E, 0x44, 0x45, 0xD2, 0xC9, 0xB8, 0x68, 0x35, 0x11, - 0x17, 0x49, 0x16, 0xDC, 0x82, 0x78, 0x87, 0x56, 0xDD, 0x15, 0xFC, 0x16, 0x3B, 0xAA, 0x7A, 0xFB, - 0xE1, 0x1E, 0x30, 0x97, 0xD1, 0x11, 0x4E, 0x84, 0x47, 0xB8, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, - 0x00, 0x80, 0x72, 0xF0, 0x0E, 0xDF, 0xB8, 0x41, 0x07, 0x47, 0x74, 0x22, 0x2A, 0x92, 0x4E, 0xC6, - 0x45, 0xAB, 0x89, 0xB0, 0x48, 0xB3, 0x3D, 0x0B, 0x8D, 0x37, 0xB2, 0x72, 0xBC, 0x1B, 0x3E, 0x4B, - 0x23, 0xD9, 0xED, 0x87, 0x88, 0x8E, 0xF8, 0xB8, 0x05, 0x01, 0x00, 0x00, 0x40, 0x19, 0x78, 0x07, - 0xAF, 0x6B, 0xF1, 0x06, 0x2C, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, 0xD5, 0x44, 0x50, 0xA4, 0xDA, - 0x1F, 0x57, 0xFE, 0xDA, 0x23, 0x2B, 0xEC, 0x56, 0xAE, 0x0F, 0x7E, 0x9B, 0x1D, 0xE1, 0x3E, 0xC7, - 0xC3, 0xBF, 0xFD, 0x70, 0x7F, 0x1F, 0x65, 0x78, 0xB8, 0x89, 0xD8, 0x50, 0xF3, 0x7F, 0x4F, 0xFD, - 0xC6, 0x1C, 0xE4, 0xB3, 0x41, 0x00, 0x00, 0x00, 0xD0, 0xC3, 0xBC, 0x03, 0x9F, 0x3B, 0x59, 0x1F, - 0x1D, 0xE1, 0x22, 0x31, 0x91, 0x76, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xD9, 0xF8, 0x08, - 0xD7, 0x05, 0xB7, 0x20, 0xFE, 0xA7, 0x9A, 0xBB, 0x07, 0xFC, 0x65, 0x78, 0xB8, 0x89, 0xD0, 0x68, - 0xB6, 0xBD, 0x97, 0xB9, 0x5B, 0x90, 0xAE, 0x7A, 0xBE, 0x05, 0x00, 0x00, 0x00, 0x48, 0xA5, 0xF1, - 0x1B, 0xB0, 0x44, 0x54, 0x24, 0x9D, 0x8C, 0x8B, 0x56, 0x53, 0x41, 0x91, 0x66, 0x91, 0xF8, 0x70, - 0x73, 0xBF, 0x8E, 0xE1, 0xA5, 0xEE, 0x13, 0xC5, 0x37, 0x04, 0xBF, 0xD5, 0x29, 0x65, 0xC2, 0x0F, - 0x1D, 0x74, 0x7F, 0x2F, 0xF3, 0x88, 0x0F, 0x37, 0xF7, 0x7B, 0xF2, 0x9F, 0x05, 0x59, 0xCE, 0x87, - 0x13, 0x02, 0x00, 0x00, 0xA0, 0xF7, 0xF8, 0x6F, 0xC0, 0x72, 0x1F, 0x8A, 0x57, 0xB6, 0xF8, 0x08, - 0xB7, 0x6B, 0x8E, 0x31, 0x87, 0x56, 0xBA, 0x43, 0xFB, 0x94, 0x7F, 0x90, 0x5F, 0xF3, 0xDB, 0x0F, - 0x11, 0x17, 0x49, 0xB7, 0x67, 0xB1, 0xF1, 0x86, 0x97, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x80, 0xDE, - 0x63, 0x0E, 0xDD, 0xB4, 0xD6, 0xFF, 0x60, 0xBC, 0x32, 0xC6, 0x47, 0x38, 0x77, 0x0B, 0x72, 0x68, - 0xE5, 0x60, 0xF0, 0x5B, 0x9E, 0x12, 0xCD, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0xDD, 0x33, 0x17, 0xDA, - 0xDF, 0x93, 0xFD, 0x7B, 0x66, 0x7F, 0x4F, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0xE7, 0x98, 0xC3, - 0x37, 0xAE, 0xF7, 0x5F, 0x5B, 0x5B, 0xD6, 0xF8, 0x70, 0x0B, 0x6F, 0x41, 0x0E, 0xF7, 0x2F, 0x09, - 0x7E, 0xDB, 0x85, 0x72, 0xCF, 0x9C, 0xF8, 0xB7, 0x1F, 0xEE, 0x66, 0x29, 0xEF, 0xF8, 0x08, 0xB7, - 0x7B, 0x9E, 0xF1, 0x46, 0x96, 0x8F, 0x9B, 0xA1, 0xCE, 0xBF, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, - 0xCC, 0x1B, 0x59, 0x39, 0x54, 0xEA, 0xF8, 0x08, 0x77, 0xE0, 0x6A, 0x77, 0x0B, 0x32, 0x25, 0xAF, - 0xB0, 0x35, 0x23, 0xFD, 0xEB, 0xCD, 0xC8, 0x72, 0xFB, 0xD7, 0xB5, 0xBF, 0xC6, 0x22, 0xE2, 0xC3, - 0x6D, 0xF3, 0xFB, 0xC2, 0x5B, 0x90, 0x8E, 0xBE, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, 0xC5, 0xDB, - 0x7F, 0xED, 0x58, 0xE9, 0xE3, 0xC3, 0x6D, 0xC7, 0x27, 0xC3, 0x67, 0x41, 0x0A, 0xFD, 0x20, 0x3F, - 0xFF, 0xF6, 0x63, 0x64, 0x60, 0xBC, 0xFE, 0xF6, 0x43, 0x44, 0x45, 0xD2, 0xC5, 0xE3, 0x23, 0x1C, - 0xB7, 0x20, 0x00, 0x00, 0x00, 0xE8, 0x35, 0x66, 0xDF, 0x12, 0x1D, 0x15, 0x49, 0x27, 0xE3, 0xA2, - 0xD5, 0x54, 0x50, 0xA4, 0x99, 0x08, 0x8C, 0x56, 0x73, 0x37, 0x06, 0x53, 0x70, 0x0B, 0xA2, 0x6F, - 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8F, 0x70, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0x97, 0x98, - 0x91, 0x35, 0xB3, 0xDD, 0xE7, 0x4A, 0xC8, 0xB0, 0x48, 0x32, 0x19, 0x17, 0xAD, 0x16, 0x8F, 0x89, - 0xB4, 0x13, 0x71, 0xD1, 0x6A, 0xEE, 0xA0, 0xEE, 0xB6, 0xED, 0x63, 0x95, 0x5B, 0x90, 0x43, 0xC5, - 0x7C, 0x90, 0x9F, 0xBE, 0xFD, 0x10, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0xE2, 0xE3, 0x16, 0x04, 0x00, - 0x00, 0x00, 0xBD, 0xC2, 0x8C, 0xAC, 0x1E, 0x30, 0x3B, 0x2F, 0xD1, 0x71, 0xD1, 0x6A, 0x32, 0x2E, - 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0x30, 0x3E, 0xC2, 0xED, 0xFD, 0x8C, 0xBB, - 0x05, 0x29, 0xE4, 0x15, 0xB6, 0xEE, 0xF3, 0x46, 0xCC, 0xF0, 0xF5, 0xF6, 0xAF, 0x33, 0x45, 0xF1, - 0x11, 0xEE, 0xE0, 0xE7, 0x6C, 0x84, 0xAC, 0xE8, 0xC8, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x89, - 0x99, 0xC3, 0xAB, 0xD7, 0x9B, 0xED, 0x17, 0xEB, 0xC0, 0x68, 0x36, 0x19, 0x17, 0xAD, 0xA6, 0x82, - 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x5A, 0x3C, 0x3E, 0xDC, 0xB6, 0x7E, 0x38, 0x7C, 0x16, 0x24, 0xD7, - 0x57, 0xD8, 0xDA, 0x9F, 0x6F, 0xB6, 0xFF, 0xDA, 0x5D, 0xF7, 0x4A, 0xE3, 0xA9, 0x8C, 0x0F, 0xB7, - 0x9D, 0xB3, 0xED, 0xEF, 0x67, 0x85, 0xFB, 0x3D, 0x4D, 0xF9, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, - 0x89, 0x79, 0x87, 0x57, 0x6F, 0x90, 0x81, 0xD1, 0x6C, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, - 0x89, 0xB8, 0x68, 0x35, 0x15, 0x1F, 0xE1, 0x82, 0x5B, 0x10, 0xF7, 0x2D, 0x53, 0xC1, 0xDF, 0x8A, - 0xB6, 0x79, 0x87, 0x06, 0x06, 0x27, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8C, 0x24, 0x73, - 0xB7, 0x20, 0xC3, 0x2B, 0xA6, 0xF4, 0xB3, 0x4E, 0x00, 0x00, 0x00, 0x80, 0x54, 0xBC, 0x83, 0x9F, - 0x1B, 0x95, 0x91, 0xD1, 0x68, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0x35, - 0x15, 0x1D, 0xD1, 0xB9, 0x5F, 0x97, 0x7F, 0x63, 0xB0, 0x32, 0x97, 0x87, 0xB7, 0x6B, 0x6F, 0x3F, - 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8B, 0xA4, 0xE3, 0x16, 0x04, 0x00, 0x00, 0x00, 0xDD, 0xCE, 0xDB, - 0x7F, 0xD5, 0xB8, 0x0C, 0x0D, 0xB5, 0xBA, 0xB0, 0x48, 0x32, 0x15, 0x14, 0x69, 0x26, 0xE2, 0xA2, - 0xD5, 0x54, 0x70, 0xA8, 0x0D, 0x2D, 0x30, 0xDE, 0xC8, 0xCA, 0xF1, 0x3C, 0x6E, 0x41, 0xFC, 0xDB, - 0x8F, 0x03, 0xD7, 0xDA, 0x9F, 0x57, 0x44, 0x45, 0xD2, 0xA9, 0xA8, 0x48, 0x3B, 0xF7, 0x96, 0xAF, - 0xE1, 0x65, 0xDC, 0x82, 0x34, 0x60, 0xC6, 0xFE, 0xC3, 0x2C, 0xF3, 0xF2, 0xBF, 0x5F, 0x67, 0x4E, - 0x7C, 0x65, 0x7D, 0x64, 0x6B, 0xDD, 0xBF, 0x1E, 0xFC, 0x47, 0x00, 0x00, 0x00, 0x50, 0x14, 0x77, - 0xF0, 0x4E, 0xFC, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, - 0x0A, 0x8D, 0x46, 0x73, 0xBF, 0xC6, 0x1C, 0x6E, 0x41, 0xDC, 0xA7, 0xAB, 0xFB, 0xB7, 0x1F, 0xEE, - 0x59, 0x1A, 0x15, 0x16, 0x49, 0xA6, 0x62, 0x22, 0xCB, 0xB6, 0x7F, 0xD4, 0xFE, 0x7E, 0x96, 0xDB, - 0x2D, 0x2D, 0xF4, 0xB3, 0x4E, 0x7A, 0x8D, 0x0B, 0x0C, 0xEF, 0xC4, 0x97, 0x07, 0xCD, 0x2F, 0xBE, - 0x62, 0xE4, 0x4E, 0x7C, 0xC9, 0xF8, 0xFF, 0x3E, 0x21, 0x02, 0x00, 0x00, 0x50, 0x1C, 0xFF, 0x0D, - 0x58, 0xBB, 0xE6, 0xE8, 0xE0, 0x88, 0xAE, 0x2E, 0x2C, 0x92, 0x4C, 0x05, 0x45, 0x9A, 0x89, 0xB8, - 0x68, 0x35, 0x15, 0x19, 0xAD, 0xE6, 0xBF, 0xC2, 0x76, 0xE5, 0x78, 0x3B, 0xDF, 0xB6, 0xE4, 0x1D, - 0x1A, 0x18, 0x35, 0xFB, 0xAF, 0xB4, 0x3F, 0x9F, 0x08, 0x8B, 0x24, 0x53, 0x21, 0x91, 0x69, 0x33, - 0x2B, 0xDB, 0x7F, 0x85, 0xF1, 0x86, 0x97, 0x4F, 0xC9, 0x27, 0xBE, 0xF7, 0x02, 0x73, 0xFC, 0xDF, - 0x2F, 0xF1, 0x7E, 0xF1, 0xE5, 0xF1, 0xDA, 0xE0, 0xB8, 0xDD, 0x98, 0xE3, 0x5F, 0xF4, 0xC3, 0x23, - 0xFA, 0xAF, 0xFB, 0xFF, 0x39, 0xFB, 0x9F, 0x0F, 0xFE, 0xAB, 0x00, 0x00, 0x00, 0xC8, 0x93, 0x39, - 0x7C, 0xE3, 0xBA, 0x96, 0xAF, 0xE0, 0x95, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, - 0xAB, 0xA9, 0xB8, 0x48, 0xBA, 0xE1, 0xEB, 0x8D, 0xFB, 0x16, 0xAA, 0xE0, 0x6F, 0x4B, 0x2A, 0x36, - 0x5C, 0x06, 0xEC, 0xB2, 0xDF, 0x7E, 0xC8, 0x90, 0xC8, 0xB2, 0x20, 0x3E, 0xDC, 0xB8, 0x05, 0xA9, - 0xAA, 0x89, 0x0F, 0x17, 0x1D, 0x2F, 0xD9, 0xFF, 0xAD, 0x5E, 0xB0, 0xB1, 0xF8, 0xFC, 0x92, 0xC9, - 0xBD, 0x70, 0xB5, 0xFD, 0xD7, 0x57, 0x55, 0xFE, 0x7D, 0x22, 0x04, 0x00, 0x00, 0xA0, 0x38, 0xFE, - 0x2B, 0x78, 0x55, 0x74, 0x84, 0x93, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, - 0xA9, 0xA8, 0x48, 0xBC, 0x59, 0x95, 0x07, 0xC7, 0xDD, 0xB7, 0x50, 0x65, 0xB8, 0x05, 0xF1, 0x86, - 0x57, 0x64, 0xBF, 0xFD, 0x90, 0x21, 0x91, 0x65, 0x91, 0xF8, 0x08, 0xC7, 0x2D, 0x48, 0x6D, 0x7C, - 0x1C, 0xB9, 0xB1, 0x36, 0x3A, 0xD4, 0x5C, 0x98, 0x1C, 0xFD, 0x42, 0x25, 0x42, 0x4E, 0x7C, 0x85, - 0x1B, 0x24, 0x00, 0x00, 0x80, 0xBC, 0x79, 0x07, 0x97, 0x35, 0x7E, 0x03, 0x96, 0x8C, 0x8B, 0x56, - 0x53, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0x85, 0x1F, 0x16, 0x68, 0xE7, - 0x6E, 0x41, 0x46, 0x06, 0x86, 0x82, 0xBF, 0x35, 0x89, 0xB4, 0x75, 0xFB, 0x21, 0x43, 0x22, 0xCB, - 0x44, 0x7C, 0xB8, 0x6D, 0xFD, 0xD0, 0xB4, 0xBE, 0x05, 0xA9, 0x89, 0x0F, 0x77, 0xEB, 0xA1, 0x82, - 0xA3, 0xD1, 0x5C, 0xAC, 0xF8, 0x37, 0x26, 0x5F, 0x29, 0xE4, 0xD3, 0xF2, 0x01, 0x00, 0x00, 0xA6, - 0x2D, 0x6F, 0xFF, 0x35, 0x63, 0xC4, 0x47, 0xB0, 0xED, 0x1F, 0xB7, 0x87, 0x75, 0xFF, 0x16, 0x24, - 0xF1, 0x81, 0xDD, 0x1B, 0x59, 0x31, 0xE6, 0x3F, 0xC4, 0xAF, 0x02, 0xA3, 0xD9, 0x64, 0x48, 0x64, - 0x99, 0x08, 0x8F, 0xE8, 0xF6, 0x2C, 0xB2, 0x51, 0xB5, 0x7C, 0x2C, 0xF8, 0xE5, 0x4E, 0x1B, 0x6D, - 0xC5, 0x47, 0xB8, 0x63, 0x7F, 0xE2, 0x3F, 0x94, 0x1E, 0xFC, 0x94, 0x00, 0x00, 0x00, 0xC8, 0x83, - 0xD9, 0xF7, 0x19, 0xE2, 0xC3, 0xED, 0x99, 0x60, 0xFB, 0xAF, 0x32, 0xDE, 0xF0, 0x40, 0xA2, 0x6F, - 0xBD, 0xB1, 0xA1, 0xB2, 0xCE, 0xBF, 0xFD, 0x70, 0x7F, 0xCF, 0x54, 0x64, 0x34, 0x9A, 0x0C, 0x89, - 0x2C, 0x13, 0xC1, 0x11, 0x9F, 0xFB, 0x7B, 0xEB, 0xDF, 0x82, 0x2C, 0xCF, 0xF5, 0x13, 0xDF, 0xBB, - 0x59, 0x2E, 0xF1, 0xE1, 0xF6, 0xC2, 0xD5, 0xEE, 0xDB, 0xB0, 0x4E, 0x06, 0x3F, 0x2D, 0x00, 0x00, - 0x00, 0xDA, 0x65, 0x0E, 0xDF, 0xB8, 0xC4, 0x0C, 0x2D, 0x9C, 0xBE, 0xF1, 0x11, 0x46, 0x47, 0xF0, - 0x7F, 0x7B, 0x6E, 0xDB, 0x3F, 0xEE, 0xBE, 0x0D, 0x2B, 0xD1, 0x2D, 0x88, 0x37, 0xBC, 0xE2, 0x64, - 0xEA, 0xDB, 0x0F, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, 0xD1, 0xDC, 0x2D, 0xC8, 0xF0, 0xB2, 0x69, - 0x71, 0x90, 0xCE, 0x2D, 0x3E, 0xC2, 0x1D, 0xBB, 0xC5, 0x04, 0x3F, 0x35, 0x00, 0x00, 0x00, 0xDA, - 0x65, 0x0E, 0xAD, 0x5A, 0x5B, 0xF3, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, - 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0xAB, 0x8F, 0x0F, 0x3F, 0x3C, 0xC2, 0x6D, 0xB2, 0xDB, 0x7B, - 0x85, 0x39, 0x3F, 0x3C, 0xD0, 0xF4, 0xC0, 0x9E, 0xE9, 0xF6, 0x43, 0x86, 0x44, 0x96, 0x89, 0xC8, - 0x68, 0x36, 0xF7, 0xF7, 0x79, 0x1A, 0xDC, 0x82, 0xE4, 0x1E, 0x1F, 0xCF, 0x7F, 0xC6, 0x98, 0x23, - 0x37, 0x18, 0xF3, 0xF2, 0x9D, 0x7C, 0x9E, 0x0A, 0x00, 0x00, 0x40, 0x1E, 0xFC, 0x37, 0x60, 0x6D, - 0xFB, 0xC8, 0xF4, 0x8D, 0x8F, 0x68, 0x78, 0xB8, 0xB9, 0xF8, 0x70, 0xDB, 0xFC, 0x21, 0xF7, 0x6D, - 0x58, 0xEE, 0x16, 0xA4, 0xE1, 0x81, 0xDD, 0xBF, 0xFD, 0xD8, 0xB3, 0xD0, 0xFE, 0x7C, 0x22, 0x34, - 0xD4, 0x64, 0x48, 0x64, 0x99, 0x08, 0x8C, 0x24, 0x1B, 0x9A, 0x5F, 0xEA, 0x5B, 0x90, 0x42, 0xE2, - 0xC3, 0x6D, 0xEC, 0x3A, 0x17, 0x20, 0xD3, 0xE6, 0xDB, 0xD7, 0x00, 0x00, 0x00, 0x0A, 0xE5, 0x1D, - 0x5A, 0x3D, 0x38, 0xED, 0xE2, 0x23, 0x12, 0x20, 0xD5, 0xE8, 0x88, 0xC4, 0xC7, 0xF9, 0x70, 0x43, - 0x97, 0x9B, 0x73, 0x07, 0xF5, 0x2D, 0xC8, 0xF9, 0x91, 0xFE, 0xF5, 0x66, 0x78, 0x99, 0xFD, 0xB9, - 0xDC, 0xAF, 0x49, 0xC4, 0x46, 0x7C, 0x32, 0x24, 0xB2, 0x4C, 0x84, 0x45, 0xD2, 0xB9, 0xDF, 0xF7, - 0xF0, 0xF5, 0xEE, 0x16, 0xA4, 0xAD, 0x4F, 0x7C, 0xEF, 0x46, 0x85, 0xC5, 0x87, 0xDB, 0x0B, 0x57, - 0x19, 0x73, 0xE2, 0xCE, 0xD2, 0xFD, 0x3D, 0x03, 0x00, 0x00, 0xE8, 0x08, 0x6F, 0xDF, 0x55, 0xA3, - 0x3A, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xC5, 0xC2, 0x22, 0xC9, 0x64, 0x54, 0x24, 0x5D, 0x24, - 0x3E, 0x82, 0xD5, 0xDC, 0x78, 0x84, 0xD1, 0xF1, 0x74, 0x64, 0x9B, 0x3F, 0x64, 0xCE, 0x1F, 0x5C, - 0x6E, 0xCE, 0x0D, 0xF7, 0xDF, 0x15, 0xFC, 0xED, 0xF2, 0x99, 0xA1, 0xFE, 0x59, 0xE7, 0x47, 0x56, - 0x8C, 0x9B, 0xDD, 0x7D, 0xF6, 0x60, 0x2F, 0x62, 0x23, 0x3E, 0x19, 0x12, 0x59, 0x26, 0xA2, 0x22, - 0xED, 0x76, 0xCF, 0x35, 0xDE, 0xC8, 0xB2, 0x71, 0xF7, 0x7B, 0x08, 0x7E, 0x3B, 0x3D, 0xAF, 0xD0, - 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x9F, 0x07, 0x02, 0x00, 0x00, 0x90, 0x07, 0xB3, 0xEF, 0x0A, - 0x7B, 0xB8, 0x57, 0x81, 0xD1, 0x6C, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, 0x48, - 0xBA, 0x48, 0x78, 0x44, 0x6F, 0x3E, 0xE2, 0xB7, 0x1E, 0x7E, 0x78, 0xBC, 0xCF, 0x9C, 0x7B, 0x6A, - 0x72, 0xE7, 0x77, 0xCE, 0x77, 0xB7, 0x20, 0x35, 0x07, 0xF6, 0xF3, 0x07, 0xFB, 0xD7, 0x7B, 0xC3, - 0xCB, 0x8C, 0xE7, 0x6E, 0x3F, 0x5A, 0x05, 0x88, 0x0C, 0x89, 0x2C, 0x13, 0x31, 0x91, 0x76, 0x9B, - 0x66, 0xD8, 0x1F, 0xED, 0xAF, 0xA9, 0x44, 0xB7, 0x20, 0x53, 0x11, 0x1F, 0x6E, 0xDE, 0xD1, 0x5B, - 0xA6, 0xDD, 0x6B, 0x8C, 0x01, 0x00, 0x00, 0x72, 0x67, 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x8B, 0xED, - 0x01, 0x5F, 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x58, 0x24, 0x99, 0x8C, 0x8A, 0xA4, - 0x8B, 0xC4, 0x47, 0x83, 0x00, 0x09, 0xE3, 0xE3, 0x5C, 0x24, 0x3E, 0xCE, 0x6E, 0x0C, 0xF6, 0xD4, - 0xFB, 0xCD, 0xF9, 0x03, 0xCB, 0x8D, 0x8B, 0x0E, 0xFF, 0xEF, 0x99, 0x0D, 0x91, 0x73, 0xC3, 0x2B, - 0xC6, 0xBD, 0x5D, 0x7D, 0xF6, 0xBF, 0x7F, 0x91, 0x3F, 0xFF, 0x50, 0xAF, 0x42, 0x44, 0x86, 0x44, - 0x96, 0x89, 0x98, 0x48, 0x3B, 0x17, 0x1F, 0xE1, 0x4A, 0x72, 0x0B, 0x32, 0x55, 0xF1, 0xE1, 0xEF, - 0xE8, 0xE7, 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xBB, 0xCC, 0xC8, 0xEA, 0x01, 0xB3, 0xEB, 0x52, - 0x7B, 0xC8, 0x57, 0xA1, 0xA1, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, - 0x4B, 0x1F, 0x1F, 0xD5, 0xF0, 0x78, 0xD2, 0x6D, 0x96, 0xBF, 0x73, 0x3B, 0xE6, 0x9B, 0xB3, 0x07, - 0x2A, 0xB7, 0x20, 0x2E, 0x44, 0xCE, 0x1F, 0x5C, 0x66, 0xFF, 0xFB, 0x7F, 0xDC, 0x3C, 0x40, 0x64, - 0x48, 0x64, 0x99, 0x88, 0x89, 0xB4, 0x8B, 0xC6, 0x87, 0x9B, 0xFB, 0xB5, 0x1E, 0xBC, 0xB6, 0xA7, - 0x6F, 0x41, 0xA6, 0x34, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0xEC, 0x5F, 0x33, 0xF8, 0xCB, 0x03, 0x00, - 0x00, 0x20, 0x0B, 0xEF, 0xD0, 0xAA, 0xBB, 0xCC, 0xF6, 0x4F, 0xD8, 0x83, 0xBE, 0x8A, 0x8D, 0xF8, - 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, 0x74, 0xB1, 0xF8, 0x08, 0x02, 0x24, - 0x49, 0x7C, 0xBC, 0x6B, 0xE3, 0xE3, 0xDD, 0xC1, 0x59, 0x93, 0xDB, 0xF8, 0x7E, 0x73, 0x6E, 0xEF, - 0xF5, 0xE6, 0xDC, 0x81, 0x81, 0x51, 0xF7, 0xED, 0x58, 0xE7, 0xB7, 0x5F, 0x62, 0xFF, 0xBB, 0x36, - 0x3E, 0xDC, 0x54, 0x84, 0xC8, 0x90, 0xC8, 0x32, 0x11, 0x13, 0x69, 0x17, 0x8F, 0x8F, 0x70, 0x3B, - 0x3E, 0xE9, 0x02, 0xC4, 0xBD, 0xE5, 0x6B, 0x76, 0xF0, 0x8F, 0x43, 0xCF, 0x98, 0xF2, 0xF8, 0x70, - 0x1B, 0x5B, 0x66, 0xCC, 0x89, 0xAF, 0xAC, 0x0D, 0x7E, 0x09, 0x00, 0x00, 0x00, 0xC8, 0xC2, 0x3B, - 0xBC, 0x7A, 0x83, 0x8E, 0x8D, 0xF8, 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, - 0x74, 0x3A, 0x3E, 0xEA, 0x02, 0xC4, 0x86, 0x47, 0xF8, 0xCC, 0x47, 0x3C, 0x3E, 0x26, 0xDC, 0x9E, - 0xA8, 0xCC, 0xFD, 0xFF, 0x67, 0xB7, 0x7C, 0xDA, 0x4C, 0x3C, 0xD3, 0x6F, 0xCE, 0x0D, 0xD9, 0x10, - 0x79, 0xCA, 0xFD, 0x77, 0x2F, 0xD2, 0x11, 0xB2, 0x49, 0x85, 0x44, 0x96, 0x89, 0x98, 0x48, 0x3B, - 0x15, 0x1E, 0xD1, 0x1D, 0xBC, 0xD6, 0xBD, 0x96, 0x77, 0x30, 0xF8, 0xC7, 0xA1, 0x27, 0x74, 0x24, - 0x3E, 0xDC, 0x5E, 0xBC, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0xB4, 0xCB, 0x3B, 0x78, 0x4D, 0x82, - 0x37, 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0xE1, 0x11, - 0x2E, 0x1E, 0x1F, 0xE1, 0xED, 0x47, 0xE4, 0x99, 0x0F, 0x17, 0x1F, 0xD1, 0xF0, 0x98, 0x78, 0x3C, - 0x98, 0xFB, 0xBF, 0x1F, 0x9B, 0x65, 0x4E, 0x3F, 0x72, 0x9D, 0x39, 0xF3, 0xF0, 0x25, 0x7E, 0x80, - 0x9C, 0xF3, 0x1F, 0x58, 0x8F, 0x05, 0x88, 0x8B, 0x8F, 0x5C, 0x02, 0x44, 0xC4, 0x44, 0xDA, 0xA9, - 0xE0, 0x88, 0xAF, 0xC7, 0x6E, 0x41, 0x3A, 0x16, 0x1F, 0xC1, 0xBC, 0x5F, 0xDC, 0x39, 0x14, 0xFC, - 0x52, 0x00, 0x00, 0x00, 0x90, 0x85, 0xB7, 0xFF, 0xEA, 0x93, 0x3A, 0x3A, 0xC2, 0xA9, 0xA0, 0x48, - 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x78, 0xB8, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, - 0xDE, 0x7E, 0xD4, 0x7E, 0xEB, 0x55, 0x34, 0x3E, 0xCE, 0xD8, 0xE8, 0x38, 0xF3, 0xF8, 0xFB, 0x82, - 0x55, 0x22, 0xE4, 0xF4, 0xFD, 0x17, 0x99, 0x53, 0xF7, 0x5E, 0x6C, 0x4E, 0xDD, 0x7D, 0x91, 0x39, - 0x6B, 0xFF, 0x33, 0x75, 0xB7, 0x20, 0x36, 0x3C, 0xDC, 0xDA, 0x0F, 0x10, 0x11, 0x13, 0x69, 0xA7, - 0x62, 0xA3, 0xD1, 0x7A, 0xE4, 0x16, 0xA4, 0xD3, 0xF1, 0xE1, 0xE6, 0x1D, 0xFB, 0x53, 0xDE, 0x84, - 0x05, 0x00, 0x00, 0xD0, 0x8E, 0xE6, 0x6F, 0xC0, 0x52, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, - 0x46, 0x45, 0xD2, 0xC5, 0xA2, 0x23, 0xBA, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDC, 0x7E, 0xD4, 0x7C, - 0xDB, 0x55, 0x18, 0x1F, 0x8F, 0xD9, 0xF0, 0xB0, 0x3B, 0x1D, 0xFC, 0x78, 0xE6, 0x91, 0xF7, 0xF9, - 0xE1, 0x11, 0xEE, 0xF4, 0x7D, 0x36, 0x42, 0x36, 0x4E, 0x46, 0x88, 0xF7, 0x74, 0x25, 0x3E, 0xAA, - 0x01, 0x92, 0x39, 0x42, 0x44, 0x4C, 0xA4, 0x9D, 0x8A, 0x8C, 0x66, 0xDB, 0x7E, 0x71, 0xD7, 0xDF, - 0x82, 0x74, 0x43, 0x7C, 0xF8, 0x3B, 0x76, 0x0B, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xC8, 0xCA, 0x7F, - 0x03, 0xD6, 0xEE, 0x79, 0xF6, 0xE0, 0x5F, 0xFE, 0xF8, 0x70, 0x3F, 0x36, 0xBF, 0xFD, 0xB0, 0xF1, - 0xE1, 0x02, 0x24, 0x88, 0x0F, 0x17, 0x1E, 0xA7, 0x1F, 0x9D, 0xDC, 0xA9, 0x7B, 0x67, 0xD5, 0x04, - 0x88, 0xDB, 0xBB, 0x3F, 0x0E, 0x02, 0xE4, 0xA9, 0x0B, 0xED, 0xCF, 0x67, 0xE3, 0x23, 0x1E, 0x21, - 0x32, 0x30, 0x9A, 0x4D, 0xC4, 0x44, 0xDA, 0xA9, 0xC0, 0x48, 0xB2, 0x7D, 0x57, 0x18, 0x6F, 0x78, - 0x79, 0x57, 0x7E, 0xD0, 0x5E, 0xD7, 0xC4, 0x87, 0x9B, 0x7B, 0x13, 0xD6, 0xCB, 0x77, 0xF6, 0xDC, - 0x43, 0xFB, 0x00, 0x00, 0x00, 0x5D, 0xC1, 0x1C, 0x5A, 0xB5, 0xD6, 0xEC, 0x9C, 0x6D, 0x0F, 0xFF, - 0x25, 0x8E, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDD, 0x7E, 0xB8, 0xD7, 0xEC, 0x46, 0x6F, - 0x3F, 0xE2, 0xF1, 0x71, 0xFA, 0x81, 0xDA, 0xDB, 0x8F, 0x70, 0xEE, 0x16, 0xE4, 0xDC, 0x93, 0x76, - 0x1B, 0x2F, 0xF2, 0x23, 0xA4, 0x26, 0x40, 0x5C, 0x50, 0xA4, 0x8A, 0x10, 0x11, 0x13, 0x69, 0xA7, - 0xC2, 0x22, 0xE9, 0xB6, 0x7D, 0x24, 0xB8, 0x05, 0x59, 0x3A, 0x10, 0xFC, 0xE3, 0xD1, 0x15, 0xBA, - 0x2A, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0xB3, 0xAB, 0xFE, 0x1E, 0x01, 0x00, 0x00, 0xF4, - 0x0C, 0x73, 0x78, 0xF5, 0x7A, 0xB3, 0xF5, 0xC3, 0x36, 0x00, 0x4A, 0x1C, 0x1F, 0xC1, 0xD4, 0xED, - 0xC7, 0x59, 0x3F, 0x40, 0x6C, 0x7C, 0xB8, 0xDB, 0x8F, 0xC8, 0xB7, 0x5E, 0x55, 0xC3, 0xE3, 0xC7, - 0x95, 0xA9, 0xDB, 0x0F, 0x7F, 0x5F, 0xBF, 0xD0, 0xBC, 0xFB, 0x48, 0x25, 0x40, 0xCE, 0xB5, 0x75, - 0x0B, 0x22, 0x62, 0x22, 0xED, 0x54, 0x54, 0xA4, 0x9D, 0xBB, 0x05, 0x39, 0xB8, 0xAC, 0x6B, 0x6E, - 0x41, 0xBA, 0x2E, 0x3E, 0xDC, 0x78, 0x13, 0x16, 0x00, 0x00, 0x40, 0x76, 0xDE, 0xC8, 0x8A, 0xA1, - 0xD2, 0xC7, 0x47, 0xC3, 0xDB, 0x8F, 0x59, 0xD5, 0xF8, 0xA8, 0xDE, 0x7E, 0x84, 0xF1, 0x11, 0x84, - 0x87, 0x1F, 0x1F, 0x3F, 0xD2, 0xB7, 0x1F, 0x2E, 0x3E, 0xDC, 0x4E, 0x7F, 0xEB, 0x42, 0x73, 0xB6, - 0xAD, 0x5B, 0x10, 0x11, 0x13, 0x69, 0xA7, 0x62, 0x22, 0xCB, 0xB6, 0xD9, 0x18, 0x1D, 0x5E, 0xD6, - 0x15, 0xB7, 0x20, 0x5D, 0x19, 0x1F, 0xC1, 0xBC, 0x13, 0x5F, 0xEE, 0xA9, 0xD7, 0x16, 0x03, 0x00, - 0x00, 0x74, 0x0D, 0x6F, 0xDF, 0x55, 0x63, 0x65, 0xBF, 0xF9, 0x70, 0xAB, 0xBF, 0xFD, 0x88, 0x04, - 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x70, 0x44, 0x02, 0xE4, 0x94, 0x7B, 0xE8, 0xDC, 0xED, 0xDB, 0xE2, - 0xF6, 0x23, 0x88, 0x8F, 0x70, 0x13, 0x0F, 0x64, 0xBD, 0x05, 0x11, 0x31, 0x91, 0x76, 0x2A, 0x24, - 0x32, 0xED, 0x82, 0xCA, 0xF6, 0x5C, 0xD6, 0xF1, 0x5B, 0x90, 0x6E, 0x8E, 0x0F, 0x37, 0xEF, 0xF8, - 0x9F, 0x75, 0xE5, 0xB3, 0x32, 0x00, 0x00, 0x00, 0x5D, 0xCF, 0xEC, 0xBD, 0xDC, 0x86, 0x40, 0x89, - 0xE3, 0x23, 0xC1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xC1, 0xB7, 0x5E, 0x9D, 0x0A, 0x03, 0xE4, 0x07, - 0xAD, 0xE3, 0xC3, 0xED, 0xF4, 0x3D, 0x2D, 0x6E, 0x41, 0xE4, 0x44, 0x4C, 0xA4, 0x9D, 0x0C, 0x89, - 0x2C, 0x0B, 0xE2, 0xC3, 0xCD, 0xFD, 0xFD, 0xF5, 0x6F, 0x41, 0x96, 0xAF, 0x0B, 0xFE, 0x31, 0x99, - 0x52, 0xDD, 0x1E, 0x1F, 0xFE, 0x8E, 0xFF, 0x29, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x48, 0xCB, 0xBD, - 0x72, 0xD5, 0xEC, 0x59, 0x64, 0x63, 0x40, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0xBA, 0xA0, - 0x48, 0x33, 0x11, 0x1A, 0x8D, 0x16, 0x0F, 0x90, 0xE0, 0xF6, 0xE3, 0x6C, 0x92, 0xDB, 0x8F, 0x87, - 0xED, 0xEE, 0x69, 0x1D, 0x1F, 0xE1, 0xC2, 0x5B, 0x90, 0x64, 0x6F, 0xC4, 0x12, 0x31, 0x91, 0x76, - 0x32, 0x24, 0xB2, 0x2C, 0x12, 0x1F, 0xE1, 0x86, 0x16, 0x1A, 0xEF, 0xE0, 0xD2, 0x93, 0xC1, 0x3F, - 0x2A, 0x53, 0xA6, 0x27, 0xE2, 0xC3, 0xED, 0xC8, 0x6A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0x90, 0x96, - 0xFF, 0x0A, 0xDE, 0x9D, 0x9F, 0xB2, 0x41, 0xA0, 0xA2, 0x22, 0xE9, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, - 0x8A, 0xA4, 0x13, 0x91, 0xA1, 0x66, 0x83, 0xA3, 0x1A, 0x1F, 0x36, 0x3C, 0x12, 0xDF, 0x7E, 0x44, - 0xBF, 0xF5, 0xEA, 0xFB, 0xB1, 0xDB, 0x0F, 0x11, 0x1D, 0xD1, 0x25, 0xBF, 0x05, 0x11, 0x31, 0x91, - 0x76, 0x32, 0x24, 0xB2, 0x4C, 0xC4, 0x87, 0x9B, 0xFB, 0x7B, 0x3D, 0xC5, 0xB7, 0x20, 0x3D, 0x13, - 0x1F, 0x3F, 0xBF, 0xDC, 0x98, 0xB1, 0x15, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x20, 0x2D, 0x73, 0x78, - 0xE5, 0x7A, 0xB3, 0xED, 0xA3, 0x36, 0x0A, 0x54, 0x58, 0x24, 0x99, 0x88, 0x8B, 0x56, 0xAB, 0x0B, - 0x8A, 0x34, 0x8B, 0x45, 0x46, 0xB3, 0x45, 0x03, 0xC4, 0xAE, 0x12, 0x1F, 0x36, 0x0E, 0xC2, 0x00, - 0x69, 0xF4, 0xDA, 0xDD, 0x46, 0xB7, 0x1F, 0x22, 0x38, 0xD4, 0x26, 0x7E, 0x50, 0x09, 0x90, 0x9A, - 0x67, 0x41, 0x82, 0x10, 0xA9, 0xDC, 0x82, 0x88, 0x98, 0x48, 0x3B, 0x19, 0x12, 0x59, 0x26, 0xC2, - 0x23, 0xBA, 0x29, 0xBC, 0x05, 0xE9, 0xA9, 0xF8, 0x70, 0x7B, 0xF1, 0x3A, 0x63, 0x7F, 0xBD, 0x77, - 0x05, 0xBF, 0x7C, 0x00, 0x00, 0x00, 0x24, 0xE1, 0x1D, 0x5E, 0xB9, 0x41, 0x87, 0x45, 0x92, 0x89, - 0xB8, 0x68, 0x35, 0x19, 0x15, 0x49, 0x17, 0x0B, 0x8C, 0x66, 0x8B, 0xC5, 0x47, 0xE5, 0xF6, 0x23, - 0x12, 0x1F, 0xCD, 0x6E, 0x3F, 0xC2, 0x00, 0x89, 0xDE, 0x7E, 0x88, 0xD0, 0x68, 0xB8, 0x6F, 0x5C, - 0x68, 0xCE, 0x3E, 0xD1, 0xE0, 0x16, 0x64, 0x93, 0x88, 0x89, 0xB4, 0x93, 0x21, 0x91, 0x65, 0x22, - 0x38, 0xE2, 0x73, 0x7F, 0xDF, 0x0F, 0x5E, 0x57, 0xF8, 0x2D, 0x48, 0xCF, 0xC5, 0x47, 0x30, 0xEF, - 0xC4, 0x9D, 0x1B, 0x82, 0xDF, 0x02, 0x00, 0x00, 0x00, 0x92, 0xF0, 0x0E, 0x5E, 0x3D, 0xAA, 0xE3, - 0xA2, 0xD5, 0x44, 0x5C, 0xB4, 0x5A, 0x5D, 0x50, 0xA4, 0x59, 0x2C, 0x30, 0x9A, 0xAD, 0x41, 0x7C, - 0xF8, 0xB7, 0x1F, 0x2E, 0x3E, 0xD4, 0xED, 0x47, 0x10, 0x1F, 0xD5, 0xDB, 0x8F, 0x87, 0xEC, 0xBE, - 0x91, 0x21, 0x3E, 0x82, 0x85, 0xB7, 0x20, 0xE7, 0x9F, 0x72, 0x7F, 0xDD, 0x20, 0x42, 0x9E, 0x9E, - 0x69, 0x7F, 0x2D, 0x2E, 0x20, 0x82, 0xA9, 0xB8, 0x68, 0x35, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, - 0xD1, 0x76, 0xCD, 0x31, 0xDE, 0xF0, 0xD2, 0x71, 0x33, 0xD4, 0x3F, 0x2B, 0xF8, 0xC7, 0x26, 0x57, - 0xBD, 0x1A, 0x1F, 0x7E, 0x80, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x74, 0xBC, 0xFD, 0x9F, 0x1D, - 0xD7, 0x81, 0xD1, 0x6C, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xC5, 0x02, 0xA3, 0xD5, 0xEA, - 0x02, 0x24, 0x88, 0x8F, 0xF8, 0xED, 0x47, 0x10, 0x1F, 0xF2, 0xD9, 0x8F, 0xFB, 0x83, 0xDB, 0x0F, - 0x11, 0x17, 0x89, 0x16, 0xBB, 0x05, 0x39, 0x1F, 0xC4, 0x47, 0x5B, 0x01, 0x22, 0x43, 0x22, 0xCB, - 0x44, 0x64, 0x34, 0x9B, 0x7B, 0x66, 0xC5, 0xDD, 0x82, 0x1C, 0x5C, 0x9A, 0xFB, 0x07, 0xEF, 0xF5, - 0x72, 0x7C, 0xB8, 0x79, 0xC7, 0xFE, 0x64, 0x3C, 0xF8, 0xAD, 0x00, 0x00, 0x00, 0xA0, 0x15, 0x33, - 0xDA, 0x3F, 0x2B, 0xFD, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x8B, 0xC5, 0x45, - 0x92, 0xC5, 0xE3, 0x23, 0x7A, 0xFB, 0x11, 0xC4, 0x47, 0xCD, 0x9B, 0xAF, 0x1A, 0xDD, 0x7E, 0xA8, - 0xB0, 0x48, 0xB1, 0x33, 0xDF, 0xBB, 0x70, 0xF2, 0x59, 0x90, 0xA7, 0x6C, 0x7C, 0xB4, 0x13, 0x21, - 0x32, 0x24, 0xB2, 0x4C, 0x04, 0x46, 0x92, 0x15, 0x70, 0x0B, 0xD2, 0xEB, 0xF1, 0xE1, 0xEF, 0xC8, - 0x4D, 0xC6, 0x8C, 0xFD, 0x87, 0x42, 0x6E, 0x86, 0x00, 0x00, 0x00, 0x4A, 0xC7, 0x7F, 0x03, 0xD6, - 0xAE, 0x4F, 0xDB, 0x48, 0x50, 0xA1, 0xA1, 0x26, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, - 0x8B, 0x56, 0xB3, 0xD1, 0x31, 0x19, 0x20, 0x17, 0x55, 0x02, 0x24, 0xB8, 0xFD, 0xA8, 0xBE, 0x76, - 0xB7, 0x7A, 0xFB, 0xF1, 0xBE, 0xC6, 0xB7, 0x1F, 0x22, 0x28, 0xB2, 0xEC, 0xEC, 0x63, 0x2E, 0x42, - 0x2A, 0x01, 0xE2, 0xDF, 0x82, 0x64, 0x89, 0x10, 0x19, 0x12, 0x59, 0x26, 0xC2, 0x22, 0xE9, 0x72, - 0xBE, 0x05, 0x29, 0x45, 0x7C, 0xB8, 0xBD, 0x34, 0xC0, 0x9B, 0xB0, 0x00, 0x00, 0x00, 0x92, 0x32, - 0x87, 0x57, 0xAD, 0x4B, 0xFE, 0x0A, 0x5E, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x61, - 0x91, 0x74, 0xF1, 0xF8, 0xC8, 0x74, 0xFB, 0xA1, 0x63, 0x22, 0xFD, 0x66, 0x9A, 0x33, 0xF7, 0xCF, - 0x34, 0x67, 0x9F, 0x9C, 0x8C, 0x90, 0xD4, 0x01, 0x22, 0x43, 0x22, 0xCB, 0x44, 0x54, 0xA4, 0xDD, - 0xCE, 0xD9, 0xC6, 0x1B, 0xBE, 0xBE, 0xED, 0x5B, 0x90, 0xD2, 0xC4, 0x87, 0x1B, 0x6F, 0xC2, 0x02, - 0x00, 0x00, 0x48, 0xCE, 0xB8, 0x57, 0xF0, 0xCA, 0xD8, 0x88, 0x4F, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, - 0x48, 0x3A, 0x11, 0x16, 0x49, 0xE6, 0x6E, 0x3F, 0xEC, 0x8F, 0x7E, 0x7C, 0xC4, 0x6E, 0x3F, 0xEA, - 0x9F, 0xFD, 0x68, 0x70, 0xFB, 0x71, 0x5F, 0xFB, 0xDF, 0x7A, 0x55, 0xD9, 0xCC, 0xEA, 0xDE, 0x0D, - 0x6E, 0x41, 0xCE, 0x35, 0xBA, 0x05, 0x51, 0xE1, 0xE1, 0x26, 0x43, 0x22, 0xCB, 0x44, 0x4C, 0x64, - 0xDA, 0x7B, 0x8D, 0x39, 0x70, 0xB5, 0x7B, 0x2D, 0xEF, 0x60, 0xF0, 0x8F, 0x50, 0x6A, 0xA5, 0x8A, - 0x0F, 0xB7, 0xE7, 0xAF, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x49, 0x79, 0x07, 0xAF, 0x4B, 0xF0, - 0x06, 0x2C, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x51, 0x91, 0x66, 0xE1, 0xCD, 0x47, - 0x83, 0xDB, 0x8F, 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0x78, 0x30, 0xAF, 0x6F, 0xBD, 0x9A, 0x8C, 0x0F, - 0xB7, 0x4C, 0xB7, 0x20, 0x32, 0x24, 0xB2, 0x4C, 0x85, 0x44, 0x96, 0xD9, 0xF8, 0x70, 0xDB, 0xFE, - 0x71, 0xF7, 0x6D, 0x58, 0xC6, 0x8C, 0x5C, 0x9B, 0xFA, 0x13, 0xC0, 0x4B, 0x17, 0x1F, 0xC1, 0xBC, - 0x13, 0x77, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x24, 0xBC, 0x7D, 0x57, 0x8E, 0xE9, 0xE8, 0x08, - 0x27, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, 0x8A, 0xA4, 0xF3, 0x6F, 0x3F, 0x82, 0xF8, - 0x88, 0xDD, 0x7E, 0xA8, 0x67, 0x3F, 0xEA, 0x3F, 0x74, 0xD0, 0xC6, 0x47, 0x2E, 0xB7, 0x1F, 0xB5, - 0xF1, 0x11, 0xEE, 0xDD, 0x47, 0x5A, 0x3C, 0x0B, 0xD2, 0x0B, 0xF1, 0xF1, 0x74, 0xB0, 0xFD, 0xE9, - 0x6F, 0x41, 0xCA, 0x1A, 0x1F, 0x6E, 0xDE, 0xB1, 0x5B, 0xA6, 0xE4, 0x83, 0x1A, 0x01, 0x00, 0x00, - 0x7A, 0x9E, 0xD9, 0x7B, 0x99, 0x8D, 0x06, 0x15, 0x1E, 0x6E, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, - 0xD2, 0xC5, 0x82, 0x22, 0xED, 0xC2, 0xF0, 0x68, 0x70, 0xFB, 0x51, 0xF7, 0xEC, 0x47, 0x10, 0x20, - 0x95, 0xDB, 0x0F, 0x1B, 0x1F, 0xB9, 0xDC, 0x7E, 0xE8, 0xF8, 0x70, 0x3B, 0x7D, 0xEF, 0x4C, 0x73, - 0xAE, 0xD1, 0x2D, 0x88, 0x1F, 0x1D, 0x3D, 0x12, 0x1F, 0xF6, 0xFF, 0xF6, 0xB6, 0x7F, 0xDC, 0x05, - 0x48, 0xE2, 0x5B, 0x90, 0x32, 0xC7, 0x87, 0xBF, 0x23, 0x37, 0x99, 0xE0, 0xB7, 0x0A, 0x00, 0x00, - 0x80, 0x46, 0xCC, 0xE1, 0xFE, 0x25, 0x66, 0x68, 0xBE, 0x0D, 0x87, 0x72, 0xC4, 0x47, 0xCB, 0xDB, - 0x0F, 0x11, 0x1F, 0x95, 0xDB, 0x0F, 0x1B, 0x1E, 0xB9, 0xDC, 0x7E, 0xE8, 0xF0, 0x88, 0x2E, 0xBC, - 0x05, 0x69, 0xF8, 0x2C, 0x88, 0x0C, 0x89, 0x2C, 0x53, 0x21, 0x91, 0x65, 0x22, 0x3E, 0xEC, 0x8F, - 0xFE, 0xF6, 0x7C, 0xC6, 0x9C, 0x3F, 0x70, 0xFD, 0x50, 0xF0, 0x8F, 0x53, 0x43, 0xA5, 0x8F, 0x0F, - 0x37, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x9A, 0xFF, 0x0A, 0x5E, 0xF9, 0x06, 0x2C, 0x11, 0x17, - 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x50, 0xA4, 0x9A, 0x8D, 0x8F, 0x30, 0x3C, 0xC2, 0xF8, 0x48, - 0x7A, 0xFB, 0xF1, 0x63, 0x1B, 0x1E, 0x2E, 0x40, 0x7E, 0xD8, 0xEE, 0xED, 0x87, 0x0E, 0x8E, 0xF8, - 0xDC, 0x2D, 0x48, 0xE3, 0x67, 0x41, 0x54, 0x48, 0x64, 0x99, 0x0A, 0x89, 0x2C, 0x6B, 0x12, 0x1F, - 0x4F, 0xBD, 0xD7, 0x9C, 0xDF, 0xF2, 0x21, 0x73, 0x7E, 0xFF, 0x32, 0x73, 0x76, 0xFF, 0xD2, 0x86, - 0x07, 0xEF, 0x69, 0x11, 0x1F, 0x6E, 0x2F, 0x5E, 0xE7, 0x02, 0x64, 0x5D, 0xF0, 0xDB, 0x06, 0x00, - 0x00, 0x80, 0xE2, 0xBF, 0x01, 0x6B, 0xEB, 0x87, 0x6C, 0x40, 0xF4, 0x7E, 0x7C, 0x64, 0xB9, 0xFD, - 0xA8, 0xC6, 0x87, 0xBB, 0xFD, 0xF8, 0x56, 0x3B, 0xB7, 0x1F, 0x3A, 0x36, 0x1A, 0x6D, 0xE2, 0x21, - 0x75, 0x0B, 0x32, 0xC3, 0x9F, 0x0E, 0x8A, 0x34, 0x53, 0x21, 0x91, 0x65, 0x2D, 0xE2, 0xC3, 0x6D, - 0xE3, 0x05, 0xE6, 0xFC, 0xEE, 0x25, 0xE6, 0xDC, 0xDE, 0x65, 0xF2, 0x01, 0xEC, 0x69, 0x13, 0x1F, - 0x6E, 0xCF, 0x5F, 0x69, 0xCC, 0x89, 0x3B, 0x73, 0xFF, 0x94, 0x78, 0x00, 0x00, 0x80, 0x52, 0xF1, - 0x0E, 0xAD, 0x1C, 0xEC, 0xF9, 0xF8, 0xC8, 0x78, 0xFB, 0x71, 0xEA, 0x51, 0x1B, 0x1D, 0xB9, 0xDC, - 0x7E, 0xE8, 0xC8, 0x68, 0xB6, 0xD3, 0xF7, 0xC4, 0x6F, 0x41, 0x2A, 0xF1, 0xD1, 0x7E, 0x80, 0xA8, - 0x90, 0xC8, 0xB2, 0x64, 0xF1, 0x71, 0xEE, 0x49, 0xBB, 0x4D, 0x1F, 0x76, 0x01, 0x62, 0xCE, 0x0E, - 0xD5, 0xDE, 0x82, 0x4C, 0xAB, 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x6F, 0xC2, 0x02, 0x00, 0x00, - 0x68, 0xC6, 0xDB, 0x77, 0x45, 0xE4, 0x15, 0xBC, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xA9, - 0xA0, 0x48, 0xB3, 0x20, 0x3E, 0x82, 0xA5, 0xBB, 0xFD, 0x88, 0xC4, 0x47, 0x5B, 0xB7, 0x1F, 0x3A, - 0x30, 0x92, 0x6C, 0xE2, 0x81, 0xE8, 0x2D, 0x88, 0x8D, 0x8F, 0xB6, 0x23, 0x44, 0x85, 0x44, 0x96, - 0x25, 0x8F, 0x8F, 0xB3, 0x83, 0x76, 0x4F, 0x5C, 0x60, 0xDE, 0xDD, 0xB1, 0xC4, 0x4C, 0xEC, 0x5E, - 0x5E, 0x3D, 0x7C, 0x4F, 0xC7, 0xF8, 0x70, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x2D, 0x98, 0x7D, - 0xF6, 0x70, 0xD7, 0xEB, 0xF1, 0x91, 0xE6, 0xF6, 0x23, 0x8C, 0x8F, 0x5C, 0x6E, 0x3F, 0x74, 0x58, - 0x24, 0x5D, 0xE5, 0x16, 0x64, 0xA6, 0x8D, 0x10, 0x1B, 0x20, 0x4F, 0xB5, 0x1B, 0x20, 0x2A, 0x24, - 0xB2, 0x2C, 0x43, 0x7C, 0x3C, 0x7E, 0x81, 0x39, 0x33, 0xF8, 0x41, 0x17, 0x20, 0xE6, 0xF4, 0x8E, - 0xA5, 0x03, 0xD3, 0x35, 0x3E, 0xFC, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x00, 0x34, 0x62, - 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x0B, 0x75, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, - 0x66, 0x91, 0xF8, 0x08, 0xA6, 0x6E, 0x3F, 0xAA, 0x01, 0x52, 0x73, 0xFB, 0x31, 0xAB, 0xFE, 0xF6, - 0xE3, 0x9B, 0x2A, 0x2E, 0x5A, 0x4D, 0x47, 0x45, 0x9A, 0xBD, 0xF3, 0xD7, 0x33, 0xCC, 0x99, 0x1F, - 0x4E, 0x06, 0x48, 0xF6, 0x5B, 0x10, 0x15, 0x12, 0x59, 0x96, 0x31, 0x3E, 0x1E, 0x9D, 0x61, 0x4E, - 0xFF, 0xD8, 0xEE, 0x99, 0x45, 0x66, 0xE2, 0xC0, 0xAA, 0x93, 0xD3, 0x36, 0x3E, 0xDC, 0x8E, 0xAC, - 0x32, 0xE6, 0xF8, 0x1D, 0x4B, 0x82, 0x2F, 0x31, 0x00, 0x00, 0x00, 0x44, 0x99, 0x91, 0xFE, 0x01, - 0xB3, 0xF3, 0x12, 0x1D, 0x18, 0xCD, 0x26, 0xA3, 0x22, 0xE9, 0x54, 0x50, 0xA4, 0x59, 0x2C, 0x3E, - 0x12, 0xDC, 0x7E, 0x4C, 0xB8, 0x00, 0x79, 0xDC, 0xDD, 0x7E, 0xC4, 0xE2, 0xC3, 0xED, 0x7B, 0x59, - 0xBE, 0xF5, 0x4A, 0x07, 0x45, 0x9A, 0xB9, 0xF8, 0xF0, 0x77, 0xF7, 0x0C, 0x7B, 0x90, 0x6F, 0xE7, - 0x16, 0x44, 0x85, 0x44, 0x96, 0xB5, 0x17, 0x1F, 0xA7, 0x1E, 0x76, 0x01, 0x32, 0xDB, 0x98, 0x63, - 0x77, 0x9A, 0x69, 0x1B, 0x1F, 0x3F, 0xBF, 0xCC, 0x98, 0x17, 0x3F, 0x67, 0xCC, 0x89, 0x2F, 0xAD, - 0x0D, 0xBE, 0xC4, 0x00, 0x00, 0x00, 0x10, 0xE5, 0x1D, 0x5A, 0x75, 0x97, 0xD9, 0x7E, 0xB1, 0x8E, - 0x8C, 0x46, 0x93, 0x51, 0x91, 0x74, 0x2A, 0x28, 0xD2, 0x2C, 0x16, 0x1F, 0x2A, 0x40, 0x1A, 0x3E, - 0xFB, 0x61, 0xE3, 0x23, 0x97, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0x56, 0x8D, 0x8F, 0x60, 0x67, 0xBE, - 0x5F, 0x09, 0x90, 0x73, 0xD1, 0x5B, 0x90, 0x20, 0x44, 0x74, 0x74, 0x84, 0x53, 0x21, 0x91, 0x65, - 0x39, 0xC4, 0xC7, 0xD3, 0x1F, 0x33, 0xDE, 0xD1, 0xDB, 0xA7, 0x77, 0x7C, 0xB8, 0x3D, 0xFF, 0x59, - 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x88, 0x19, 0x59, 0xB9, 0x5E, 0x46, 0x46, 0xA3, 0xC9, 0xA8, - 0x48, 0x3A, 0x15, 0x14, 0x69, 0x56, 0x1F, 0x1E, 0xD5, 0xF8, 0xB0, 0xE1, 0x31, 0x79, 0xFB, 0x11, - 0xF9, 0xD6, 0xAB, 0xEA, 0xED, 0xC7, 0x45, 0x95, 0xDB, 0x0F, 0xBB, 0xF6, 0x6E, 0x3F, 0x74, 0x50, - 0xA4, 0x59, 0x3C, 0x3E, 0xFC, 0x65, 0xBA, 0x05, 0x51, 0x21, 0x91, 0x65, 0xC4, 0x47, 0xFB, 0x0B, - 0xE2, 0x23, 0x98, 0xF7, 0x8B, 0x3B, 0x5B, 0x7E, 0x30, 0x23, 0x00, 0x00, 0xC0, 0xB4, 0xE4, 0x1D, - 0xB8, 0x7A, 0x54, 0x86, 0x86, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, 0x66, 0xB1, 0xF8, 0x88, - 0x07, 0x88, 0x5D, 0xF5, 0x5B, 0xAF, 0xC2, 0x00, 0xA9, 0x3E, 0x78, 0x6E, 0xE3, 0xC3, 0x06, 0x48, - 0xFB, 0xB7, 0x1F, 0x3A, 0x28, 0xD2, 0x4C, 0xC6, 0x47, 0xB0, 0xF0, 0x16, 0xC4, 0xBD, 0x92, 0xB7, - 0xF5, 0x2D, 0x88, 0x0A, 0x89, 0x2C, 0x23, 0x3E, 0xDA, 0x5F, 0x6D, 0x7C, 0xF8, 0x01, 0x72, 0xF4, - 0xD6, 0xB1, 0xE0, 0x4B, 0x0C, 0x00, 0x00, 0x00, 0x51, 0xDE, 0xFE, 0x2B, 0x4F, 0xCA, 0xD8, 0x88, - 0x4F, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x78, 0x88, 0xF8, 0x08, 0x6F, 0x3F, 0x6A, - 0x1E, 0x3C, 0xF7, 0x6F, 0x3F, 0x2E, 0x9A, 0xBC, 0xFD, 0x08, 0xE3, 0x23, 0x0C, 0x90, 0xFB, 0xD3, - 0xDC, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x1D, 0x35, 0x73, 0xB7, 0x20, 0x8F, 0x4D, 0xDE, 0x82, - 0xF8, 0x11, 0x62, 0x63, 0xA3, 0x3E, 0x40, 0x54, 0x48, 0x64, 0x19, 0xF1, 0xD1, 0xFE, 0xEA, 0xE3, - 0xC3, 0xDF, 0xB1, 0x2F, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x00, 0x25, 0xD1, 0x1B, 0xB0, 0x64, 0x54, - 0x24, 0x9D, 0x0A, 0x8A, 0x34, 0x8B, 0x85, 0x47, 0x93, 0xF8, 0xA8, 0x3E, 0x78, 0x5E, 0xBD, 0xFD, - 0xB0, 0xF1, 0x11, 0xDE, 0x7E, 0xC4, 0xE3, 0xE3, 0x21, 0xBB, 0xBB, 0x55, 0x68, 0xA8, 0xE9, 0xA0, - 0x48, 0x33, 0x19, 0x1C, 0x62, 0xA7, 0xBF, 0x3B, 0x23, 0x78, 0x16, 0xA4, 0xC1, 0xB7, 0x62, 0x3D, - 0xAD, 0x42, 0x22, 0xCB, 0x88, 0x8F, 0xF6, 0x27, 0xC2, 0x23, 0x1C, 0x6F, 0xC2, 0x02, 0x00, 0x00, - 0xA8, 0xE7, 0xBF, 0x01, 0x6B, 0xD7, 0x1C, 0x1D, 0x1D, 0xE1, 0x64, 0x54, 0x24, 0x9D, 0x0A, 0x8A, - 0x34, 0x8B, 0x85, 0x47, 0x38, 0x15, 0x20, 0xF1, 0xD7, 0xEE, 0x3E, 0x39, 0x19, 0x1F, 0xF2, 0xCD, - 0x57, 0x89, 0x6F, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0A, 0x8D, 0x66, 0x7B, 0x37, 0x7E, 0x0B, 0x12, - 0x46, 0x88, 0x8B, 0x8F, 0x70, 0x32, 0x2A, 0x92, 0x8E, 0xF8, 0x68, 0x7F, 0x22, 0x3A, 0xA2, 0x7B, - 0xF1, 0x7A, 0x63, 0x5E, 0xBE, 0xB3, 0xE6, 0x53, 0xE1, 0x01, 0x00, 0x00, 0xA6, 0x3D, 0x73, 0xA8, - 0x7F, 0xAD, 0xD9, 0xF1, 0x49, 0x1D, 0x1E, 0x6E, 0x32, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, 0xC5, - 0xA2, 0x23, 0xBA, 0x78, 0x7C, 0x44, 0x6F, 0x3F, 0x82, 0xF8, 0x98, 0xBC, 0xFD, 0x10, 0xDF, 0x7A, - 0x95, 0xF8, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xA9, 0xC0, 0x68, 0x35, 0x77, 0x0B, 0x52, 0xF7, 0xE1, - 0x84, 0x36, 0x3A, 0xF2, 0x09, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xE0, 0x88, 0xEF, 0x85, 0xAB, 0x79, - 0x13, 0x16, 0x00, 0x00, 0x40, 0x9C, 0xFF, 0x06, 0xAC, 0xAD, 0x1F, 0xEC, 0xB9, 0xF8, 0x68, 0x74, - 0xFB, 0xE1, 0xE2, 0xE3, 0x6C, 0x2C, 0x3E, 0xB2, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x17, - 0x49, 0xF7, 0xEE, 0x8F, 0x2B, 0x01, 0xE2, 0xBF, 0x96, 0xF7, 0x29, 0x1B, 0x1F, 0x6E, 0xD1, 0x08, - 0x91, 0x71, 0xD1, 0x6A, 0xC4, 0x47, 0xFB, 0x13, 0xB1, 0xD1, 0x60, 0xDE, 0x89, 0x2F, 0x0D, 0x06, - 0x5F, 0x6A, 0x00, 0x00, 0x00, 0x70, 0xBC, 0xE1, 0xE5, 0x43, 0x3D, 0x15, 0x1F, 0x6E, 0xF1, 0xF8, - 0x88, 0xDE, 0x7E, 0xB8, 0xF8, 0x68, 0x75, 0xFB, 0xF1, 0xA0, 0x9D, 0x0C, 0x8E, 0xE8, 0x74, 0x50, - 0xA4, 0x99, 0x8A, 0x8A, 0x34, 0x3B, 0xFD, 0xED, 0xE0, 0x16, 0xE4, 0x49, 0x1B, 0x20, 0x36, 0x0A, - 0xEA, 0x02, 0x24, 0x75, 0x84, 0x10, 0x1F, 0xED, 0x4F, 0x87, 0x46, 0xA3, 0x79, 0x47, 0x6F, 0x1D, - 0x0D, 0xBE, 0xD4, 0x00, 0x00, 0x00, 0xE0, 0x78, 0x7B, 0xAF, 0xA8, 0x7F, 0x05, 0xAF, 0x8C, 0x8A, - 0xA4, 0x53, 0x41, 0x91, 0x66, 0x22, 0x38, 0xA2, 0xB3, 0xD1, 0xE1, 0x7E, 0xAC, 0xBB, 0xFD, 0xB0, - 0xF1, 0x71, 0x6E, 0xE3, 0x45, 0xC9, 0x6E, 0x3F, 0xEE, 0x6B, 0x75, 0xFB, 0xA1, 0x83, 0x22, 0xCD, - 0x54, 0x50, 0x64, 0xD9, 0xBB, 0xF6, 0xD0, 0x1F, 0x06, 0x48, 0x7B, 0xB7, 0x20, 0xC4, 0x47, 0xFB, - 0xD3, 0x91, 0xD1, 0x74, 0xC7, 0x6E, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x51, 0x66, 0xEF, 0xE2, - 0xDE, 0x89, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x08, 0x03, 0x24, 0x88, 0x8F, 0x78, 0x80, 0xD4, - 0xC5, 0x47, 0xCB, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0xA6, 0x42, 0x22, 0xDB, 0x2E, 0x30, 0xA7, 0xBF, - 0x6D, 0xA3, 0x60, 0x70, 0x32, 0x42, 0x6A, 0x02, 0xC4, 0x85, 0x45, 0xA2, 0x08, 0x21, 0x3E, 0xDA, - 0x9F, 0x88, 0x8B, 0x24, 0x73, 0x6F, 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x1B, 0x00, 0x00, - 0xC0, 0xF4, 0x66, 0x46, 0xFA, 0x67, 0xD7, 0xBC, 0x82, 0x57, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, - 0x33, 0x11, 0x1B, 0xF1, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, 0xDF, 0x7E, 0xD8, 0xF0, 0x10, 0xB7, 0x1F, - 0xF2, 0x43, 0x07, 0x9B, 0xDE, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x76, 0x41, 0x75, - 0xE1, 0x2D, 0xC8, 0xB9, 0x4C, 0xB7, 0x20, 0xC4, 0x47, 0xFB, 0x13, 0x61, 0x91, 0x74, 0x63, 0xCB, - 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xC8, 0x7F, 0x05, 0x6F, 0xF8, 0x06, 0x2C, 0x19, 0x15, 0x49, - 0xA7, 0x82, 0x22, 0xCD, 0x62, 0xA1, 0xD1, 0x68, 0x61, 0x78, 0x84, 0xF1, 0xE1, 0xF6, 0xD4, 0x85, - 0x35, 0xDF, 0x7A, 0x15, 0x0F, 0x90, 0x53, 0x2E, 0x40, 0xC2, 0xDB, 0x8F, 0x1F, 0xD9, 0xC9, 0xF0, - 0x70, 0xD3, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x6C, 0x32, 0x3E, 0xDC, 0x4E, 0x7D, 0xD3, 0xC5, - 0x41, 0x96, 0x5B, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xA8, 0x48, 0xB3, 0x17, 0x3F, 0xC7, 0x9B, 0xB0, - 0x00, 0x00, 0x00, 0x42, 0xFE, 0x1B, 0xB0, 0xB6, 0x7D, 0xC4, 0x1E, 0xEE, 0x55, 0x54, 0x24, 0x9D, - 0x0A, 0x8A, 0x34, 0x13, 0xA1, 0xA1, 0x66, 0xA3, 0xC3, 0xFD, 0x58, 0x7B, 0xFB, 0x61, 0xE3, 0x23, - 0xCD, 0xED, 0xC7, 0xB7, 0x1A, 0xDD, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x56, 0x1B, - 0x1F, 0xE1, 0x26, 0x7E, 0x94, 0xF6, 0x16, 0x84, 0xF8, 0x68, 0x7F, 0x22, 0x28, 0x32, 0x8C, 0x37, - 0x61, 0x01, 0x00, 0x00, 0x04, 0xBC, 0x91, 0x81, 0x0D, 0x3A, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, - 0xC5, 0x22, 0xA3, 0xD9, 0xC2, 0xF0, 0x88, 0xC4, 0x47, 0xA2, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x68, - 0xD7, 0xA3, 0xF1, 0xE1, 0xD6, 0xF2, 0x16, 0x84, 0xF8, 0xC8, 0x79, 0x3A, 0x26, 0xB2, 0xCC, 0x3B, - 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0x38, 0xDE, 0x81, 0xAB, 0x47, 0x75, 0x58, 0x24, 0x99, - 0x0A, 0x8A, 0x34, 0x13, 0x91, 0xD1, 0x62, 0xD5, 0x00, 0x09, 0xE3, 0xA3, 0xED, 0xDB, 0x0F, 0x1D, - 0x14, 0x69, 0xA6, 0x43, 0x22, 0xCB, 0x74, 0x78, 0x44, 0x17, 0xDE, 0x82, 0xB8, 0x78, 0x68, 0x7C, - 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x12, 0x59, 0xE7, 0x1D, 0xBB, 0x65, 0x3C, 0xF8, 0x92, 0x03, - 0x00, 0x00, 0x98, 0xDE, 0xBC, 0x7D, 0x57, 0x8C, 0xEB, 0xB8, 0x68, 0x35, 0x15, 0x14, 0x69, 0xA6, - 0x03, 0xA3, 0xE1, 0x6A, 0x6E, 0x3F, 0x6C, 0x7C, 0x34, 0xBB, 0xFD, 0x08, 0xE3, 0xA3, 0xE5, 0xED, - 0x87, 0x0E, 0x8A, 0x34, 0xD3, 0x21, 0x91, 0x65, 0x3A, 0x38, 0xE2, 0xF3, 0x6F, 0x41, 0x1E, 0x6F, - 0x76, 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x11, 0x6D, 0xCD, 0xBD, 0x09, 0x6B, 0xEC, 0x8B, 0xB3, - 0x82, 0x2F, 0x3B, 0x00, 0x00, 0x80, 0xE9, 0xCB, 0x0C, 0x2D, 0xB0, 0x07, 0x7C, 0x15, 0x18, 0xCD, - 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x60, 0x24, 0x58, 0x18, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xB9, 0x1F, - 0xC9, 0x6E, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0E, 0x89, 0x2C, 0xD3, 0xB1, 0xD1, 0x68, 0x67, 0xBE, - 0x2F, 0x9E, 0x05, 0xF1, 0x43, 0x24, 0x12, 0x1E, 0x6E, 0xC4, 0x47, 0x86, 0x89, 0x78, 0xC8, 0x63, - 0x63, 0xCB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x80, 0xFF, 0x06, 0xAC, 0x9D, 0xB3, 0xED, 0xE1, 0x5E, - 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0x33, 0x1D, 0x17, 0x4D, 0x17, 0xB9, 0xF9, 0xF0, 0xE3, 0x43, - 0xDC, 0x7E, 0x4C, 0xB8, 0x3D, 0x1E, 0xB9, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xE5, 0x89, 0x0F, - 0x7F, 0x77, 0xAB, 0x5B, 0x90, 0x4A, 0x68, 0x18, 0x1B, 0x19, 0xC4, 0x47, 0xD6, 0x89, 0x70, 0xC8, - 0x65, 0x8B, 0x8D, 0x79, 0xF1, 0x5A, 0xE3, 0xFD, 0xE2, 0x4B, 0x77, 0x05, 0x5F, 0x7A, 0x00, 0x00, - 0x00, 0xD3, 0x93, 0x0D, 0x90, 0x75, 0x66, 0xC7, 0x27, 0xEC, 0x21, 0x5F, 0x85, 0x86, 0x9A, 0x0A, - 0x8A, 0x34, 0x13, 0x71, 0x91, 0x64, 0x61, 0x7C, 0xC4, 0x6E, 0x3F, 0x12, 0x3F, 0xFB, 0xF1, 0xCD, - 0x12, 0xC5, 0x47, 0xB0, 0x33, 0xDF, 0x8B, 0x3E, 0x0B, 0x52, 0x89, 0x8C, 0x70, 0x2E, 0x40, 0xC2, - 0xF0, 0x20, 0x3E, 0x92, 0x4E, 0x85, 0x43, 0x1E, 0xB3, 0xF1, 0xE1, 0x66, 0x7F, 0xED, 0xDE, 0x89, - 0x3B, 0x36, 0x04, 0x5F, 0x7A, 0x00, 0x00, 0x00, 0xD3, 0x93, 0xFF, 0x0A, 0x5E, 0x19, 0x1A, 0x6A, - 0x2A, 0x28, 0xD2, 0x4C, 0x84, 0x45, 0xAB, 0xD9, 0xF0, 0xA8, 0xC6, 0x87, 0x0D, 0x8F, 0xC9, 0xDB, - 0x8F, 0xD8, 0xB7, 0x5E, 0x45, 0x6F, 0x3F, 0xEC, 0x1A, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, - 0x12, 0x59, 0xA6, 0xC3, 0x22, 0xF1, 0xAA, 0xB7, 0x20, 0x36, 0x40, 0x36, 0xBA, 0xC0, 0x08, 0x82, - 0x23, 0x12, 0x1E, 0xC4, 0x47, 0xD2, 0xA9, 0x70, 0xC8, 0x63, 0x41, 0x7C, 0x04, 0xF3, 0x4E, 0xFC, - 0x39, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x9B, 0x77, 0xF0, 0xBA, 0x84, 0x6F, 0xC0, 0x52, 0x41, - 0x91, 0x66, 0xB1, 0xB0, 0x48, 0x3A, 0x17, 0x20, 0xE1, 0xCD, 0x87, 0x5D, 0xF5, 0x5B, 0xAF, 0xE4, - 0xB3, 0x1F, 0x17, 0xB5, 0xB8, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x04, 0x45, - 0x86, 0x9D, 0xFE, 0xCE, 0x7B, 0xFD, 0xB0, 0x08, 0x23, 0xA4, 0x1A, 0x1C, 0x2E, 0x3E, 0x82, 0x28, - 0x21, 0x3E, 0x5A, 0x4D, 0x85, 0x43, 0x1E, 0xAB, 0x8D, 0x0F, 0x3F, 0x40, 0x8E, 0x7D, 0x81, 0x37, - 0x61, 0x01, 0x00, 0x80, 0xE9, 0xCD, 0xDB, 0xFB, 0xD9, 0x31, 0x1D, 0x1C, 0xD1, 0xA9, 0xA0, 0x48, - 0xB3, 0x58, 0x54, 0x24, 0x5D, 0x2C, 0x3E, 0xC2, 0xDB, 0x8F, 0xBA, 0xF8, 0x88, 0xDE, 0x7E, 0x84, - 0xF1, 0x11, 0x06, 0xC8, 0x86, 0xF0, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xE9, 0x90, 0xC8, 0x32, 0x1D, - 0x13, 0xA9, 0xF7, 0x57, 0xEF, 0xF5, 0xF7, 0xEE, 0xA3, 0x93, 0x01, 0x12, 0x9F, 0x1F, 0x27, 0x2E, - 0x3C, 0x88, 0x8F, 0x06, 0x53, 0xE1, 0x90, 0xC7, 0xEA, 0xE3, 0xC3, 0xDF, 0x91, 0x1B, 0x4C, 0xF0, - 0xA5, 0x07, 0x00, 0x00, 0x30, 0x3D, 0x99, 0x3D, 0xF6, 0x50, 0x24, 0xA3, 0x23, 0x9C, 0x0A, 0x8A, - 0x34, 0x8B, 0x45, 0x45, 0xD2, 0x35, 0x88, 0x8F, 0xEA, 0x83, 0xE7, 0xEA, 0xF6, 0x23, 0x1E, 0x1F, - 0x0F, 0xD9, 0xDD, 0x5D, 0xEE, 0xF8, 0x70, 0x73, 0xB7, 0x20, 0x7E, 0x60, 0xD8, 0x9D, 0x7B, 0xD2, - 0x86, 0x87, 0xDD, 0xB9, 0x68, 0x7C, 0xD8, 0xF0, 0x38, 0x6B, 0xC3, 0x83, 0xF8, 0x88, 0x4F, 0x85, - 0x43, 0x1E, 0x8B, 0x45, 0x47, 0x74, 0x2F, 0xAD, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xFA, 0x32, - 0x87, 0xFB, 0x97, 0x98, 0xDD, 0xF3, 0xEC, 0x81, 0x5F, 0x85, 0x87, 0x9B, 0x0A, 0x8A, 0x34, 0x8B, - 0x45, 0x45, 0x9A, 0xD9, 0xE8, 0xA8, 0x0B, 0x90, 0x26, 0xDF, 0x7A, 0x25, 0xDF, 0x7C, 0x75, 0xBF, - 0xBB, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x45, 0xE2, 0x23, - 0x9C, 0xBB, 0x05, 0xF1, 0x43, 0x63, 0xD0, 0xC6, 0x88, 0x0D, 0x90, 0xB3, 0xB1, 0x6F, 0xB9, 0x7A, - 0xF7, 0x31, 0xE2, 0xA3, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x88, 0x8E, 0xE8, 0x5E, 0xBC, 0xD6, 0x06, - 0xC8, 0x1D, 0xEB, 0x82, 0x2F, 0x41, 0x00, 0x00, 0x80, 0xE9, 0xC5, 0x7F, 0x05, 0x6F, 0xC3, 0x37, - 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x15, 0x49, 0xF7, 0x8C, 0x88, 0x8F, 0xE8, 0xED, 0x87, 0x8B, - 0x8F, 0x9A, 0x00, 0x11, 0xDF, 0x7A, 0xE5, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, - 0x26, 0x42, 0x22, 0xCB, 0x44, 0x7C, 0xBC, 0xBD, 0xFE, 0xBD, 0xE6, 0xD4, 0x3D, 0x36, 0x42, 0x5C, - 0x68, 0xB8, 0xE0, 0x70, 0x21, 0x12, 0xFC, 0xE8, 0xFE, 0xB5, 0x09, 0x17, 0x1F, 0x36, 0x3C, 0x4E, - 0x3F, 0x42, 0x7C, 0x54, 0xA6, 0xC2, 0x21, 0x8F, 0x89, 0xE0, 0x88, 0xCF, 0xFD, 0xBE, 0x4E, 0xDC, - 0xB1, 0x3E, 0xF8, 0x12, 0x04, 0x00, 0x00, 0x98, 0x5E, 0xFC, 0x37, 0x60, 0x6D, 0xF9, 0x80, 0x3D, - 0xF4, 0x77, 0x5F, 0x7C, 0x34, 0xBA, 0xFD, 0x50, 0xAF, 0xDD, 0xD5, 0xB7, 0x1F, 0xED, 0x7F, 0xEB, - 0x95, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0x0D, 0xE2, 0x23, 0xDC, 0x99, 0x07, 0x6D, 0x6C, - 0x3C, 0x3E, 0xA3, 0x12, 0x22, 0x41, 0x78, 0x4C, 0x3C, 0x7A, 0x81, 0x7F, 0xEB, 0x41, 0x7C, 0x84, - 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x6C, 0x34, 0x98, 0x77, 0xE2, 0x0E, 0xDE, 0x84, 0x05, 0x00, 0x00, - 0xA6, 0x27, 0xEF, 0xD0, 0xCA, 0xC1, 0xAE, 0x8B, 0x8F, 0x5C, 0x6E, 0x3F, 0x2E, 0x6A, 0xFB, 0xF6, - 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0xD6, 0xD7, 0xEC, 0xBF, 0xF6, - 0x4D, 0x17, 0x1D, 0x33, 0xFC, 0x9D, 0xB1, 0xE1, 0xE1, 0xE6, 0x7F, 0xCB, 0x55, 0x18, 0x1F, 0x4F, - 0x11, 0x1F, 0xC5, 0x4C, 0x87, 0x46, 0xA3, 0x79, 0xC7, 0xBE, 0x70, 0x32, 0xF8, 0x12, 0x04, 0x00, - 0x00, 0x98, 0x5E, 0xBC, 0xBD, 0x57, 0xC4, 0x5E, 0xC1, 0xAB, 0x82, 0x22, 0xCD, 0x44, 0x54, 0x24, - 0x5D, 0x24, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0xA3, 0xFE, 0xD9, 0x0F, 0x75, 0xFB, 0x61, 0xE3, 0xE3, - 0xBE, 0xF6, 0x6E, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x4B, 0x10, 0x1F, 0x6F, 0x7D, - 0xED, 0x02, 0xF3, 0xD6, 0x7F, 0xB9, 0xC0, 0x9C, 0xFA, 0xA1, 0x0D, 0x0D, 0x77, 0xE3, 0xF1, 0x63, - 0x1B, 0x1F, 0x41, 0x78, 0xBC, 0xF3, 0x90, 0xFD, 0x91, 0xF8, 0x28, 0x68, 0x3A, 0x32, 0x9A, 0xEE, - 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x4C, 0x4F, 0x66, 0xAF, 0x3D, 0xF0, 0x75, 0x53, 0x7C, - 0x04, 0x01, 0xD2, 0xEC, 0xF6, 0x23, 0x1E, 0x20, 0x75, 0xF1, 0xF1, 0x60, 0x7B, 0x0F, 0x9E, 0xEB, - 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x96, 0x22, 0x3E, 0xDE, 0xFC, 0xCF, 0xF6, 0xC7, 0xBB, 0x6D, - 0x84, 0x04, 0xD1, 0xE1, 0xEF, 0x41, 0xE2, 0x43, 0x87, 0x43, 0x1E, 0x13, 0x71, 0x91, 0x64, 0x47, - 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xFD, 0x98, 0xD1, 0xFE, 0x59, 0x66, 0x68, 0x81, 0x0D, - 0x80, 0xEE, 0x8A, 0x0F, 0xF7, 0xA3, 0xBA, 0xFD, 0x50, 0xCF, 0x7E, 0xD4, 0x7E, 0xE8, 0xA0, 0x0D, - 0x8F, 0x87, 0xDB, 0xBB, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x2C, 0x65, 0x7C, 0xB8, - 0xFD, 0xE1, 0xFF, 0xB1, 0xFF, 0xFF, 0x77, 0x66, 0x98, 0xB7, 0x1F, 0x98, 0x69, 0x67, 0xE3, 0x63, - 0x23, 0xF1, 0x51, 0xCC, 0x44, 0x58, 0x24, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x2F, 0xAD, 0x0D, 0xBE, - 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0xFF, 0x0D, 0x58, 0x3B, 0x67, 0xDB, 0x08, 0x50, 0x41, 0x91, - 0x66, 0x22, 0x2A, 0x92, 0x2E, 0x1A, 0x1F, 0x41, 0x80, 0x34, 0xBB, 0xFD, 0x70, 0xF1, 0x11, 0x0F, - 0x90, 0x6A, 0x7C, 0xB4, 0x79, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, 0x64, 0x59, 0xC6, 0xF8, - 0x78, 0xE3, 0x2F, 0x67, 0x98, 0xF1, 0xFF, 0x3C, 0xC3, 0xBC, 0xF5, 0x23, 0xFB, 0x7B, 0x7A, 0x92, - 0xF8, 0x28, 0x66, 0x22, 0x2A, 0xD2, 0xEC, 0xF9, 0x2B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x7E, - 0xBC, 0x43, 0xAB, 0xEE, 0x32, 0xDB, 0x3E, 0x6A, 0x43, 0x40, 0x45, 0x45, 0xD2, 0x89, 0xA8, 0x48, - 0x3A, 0x11, 0x1F, 0xEE, 0xC7, 0xD4, 0xB7, 0x1F, 0x61, 0x7C, 0xB8, 0xDB, 0x8F, 0x7B, 0xB3, 0xDD, - 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x4E, 0x7C, 0xFC, 0xA7, 0x19, 0xE6, 0xF7, - 0xFF, 0xF7, 0x0C, 0xF3, 0xE6, 0x03, 0xC4, 0x47, 0x31, 0x13, 0x41, 0x91, 0x61, 0xDE, 0x2F, 0xEE, - 0x18, 0x0A, 0xBE, 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0x33, 0xD2, 0xBF, 0x5E, 0x47, 0x45, 0xD2, - 0x89, 0xA8, 0x48, 0xBA, 0x78, 0x7C, 0xB8, 0x85, 0xE1, 0x11, 0xC6, 0x47, 0xAB, 0xDB, 0x0F, 0xFF, - 0x5B, 0xAF, 0x82, 0xF8, 0x70, 0xFB, 0xA1, 0x9D, 0x88, 0x8B, 0x56, 0xD3, 0x21, 0x91, 0x65, 0x22, - 0x24, 0xB2, 0x2C, 0x87, 0xF8, 0x78, 0xE3, 0xDB, 0x36, 0x3E, 0x5E, 0x22, 0x3E, 0xF2, 0x9F, 0x8E, - 0x89, 0x2C, 0xF3, 0x8E, 0xDE, 0x3C, 0x16, 0x7C, 0x29, 0x02, 0x00, 0x00, 0x4C, 0x0F, 0xDE, 0x81, - 0xAB, 0x46, 0x75, 0x58, 0x24, 0x99, 0x88, 0x8A, 0xA4, 0x6B, 0x10, 0x1F, 0xEE, 0xC7, 0x54, 0xB7, - 0x1F, 0xD1, 0xF8, 0x70, 0xB7, 0x1F, 0xDF, 0x4A, 0x7F, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, - 0x64, 0x19, 0xF1, 0x91, 0xC3, 0x54, 0x38, 0xE4, 0x31, 0x1D, 0x12, 0x99, 0xC7, 0x9B, 0xB0, 0x00, - 0x00, 0xC0, 0x74, 0xE3, 0xED, 0xFF, 0xEC, 0x49, 0x1D, 0x17, 0xAD, 0x26, 0xA2, 0x22, 0xE9, 0xE2, - 0xE1, 0x11, 0x2E, 0x0C, 0x8F, 0x30, 0x3E, 0x9A, 0xDD, 0x7E, 0x3C, 0x76, 0x91, 0x39, 0xFD, 0xA8, - 0x0D, 0x8E, 0x36, 0x6F, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, - 0x0A, 0x87, 0x3C, 0x26, 0x02, 0xA2, 0xDD, 0xB9, 0x37, 0x61, 0x1D, 0xBF, 0x63, 0x49, 0xF0, 0xE5, - 0x08, 0x00, 0x00, 0x50, 0x7E, 0x66, 0x68, 0xBE, 0x8D, 0x02, 0x15, 0x18, 0xCD, 0x26, 0xA2, 0x22, - 0xE9, 0x54, 0x78, 0x44, 0x96, 0xE8, 0xF6, 0x23, 0x88, 0x8F, 0x76, 0x6F, 0x3F, 0x74, 0x48, 0x64, - 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0x26, 0xE2, 0x21, 0x8F, 0xBD, - 0x78, 0x1D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x87, 0xFF, 0x06, 0xAC, 0x5D, 0x9F, 0xB6, 0x61, - 0xA0, 0x22, 0xA3, 0xD1, 0x44, 0x54, 0x24, 0x9D, 0x08, 0x8E, 0xEA, 0x92, 0xDE, 0x7E, 0x3C, 0x6E, - 0x03, 0x24, 0x8C, 0x8F, 0x68, 0x80, 0xFC, 0x80, 0xF8, 0x20, 0x3E, 0x54, 0x38, 0xE4, 0x31, 0x11, - 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x3E, 0xCC, 0xA1, 0xFE, 0xB5, - 0x66, 0xC7, 0xC7, 0x6D, 0x1C, 0xA8, 0xD0, 0x50, 0x13, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0x62, 0x53, - 0xB7, 0x1F, 0xD1, 0x00, 0xF1, 0xE3, 0xA3, 0xD1, 0xED, 0xC7, 0x37, 0x75, 0x68, 0xA8, 0xE9, 0x90, - 0xC8, 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x44, 0x43, 0xCE, - 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xDA, 0xF0, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0x36, 0x10, 0x54, - 0x6C, 0xC4, 0x27, 0xA2, 0x22, 0xE9, 0x44, 0x6C, 0xD4, 0x2C, 0xC1, 0xED, 0x87, 0xFB, 0xD6, 0xAB, - 0x89, 0xC7, 0x2E, 0x9C, 0xBC, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xC9, 0x6F, 0x3F, 0x74, 0x48, - 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0xA6, 0x83, 0x21, 0xEF, - 0x79, 0x47, 0xFF, 0x64, 0x34, 0xF8, 0x92, 0x04, 0x00, 0x00, 0x28, 0x37, 0x6F, 0x78, 0xE9, 0x90, - 0x8E, 0x8D, 0xF8, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8E, 0xF8, 0xE2, 0x01, 0xA2, 0x9E, 0xFD, 0x78, - 0xDC, 0xC6, 0x47, 0x9B, 0xB7, 0x1F, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x11, 0x1F, 0x39, - 0x4C, 0x85, 0x43, 0x1E, 0xD3, 0xB1, 0x50, 0xC8, 0x8E, 0x7D, 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, - 0xE9, 0xC1, 0xDB, 0xBB, 0x24, 0xC1, 0x2B, 0x78, 0x45, 0x54, 0x24, 0x9D, 0x8A, 0x8D, 0xE8, 0x6C, - 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, 0x47, 0xEC, 0x5B, 0xAF, 0x9E, 0xB8, 0x70, 0xF2, - 0xF6, 0xC3, 0x2E, 0xCB, 0xED, 0x87, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, - 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x24, 0x14, 0xB6, 0x45, 0x95, 0x37, 0x61, 0xBD, 0x7C, 0xE7, 0xEC, - 0xE0, 0xCB, 0x12, 0x00, 0x00, 0xA0, 0xBC, 0xCC, 0x1E, 0x7B, 0xF8, 0x91, 0xD1, 0x11, 0x4E, 0x44, - 0x45, 0xD2, 0xA9, 0xE0, 0x88, 0x2F, 0x1A, 0x20, 0x76, 0xD5, 0x6F, 0xBD, 0x8A, 0x06, 0x88, 0x8B, - 0x0F, 0xFF, 0xF6, 0xE3, 0xC2, 0xFA, 0xDB, 0x8F, 0x87, 0xEC, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, - 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xB3, - 0x5F, 0x7F, 0x6E, 0x2F, 0x7E, 0xCE, 0x05, 0xC8, 0x40, 0xF0, 0x65, 0x09, 0x00, 0x00, 0x50, 0x4E, - 0x66, 0xA4, 0x7F, 0x76, 0xF3, 0x57, 0xF0, 0x8A, 0xA8, 0x48, 0x3A, 0x15, 0x1B, 0xF1, 0xC5, 0xE2, - 0x23, 0xBC, 0xFD, 0xA8, 0x7D, 0xF0, 0xDC, 0xC6, 0x47, 0xF4, 0xF6, 0x23, 0xFE, 0xAD, 0x57, 0xF7, - 0xB7, 0xBE, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, - 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x16, 0xC4, 0x87, 0x1F, 0x20, 0xD7, 0xF0, 0x26, 0x2C, 0x00, 0x00, - 0x50, 0x7E, 0xFE, 0x2B, 0x78, 0x1B, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, 0xA9, 0xD8, 0x88, 0xAF, - 0x41, 0x7C, 0x54, 0x1F, 0x3C, 0x77, 0xB3, 0xF1, 0x51, 0x73, 0xFB, 0x11, 0x7F, 0xF0, 0xDC, 0xDD, - 0x7E, 0xDC, 0xAD, 0xA3, 0x23, 0x9C, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, - 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0xB5, 0x48, 0x7C, 0x04, 0xF3, 0x4E, 0x7C, 0x69, 0x30, - 0xF8, 0xD2, 0x04, 0x00, 0x00, 0x28, 0x27, 0xFF, 0x0D, 0x58, 0x5B, 0x3F, 0x64, 0xA3, 0x61, 0x8A, - 0xE3, 0xC3, 0x4D, 0x05, 0x48, 0xCD, 0xB7, 0x5E, 0xD9, 0xF8, 0x70, 0xB7, 0x1F, 0x41, 0x7C, 0x64, - 0xB9, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, 0xF2, - 0x98, 0x8A, 0x84, 0xA2, 0x56, 0x1F, 0x1F, 0x6E, 0xDE, 0xF1, 0x3F, 0xE5, 0x4D, 0x58, 0x00, 0x00, - 0xA0, 0xDC, 0xBC, 0x91, 0x81, 0x0D, 0x1D, 0x89, 0x0F, 0xB7, 0x78, 0x7C, 0x54, 0x6F, 0x3F, 0x2E, - 0xAC, 0xC6, 0xC7, 0xE4, 0xED, 0x47, 0x2C, 0x3E, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, - 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xF1, 0xE1, - 0xEF, 0xD8, 0x2D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x94, 0x9B, 0x77, 0xE0, 0xAA, 0xD8, 0x1B, 0xB0, - 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x8C, 0x46, 0xB3, 0xD1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0x44, 0x02, - 0x24, 0x8C, 0x0F, 0xF9, 0xB9, 0x1F, 0xDF, 0x69, 0x7C, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, - 0x64, 0x59, 0x34, 0x3A, 0x88, 0x8F, 0x8C, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x11, - 0x1D, 0xD1, 0xB9, 0x37, 0x61, 0x8D, 0x7D, 0x71, 0x56, 0xF0, 0xE5, 0x09, 0x00, 0x00, 0x50, 0x3E, - 0xDE, 0xBE, 0x25, 0xE3, 0x53, 0x1E, 0x1F, 0x6E, 0xF1, 0xF8, 0x48, 0x7B, 0xFB, 0xF1, 0xA0, 0x9D, - 0x08, 0x0F, 0x37, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x52, 0xC4, 0x47, 0x18, 0x20, 0x2E, - 0x3E, 0xFE, 0x40, 0x7C, 0x44, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x38, 0xE2, - 0x1B, 0x5B, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB9, 0x4D, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, - 0xA9, 0xC0, 0x68, 0x36, 0x1B, 0x1D, 0xEE, 0x47, 0x75, 0xFB, 0x11, 0x0D, 0x90, 0xA6, 0xB7, 0x1F, - 0xF7, 0xE9, 0xDB, 0x0F, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x22, 0xF1, 0x11, 0xAE, 0x3E, - 0x3E, 0xEC, 0x5C, 0x78, 0x84, 0xB7, 0x1F, 0xC4, 0x47, 0x6C, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, - 0xA2, 0x26, 0x62, 0x43, 0xED, 0xC5, 0x6B, 0x8C, 0xF7, 0x8B, 0x2F, 0xDD, 0x15, 0x7C, 0x79, 0x02, - 0x00, 0x00, 0x94, 0x8B, 0xFF, 0x06, 0xAC, 0x9D, 0x9F, 0xD2, 0x51, 0x91, 0x74, 0xF1, 0xB8, 0x48, - 0xB2, 0x30, 0x3C, 0xC2, 0xF8, 0xF0, 0x03, 0x64, 0x66, 0x35, 0x3E, 0x6A, 0xDF, 0x7C, 0x95, 0xFC, - 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0x76, 0x24, 0x3E, 0xE2, - 0x37, 0x1F, 0x6F, 0x04, 0xF1, 0xF1, 0x07, 0xE2, 0xA3, 0xA0, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x34, - 0x9A, 0xCC, 0x3B, 0x71, 0xC7, 0x86, 0xE0, 0x4B, 0x14, 0x00, 0x00, 0xA0, 0x5C, 0x6C, 0x80, 0xAC, - 0x33, 0xDB, 0x2F, 0xD6, 0x61, 0x91, 0x64, 0x2A, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0xF6, - 0xF6, 0xC3, 0xC6, 0x47, 0x83, 0x67, 0x3F, 0xEA, 0x3E, 0x74, 0xD0, 0xBD, 0xF9, 0x4A, 0xDC, 0x7E, - 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x22, 0x3E, 0xA2, 0x37, 0x1F, 0x61, 0x7C, 0x84, - 0x37, 0x1F, 0xC4, 0x47, 0x38, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x91, 0xD1, 0x6C, - 0xDE, 0x89, 0x3F, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x9C, 0xFC, 0x57, 0xF0, 0xAA, 0xB0, 0x48, - 0xB2, 0x78, 0x58, 0x24, 0x5D, 0x18, 0x1E, 0x61, 0x7C, 0x3C, 0x3D, 0xB3, 0xE6, 0xF6, 0xA3, 0xEE, - 0xD9, 0x0F, 0x1B, 0x20, 0xA7, 0xA2, 0x01, 0xF2, 0x23, 0xBB, 0x1E, 0x8C, 0x0F, 0xB7, 0xBA, 0x00, - 0x69, 0x10, 0x1F, 0xE3, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0xC0, - 0x68, 0x35, 0xEF, 0xD8, 0x17, 0xC6, 0x83, 0x2F, 0x51, 0x00, 0x00, 0x80, 0x72, 0xF1, 0x0E, 0x5C, - 0x33, 0x2A, 0xE3, 0xA2, 0xD5, 0x54, 0x58, 0x24, 0x99, 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, - 0xF1, 0x11, 0xBD, 0xFD, 0x88, 0xC5, 0x47, 0xDD, 0xED, 0xC7, 0xB7, 0x6A, 0x6F, 0x3F, 0x74, 0x48, - 0x64, 0x99, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x56, 0x17, 0x1F, 0xEA, 0x8D, 0x57, 0xC4, 0x47, - 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x71, 0x91, 0x68, 0x47, 0x56, 0xF3, 0x26, - 0x2C, 0x00, 0x00, 0x50, 0x4E, 0xDE, 0xDE, 0x25, 0x63, 0x32, 0x30, 0x9A, 0x2D, 0x1E, 0x15, 0x69, - 0x16, 0x86, 0x47, 0x18, 0x1F, 0x69, 0x6F, 0x3F, 0x7E, 0x68, 0x57, 0xB6, 0xF8, 0x70, 0x37, 0x1F, - 0x2E, 0x3E, 0xDC, 0x43, 0xE7, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, - 0xA8, 0x48, 0xB3, 0x97, 0x56, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x4E, 0x66, 0xCF, 0x42, 0x1D, - 0x19, 0x8D, 0xA6, 0xA2, 0x22, 0xE5, 0x2A, 0x01, 0x32, 0xB3, 0xED, 0xDB, 0x0F, 0x1D, 0x12, 0x59, - 0x26, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0xB5, 0x8C, 0x8F, 0xBF, 0x9C, 0xFC, 0xAC, 0x8F, 0x3F, - 0xDC, 0x4B, 0x7C, 0x14, 0x33, 0x15, 0x09, 0x45, 0x4D, 0x04, 0x45, 0xDA, 0xBD, 0x78, 0x8D, 0x0D, - 0x90, 0x3B, 0xD6, 0x05, 0x5F, 0xA6, 0x00, 0x00, 0x00, 0xE5, 0x60, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, - 0xE6, 0xE8, 0xD0, 0x50, 0x13, 0x31, 0x91, 0x6A, 0xD5, 0xDB, 0x8F, 0x20, 0x3E, 0x9A, 0xDD, 0x7E, - 0x84, 0xF1, 0xD1, 0xE0, 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, - 0x0D, 0xE3, 0x23, 0x08, 0x90, 0xE8, 0x07, 0x0D, 0x12, 0x1F, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, - 0xA2, 0x26, 0x62, 0x22, 0xCB, 0x9E, 0xB7, 0x7F, 0x3F, 0x4E, 0xDC, 0xB1, 0x3E, 0xF8, 0x52, 0x05, - 0x00, 0x00, 0x28, 0x07, 0xFF, 0x15, 0xBC, 0x49, 0xDF, 0x80, 0xA5, 0x82, 0x22, 0xC3, 0xFC, 0xF8, - 0x88, 0xDD, 0x7E, 0x54, 0x03, 0xA4, 0xD5, 0xED, 0xC7, 0x3D, 0xBD, 0x1B, 0x1F, 0x95, 0xD7, 0xED, - 0x12, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x24, 0xDA, 0x18, 0x6F, - 0xC2, 0x02, 0x00, 0x00, 0xA5, 0xE3, 0xBF, 0x01, 0x6B, 0xEB, 0x07, 0x75, 0x70, 0x44, 0x27, 0x42, - 0x22, 0xF5, 0xC2, 0x9B, 0x8F, 0x26, 0xB7, 0x1F, 0x13, 0x2E, 0x40, 0x1E, 0x8B, 0xDC, 0x7E, 0x84, - 0xF1, 0xE1, 0xF6, 0xBD, 0xCA, 0xB7, 0x5E, 0xE9, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x26, 0xC2, - 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x11, 0xD1, 0xCE, - 0xBC, 0x63, 0x5F, 0x38, 0x19, 0x7C, 0xA9, 0x02, 0x00, 0x00, 0x94, 0x83, 0x37, 0xBC, 0x62, 0x50, - 0x06, 0x47, 0x74, 0x2A, 0x26, 0xB2, 0x2C, 0x8C, 0x8F, 0xD8, 0xED, 0x47, 0xE2, 0x67, 0x3F, 0xBE, - 0xC9, 0xB7, 0x5D, 0x25, 0x9B, 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, - 0x2A, 0x12, 0x8A, 0x9A, 0x0E, 0x88, 0xB6, 0x77, 0x64, 0xB5, 0x09, 0xBE, 0x54, 0x01, 0x00, 0x00, - 0xCA, 0xC1, 0xDB, 0x7B, 0x79, 0xF3, 0x57, 0xF0, 0xAA, 0x90, 0x48, 0xBB, 0x4D, 0x6E, 0x93, 0xE1, - 0x31, 0x79, 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xFC, 0xF6, 0x43, 0x87, 0x44, - 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0x0D, 0xE3, 0xC3, 0x3D, 0x70, 0x1E, 0x8B, 0x8F, - 0xF1, 0xFF, 0x32, 0xCB, 0x9C, 0xFF, 0xD7, 0x5B, 0x83, 0xF8, 0x58, 0x65, 0x0F, 0xFA, 0x2A, 0x28, - 0xD2, 0x4C, 0x84, 0x43, 0x1E, 0x93, 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, - 0x4D, 0x84, 0x43, 0x5E, 0x3B, 0xB2, 0x92, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF1, 0xF6, 0x2C, - 0x1A, 0x97, 0xE1, 0xE1, 0xA6, 0x62, 0x22, 0xCB, 0x6C, 0x78, 0x44, 0x6F, 0x3F, 0xAA, 0xDF, 0x7A, - 0x15, 0x06, 0x48, 0xCD, 0x6B, 0x77, 0x2F, 0x94, 0xB7, 0x1F, 0xEF, 0x7C, 0x23, 0xAF, 0xDB, 0x0F, - 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x2D, 0x6D, 0x7C, 0x9C, 0xFB, 0xE9, 0x17, 0x2A, 0xF1, 0x71, - 0xD4, 0xFE, 0x28, 0x83, 0x22, 0xCD, 0x44, 0x38, 0xE4, 0x31, 0x19, 0x0E, 0x79, 0x4C, 0x85, 0x43, - 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x44, 0x34, 0xE4, 0x39, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xCA, 0xC4, - 0x0C, 0xF5, 0xCF, 0x32, 0x43, 0x7D, 0x53, 0x1A, 0x1F, 0xE1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xCD, - 0x9E, 0xFD, 0x70, 0xF1, 0x71, 0x7F, 0x5E, 0xB7, 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, - 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x82, 0x21, 0xEF, 0xB9, 0xFF, - 0x6D, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0x0B, 0xFF, 0x0D, 0x58, 0x3B, 0x3E, 0x39, 0xE5, 0xF1, - 0x51, 0x7D, 0xF0, 0x5C, 0xDD, 0x7E, 0xC4, 0x1E, 0x3C, 0x7F, 0xE7, 0x41, 0x1B, 0x1F, 0x5F, 0x57, - 0x31, 0x91, 0x76, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, - 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x62, 0xA1, 0xA0, 0x79, 0x27, 0xEE, 0xE0, 0x4D, 0x58, 0x00, 0x00, - 0xA0, 0x1C, 0xBC, 0xE1, 0xFE, 0xBB, 0xCC, 0xB6, 0x8F, 0x14, 0x13, 0x1F, 0xCF, 0x54, 0xE2, 0xA3, - 0x2E, 0x40, 0xE2, 0xAF, 0xDD, 0x75, 0xB7, 0x1F, 0x41, 0x7C, 0xC4, 0x6F, 0x3F, 0xDE, 0x79, 0xD8, - 0xC6, 0xC7, 0x77, 0xF3, 0xF8, 0xD6, 0x2B, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, - 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xA1, 0x50, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, - 0x82, 0x2F, 0x59, 0x00, 0x00, 0x80, 0xDE, 0xE6, 0xBF, 0x82, 0xB7, 0xA8, 0xF8, 0x08, 0x02, 0xA4, - 0xE1, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0x8A, 0xC7, 0x47, 0x2E, 0xB7, 0x1F, 0x22, 0x24, - 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0xA6, - 0x23, 0xA1, 0xD0, 0x1D, 0xB9, 0x91, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF0, 0x0E, 0x5C, 0x33, - 0xF9, 0x06, 0x2C, 0x19, 0x12, 0x59, 0x36, 0x19, 0x1F, 0x8D, 0x6E, 0x3F, 0xAA, 0xAF, 0xDD, 0xAD, - 0xDE, 0x7E, 0x5C, 0x14, 0xBB, 0xFD, 0xB0, 0xE1, 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, - 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x38, 0x98, - 0x8A, 0xBD, 0x34, 0x60, 0xCC, 0xF1, 0x3B, 0x96, 0x04, 0x5F, 0xB6, 0x00, 0x00, 0x00, 0xBD, 0xCB, - 0xDB, 0x77, 0xC5, 0xC9, 0x42, 0xE2, 0xA3, 0xAD, 0xDB, 0x8F, 0x20, 0x3E, 0x1E, 0x68, 0xF7, 0xF6, - 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, - 0x50, 0xD4, 0x44, 0x18, 0x4C, 0xD5, 0xDC, 0x9B, 0xB0, 0x4E, 0x7C, 0x69, 0x6D, 0xF0, 0x65, 0x0B, - 0x00, 0x00, 0xD0, 0xBB, 0xCC, 0xEE, 0xBE, 0x48, 0x3C, 0xB4, 0xBB, 0xDA, 0xF8, 0x70, 0x3F, 0xAA, - 0xDB, 0x8F, 0xFA, 0x67, 0x3F, 0xA2, 0xB7, 0x1F, 0x41, 0x7C, 0xB8, 0xDD, 0xDB, 0xCE, 0xED, 0x87, - 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, - 0xA8, 0x89, 0x28, 0x98, 0xCA, 0xBD, 0x70, 0x25, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xCF, 0x1C, - 0xE8, 0x5F, 0x62, 0x76, 0xCE, 0x0E, 0xE2, 0xA1, 0xDD, 0x45, 0xE2, 0x23, 0x08, 0x90, 0x66, 0xB7, - 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xE1, 0x6E, 0x3F, 0x64, 0x58, 0x24, 0x99, 0x08, 0x89, 0x2C, - 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x20, - 0xE8, 0xC0, 0xBC, 0xE3, 0xB7, 0x0F, 0x05, 0x5F, 0xBA, 0x00, 0x00, 0x00, 0xBD, 0xC9, 0x1C, 0x5C, - 0xB6, 0xD6, 0x6C, 0xFF, 0x58, 0x10, 0x10, 0xED, 0xAC, 0x3E, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0x43, - 0x3D, 0xFB, 0x51, 0xF9, 0xD0, 0xC1, 0x0B, 0x27, 0x03, 0xE4, 0x21, 0xBB, 0xCC, 0xB7, 0x1F, 0x22, - 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, - 0xA6, 0x63, 0xA0, 0x13, 0xF3, 0x8E, 0xDE, 0xC2, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x33, 0x23, - 0xCB, 0xD7, 0x9B, 0xCD, 0xEF, 0xB3, 0xB1, 0xA0, 0xA2, 0x22, 0xE9, 0x62, 0xF1, 0xE1, 0x16, 0x86, - 0x47, 0x18, 0x1F, 0xB1, 0xDB, 0x8F, 0xBA, 0x67, 0x3F, 0x1E, 0xB5, 0xF1, 0xE1, 0x02, 0xA4, 0xED, - 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, - 0x45, 0x42, 0x51, 0xD3, 0x21, 0xD0, 0xB1, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, - 0xE6, 0x1D, 0xB8, 0x7E, 0xA8, 0x36, 0x26, 0xD2, 0x4E, 0xC7, 0x87, 0xFB, 0xB1, 0xE9, 0xED, 0x47, - 0x2C, 0x3E, 0xEA, 0x6E, 0x3F, 0xEE, 0xC9, 0x72, 0xFB, 0x21, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, - 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x00, 0x3A, 0x3D, 0xF7, - 0x26, 0xAC, 0x97, 0xEF, 0x9C, 0x1D, 0x7C, 0xF9, 0x02, 0x00, 0x00, 0xF4, 0x1E, 0x6F, 0xEF, 0x65, - 0xA3, 0xF5, 0x51, 0x91, 0x74, 0xB1, 0xF0, 0x08, 0x17, 0x86, 0x47, 0x18, 0x1F, 0x4D, 0x6F, 0x3F, - 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x4E, 0x06, 0x46, 0xB3, 0x89, 0x90, 0xC8, - 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, - 0xFC, 0x77, 0xC3, 0x5E, 0xFC, 0x9C, 0x31, 0xC7, 0x6E, 0x1B, 0x08, 0xBE, 0x7C, 0x01, 0x00, 0x00, - 0x7A, 0x8F, 0xD9, 0x63, 0x0F, 0x5B, 0x32, 0x2E, 0x5A, 0x4D, 0x84, 0x47, 0x64, 0xC9, 0x6E, 0x3F, - 0x2A, 0xF1, 0xD1, 0xFE, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, - 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xFE, 0xDD, 0x32, 0xDE, 0x84, 0x05, 0x00, - 0x00, 0x7A, 0x99, 0x19, 0xE9, 0x9F, 0x6D, 0x76, 0xCF, 0xB3, 0xC1, 0xA0, 0x02, 0xA3, 0xD9, 0x74, - 0x74, 0xF8, 0x4B, 0x7C, 0xFB, 0x31, 0xD3, 0x9C, 0x09, 0xE3, 0xA3, 0xAD, 0xDB, 0x0F, 0x11, 0x12, - 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, - 0x87, 0xFE, 0x2E, 0x9B, 0x77, 0xE2, 0xF6, 0xC1, 0xE0, 0x4B, 0x18, 0x00, 0x00, 0xA0, 0xB7, 0xD8, - 0x00, 0x19, 0x48, 0xFF, 0x06, 0x2C, 0x11, 0x1D, 0xB1, 0xA9, 0xDB, 0x8F, 0x6A, 0x80, 0x84, 0xF1, - 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, - 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7F, 0xB7, 0xCD, 0x3B, 0xFA, 0x85, 0xD1, 0xE0, 0x4B, - 0x18, 0x00, 0x00, 0xA0, 0xB7, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0x3E, 0x60, 0xA3, 0x41, 0x85, - 0x86, 0x9A, 0x0E, 0x8E, 0xEA, 0x12, 0xDC, 0x7E, 0x4C, 0x3C, 0x31, 0xD3, 0x4C, 0x3C, 0x16, 0xB9, - 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0xFB, 0xC4, 0x47, 0x65, 0x22, 0x1C, 0xF2, 0x98, 0x0C, 0x87, 0x3C, - 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0xB0, 0xDF, 0x95, 0x3B, 0x76, 0x0B, 0x6F, - 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xC9, 0x1B, 0x59, 0xB1, 0xA1, 0x3E, 0x32, 0x1A, 0x4D, 0x04, 0x47, - 0x7C, 0xF1, 0x00, 0xA9, 0x7B, 0xF6, 0xC3, 0xC6, 0x47, 0xB3, 0xDB, 0x8F, 0x6F, 0xA8, 0xD0, 0x50, - 0x13, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, - 0x14, 0x35, 0x71, 0xC8, 0xEF, 0xE6, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xAB, 0xBC, 0x7D, 0x57, - 0x24, 0x7C, 0x03, 0x96, 0x88, 0x8D, 0xE8, 0x6C, 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, - 0x47, 0xE4, 0x5B, 0xAF, 0x06, 0x6D, 0x7C, 0x44, 0x6F, 0x3F, 0xEC, 0x6A, 0x6E, 0x3F, 0x36, 0x24, - 0xBD, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, - 0x54, 0x24, 0x14, 0x35, 0x71, 0xC0, 0xEF, 0xF6, 0x8D, 0x2D, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0xA0, - 0x37, 0x79, 0x7B, 0x2F, 0x1B, 0xAF, 0x8F, 0x8D, 0xF8, 0x62, 0xB1, 0xA1, 0x16, 0x0D, 0x10, 0xBB, - 0xEA, 0xB7, 0x5E, 0x85, 0x01, 0x62, 0xE3, 0x63, 0xF2, 0xF6, 0x63, 0x66, 0x1B, 0xB7, 0x1F, 0x22, - 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, - 0x26, 0x0E, 0xF7, 0xBD, 0xB0, 0x17, 0xAF, 0x31, 0xDE, 0x2F, 0x6E, 0xBF, 0x2B, 0xF8, 0x32, 0x06, - 0x00, 0x00, 0xE8, 0x1D, 0xAD, 0xDF, 0x80, 0x15, 0x0B, 0x0D, 0xB5, 0x58, 0x7C, 0x84, 0xB7, 0x1F, - 0x93, 0x0F, 0x9E, 0xDB, 0xF8, 0x88, 0xDF, 0x7E, 0x84, 0xF1, 0x11, 0x06, 0x48, 0xA2, 0xDB, 0x0F, - 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, - 0x51, 0x13, 0x07, 0xFB, 0x1E, 0x9A, 0x77, 0xFC, 0x8E, 0x0D, 0xC1, 0x97, 0x31, 0x00, 0x00, 0x40, - 0x6F, 0xF0, 0xDF, 0x80, 0xB5, 0x73, 0xB6, 0x8D, 0x08, 0x15, 0x1E, 0x6E, 0xB1, 0xD0, 0x50, 0x6B, - 0x10, 0x1F, 0xD5, 0x07, 0xCF, 0x37, 0xCE, 0xAC, 0xBF, 0xFD, 0x08, 0xE2, 0xA3, 0x7A, 0xFB, 0xF1, - 0xA0, 0xDD, 0xD7, 0x55, 0x70, 0x44, 0x27, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, - 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0x50, 0xDF, 0x4B, 0xF3, 0x8E, 0xDE, 0xCA, - 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x31, 0x23, 0xCB, 0xD7, 0x35, 0x7E, 0x05, 0x6F, 0x2C, 0x34, - 0x1A, 0x4D, 0x05, 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x41, 0x7C, 0xC8, 0x37, - 0x5F, 0x7D, 0xB7, 0xD5, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, - 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7D, 0xAF, 0xCD, 0x3B, 0xFA, 0xF9, 0xF1, - 0xE0, 0x4B, 0x19, 0x00, 0x00, 0xA0, 0x37, 0xD8, 0x00, 0x59, 0x5F, 0x1F, 0x1E, 0x29, 0xE2, 0xC3, - 0x2D, 0x1E, 0x1F, 0xD5, 0xDB, 0x8F, 0xC9, 0xF8, 0xA8, 0x79, 0xF3, 0x55, 0xEA, 0xDB, 0x0F, 0x11, - 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, - 0xD3, 0x87, 0xF9, 0x9E, 0x9C, 0x7B, 0x13, 0xD6, 0xD8, 0x17, 0x67, 0x05, 0x5F, 0xCE, 0x00, 0x00, - 0x00, 0xDD, 0xCF, 0x3B, 0x70, 0xD5, 0x50, 0xBB, 0xF1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0xD4, 0xDD, - 0x7E, 0x5C, 0x98, 0xE1, 0xF6, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, - 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBE, 0x97, 0x37, 0xB6, 0x9C, 0x37, 0x61, - 0x01, 0x00, 0x80, 0xDE, 0xE2, 0xED, 0xBD, 0x7C, 0x2C, 0x73, 0x7C, 0xB8, 0xC5, 0xE3, 0xC3, 0x0F, - 0x90, 0x19, 0x39, 0xDD, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, - 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xC0, 0xF7, 0xFA, 0x78, 0x13, 0x16, 0x00, 0x00, - 0xE8, 0x35, 0x66, 0x68, 0x81, 0x0D, 0x89, 0xEC, 0xF1, 0xE1, 0x7E, 0xAC, 0xBD, 0xFD, 0xB0, 0xF1, - 0x11, 0xFB, 0xF6, 0xAB, 0xA6, 0xB7, 0x1F, 0xF7, 0x35, 0xBA, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, - 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x78, 0x2F, - 0xC3, 0x9E, 0xBF, 0x9C, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, 0x61, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, - 0x2E, 0xB5, 0x11, 0x91, 0x21, 0x3E, 0xDC, 0xC2, 0xF0, 0x08, 0xE3, 0xE3, 0xE9, 0x19, 0x35, 0xB7, - 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xF1, 0x80, 0x1D, 0xF1, 0x91, 0xCF, 0x64, 0x38, 0xE4, 0x31, - 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x07, 0xF7, 0x12, 0xCD, 0x3B, 0xFE, 0x67, 0xBC, - 0x09, 0x0B, 0x00, 0x00, 0xF4, 0x06, 0xFF, 0x15, 0xBC, 0xFE, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, - 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, 0xF1, 0xD1, 0xE0, 0xD9, 0x0F, 0xF9, 0xA1, 0x83, 0xF7, - 0xAA, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, - 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x87, 0xF6, 0x32, 0xCD, 0x3B, 0xFA, 0xF9, 0x93, 0xC1, 0x97, 0x34, - 0x00, 0x00, 0x40, 0x77, 0xF3, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0xF5, 0x71, 0x91, 0x64, 0x61, 0x78, - 0x84, 0xF1, 0x11, 0xBB, 0xFD, 0xA8, 0x7B, 0xF6, 0xC3, 0x06, 0xC8, 0x29, 0x17, 0x20, 0x4D, 0x6F, - 0x3F, 0x44, 0x48, 0x64, 0x99, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, - 0x09, 0x45, 0x4D, 0x1F, 0xD8, 0x4B, 0xB7, 0x23, 0xAB, 0x4C, 0xF0, 0x25, 0x0D, 0x00, 0x00, 0xD0, - 0xDD, 0xBC, 0xE1, 0x65, 0x83, 0x32, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0x12, 0x20, 0x33, - 0xF4, 0xED, 0x47, 0x2C, 0x3E, 0x5A, 0xDF, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, - 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA8, 0x97, 0x75, 0x63, 0xCB, - 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0D, 0xDE, 0xDE, 0xCB, 0x46, 0xEB, 0xE2, 0x22, 0xC9, 0xAA, - 0xB7, 0x1F, 0x41, 0x7C, 0x24, 0xBD, 0xFD, 0x08, 0x03, 0xE4, 0x07, 0x76, 0xC4, 0x47, 0x7B, 0x93, - 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0xBA, 0x7F, - 0x5D, 0x68, 0xCC, 0x0B, 0x57, 0x1B, 0x73, 0xFC, 0x8E, 0x75, 0xC1, 0x97, 0x35, 0x00, 0x00, 0x40, - 0xF7, 0xF2, 0xF6, 0x2C, 0x18, 0x97, 0x81, 0xD1, 0x6C, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0x59, 0x6F, - 0x3F, 0xEE, 0x89, 0xDE, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, - 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2E, 0x3E, 0xDC, 0x7E, 0x6E, - 0xFF, 0x99, 0x38, 0x71, 0xDB, 0xFA, 0xE0, 0xCB, 0x1A, 0x00, 0x00, 0xA0, 0x3B, 0x99, 0xA1, 0xFE, - 0x59, 0x66, 0xF7, 0xDC, 0xFA, 0xC0, 0x68, 0xB5, 0xF0, 0xE6, 0x23, 0x97, 0xDB, 0x0F, 0x11, 0x12, - 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, - 0x87, 0xF4, 0xB2, 0x2E, 0x8C, 0x8F, 0x60, 0xDE, 0x89, 0xDB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, - 0x6E, 0x66, 0x64, 0xE9, 0x80, 0xD9, 0xF1, 0x71, 0x1D, 0x19, 0xCD, 0x16, 0xC6, 0x47, 0xDB, 0xB7, - 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, - 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x5D, 0x2C, 0x3E, 0xFC, 0x00, 0x39, 0x7A, 0x33, 0x6F, 0xC2, - 0x02, 0x00, 0x00, 0xDD, 0xCD, 0x1B, 0x5E, 0x7E, 0x97, 0xD9, 0xFA, 0x21, 0x1D, 0x19, 0x8D, 0x16, - 0x8F, 0x8F, 0x66, 0xB7, 0x1F, 0x61, 0x7C, 0xC8, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, - 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, - 0xC4, 0x87, 0xBF, 0x23, 0x37, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xDD, 0xFC, 0x57, 0xF0, 0xAA, - 0xC8, 0x68, 0x34, 0x1B, 0x1D, 0x8D, 0x6E, 0x3F, 0xAA, 0x01, 0xD2, 0xEA, 0xF6, 0xE3, 0x1B, 0xC4, - 0x47, 0xA6, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, - 0x65, 0x9D, 0x0A, 0x8F, 0x70, 0x2F, 0xF5, 0xBB, 0x07, 0xD1, 0x97, 0x04, 0x5F, 0xDE, 0x00, 0x00, - 0x00, 0xDD, 0xC7, 0x3B, 0x70, 0x75, 0xF2, 0x37, 0x60, 0x45, 0xE3, 0xC3, 0x86, 0x47, 0xA3, 0xDB, - 0x8F, 0x09, 0x17, 0x20, 0x8F, 0x45, 0x6E, 0x3F, 0xC2, 0xF8, 0x70, 0xDB, 0xE0, 0xBE, 0xF5, 0x4A, - 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, - 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xD1, 0x11, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x3F, 0x5F, 0x1B, - 0x7C, 0x79, 0x03, 0x00, 0x00, 0x74, 0x1F, 0x6F, 0xDF, 0xE5, 0x27, 0x65, 0x6C, 0xC4, 0x17, 0xC4, - 0x47, 0xA3, 0xDB, 0x8F, 0xC4, 0xCF, 0x7E, 0x7C, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, - 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xC1, - 0x11, 0x1F, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xDD, 0x2E, 0xD1, 0x1B, 0xB0, 0xE2, 0xF1, 0x51, 0x73, - 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xED, 0xED, 0x47, 0x4E, 0xDF, 0x7A, 0x25, - 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, - 0xB2, 0x4E, 0xC5, 0x46, 0x83, 0x79, 0xC7, 0x6F, 0x1F, 0x0A, 0xBE, 0xBC, 0x01, 0x00, 0x00, 0xBA, - 0x8B, 0x39, 0x70, 0xFD, 0x12, 0xB3, 0xF3, 0x53, 0x3A, 0x3A, 0xC2, 0x45, 0xE2, 0xA3, 0x1A, 0x20, - 0x76, 0xD5, 0x6F, 0xBD, 0x0A, 0x03, 0xA4, 0xE6, 0xB5, 0xBB, 0x33, 0xC5, 0xED, 0xC7, 0xCC, 0x7C, - 0x6E, 0x3F, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, - 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0xC8, 0x68, 0x36, 0xEF, 0xC8, 0x9A, 0xB1, 0xE0, 0x4B, 0x1C, 0x00, - 0x00, 0xA0, 0xBB, 0x98, 0x83, 0xCB, 0xD6, 0x9A, 0xED, 0x1F, 0xD5, 0xE1, 0xE1, 0x16, 0x09, 0x8F, - 0x68, 0x7C, 0x84, 0xB7, 0x1F, 0x35, 0x0F, 0x9E, 0x37, 0x7A, 0xF6, 0xC3, 0x0F, 0x10, 0x1B, 0x1F, - 0xDF, 0xCD, 0xE1, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, - 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x08, 0x8C, 0x96, 0x3B, 0xBA, 0x86, 0x37, 0x61, 0x01, - 0x00, 0x80, 0xEE, 0xE4, 0xBF, 0x01, 0x6B, 0xF3, 0xAC, 0x4C, 0xF1, 0x51, 0x7D, 0xF0, 0x5C, 0xDD, - 0x7E, 0x04, 0xF1, 0x51, 0xB9, 0xFD, 0xB0, 0xF1, 0xF1, 0xA0, 0xDD, 0xD7, 0x45, 0x50, 0xA4, 0x99, - 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, - 0xCB, 0x3A, 0x15, 0x17, 0x49, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB7, 0xF2, 0x0E, 0x7C, 0x6E, - 0x28, 0x49, 0x7C, 0xD4, 0x05, 0x48, 0xFC, 0xB5, 0xBB, 0xEE, 0xF6, 0x23, 0x88, 0x8F, 0xDA, 0x37, - 0x5F, 0xD9, 0xF0, 0xC8, 0xE3, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, - 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x0A, 0x8B, 0xA4, 0x7B, 0xE1, 0x5A, 0x63, - 0x8E, 0xDD, 0x36, 0x10, 0x7C, 0x99, 0x03, 0x00, 0x00, 0x74, 0x0F, 0x6F, 0xEF, 0x65, 0xF5, 0xAF, - 0xE0, 0x8D, 0x44, 0x87, 0x8C, 0x8F, 0xE8, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0xAA, 0xDE, - 0x7E, 0x04, 0xF1, 0xD1, 0xEE, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, - 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x15, 0x69, 0xF6, 0xFC, 0x67, 0x79, - 0x13, 0x16, 0x00, 0x00, 0xE8, 0x4E, 0x66, 0x8F, 0x3D, 0xEC, 0xB4, 0x88, 0x0F, 0x37, 0x75, 0xFB, - 0x51, 0x7D, 0xED, 0x6E, 0xF5, 0xF6, 0xE3, 0xC2, 0xC8, 0xED, 0x47, 0x10, 0x1F, 0xED, 0xDE, 0x7E, - 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x62, 0x07, - 0xF4, 0x32, 0x4F, 0x05, 0x45, 0x86, 0x79, 0x27, 0x6E, 0x1B, 0x0C, 0xBE, 0xCC, 0x01, 0x00, 0x00, - 0xBA, 0x83, 0x19, 0xE9, 0x9F, 0x5D, 0xF3, 0x0A, 0xDE, 0x48, 0x70, 0x44, 0x97, 0xFE, 0xF6, 0x63, - 0xE6, 0x64, 0x80, 0x3C, 0x60, 0xA7, 0xC2, 0x22, 0xC9, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, - 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0x90, 0xC8, 0x3A, 0xEF, - 0xC8, 0xE7, 0x47, 0x83, 0x2F, 0x75, 0x00, 0x00, 0x80, 0xEE, 0x60, 0x46, 0x96, 0x0E, 0x54, 0xDF, - 0x80, 0x15, 0x09, 0x8E, 0xF8, 0xD4, 0xED, 0x47, 0xFD, 0xB3, 0x1F, 0xE1, 0xED, 0x47, 0x24, 0x3E, - 0xDC, 0xEE, 0xCD, 0x78, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, - 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x44, 0x44, 0x5B, 0xE3, 0x4D, 0x58, 0x00, 0x00, - 0xA0, 0xDB, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0xDE, 0x2F, 0xA3, 0x23, 0x5C, 0xB3, 0xDB, 0x8F, - 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0xC8, 0x7A, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, - 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x05, 0x44, 0xBB, 0x73, 0x6F, - 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x3B, 0x00, 0x00, 0x40, 0xE7, 0x79, 0x23, 0xCB, 0x36, - 0xA8, 0xE8, 0x88, 0x4E, 0xDD, 0x7E, 0xD4, 0x3F, 0xFB, 0xE1, 0x3E, 0x74, 0xD0, 0xBD, 0x7A, 0x37, - 0x12, 0x20, 0xEE, 0x43, 0x07, 0xB3, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, - 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xF1, 0x90, 0xC7, 0x5E, 0xBC, - 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, 0xEE, 0xE2, 0xED, 0xBD, 0x62, 0x54, 0x45, 0x47, 0xB8, 0x66, - 0xB7, 0x1F, 0xD5, 0x67, 0x3F, 0xFC, 0xD7, 0xEE, 0x06, 0xF1, 0xE1, 0xD6, 0xCE, 0xED, 0x87, 0x08, - 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, - 0x3A, 0x15, 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x2E, 0xDE, 0xDE, - 0xC5, 0xE3, 0x2A, 0x3C, 0xC2, 0x35, 0xBD, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC5, 0x87, 0xBA, 0xFD, - 0xB8, 0x27, 0xE5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, - 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x0D, 0x39, 0xCF, 0x3B, 0xB6, 0x96, 0x37, 0x61, - 0x01, 0x00, 0x80, 0xEE, 0xE1, 0xBF, 0x01, 0x2B, 0x12, 0x1C, 0xD1, 0xB5, 0xBC, 0xFD, 0xB0, 0xF1, - 0x31, 0xF1, 0xD8, 0x8C, 0xDA, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x60, 0xA7, 0x22, 0xA3, 0xD1, 0x44, - 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, - 0xD6, 0x89, 0x58, 0x28, 0x62, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0E, 0xFE, - 0x1B, 0xB0, 0x76, 0x7C, 0x52, 0xC6, 0x87, 0x5B, 0xCB, 0xDB, 0x8F, 0x30, 0x3E, 0xDA, 0xBD, 0xFD, - 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, - 0x7A, 0x59, 0x27, 0x42, 0xA1, 0xA8, 0x79, 0x47, 0x6F, 0x1E, 0x0F, 0xBE, 0xE4, 0x01, 0x00, 0x00, - 0x3A, 0xCB, 0x8C, 0x2C, 0x5F, 0x67, 0xB6, 0x7D, 0xA4, 0x75, 0x7C, 0xC8, 0xDB, 0x8F, 0x19, 0xF9, - 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, - 0xC4, 0x21, 0xBD, 0xAC, 0x13, 0x91, 0x50, 0xE8, 0xDC, 0x9B, 0xB0, 0xC6, 0xBE, 0x38, 0x2B, 0xF8, - 0xB2, 0x07, 0x00, 0x00, 0xE8, 0x1C, 0x1B, 0x20, 0xEB, 0x55, 0x7C, 0xB8, 0xA9, 0xDB, 0x0F, 0x3F, - 0x40, 0x44, 0x7C, 0x64, 0xBE, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, - 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA1, 0xE8, 0xF1, 0x26, 0x2C, 0x00, - 0x00, 0xD0, 0x2D, 0xBC, 0x03, 0x57, 0x0D, 0x35, 0x8C, 0x0F, 0x1B, 0x1E, 0xF2, 0xF6, 0xE3, 0x09, - 0x1B, 0x1F, 0x2E, 0x40, 0x1E, 0x8D, 0xDC, 0x7E, 0x84, 0xF1, 0xE1, 0xB6, 0x81, 0xF8, 0xA8, 0x9B, - 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xA9, - 0x38, 0x98, 0x8A, 0xBD, 0x70, 0xB5, 0xF1, 0x7E, 0x71, 0xFB, 0x5D, 0xC1, 0x97, 0x3D, 0x00, 0x00, - 0x40, 0xE7, 0x78, 0x7B, 0x2F, 0x1B, 0x6B, 0x18, 0x20, 0x6E, 0x91, 0xDB, 0x0F, 0x17, 0x1F, 0x67, - 0x07, 0x67, 0xD4, 0xDE, 0x7E, 0xA8, 0x67, 0x3F, 0xBE, 0x21, 0x62, 0x23, 0x3E, 0x11, 0x1E, 0x6E, - 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2A, - 0x0C, 0xA6, 0x70, 0xDE, 0xF1, 0xDB, 0x36, 0x04, 0x5F, 0xF6, 0x00, 0x00, 0x00, 0x9D, 0x63, 0x86, - 0xE6, 0xEB, 0xF8, 0xA8, 0xB9, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC6, 0x47, 0x1E, 0xB7, 0x1F, 0x22, - 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, - 0xEB, 0x44, 0x10, 0x4C, 0xF5, 0xBC, 0xE3, 0x7F, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x67, 0x99, - 0x91, 0xFE, 0xD9, 0x66, 0xE7, 0x25, 0x3A, 0x40, 0xEC, 0xA2, 0xDF, 0x7A, 0x75, 0xEE, 0xC9, 0x19, - 0xE6, 0xAC, 0x8D, 0x8F, 0xC9, 0xDB, 0x8F, 0x19, 0xFA, 0xD9, 0x8F, 0x56, 0xB7, 0x1F, 0x22, 0x3C, - 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, - 0x44, 0x0C, 0x74, 0x62, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x74, 0x9C, 0xFF, 0x0A, 0xDE, 0xD8, 0x1B, - 0xB0, 0x6A, 0xBE, 0xF5, 0xCA, 0xEE, 0x9C, 0x0B, 0x10, 0x17, 0x1F, 0xF1, 0xDB, 0x8F, 0x68, 0x7C, - 0x84, 0x01, 0x72, 0x7F, 0x8B, 0xDB, 0x0F, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, - 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x22, 0x04, 0x3A, 0xB6, 0x97, 0x56, 0x99, - 0xE0, 0x4B, 0x1F, 0x00, 0x00, 0xA0, 0x33, 0xFC, 0x37, 0x60, 0x6D, 0xFE, 0xE3, 0x86, 0xF1, 0x51, - 0xB9, 0xFD, 0xB0, 0xF1, 0xD1, 0xE0, 0xF6, 0xC3, 0xC5, 0x47, 0xF5, 0xF6, 0xE3, 0x41, 0xBB, 0xAF, - 0x8B, 0xE8, 0x08, 0x27, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, - 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x45, 0x40, 0x27, 0x37, 0xB6, 0x8C, 0x37, 0x61, 0x01, 0x00, - 0x80, 0xCE, 0xF2, 0x86, 0x97, 0x0D, 0x36, 0xBC, 0xFD, 0x08, 0xE2, 0xA3, 0xE6, 0xF6, 0x23, 0x88, - 0x8F, 0x9A, 0xDB, 0x8F, 0xF0, 0xD9, 0x8F, 0xEF, 0x36, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, - 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA0, - 0xD3, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0xF2, 0x07, 0x00, 0x00, 0x98, 0x7A, - 0xDE, 0xDE, 0xCB, 0x46, 0x1B, 0xDE, 0x7E, 0x6C, 0xBC, 0xA0, 0x26, 0x3E, 0xEA, 0x3E, 0x74, 0x30, - 0xE9, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, - 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x75, 0xF8, 0xEF, 0xF8, 0x16, 0xD8, 0x5F, 0x9B, 0xFD, 0xDF, 0xE1, - 0xC4, 0x6D, 0xEB, 0x83, 0x2F, 0x7F, 0x00, 0x00, 0x80, 0xA9, 0xE7, 0xED, 0x9E, 0x3F, 0xAE, 0x6F, - 0x3F, 0x6C, 0x7C, 0x84, 0xDF, 0x7A, 0x55, 0x73, 0xFB, 0x31, 0x33, 0xDD, 0xED, 0x87, 0x08, 0x0F, - 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0xB1, 0x78, 0x20, 0x14, 0x39, 0x71, 0x48, 0x2F, 0xEB, - 0xE4, 0xE1, 0xBF, 0xD3, 0xB3, 0xF1, 0x11, 0xCC, 0x3B, 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x80, - 0xCE, 0x30, 0x43, 0xFD, 0xB3, 0xCC, 0xEE, 0xB9, 0x32, 0x3E, 0x72, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, - 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, - 0x0F, 0xFF, 0x9D, 0xDE, 0x64, 0x7C, 0xF8, 0x01, 0x72, 0xF4, 0xE6, 0x93, 0xC1, 0x1F, 0x01, 0x00, - 0x00, 0x00, 0x53, 0xCB, 0x7F, 0x03, 0xD6, 0xF6, 0x8B, 0x6B, 0x03, 0x24, 0x8C, 0x0F, 0xF9, 0xEC, - 0x47, 0x83, 0xDB, 0x8F, 0x7B, 0xC5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, - 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x6A, 0xE3, - 0xC3, 0xDF, 0x91, 0x1B, 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0C, 0x33, 0xB2, 0x7C, 0x9D, 0xD9, - 0xFA, 0xC1, 0xC8, 0xED, 0x87, 0x8D, 0x8F, 0xD8, 0xED, 0x47, 0xED, 0x9B, 0xAF, 0x44, 0x7C, 0x3C, - 0x60, 0x47, 0x7C, 0x14, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, - 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x11, 0x1F, 0x6E, 0x2F, 0xF5, 0xF3, 0x26, 0x2C, 0x00, 0x00, 0xD0, - 0x19, 0xE6, 0xE0, 0xF2, 0xF5, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xEC, 0xC7, - 0xE9, 0x78, 0x80, 0xB8, 0x0F, 0x1D, 0x8C, 0xDF, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, - 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, - 0x84, 0x47, 0x38, 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x00, 0x00, 0x00, 0x60, - 0xEA, 0x78, 0xFB, 0xAE, 0x1E, 0xAD, 0x89, 0x8F, 0x24, 0xCF, 0x7E, 0xB8, 0x35, 0xBA, 0xFD, 0x10, - 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, - 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x88, 0x8E, 0xE8, 0xDC, 0x3F, 0x67, 0xBC, 0x09, 0x0B, 0x00, - 0x00, 0x74, 0x82, 0xB7, 0xF7, 0xF2, 0x93, 0x7E, 0x7C, 0x34, 0xBA, 0xFD, 0x88, 0xC6, 0x87, 0xBA, - 0xFD, 0xF8, 0x76, 0xE4, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, - 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x38, 0xC4, 0xBC, - 0xE3, 0xB7, 0x0F, 0x05, 0x7F, 0x0C, 0x00, 0x00, 0x00, 0x4C, 0x1D, 0x6F, 0xE7, 0x9C, 0xF4, 0xB7, - 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x8E, 0xF8, 0xC8, 0x71, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, - 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x36, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, - 0x82, 0x3F, 0x06, 0x00, 0x00, 0x00, 0xA6, 0x86, 0x39, 0x70, 0xFD, 0x12, 0x6F, 0xFB, 0x27, 0xB2, - 0xDF, 0x7E, 0xDC, 0x13, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, - 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x87, 0x46, 0xC3, - 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xD5, 0xCC, 0xC1, 0x65, 0x6B, 0xBD, 0xAD, 0x1F, 0x6E, 0xEF, - 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, - 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x30, 0x5A, 0xCD, 0xBD, 0x09, 0xEB, 0xF8, - 0x1D, 0x4B, 0x82, 0x3F, 0x0E, 0x00, 0x00, 0x00, 0x8A, 0x77, 0xFE, 0xE0, 0xD2, 0xF5, 0xDE, 0xA6, - 0x0B, 0x33, 0xDE, 0x7E, 0x10, 0x1F, 0xF9, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, - 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC4, 0x45, 0x92, 0xBD, 0x70, 0x0D, 0x6F, 0xC2, - 0x02, 0x00, 0x00, 0x53, 0xEB, 0xFC, 0xFE, 0x6B, 0x06, 0xB3, 0xDD, 0x7E, 0xCC, 0x90, 0xE1, 0xE1, - 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, - 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x8B, 0xA4, 0x7B, 0xFE, 0x0A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xA6, - 0xD6, 0xF9, 0xDD, 0x8B, 0x47, 0xA3, 0xB7, 0x1F, 0xD5, 0x00, 0x89, 0xC5, 0x47, 0xDD, 0xED, 0xC7, - 0xDD, 0xC4, 0x47, 0xFB, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, - 0xE4, 0xE1, 0xBF, 0xD3, 0x13, 0x51, 0x91, 0x72, 0xDE, 0xB1, 0xB5, 0xBC, 0x09, 0x0B, 0x00, 0x00, - 0x4C, 0x1D, 0x6F, 0xF7, 0x42, 0x79, 0xFB, 0x31, 0xE1, 0x02, 0xE4, 0xD1, 0xC8, 0xED, 0x47, 0x18, - 0x1F, 0x6E, 0xF7, 0xEB, 0x6F, 0xBD, 0x22, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, - 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x07, 0x45, 0xDA, 0x79, 0x47, 0x3E, - 0x3F, 0x1A, 0xFC, 0x71, 0x00, 0x00, 0x00, 0x50, 0x2C, 0x33, 0xD2, 0x3F, 0xDB, 0xDB, 0x31, 0x27, - 0xDD, 0xB3, 0x1F, 0x0F, 0xCE, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, - 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x98, 0xC8, 0xB4, 0xA3, - 0x6B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x1A, 0x66, 0xFF, 0xD2, 0x81, 0xF3, 0x5B, 0x3E, 0x6C, - 0x03, 0x24, 0xF2, 0xAD, 0x57, 0xCD, 0x6E, 0x3F, 0x1E, 0xB2, 0xF1, 0x21, 0x6E, 0x3F, 0x88, 0x8F, - 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, - 0xD3, 0x13, 0x11, 0xD1, 0xCE, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0x73, 0x76, 0xF0, 0xC7, 0x02, 0x00, - 0x00, 0x40, 0x71, 0xCE, 0xED, 0x5F, 0x7A, 0xD7, 0xF9, 0x4D, 0xEF, 0x9B, 0x7C, 0xF6, 0xA3, 0xE6, - 0xC1, 0xF3, 0x19, 0xB5, 0xCF, 0x7E, 0xB8, 0xF8, 0x78, 0xA0, 0xFE, 0xF6, 0x83, 0xF8, 0x48, 0x33, - 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, - 0x11, 0x10, 0xED, 0xCE, 0xBD, 0x09, 0xEB, 0xD8, 0x6D, 0x03, 0xC1, 0x1F, 0x0B, 0x00, 0x00, 0x00, - 0xC5, 0x39, 0x7F, 0x60, 0xD9, 0x86, 0x9A, 0x07, 0xCF, 0xA3, 0xB7, 0x1F, 0xD1, 0xF8, 0x78, 0xD8, - 0x86, 0x87, 0x0B, 0x90, 0xEF, 0xD4, 0xDE, 0x7E, 0x10, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, - 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x21, 0x8F, 0xF1, - 0x26, 0x2C, 0x00, 0x00, 0x30, 0x55, 0xCE, 0xEF, 0x5E, 0x32, 0xEA, 0xC7, 0x47, 0x83, 0xDB, 0x0F, - 0x17, 0x1F, 0xA7, 0xC2, 0xF8, 0x70, 0xB7, 0x1F, 0x7F, 0x4D, 0x7C, 0x64, 0x9B, 0x0A, 0x87, 0x3C, - 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x87, 0x1C, - 0xE7, 0x9D, 0xB8, 0x6D, 0x30, 0xF8, 0x63, 0x01, 0x00, 0x00, 0xA0, 0x38, 0xE7, 0x76, 0x2E, 0x3A, - 0x59, 0x73, 0xFB, 0x11, 0xC4, 0x47, 0xF5, 0xD9, 0x8F, 0x30, 0x3E, 0x62, 0xB7, 0x1F, 0xC4, 0x47, - 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, - 0xE9, 0xE9, 0x68, 0xC8, 0x73, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0xDE, 0xF9, - 0xED, 0x73, 0xAA, 0xF1, 0x51, 0xF7, 0xA1, 0x83, 0x8F, 0xCC, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, - 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, - 0xE9, 0x60, 0xC8, 0x7D, 0x47, 0x3F, 0xCF, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB1, 0xCE, 0xEE, 0x5F, - 0x3A, 0x70, 0x6E, 0xCB, 0x27, 0x63, 0xB7, 0x1F, 0x33, 0x2B, 0xCF, 0x7E, 0x44, 0xE3, 0xC3, 0xED, - 0xDE, 0xCA, 0xED, 0x07, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, - 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x14, 0x8A, 0x9A, 0x7B, 0x13, 0xD6, 0xD8, 0x17, - 0x67, 0x05, 0x7F, 0x3C, 0x00, 0x00, 0x00, 0xE4, 0xEF, 0xDC, 0xDE, 0xE5, 0xEB, 0xCE, 0x6D, 0xFA, - 0x48, 0xEC, 0xF6, 0x63, 0x46, 0x35, 0x3E, 0xAA, 0x01, 0xF2, 0x23, 0x3B, 0xE2, 0x23, 0xE5, 0x54, - 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x44, - 0x24, 0x14, 0xB9, 0x17, 0xAF, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x58, 0xE7, 0xF7, 0x2E, 0x5F, - 0x5F, 0xF7, 0xEC, 0xC7, 0x8F, 0x27, 0x03, 0xA4, 0x7A, 0xFB, 0xF1, 0xED, 0x0B, 0x88, 0x8F, 0x54, - 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, - 0x13, 0x81, 0x50, 0xF4, 0x5E, 0xB8, 0xCA, 0x78, 0xBF, 0xB8, 0xFD, 0xAE, 0xE0, 0x8F, 0x07, 0x00, - 0x00, 0x80, 0xFC, 0x9D, 0xDB, 0x7D, 0xD5, 0x50, 0xCD, 0x9B, 0xAF, 0xC2, 0xF8, 0x88, 0x06, 0xC8, - 0x8F, 0x66, 0x10, 0x1F, 0xA9, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, - 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x60, 0x8A, 0xE6, 0x1D, 0xBF, 0x6D, 0x43, 0xF0, 0xC7, - 0x03, 0x00, 0x00, 0x40, 0xFE, 0xCE, 0xED, 0xB8, 0x6C, 0x6C, 0xF2, 0xF6, 0xE3, 0x02, 0x79, 0xFB, - 0xF1, 0x76, 0xE4, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, - 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x06, 0x53, 0x35, 0xDE, 0x84, 0x05, 0x00, - 0x00, 0x0A, 0x75, 0x76, 0xDB, 0xFC, 0xE0, 0xF6, 0xC3, 0xC6, 0x87, 0x78, 0xF6, 0xE3, 0xED, 0x1F, - 0x4C, 0xDE, 0x7E, 0x10, 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, - 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0xA3, 0x60, 0x2A, 0xE7, 0x1D, 0xBD, 0x79, 0x3C, 0xF8, - 0xE3, 0x01, 0x00, 0x00, 0x20, 0x5F, 0x66, 0xA8, 0x7F, 0xF6, 0xD9, 0xCD, 0x97, 0x04, 0xF1, 0x51, - 0x7B, 0xFB, 0x71, 0x2A, 0xBC, 0xFD, 0xF8, 0x66, 0xE5, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, - 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x04, - 0x53, 0xBE, 0x97, 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x8C, 0xB3, 0x43, 0x4B, 0x07, 0xDE, - 0xDD, 0xF8, 0xE1, 0x6A, 0x80, 0x9C, 0xB6, 0x01, 0x52, 0xF3, 0xEC, 0xC7, 0xF7, 0x2B, 0xB7, 0x1F, - 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, - 0xF0, 0xDF, 0xE9, 0x89, 0x10, 0xE8, 0xD4, 0xC6, 0x96, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x0C, - 0x1B, 0x20, 0xEB, 0x27, 0x06, 0xDF, 0x57, 0x73, 0xFB, 0x11, 0x7D, 0xFE, 0xC3, 0xDD, 0x7E, 0x10, - 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, - 0x7F, 0xA7, 0x27, 0x22, 0xA0, 0x93, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0x63, - 0x02, 0x00, 0x00, 0x20, 0x3F, 0xEF, 0xEE, 0x59, 0x3A, 0xE8, 0xDF, 0x7E, 0x88, 0xF8, 0x70, 0xB7, - 0x1F, 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, - 0xF2, 0xF0, 0xDF, 0xE9, 0x89, 0x00, 0xE8, 0xF4, 0xDC, 0x3F, 0x17, 0x27, 0x6E, 0x5B, 0x1F, 0xFC, - 0x31, 0x01, 0x00, 0x00, 0x90, 0x9F, 0x89, 0x6D, 0x8B, 0x47, 0xEB, 0xDE, 0x7C, 0x15, 0xDE, 0x7E, - 0xDC, 0x4D, 0x7C, 0x34, 0x9F, 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xE9, 0x65, - 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xE2, 0xF0, 0xDF, 0x25, 0xF3, 0x8E, 0xAF, 0xE5, 0x4D, 0x58, 0x00, - 0x00, 0x20, 0x7F, 0x13, 0x5B, 0xFA, 0xC6, 0xE5, 0xC3, 0xE7, 0xF7, 0xBB, 0x6F, 0xBD, 0x22, 0x3E, - 0x1A, 0x4F, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, - 0x4E, 0x4F, 0x1F, 0xFC, 0xBB, 0x65, 0xDE, 0xD1, 0x9B, 0x4F, 0x06, 0x7F, 0x4C, 0x00, 0x00, 0x00, - 0xE4, 0xC3, 0x0C, 0xF5, 0xCF, 0x7A, 0xF7, 0x99, 0x39, 0x95, 0xF8, 0xB0, 0x8B, 0x3E, 0x7C, 0xFE, - 0xD6, 0x5F, 0x11, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, - 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFD, 0x5D, 0xB5, 0x97, 0x56, 0x9A, 0xE0, 0x8F, 0x0A, - 0x00, 0x00, 0x80, 0x7C, 0xB8, 0x37, 0x60, 0x4D, 0x6C, 0xFC, 0x98, 0x0D, 0x90, 0x0B, 0xCC, 0xE9, - 0x47, 0xEC, 0xDC, 0xED, 0x87, 0x0B, 0x90, 0xFB, 0x6D, 0x80, 0x10, 0x1F, 0x0D, 0xA6, 0xC2, 0x21, - 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xFB, - 0xDD, 0x38, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x7C, 0xDD, 0xC4, 0x13, 0x1F, - 0x30, 0xA7, 0xFD, 0x00, 0x09, 0xBE, 0xFD, 0xEA, 0xE1, 0x99, 0xFE, 0xED, 0x07, 0xF1, 0xA1, 0xA6, - 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, - 0x0E, 0xFA, 0xDD, 0x3A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x74, 0x7D, 0x78, - 0xFB, 0x71, 0xCA, 0xCD, 0xDD, 0x7E, 0x7C, 0x67, 0x06, 0xF1, 0x21, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, - 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF9, 0xDD, 0x3C, - 0xF7, 0xCF, 0x3D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x79, 0x9A, 0xD8, 0x79, 0xD5, 0x68, 0xF5, 0xDB, - 0xAF, 0xDC, 0x0D, 0x88, 0x7B, 0xF6, 0xE3, 0x6B, 0xC4, 0x47, 0xFD, 0x54, 0x38, 0xE4, 0x31, 0x15, - 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, 0x01, 0xBF, 0x07, 0xC6, - 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xAE, 0x26, 0xB6, 0x5D, 0x76, 0xB2, 0x7A, 0x03, 0xF2, 0xF0, 0x0C, - 0xF3, 0xF6, 0x7D, 0xC1, 0xED, 0x87, 0x8D, 0x8F, 0x3F, 0x10, 0x1F, 0xC1, 0x54, 0x38, 0xE4, 0x31, - 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0xE1, 0xBE, 0x17, - 0xE6, 0x1D, 0x59, 0x33, 0x16, 0xFC, 0x71, 0x01, 0x00, 0x00, 0xD0, 0xBE, 0x09, 0xFF, 0x0D, 0x58, - 0x93, 0xB7, 0x1F, 0x6F, 0x7E, 0x6D, 0xF2, 0xE6, 0xE3, 0x0D, 0xE2, 0xC3, 0x4E, 0x85, 0x43, 0x1E, - 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xEC, 0x7B, - 0x66, 0x47, 0x6E, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x20, 0x1F, 0x13, 0x43, 0xD7, 0x2F, 0x99, 0x78, - 0xFA, 0x13, 0xE6, 0xCC, 0xA3, 0x95, 0xCF, 0xFF, 0x70, 0xB7, 0x1F, 0x95, 0xF8, 0xB8, 0xC0, 0xBF, - 0xF9, 0x78, 0x83, 0xF8, 0x28, 0x68, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, - 0xDF, 0xE9, 0x89, 0x03, 0x7D, 0xAF, 0xED, 0xA5, 0x7E, 0xF7, 0x20, 0xFA, 0x92, 0xE0, 0x8F, 0x0D, - 0x00, 0x00, 0x80, 0xEC, 0xCE, 0x0C, 0x2D, 0x5B, 0x3B, 0xF1, 0xE4, 0x87, 0x2B, 0x9F, 0x01, 0xF2, - 0x60, 0xE5, 0xB5, 0xBB, 0xD5, 0xDB, 0x8F, 0xAF, 0xD9, 0xF8, 0xF8, 0x47, 0xE2, 0x23, 0xFF, 0xA9, - 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF3, 0xBD, 0x38, - 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x03, 0x00, 0x00, 0x20, 0x3B, 0xF7, 0x06, - 0xAC, 0x89, 0xC7, 0x2F, 0xF2, 0x03, 0xE4, 0xED, 0x6F, 0x55, 0x9E, 0xFB, 0x20, 0x3E, 0xDC, 0x54, - 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, - 0x41, 0xBE, 0x57, 0xE7, 0xBE, 0x26, 0x78, 0x13, 0x16, 0x00, 0x00, 0xC8, 0xC3, 0xD9, 0x5D, 0xD7, - 0x0C, 0x4E, 0x3C, 0x36, 0xC3, 0x9C, 0x71, 0xCF, 0x7E, 0x04, 0x6F, 0xBD, 0xFA, 0xC3, 0x7A, 0xE2, - 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, - 0xF1, 0x3D, 0xBB, 0xF9, 0xFE, 0xBC, 0xE3, 0xB7, 0x0D, 0x05, 0x7F, 0x6C, 0x00, 0x00, 0x00, 0x64, - 0xF7, 0xEE, 0xB6, 0xC5, 0xA3, 0x13, 0x8F, 0xCF, 0x30, 0xEF, 0x7C, 0xBB, 0x72, 0xFB, 0xF1, 0xE6, - 0x5F, 0x5D, 0x44, 0x7C, 0x14, 0x32, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, - 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x57, 0x89, 0x0F, 0x3F, 0x40, 0x8E, 0xDC, 0xCC, 0x9B, 0xB0, - 0x00, 0x00, 0x40, 0xFB, 0xCE, 0x6D, 0x5F, 0x60, 0x26, 0x1E, 0xB9, 0xC0, 0xBC, 0xE5, 0x5E, 0xBB, - 0xFB, 0xD7, 0xC4, 0x47, 0x31, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, - 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0xE1, 0xEF, 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, - 0x00, 0xB4, 0xC7, 0x0C, 0x5D, 0x3B, 0xFB, 0xDC, 0xB6, 0x4B, 0xCD, 0x3B, 0xDF, 0xB4, 0x01, 0xF2, - 0x75, 0xE2, 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, - 0xA7, 0x0E, 0xF1, 0xBD, 0xBA, 0x58, 0x7C, 0xB8, 0xBD, 0xB4, 0xC2, 0x98, 0x97, 0xBF, 0x38, 0x3B, - 0xF8, 0xE3, 0x03, 0x00, 0x00, 0x20, 0xBD, 0xB3, 0xFB, 0x97, 0x0E, 0xBC, 0xFB, 0xD8, 0x87, 0xCC, - 0xDB, 0x77, 0x5F, 0x64, 0xCE, 0x13, 0x1F, 0x05, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, - 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x89, 0xF8, 0x70, 0x7B, 0xE1, 0x6A, 0x63, - 0x8E, 0xDD, 0x36, 0x10, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDE, 0x99, 0x5D, 0x9F, 0xBB, 0xEB, - 0xD4, 0x86, 0x0F, 0x98, 0xF3, 0xFF, 0x44, 0x7C, 0xE4, 0x3F, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, - 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x27, 0xC2, 0x23, 0x98, 0xF7, 0xAF, - 0x4B, 0xCC, 0xE9, 0x9F, 0xDD, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x76, 0xAF, 0x3D, 0x70, 0xED, - 0x86, 0xF1, 0xDD, 0xAB, 0xCD, 0xD9, 0x17, 0xBF, 0x44, 0x7C, 0xE4, 0x3A, 0x15, 0x09, 0x45, 0x4D, - 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0xA7, 0xC3, 0xC3, 0xED, - 0xD4, 0xB3, 0xF3, 0xCC, 0xEF, 0x77, 0xCC, 0x31, 0xBF, 0xDB, 0x77, 0xD3, 0x60, 0xF0, 0xC7, 0x07, - 0x00, 0x00, 0x40, 0x7A, 0xAF, 0xEF, 0xB9, 0x75, 0xF8, 0xF7, 0x07, 0x6F, 0x35, 0xBF, 0xDF, 0xB7, - 0xD2, 0xBC, 0x79, 0xE0, 0x32, 0x73, 0xFE, 0x9F, 0x55, 0x54, 0x24, 0x9D, 0x08, 0x87, 0x3C, 0x26, - 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, - 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0x4E, 0x87, 0xC7, 0x99, 0xBF, 0xEB, 0x33, 0xE3, 0xBB, - 0xE6, 0x9A, 0xDF, 0x6D, 0xB3, 0xF1, 0xE1, 0xB6, 0x67, 0x39, 0xAF, 0xE2, 0x05, 0x00, 0x00, 0xD9, - 0xFD, 0xF3, 0xFF, 0xFE, 0x17, 0x17, 0xFE, 0x76, 0xFB, 0xEA, 0xFB, 0x7E, 0xB7, 0x6D, 0xF1, 0x5B, - 0xBF, 0xDF, 0xB9, 0xD8, 0xB8, 0xBD, 0x7D, 0xE8, 0x72, 0xFF, 0x5B, 0x2D, 0x74, 0x64, 0x34, 0x9A, - 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, - 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0xAE, 0x3E, 0x3C, 0xCE, 0xFE, - 0x43, 0x9F, 0x79, 0x73, 0xEF, 0x64, 0x78, 0xBC, 0xBE, 0x75, 0xCE, 0xF8, 0xEF, 0xB6, 0x5D, 0xBA, - 0x7E, 0xB4, 0xFF, 0x3D, 0x7F, 0x14, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDD, 0x7F, 0xBF, 0xFB, - 0x33, 0x17, 0xBF, 0xB6, 0x79, 0xF1, 0x96, 0x30, 0x42, 0xC6, 0x77, 0x2F, 0x36, 0xA7, 0xFF, 0xC6, - 0x1E, 0xD4, 0x65, 0x6C, 0xC4, 0x27, 0xC2, 0x21, 0x8F, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, - 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, 0xDF, - 0xAB, 0xAB, 0x0D, 0x8F, 0xF3, 0xFF, 0x34, 0xDF, 0xBC, 0xB5, 0x3F, 0x72, 0xE3, 0x61, 0xF7, 0xEA, - 0x33, 0x73, 0x7E, 0x34, 0x3E, 0xF4, 0xA9, 0x59, 0xC1, 0x1F, 0x17, 0x00, 0x00, 0x00, 0xF9, 0xF9, - 0xEF, 0xDF, 0x5D, 0xF2, 0x99, 0xD7, 0xB6, 0x2C, 0xFA, 0x59, 0x18, 0x22, 0x6F, 0xEC, 0xB9, 0xCC, - 0x4C, 0xFC, 0xBD, 0x0B, 0x02, 0x15, 0x1E, 0x6E, 0xB1, 0x68, 0xC8, 0x6B, 0x32, 0x1C, 0xF2, 0x98, - 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, - 0x3A, 0xC4, 0xF7, 0xEA, 0x26, 0xC3, 0xC3, 0xFB, 0xE7, 0xF9, 0xE6, 0x9D, 0x91, 0x79, 0x35, 0xE1, - 0xF1, 0xDA, 0xE6, 0x4B, 0xF7, 0x8F, 0x6F, 0xE9, 0xE3, 0xB5, 0xBB, 0x00, 0x00, 0xA0, 0x78, 0xFF, - 0xEB, 0xA1, 0xCB, 0xBE, 0xF8, 0xBB, 0x6D, 0x8B, 0x7E, 0x19, 0x86, 0x88, 0x7B, 0x3E, 0xE4, 0xEC, - 0x4F, 0x5D, 0x1C, 0x10, 0x1F, 0xF5, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, - 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0x51, 0x7D, 0xC0, 0x3C, 0x08, 0x8F, 0xD7, - 0xB7, 0x5E, 0x3A, 0xF6, 0xDA, 0x96, 0x4B, 0x79, 0xDD, 0x2E, 0x00, 0x00, 0x98, 0x5A, 0xA3, 0xFD, - 0xFD, 0x7F, 0xF4, 0xAB, 0x27, 0x2E, 0xFB, 0x3F, 0xA2, 0xCF, 0x87, 0xBC, 0x35, 0xEC, 0x1E, 0x54, - 0x17, 0xD1, 0x90, 0xD7, 0x64, 0x38, 0xE4, 0x31, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, - 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x55, 0xC2, 0x23, 0xFE, - 0x80, 0xB9, 0x8D, 0x8E, 0x5F, 0xBE, 0xBE, 0x7D, 0xEE, 0xBA, 0xE0, 0x8F, 0x00, 0x00, 0x00, 0x80, - 0xCE, 0xF8, 0xD5, 0x23, 0x57, 0x7E, 0xE0, 0x37, 0x4F, 0x2E, 0xDE, 0x30, 0x19, 0x22, 0x8B, 0xCC, - 0xE9, 0xBF, 0xB9, 0xCC, 0x78, 0xFF, 0x2A, 0x02, 0xA2, 0x9D, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, - 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, - 0xDF, 0xAB, 0x6B, 0xFC, 0x80, 0x39, 0xCF, 0x79, 0x00, 0x00, 0x80, 0xAE, 0x72, 0xF2, 0x91, 0xC5, - 0xF3, 0x5F, 0x7D, 0x66, 0xF1, 0x0E, 0x17, 0x20, 0x6E, 0xE3, 0xBB, 0x17, 0x99, 0x33, 0x7F, 0x67, - 0x0F, 0xE2, 0x2A, 0x26, 0xD2, 0x4E, 0x86, 0x43, 0x1E, 0x8B, 0x47, 0x43, 0x5E, 0x53, 0x91, 0x50, - 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x73, 0xEA, 0x01, - 0xF3, 0xDF, 0x6D, 0xBD, 0x74, 0xF0, 0xBF, 0x7D, 0x67, 0xDE, 0x07, 0x82, 0x2F, 0x73, 0x00, 0x00, - 0x80, 0xEE, 0xF3, 0xAB, 0x8D, 0x8B, 0xD6, 0xBC, 0xFA, 0xCC, 0xC2, 0x9F, 0x87, 0x21, 0xF2, 0xC6, - 0x9E, 0xC5, 0xE6, 0xDD, 0x7F, 0xB0, 0x87, 0x7D, 0x15, 0x16, 0x49, 0x26, 0xC3, 0x21, 0x8F, 0xA9, - 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, - 0x83, 0x7C, 0xAF, 0xCD, 0xFB, 0xE7, 0x05, 0x75, 0x0F, 0x98, 0xDB, 0x8D, 0xFE, 0x7F, 0x8F, 0x5E, - 0x3A, 0x27, 0xF8, 0xB2, 0x06, 0x00, 0x00, 0xE8, 0x6E, 0xFE, 0xF3, 0x21, 0x83, 0x8B, 0xFF, 0xE2, - 0x77, 0xDB, 0x16, 0xFE, 0x32, 0x0C, 0x91, 0x37, 0x0F, 0x2C, 0x36, 0x67, 0x7F, 0x6A, 0x0F, 0xFE, - 0x2A, 0x32, 0x1A, 0x4D, 0x86, 0x43, 0x1E, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, - 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x87, 0xF9, 0x5E, 0xDB, 0xE9, 0xBF, 0xE9, 0xAB, - 0x79, 0xC0, 0xFC, 0xB5, 0x67, 0xE6, 0x1C, 0xE3, 0x01, 0x73, 0x00, 0x00, 0xD0, 0xB3, 0x6C, 0x88, - 0xFC, 0xBB, 0x57, 0x37, 0x2F, 0xBA, 0xE7, 0x77, 0xDB, 0x16, 0xBD, 0x15, 0x86, 0xC8, 0xDB, 0x87, - 0x12, 0x3E, 0xA8, 0x2E, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, - 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xC3, 0x7C, 0x2F, 0x6D, 0xE2, 0xEF, 0xE7, 0xF3, - 0x80, 0x39, 0x00, 0x00, 0x28, 0xAF, 0x93, 0xF7, 0x2E, 0xFC, 0xC8, 0x2B, 0x9B, 0x16, 0x3F, 0x1A, - 0x46, 0x88, 0x7B, 0x3E, 0xA4, 0xE9, 0x83, 0xEA, 0x32, 0x1C, 0xF2, 0x98, 0x0A, 0x87, 0x3C, 0xA6, - 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x3E, 0xD0, 0xF7, 0xCA, - 0xCE, 0xFE, 0xC3, 0x7C, 0xF3, 0xE6, 0x5E, 0xF7, 0xED, 0x56, 0x95, 0xF8, 0xE0, 0x01, 0x73, 0x00, - 0x00, 0x50, 0x6A, 0xFF, 0xE3, 0xFE, 0xCF, 0x2C, 0x7A, 0x75, 0xF3, 0xA2, 0xE7, 0xA2, 0x21, 0x32, - 0xF1, 0xF7, 0x36, 0x0C, 0x88, 0x8F, 0x84, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, - 0x7D, 0xA8, 0xEF, 0x85, 0x9D, 0xFF, 0xA7, 0x05, 0xE6, 0xED, 0x83, 0x7D, 0x41, 0x78, 0x04, 0x37, - 0x1F, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0xA6, 0x8B, 0x5F, 0x3E, 0xB6, 0xF8, 0x96, 0xD7, 0xB7, 0x2E, - 0x7C, 0x39, 0x0C, 0x11, 0xF7, 0xA0, 0xBA, 0xFF, 0x7C, 0x88, 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, - 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xF6, - 0xDD, 0x3E, 0xF7, 0x80, 0xF9, 0xA9, 0x67, 0xA3, 0xE1, 0xE1, 0xC7, 0x07, 0x0F, 0x98, 0x03, 0x00, - 0x80, 0xE9, 0xC7, 0x3D, 0xA8, 0xFE, 0xDB, 0xA7, 0x17, 0x7F, 0xF5, 0xF5, 0xAD, 0x8B, 0x7E, 0xE3, - 0x22, 0xE4, 0x77, 0x3B, 0x16, 0x9A, 0x37, 0xF7, 0x2F, 0x32, 0xE7, 0xFE, 0xD1, 0x1D, 0xEC, 0x55, - 0x44, 0x64, 0x5D, 0x3C, 0x1A, 0xF2, 0x9A, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, - 0xFC, 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xED, 0xAB, 0x3C, 0x60, 0x3E, 0x19, 0x1E, 0xAF, 0x3D, 0x33, - 0x97, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x7E, 0xF5, 0xC8, 0xBC, 0x0F, 0xFC, 0xE6, 0xE9, 0x85, 0xF7, - 0xBD, 0xBE, 0x75, 0xC1, 0x5B, 0x2E, 0x42, 0xDC, 0xDE, 0x1E, 0x59, 0x6C, 0xBC, 0x7F, 0x51, 0x31, - 0x91, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, - 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xCD, 0xAB, 0x3C, 0x60, 0x1E, 0x3E, 0xE7, 0x61, 0xC3, 0x63, 0xCB, - 0x5C, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x88, 0x1B, 0xFB, 0x4F, 0x9F, 0xB9, 0xF8, 0x95, 0xCD, 0x0B, - 0xB7, 0x84, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCD, 0xA9, 0xE7, 0xDA, 0x09, 0x11, 0x15, 0x0E, 0x79, - 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC0, 0xEF, - 0xD6, 0xD5, 0x3E, 0x60, 0x3E, 0xD7, 0xBC, 0xBE, 0x75, 0xEE, 0xB8, 0xFD, 0x91, 0x07, 0xCC, 0x01, - 0x00, 0x00, 0x9A, 0xF9, 0x9F, 0x0F, 0x2D, 0x5A, 0xFA, 0xEA, 0xE6, 0x85, 0x3F, 0x0B, 0x43, 0x64, - 0x7C, 0x68, 0x91, 0x39, 0x33, 0xEA, 0x0E, 0xFE, 0x2A, 0x32, 0x1A, 0x2D, 0x1E, 0x0D, 0x79, 0x4D, - 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC8, 0xEF, 0xC6, - 0xD5, 0x3F, 0x60, 0x6E, 0xB7, 0x75, 0x0E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA4, 0xF1, 0xBF, 0x1E, - 0x5A, 0xF0, 0xC5, 0xD7, 0xB6, 0x2E, 0xF8, 0x65, 0x18, 0x22, 0x6F, 0xEC, 0x5D, 0x64, 0xCE, 0xFE, - 0xC4, 0x45, 0x80, 0x0A, 0x8E, 0xE8, 0xE2, 0xD1, 0x90, 0xD7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, - 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x07, 0xFD, 0x6E, 0x9B, 0x7E, 0xC0, 0x7C, 0x2E, 0x0F, - 0x98, 0x03, 0x00, 0x00, 0x64, 0xE5, 0x1E, 0x54, 0xFF, 0xF5, 0xC6, 0x45, 0x7F, 0x19, 0x7D, 0x3E, - 0xC4, 0x3D, 0xA8, 0x7E, 0xFE, 0x67, 0x2A, 0x3C, 0xDC, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, - 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0x61, 0xBF, 0xDB, 0xC6, 0x03, 0xE6, - 0x00, 0x00, 0x00, 0x05, 0x72, 0x0F, 0xAA, 0xFF, 0xFA, 0xC9, 0x85, 0x1B, 0xC2, 0x08, 0x71, 0x7B, - 0xE7, 0x70, 0xFC, 0xF9, 0x10, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, - 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xD8, 0xEF, 0xA6, 0xF1, 0x80, 0x39, 0x00, 0x00, 0xC0, 0x14, - 0x3A, 0xF9, 0xC8, 0xE2, 0xF9, 0xBF, 0xDD, 0xB4, 0x60, 0x47, 0x18, 0x21, 0xE1, 0x83, 0xEA, 0x3A, - 0x1C, 0xF2, 0x58, 0x3C, 0x10, 0x8A, 0x9C, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, - 0x03, 0x7F, 0xB7, 0x8C, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x3A, 0xE8, 0x57, 0x1B, 0x17, 0xAD, 0x79, - 0x65, 0xD3, 0x82, 0x9F, 0x57, 0x42, 0x64, 0x81, 0x19, 0x1F, 0x5A, 0x68, 0xCE, 0x8C, 0xBA, 0x43, - 0xBC, 0x8A, 0x88, 0xAC, 0x8B, 0x07, 0x42, 0x91, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, - 0x3D, 0x7D, 0xE8, 0xEF, 0x86, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x40, 0x97, 0xA8, 0x7C, 0x90, 0xE1, - 0xC2, 0xAF, 0xBE, 0xB6, 0x75, 0xFE, 0x2F, 0x5D, 0x84, 0xB8, 0xBD, 0xB9, 0x7F, 0xA1, 0x39, 0xFB, - 0x13, 0x77, 0xA0, 0x57, 0x41, 0x91, 0x66, 0xF1, 0x40, 0x28, 0x72, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, - 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFE, 0x9D, 0x5E, 0xA3, 0x07, 0xCC, 0x4F, 0x7E, 0xE7, 0x53, 0xF3, - 0x83, 0x2F, 0x01, 0x00, 0x00, 0x00, 0x74, 0xC2, 0x60, 0xFF, 0xA7, 0xFE, 0xDD, 0xAB, 0x9B, 0x16, - 0xDC, 0xF3, 0xFA, 0xD6, 0xF9, 0x6F, 0x85, 0x21, 0xF2, 0xF6, 0x88, 0x7B, 0x50, 0x5D, 0x85, 0x45, - 0x92, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFF, - 0x9D, 0x9E, 0x7A, 0xC0, 0xFC, 0xB7, 0x1B, 0xE7, 0xDE, 0x10, 0xFC, 0x23, 0x0F, 0x00, 0x00, 0x80, - 0x6E, 0xF0, 0xFF, 0x7E, 0x63, 0xF1, 0x87, 0x7F, 0xF3, 0xD4, 0x82, 0x47, 0xC3, 0x08, 0x71, 0x3B, - 0xF5, 0xDC, 0x22, 0xE3, 0xFD, 0x8B, 0x8A, 0x8C, 0x46, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, - 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xFE, 0x3B, 0xB9, 0xF8, 0x03, 0xE6, 0xEE, 0x39, 0x8F, - 0x57, 0x9F, 0xBE, 0xF4, 0x3F, 0x06, 0xFF, 0x88, 0x03, 0x00, 0x00, 0xA0, 0x1B, 0xFD, 0x8F, 0xFB, - 0x17, 0x2C, 0x7A, 0x75, 0xF3, 0x82, 0x9F, 0x85, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCC, 0xE9, 0xBF, - 0x75, 0x07, 0x61, 0x15, 0x1C, 0xD1, 0xA9, 0x48, 0x28, 0x6A, 0xB1, 0x03, 0x7A, 0x99, 0x27, 0x0F, - 0xFF, 0x9D, 0x9E, 0x0E, 0x80, 0x4E, 0xAD, 0xEE, 0x01, 0xF3, 0xCD, 0x73, 0xDE, 0xB2, 0x3F, 0xF2, - 0x80, 0x39, 0x00, 0x00, 0x40, 0x2F, 0xF9, 0xE5, 0xC3, 0xF3, 0x6F, 0x79, 0x75, 0xCB, 0x82, 0x97, - 0xC3, 0x10, 0x71, 0x0F, 0xAA, 0x4F, 0xFC, 0x57, 0x77, 0xF8, 0x27, 0x3E, 0xA6, 0x6C, 0xF2, 0xF0, - 0xDF, 0xE9, 0xE9, 0x08, 0xE8, 0xC4, 0x1A, 0x3D, 0x60, 0x3E, 0xBE, 0xA5, 0x6F, 0x76, 0xF0, 0x8F, - 0x31, 0x00, 0x00, 0x00, 0x7A, 0x49, 0xF8, 0xA0, 0x7A, 0xF4, 0xF9, 0x10, 0xF7, 0xA0, 0xFA, 0xB9, - 0x7F, 0x74, 0x21, 0x40, 0x7C, 0x14, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x74, 0x08, 0x4C, 0xF5, 0x1A, - 0x3D, 0x60, 0xFE, 0xEB, 0xC7, 0x3E, 0x7D, 0x55, 0xF0, 0x8F, 0x2E, 0x00, 0x00, 0x00, 0x7A, 0x99, - 0xFB, 0x20, 0xC3, 0xDF, 0x6C, 0x9C, 0x7F, 0x5F, 0xED, 0x83, 0xEA, 0x0B, 0xCD, 0xF9, 0x9F, 0xA9, - 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x63, 0x60, 0xAA, 0x17, - 0x7F, 0xC0, 0xFC, 0xF5, 0x6D, 0x73, 0x4E, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x40, 0x49, 0xFD, 0xDB, - 0x83, 0x7D, 0x7D, 0xAF, 0x6C, 0x5E, 0xB0, 0xA5, 0x12, 0x21, 0xF3, 0xCD, 0xEF, 0x77, 0xCD, 0x37, - 0xA7, 0x9E, 0x5B, 0x68, 0xBC, 0x7F, 0x51, 0xC1, 0x90, 0xE7, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, - 0xFF, 0x4E, 0x4F, 0xC7, 0xC0, 0x54, 0x8E, 0x07, 0xCC, 0x01, 0x00, 0x00, 0xA6, 0xB1, 0xFF, 0xF9, - 0xD0, 0xBC, 0xA5, 0xAF, 0x6E, 0xEE, 0xFB, 0x99, 0x8B, 0x90, 0x30, 0x44, 0xCE, 0x8C, 0xBA, 0x03, - 0xB4, 0x8A, 0x87, 0x76, 0x17, 0x3B, 0xA0, 0x97, 0x79, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x20, 0x98, - 0xAA, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xAA, 0x7E, 0xF5, 0x58, 0xDF, 0x5F, 0x54, 0x3E, 0xC8, - 0xB0, 0x12, 0x22, 0xE3, 0x43, 0xF6, 0xC0, 0xF8, 0x13, 0x77, 0x98, 0x56, 0x21, 0x91, 0x65, 0xB1, - 0x03, 0x7A, 0x99, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x82, 0xA9, 0x18, 0x0F, 0x98, 0x03, 0x00, - 0x00, 0x40, 0x72, 0x0F, 0xAA, 0xFF, 0x7A, 0x63, 0xDF, 0x5F, 0xBE, 0xBE, 0xB5, 0xEF, 0xAD, 0x30, - 0x44, 0xDE, 0xDC, 0x6F, 0x0F, 0x90, 0x6D, 0x3F, 0x1F, 0x22, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, - 0x77, 0x7A, 0x3A, 0x0C, 0x8A, 0x1E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x20, 0x11, 0xFF, 0x41, 0xF5, - 0xA7, 0xFA, 0x1E, 0x0D, 0x23, 0xC4, 0xCD, 0x3D, 0xA8, 0x9E, 0xED, 0xF9, 0x10, 0x71, 0x48, 0x2F, - 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x71, 0x50, 0xF4, 0xCE, 0xFC, 0xDD, 0x7C, 0x1E, 0x30, 0x07, - 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x41, 0xF5, 0x57, 0x9F, 0x99, 0x3F, 0x12, 0x46, 0x48, 0xFA, 0x07, - 0xD5, 0xC5, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x41, 0x91, 0x73, 0xCF, 0x79, - 0xF0, 0x80, 0x39, 0x00, 0x00, 0x00, 0xDA, 0xF2, 0xAB, 0x27, 0xFA, 0xD6, 0x44, 0x1F, 0x54, 0x77, - 0xCF, 0x87, 0xB4, 0x7E, 0x50, 0x3D, 0x76, 0x40, 0x2F, 0xF3, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x81, - 0x50, 0xD4, 0xCE, 0xFD, 0x94, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x90, 0xA3, 0xCA, 0x07, 0x19, 0xF6, - 0x7D, 0x35, 0xFA, 0xA0, 0xBA, 0x7B, 0x3E, 0x44, 0x3F, 0xA8, 0x1E, 0x3B, 0xA0, 0x97, 0x79, 0xF2, - 0xF0, 0xDF, 0xE9, 0xE9, 0x48, 0x28, 0x62, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x42, 0xB9, 0xE7, - 0x43, 0x5E, 0xDD, 0xD4, 0x77, 0x4F, 0xF4, 0x41, 0xF5, 0xB7, 0x0E, 0x46, 0x1F, 0x54, 0x17, 0x87, - 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0A, 0x79, 0x2F, 0x7C, 0xC0, 0x3C, 0xFA, 0x9C, - 0x87, 0x1D, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA0, 0x18, 0x47, 0xBF, 0xB1, 0xF8, 0xC3, 0xAF, 0x6C, - 0xEE, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0x3B, 0x87, 0xEC, 0xC1, 0xF4, 0x5F, 0xC4, 0x41, 0xBD, 0x8C, - 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x42, 0xDE, 0x53, 0x0F, 0x98, 0xFF, 0xFA, 0xE1, 0x4B, 0x6F, - 0x0E, 0xFE, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0x3F, 0xA8, 0xEE, 0x9E, 0x0F, 0xD9, 0xDE, - 0x67, 0xDC, 0x7E, 0xBF, 0xB3, 0xCF, 0x9C, 0x7A, 0xCE, 0x1E, 0x54, 0xD5, 0xA1, 0xBD, 0x2C, 0x93, - 0x87, 0xFF, 0x4E, 0xAF, 0x3E, 0x14, 0xF2, 0x9E, 0x7A, 0xC0, 0xFC, 0xD7, 0x83, 0x73, 0xFE, 0xB7, - 0xE0, 0x1F, 0x05, 0x00, 0x00, 0x00, 0x60, 0xEA, 0xFC, 0xF2, 0xE1, 0xB9, 0xB7, 0xBC, 0xB6, 0xB5, - 0xEF, 0x97, 0x61, 0x88, 0x8C, 0xEF, 0x9E, 0x6F, 0x26, 0xFE, 0xAB, 0x3D, 0x18, 0xAB, 0x03, 0x7C, - 0x2F, 0x4F, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0C, 0x79, 0x4D, 0x3D, 0x60, 0xFE, 0xDA, 0xA6, 0x39, - 0x77, 0xF3, 0x80, 0x39, 0x00, 0x00, 0x00, 0x3A, 0xCA, 0x7F, 0x50, 0xFD, 0xC9, 0xBE, 0xAF, 0xBE, - 0xBE, 0x65, 0xDE, 0x5B, 0x61, 0x88, 0xBC, 0xB9, 0x6F, 0xBE, 0x39, 0xFB, 0x13, 0x7B, 0x48, 0x56, - 0x87, 0xF9, 0x5E, 0x9B, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x1A, 0xF2, 0x98, 0x7A, 0xC0, 0xFC, 0xD5, - 0xCD, 0x73, 0x37, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xBA, 0x8A, 0x7B, 0x50, 0xFD, 0xB7, 0x9B, - 0xFA, 0xEE, 0x09, 0x23, 0xC4, 0xED, 0xED, 0x61, 0xF7, 0xA0, 0xBA, 0x38, 0xD4, 0xF7, 0xCA, 0xE4, - 0xE1, 0xBF, 0xD3, 0xD3, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0xC9, 0x3D, - 0x1F, 0xF2, 0xCA, 0xA6, 0xBE, 0x2D, 0xD1, 0x10, 0x71, 0xCF, 0x87, 0xF4, 0xDC, 0x83, 0xEA, 0xF2, - 0xF0, 0xDF, 0xE9, 0xE9, 0x78, 0x68, 0x77, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x9E, 0x57, 0xF9, - 0x20, 0xC3, 0x79, 0x35, 0x0F, 0xAA, 0x9F, 0xFE, 0x5B, 0x7B, 0xE0, 0x55, 0x87, 0xFD, 0x6E, 0x9B, - 0x3C, 0xFC, 0x77, 0x7A, 0xF5, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xA5, 0xF3, - 0xAB, 0xC7, 0xFA, 0xFE, 0x22, 0xFE, 0xA0, 0x7A, 0x57, 0x3F, 0x1F, 0x22, 0x0F, 0xFF, 0x9D, 0x9E, - 0x0E, 0x88, 0xAC, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0x94, 0x9A, 0x7B, 0x50, 0xFD, 0xB5, 0x2D, - 0xF3, 0xBE, 0x1E, 0x7F, 0x50, 0xFD, 0xDC, 0x3F, 0xDA, 0xC3, 0xB5, 0x8A, 0x80, 0x4E, 0x4D, 0x1E, - 0xFE, 0x3B, 0x3D, 0x1D, 0x11, 0x59, 0xC6, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x98, 0x56, 0xDC, 0x83, - 0xEA, 0xBF, 0x79, 0xAA, 0xEF, 0xC7, 0x61, 0x84, 0xB8, 0x75, 0xCD, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, - 0xE9, 0xE9, 0x90, 0x48, 0xBB, 0x46, 0x0F, 0x98, 0xBF, 0xB6, 0xE5, 0xD2, 0x81, 0xE0, 0x7F, 0x1A, - 0x00, 0x00, 0x00, 0xA0, 0xBC, 0xFC, 0x0F, 0x32, 0xDC, 0xD4, 0x37, 0x12, 0x46, 0x48, 0xF8, 0x41, - 0x86, 0x1D, 0x7B, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x13, 0x69, 0xA7, 0x1E, 0x30, 0x7F, - 0xE5, 0xC9, 0x39, 0xB7, 0x07, 0xFF, 0x53, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x87, 0x7B, 0x50, 0xFD, - 0xB5, 0x2D, 0xF3, 0x8E, 0x85, 0x21, 0xE2, 0x9E, 0x0F, 0x39, 0x33, 0x6A, 0x0F, 0xDF, 0x2A, 0x12, - 0x8A, 0x9A, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x26, 0xD2, 0x4C, 0x3D, 0x60, 0xFE, 0xCA, 0xA6, 0xB9, - 0xFF, 0x57, 0xF0, 0xB7, 0x1E, 0x00, 0x00, 0x00, 0x98, 0x9E, 0xC2, 0x0F, 0x32, 0x8C, 0x3E, 0xA8, - 0xFE, 0xC6, 0x9E, 0x29, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x14, 0x49, 0x17, 0x7F, - 0xC0, 0xDC, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x98, 0xF0, 0x83, 0x0C, 0xE3, 0x0F, 0xAA, - 0x17, 0xF6, 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2A, 0x92, 0x8C, 0x07, 0xCC, 0x01, 0x00, - 0x00, 0x80, 0x0C, 0x5E, 0x79, 0x72, 0xCE, 0xA5, 0xF1, 0x0F, 0x32, 0x74, 0x0F, 0xAA, 0xE7, 0xFA, - 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2C, 0x5A, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, - 0x1C, 0xFC, 0x7A, 0x63, 0xDF, 0x55, 0xAF, 0x6E, 0x9E, 0xF7, 0x4F, 0x61, 0x84, 0x84, 0x0F, 0xAA, - 0xCB, 0xA0, 0x48, 0x33, 0x79, 0xF8, 0xEF, 0xF4, 0xEA, 0xC3, 0x22, 0xC9, 0x78, 0xC0, 0x1C, 0x00, - 0x00, 0x00, 0xC8, 0xD9, 0x2F, 0x1F, 0x9E, 0x7B, 0x4B, 0xFC, 0x83, 0x0C, 0x33, 0x3F, 0xA8, 0x2E, - 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x8B, 0x66, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, 0x40, 0xFE, - 0x07, 0x19, 0x6E, 0xEE, 0xFB, 0x3F, 0xE3, 0xCF, 0x87, 0xA4, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, - 0x3D, 0x1D, 0x18, 0x8D, 0xA6, 0x1E, 0x30, 0xFF, 0xED, 0xC6, 0x4B, 0xBF, 0xC5, 0x03, 0xE6, 0x00, - 0x00, 0x00, 0x40, 0x01, 0xC2, 0x07, 0xD5, 0xC3, 0x08, 0x71, 0x7B, 0xEB, 0x40, 0x82, 0x07, 0xD5, - 0xE5, 0xE1, 0xBF, 0xD3, 0xD3, 0x91, 0xA1, 0xE6, 0x9E, 0xF3, 0x88, 0x3F, 0x60, 0xFE, 0xCA, 0x53, - 0x73, 0xB6, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x00, 0x30, 0x05, 0xDC, 0x07, 0x19, 0xBE, 0xBE, 0x75, - 0xDE, 0xFE, 0x68, 0x88, 0xBC, 0x73, 0xA8, 0xC1, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xD0, - 0x88, 0x4F, 0x3D, 0x60, 0xFE, 0xDA, 0xE6, 0x39, 0x3F, 0xE1, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, - 0x03, 0xDC, 0x07, 0x19, 0xC6, 0x1F, 0x54, 0x3F, 0xFD, 0xB7, 0xF6, 0xF0, 0x5E, 0x82, 0xF8, 0x70, - 0x0F, 0x98, 0xD7, 0x3C, 0xE7, 0xC1, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x40, 0x77, 0x88, 0x7F, 0x90, - 0xE1, 0xF8, 0xEE, 0x3E, 0x33, 0xF1, 0xF7, 0xEE, 0x20, 0xAF, 0x02, 0xA0, 0x93, 0xAB, 0x0F, 0x8D, - 0xF8, 0xDC, 0x03, 0xE6, 0x6F, 0x0C, 0xD5, 0x3F, 0x60, 0x3E, 0xDA, 0xFF, 0x9E, 0x3F, 0x0A, 0x7E, - 0xBB, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xCD, 0x7F, 0x50, 0x7D, 0xCB, 0xBC, 0xAF, 0x57, 0x1E, 0x54, - 0xB7, 0x07, 0x78, 0xBB, 0x37, 0xF7, 0xF5, 0xD9, 0x03, 0xBD, 0x3B, 0xD8, 0xAB, 0x18, 0x98, 0xEA, - 0xD5, 0xC7, 0x46, 0x74, 0xEE, 0x83, 0x04, 0x79, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xE8, 0x31, 0xEE, - 0x41, 0xF5, 0x57, 0x36, 0xCD, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0xDB, 0xC3, 0xF3, 0xED, 0x01, 0x5F, - 0x45, 0xC1, 0x54, 0x4D, 0x47, 0x87, 0x1B, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x00, 0x25, 0xF0, 0x6F, - 0x1B, 0xFA, 0xFA, 0x5E, 0xDB, 0x32, 0xF7, 0x27, 0x61, 0x84, 0xFC, 0x7E, 0xE7, 0x3C, 0x73, 0xEA, - 0xD9, 0xF9, 0xF6, 0xC0, 0xAF, 0x02, 0xA1, 0xC8, 0x35, 0x0E, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, - 0x00, 0x4A, 0xE6, 0x57, 0x4F, 0x5C, 0xBA, 0xC6, 0x86, 0xC8, 0xB1, 0x68, 0x88, 0x9C, 0xF9, 0x3B, - 0x17, 0x01, 0x2A, 0x16, 0xF2, 0x5E, 0x7D, 0x78, 0xB8, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0x50, - 0x62, 0xEE, 0x01, 0xEE, 0xDF, 0x3E, 0x39, 0xF7, 0xAB, 0xAF, 0x6F, 0x9B, 0x37, 0x1E, 0x86, 0x88, - 0x7B, 0x50, 0xBD, 0xD8, 0xE7, 0x43, 0xEA, 0xC3, 0x83, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x69, - 0xA4, 0xF2, 0x41, 0x86, 0x73, 0xEF, 0x79, 0x7D, 0xCB, 0xDC, 0x9A, 0x07, 0xD5, 0xCF, 0xFD, 0x34, - 0xEF, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, 0xA6, 0xB1, 0x57, 0x9E, 0x9C, - 0x73, 0xA9, 0x7A, 0x50, 0x3D, 0x9F, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, - 0xE0, 0x7B, 0x6D, 0x47, 0xDF, 0x40, 0xE5, 0x83, 0x0C, 0x27, 0x43, 0xE4, 0x8D, 0x3D, 0x7D, 0xFE, - 0x33, 0x22, 0xD9, 0xDE, 0x9A, 0x55, 0x79, 0xB8, 0xDC, 0x3D, 0xE3, 0x11, 0xBF, 0xF1, 0xE0, 0x01, - 0x73, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x57, 0x9E, 0x99, 0x73, 0xDB, 0xEB, 0xDB, 0xE7, 0x9E, 0x8C, - 0x86, 0x48, 0x18, 0x23, 0xEF, 0x1C, 0x9A, 0x6F, 0x4E, 0xFF, 0xCD, 0x7C, 0xFF, 0x79, 0x91, 0xF8, - 0x0D, 0x89, 0xFB, 0xFF, 0xDD, 0xBF, 0xEE, 0xFE, 0xFD, 0x77, 0x0E, 0xF5, 0xD5, 0x3C, 0xDF, 0x11, - 0xCE, 0x3D, 0x60, 0x6E, 0x7F, 0xEE, 0x75, 0xC1, 0x5F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xDC, - 0x1B, 0xB3, 0x5E, 0x79, 0x66, 0xEE, 0x70, 0x3C, 0x44, 0x5A, 0x2E, 0x16, 0x1D, 0x95, 0xCD, 0x19, - 0xFA, 0xF5, 0xA3, 0x97, 0xDE, 0x1C, 0xFC, 0xD4, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xB9, 0x87, 0xD5, - 0x7F, 0xB3, 0x71, 0xDE, 0x9D, 0xAF, 0x3E, 0x3D, 0xEF, 0xA1, 0x57, 0x37, 0xCF, 0x7D, 0x59, 0x46, - 0x47, 0xB8, 0x20, 0x38, 0x5E, 0xDB, 0x3C, 0xF7, 0xD8, 0xAB, 0xCF, 0xCC, 0x7D, 0xDA, 0xDD, 0x76, - 0xFC, 0xB7, 0xEF, 0xCC, 0xFB, 0x40, 0xF0, 0x53, 0x01, 0x00, 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x35, - 0xB9, 0xFE, 0x07, 0x1B, 0xEE, 0xE8, 0x1B, 0x88, 0xEF, 0xDF, 0x36, 0xCC, 0xEE, 0x0B, 0xFE, 0x63, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xD0, 0x15, 0xDE, 0xF3, 0x9E, 0xFF, 0x1F, 0x5B, 0xE2, 0x94, 0x1D, 0x86, - 0x86, 0x23, 0x09, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; - -static const uint8_t tree_gif[] PROGMEM = { - - 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x28, 0x00, 0x3C, 0x00, 0x83, 0x0B, 0x00, 0x00, 0xFF, 0xFF, - 0x00, 0x21, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x94, 0x00, 0x00, 0xB5, 0x00, 0x00, - 0xDE, 0x00, 0x00, 0xFF, 0x00, 0x6B, 0x00, 0x00, 0xFF, 0x33, 0x33, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x00, 0xCC, 0x00, 0x00, 0x21, 0xFF, 0x0B, - 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0xA0, 0x0F, 0x00, - 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, - 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, - 0x8C, 0xCA, 0xE8, 0x85, 0xE8, 0xA5, 0xAC, 0x67, 0xEA, 0x8A, 0xE5, 0x2B, 0x2F, 0xE3, 0x31, 0xCE, - 0xAF, 0x41, 0x1C, 0xB8, 0x1B, 0x24, 0x80, 0x04, 0xAF, 0x87, 0x02, 0x26, 0x88, 0xA1, 0x07, 0x60, - 0xB9, 0x44, 0x82, 0x04, 0x02, 0x80, 0x61, 0x30, 0x70, 0x6E, 0x0C, 0x86, 0x03, 0x60, 0x20, 0xB0, - 0x6A, 0xA8, 0xD3, 0x03, 0x21, 0xEC, 0xAD, 0x18, 0x12, 0xE8, 0xF4, 0xB1, 0x4C, 0x51, 0xA0, 0x07, - 0xEA, 0x07, 0x5B, 0xF2, 0x70, 0x13, 0x76, 0xD4, 0xA8, 0xBC, 0xBC, 0xEA, 0x1F, 0x06, 0x77, 0x51, - 0x73, 0x50, 0x0A, 0x80, 0x7F, 0x04, 0x4C, 0x4D, 0x65, 0x06, 0x0A, 0x3B, 0x3B, 0x62, 0x5A, 0x53, - 0x65, 0x05, 0x02, 0x04, 0x68, 0x0C, 0x6A, 0x00, 0x5D, 0x5E, 0x0F, 0x0F, 0x6A, 0x98, 0x6A, 0x09, - 0x7B, 0x56, 0x9D, 0x09, 0x0C, 0xA7, 0xA7, 0x7F, 0x06, 0x9D, 0xA3, 0x44, 0x02, 0x01, 0x03, 0x90, - 0x0C, 0x87, 0x03, 0x06, 0x02, 0x05, 0x56, 0x06, 0x01, 0x02, 0x53, 0xB1, 0xB3, 0x04, 0x79, 0xAF, - 0x55, 0x48, 0x51, 0xB0, 0x87, 0xC0, 0x7F, 0x07, 0x95, 0x05, 0x85, 0x44, 0xB6, 0x00, 0x05, 0x53, - 0x96, 0x6A, 0x60, 0x02, 0x0A, 0x48, 0x89, 0x00, 0x07, 0xA1, 0x69, 0x7D, 0x2B, 0x3D, 0x9D, 0x41, - 0xA1, 0x04, 0xA0, 0xDD, 0x9D, 0x38, 0x02, 0xE1, 0x6A, 0x07, 0x62, 0x0C, 0x77, 0xE6, 0xAD, 0x2F, - 0x05, 0x01, 0xB6, 0x90, 0x07, 0xA8, 0xA7, 0x54, 0xB5, 0xBC, 0x06, 0x33, 0x50, 0x53, 0x3A, 0x00, - 0x39, 0x62, 0x10, 0x6B, 0xDF, 0xBE, 0x19, 0x03, 0x18, 0x40, 0xA9, 0x15, 0x4B, 0xCC, 0x0E, 0x77, - 0x3B, 0x04, 0xC4, 0x02, 0x38, 0x43, 0x21, 0x96, 0x2C, 0xD3, 0xD6, 0x81, 0x01, 0x26, 0x2A, 0xFB, - 0xDE, 0x07, 0x7C, 0x0A, 0xB7, 0x71, 0x1B, 0x79, 0xEE, 0xC5, 0x83, 0x72, 0xDD, 0x84, 0xBC, 0x4B, - 0x13, 0xA4, 0x13, 0x15, 0x17, 0xAB, 0x18, 0x78, 0x4A, 0x43, 0x40, 0x81, 0x43, 0x76, 0x8E, 0xB6, - 0x04, 0x7C, 0x19, 0x02, 0x98, 0xC4, 0x86, 0x35, 0xBD, 0xE1, 0x1C, 0x90, 0x4D, 0x62, 0xBF, 0x14, - 0xFC, 0x7E, 0x02, 0x1A, 0x60, 0xD3, 0xD1, 0x9D, 0x3B, 0x3A, 0x09, 0xFC, 0x44, 0xB1, 0xD0, 0x96, - 0x8E, 0x43, 0x8D, 0x9E, 0xDA, 0xDB, 0x22, 0x11, 0x8A, 0x42, 0x10, 0x5C, 0x00, 0x1A, 0x2D, 0x38, - 0xF2, 0x0E, 0xA0, 0x4A, 0x03, 0x4E, 0xA2, 0xF0, 0xF4, 0x80, 0x17, 0x95, 0x8C, 0x23, 0xD1, 0xD8, - 0x12, 0x00, 0x92, 0x03, 0xAB, 0x99, 0x23, 0x71, 0x3E, 0x8D, 0xEB, 0x6E, 0x18, 0x07, 0x66, 0x23, - 0x05, 0x3E, 0x72, 0xE4, 0x06, 0x0D, 0x81, 0x02, 0xE4, 0x36, 0x5D, 0xD9, 0xA5, 0xC0, 0xAD, 0x59, - 0xA2, 0x86, 0x6E, 0xD6, 0xC4, 0x73, 0xEB, 0x15, 0xA5, 0xC5, 0xDE, 0x14, 0xF4, 0x62, 0x07, 0xC0, - 0xE9, 0x9D, 0xCC, 0x58, 0x02, 0x14, 0xA0, 0x84, 0x45, 0x83, 0x68, 0x7A, 0x8D, 0x81, 0x66, 0xC3, - 0xE9, 0xD0, 0xA6, 0x3E, 0x03, 0xF3, 0x80, 0x7D, 0x90, 0xD8, 0x58, 0xA2, 0x59, 0x2D, 0x90, 0x68, - 0xD6, 0x64, 0x17, 0x76, 0x5A, 0x23, 0xBF, 0x13, 0x58, 0x89, 0x7A, 0xC3, 0xF0, 0x8F, 0xB6, 0xB8, - 0x4B, 0xD3, 0x74, 0x52, 0x50, 0x92, 0xC2, 0x03, 0xD1, 0x78, 0xD7, 0x89, 0x4C, 0x23, 0x26, 0x6E, - 0x82, 0xCC, 0x15, 0x5E, 0x05, 0x08, 0x30, 0x06, 0x8A, 0x75, 0x64, 0xFA, 0x42, 0xF1, 0x12, 0xAD, - 0x60, 0xDE, 0x51, 0x0A, 0x94, 0xBA, 0x5E, 0x2C, 0x8C, 0x86, 0xDD, 0x3D, 0xDE, 0x8F, 0x0A, 0x70, - 0x51, 0x5F, 0xFE, 0xF2, 0x84, 0xD1, 0xD0, 0xA6, 0x68, 0xB7, 0x96, 0x62, 0x14, 0x0C, 0xC1, 0xB7, - 0x90, 0x68, 0x72, 0xD1, 0x7C, 0xD9, 0x3D, 0xA3, 0x94, 0x35, 0xDE, 0x54, 0x06, 0x92, 0x51, 0x50, - 0x68, 0xC2, 0xC5, 0x44, 0xB7, 0x30, 0x70, 0xDE, 0x6A, 0x49, 0x69, 0x86, 0xC5, 0x2D, 0xA3, 0x29, - 0x04, 0x05, 0x2F, 0xD9, 0xC4, 0x02, 0x0C, 0x6C, 0x0C, 0x48, 0xB0, 0x94, 0x01, 0xDA, 0x3C, 0xF2, - 0x56, 0x21, 0xFA, 0xE8, 0xA3, 0xA1, 0x55, 0x12, 0xE9, 0xF4, 0x56, 0x42, 0xF8, 0x50, 0x00, 0x40, - 0x08, 0x08, 0xD4, 0x88, 0x80, 0x05, 0x33, 0x66, 0x10, 0xA2, 0x0C, 0xDC, 0xA0, 0xB0, 0xA3, 0x0B, - 0x71, 0xCD, 0xB1, 0x80, 0x75, 0x69, 0x20, 0x41, 0xE4, 0x91, 0x6B, 0x64, 0x10, 0x01, 0x00, 0x21, - 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, 0x00, - 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, 0x8C, - 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0x31, 0x1C, 0x34, - 0x1B, 0x24, 0x4C, 0x82, 0xE7, 0x28, 0x5E, 0x02, 0x78, 0x7A, 0x30, 0x8E, 0x47, 0x62, 0x48, 0x20, - 0x60, 0xD8, 0x06, 0x4A, 0x8E, 0xC1, 0x70, 0x60, 0x0C, 0x04, 0xD1, 0xCD, 0x60, 0x60, 0x3B, 0x10, - 0xBA, 0x59, 0x8B, 0x21, 0x41, 0x2E, 0x0F, 0xC3, 0x16, 0xF2, 0xC0, 0xAC, 0x40, 0x4F, 0x1E, 0x80, - 0x04, 0x81, 0x70, 0xD8, 0x0A, 0x14, 0x0F, 0xF7, 0x42, 0x00, 0xA0, 0xD6, 0x09, 0x0A, 0x81, 0x81, - 0x68, 0x00, 0x85, 0x85, 0x7F, 0x07, 0x07, 0x0A, 0x06, 0x7A, 0x06, 0x00, 0x74, 0x74, 0x5E, 0x8A, - 0x36, 0x68, 0x05, 0x7C, 0x66, 0x3D, 0x64, 0x58, 0x61, 0x0F, 0x0F, 0x66, 0x64, 0x99, 0x64, 0x79, - 0x9C, 0x9E, 0xA0, 0x48, 0x4E, 0x9D, 0xA3, 0x4A, 0x02, 0x01, 0x37, 0x90, 0x55, 0x04, 0x5C, 0x02, - 0x05, 0x59, 0x06, 0x01, 0x02, 0x4F, 0x89, 0x55, 0x76, 0xAC, 0x50, 0xAB, 0x0A, 0xAD, 0x7F, 0xB1, - 0x75, 0x07, 0x02, 0x04, 0x05, 0x00, 0xBE, 0x39, 0x06, 0x77, 0x05, 0x36, 0x04, 0x9F, 0x5B, 0xCC, - 0x00, 0x4A, 0x82, 0x81, 0x07, 0x9F, 0x65, 0x86, 0x85, 0x40, 0x9D, 0x0A, 0x9F, 0x0C, 0xD0, 0x9F, - 0x00, 0x9D, 0x39, 0x02, 0xDE, 0x66, 0xB0, 0x73, 0xE2, 0x09, 0xE4, 0xAA, 0x2F, 0x05, 0x01, 0xCC, - 0x5E, 0xA7, 0x56, 0x75, 0xD2, 0xB8, 0x8C, 0x2F, 0x4C, 0x36, 0x06, 0xB1, 0x73, 0xE1, 0x88, 0xC9, - 0x92, 0x45, 0x43, 0x96, 0x00, 0x2E, 0x37, 0xE8, 0x79, 0x99, 0x53, 0xEC, 0x86, 0x0D, 0x06, 0x05, - 0xF3, 0x51, 0x61, 0x57, 0xE6, 0x9E, 0xBF, 0x35, 0x0C, 0xDE, 0x81, 0xE8, 0x64, 0x10, 0xFB, 0x5B, - 0xB6, 0x6C, 0xF5, 0x56, 0x94, 0x22, 0x13, 0xA7, 0xE2, 0x9C, 0x04, 0xDF, 0xCA, 0x74, 0xB2, 0xB2, - 0xC2, 0x40, 0x2A, 0x92, 0x72, 0x20, 0x45, 0x52, 0xE0, 0x45, 0x1A, 0x01, 0x2B, 0xCA, 0x3E, 0xC4, - 0x3A, 0x38, 0x60, 0xDB, 0x23, 0x86, 0xD6, 0x14, 0x0C, 0x20, 0xC0, 0x84, 0xCB, 0x8A, 0x7C, 0x3C, - 0x1F, 0x25, 0x94, 0xA9, 0x80, 0x21, 0x17, 0xA2, 0x5B, 0x4E, 0x34, 0x91, 0xE5, 0x2F, 0x99, 0x4C, - 0xA0, 0x89, 0xEC, 0x5C, 0xC1, 0xB5, 0x89, 0xC3, 0x15, 0x2B, 0xCC, 0x10, 0xD6, 0xF9, 0x38, 0x67, - 0xA8, 0xB1, 0x01, 0xE5, 0x40, 0xD4, 0x7B, 0x42, 0xF1, 0x63, 0x02, 0x66, 0x02, 0x12, 0xA4, 0xFA, - 0x90, 0x2A, 0x54, 0xB6, 0x44, 0xEB, 0xDA, 0x96, 0x19, 0x9A, 0x53, 0x43, 0x01, 0xBB, 0x64, 0x84, - 0xAE, 0xC3, 0xBB, 0xB0, 0xCC, 0x31, 0x40, 0x5D, 0x35, 0xD8, 0x62, 0x82, 0x6B, 0x68, 0xAC, 0xA6, - 0x43, 0xF1, 0xD2, 0x01, 0x20, 0xE9, 0x8A, 0x25, 0x05, 0x96, 0x36, 0xD8, 0x8A, 0xD7, 0xD8, 0x46, - 0xD0, 0x85, 0xEB, 0x7E, 0x72, 0x31, 0x10, 0x54, 0x9F, 0x85, 0x00, 0xF1, 0xA6, 0x1C, 0x94, 0x2C, - 0x34, 0xB2, 0x17, 0x9F, 0x5B, 0xB8, 0x14, 0x80, 0xFC, 0x41, 0x28, 0x63, 0xC7, 0x03, 0x9A, 0x4A, - 0x32, 0x9C, 0x2C, 0x2B, 0x2E, 0x40, 0x72, 0x63, 0x59, 0x48, 0x85, 0x47, 0x8D, 0xD8, 0xC8, 0xD9, - 0xE2, 0xF0, 0x55, 0x99, 0x4A, 0xE3, 0x82, 0x07, 0x41, 0x3F, 0x25, 0x92, 0xAE, 0xD7, 0x4C, 0x3C, - 0xE7, 0xAC, 0x02, 0x04, 0x58, 0xC4, 0xC4, 0xAD, 0x9C, 0x1B, 0xB1, 0x3F, 0xE1, 0x42, 0x3D, 0x4B, - 0x9E, 0x85, 0xCB, 0x57, 0xA6, 0x30, 0x4B, 0x97, 0x88, 0x26, 0xA2, 0x03, 0x7F, 0x8B, 0x72, 0x2D, - 0x90, 0x79, 0x02, 0xFD, 0x59, 0x36, 0xB2, 0xF3, 0x41, 0x2A, 0x65, 0xAD, 0x75, 0x64, 0x3A, 0x0C, - 0x48, 0xB4, 0x15, 0x35, 0x13, 0xE0, 0xC2, 0xC0, 0x2D, 0xB1, 0x15, 0x95, 0x0C, 0x13, 0x97, 0x59, - 0x73, 0x90, 0x01, 0xF5, 0xAC, 0x36, 0x8D, 0x79, 0x12, 0x40, 0xB8, 0x45, 0x22, 0xB8, 0xF8, 0xC4, - 0x0C, 0x7D, 0xB3, 0x31, 0x96, 0xCF, 0x00, 0x01, 0x76, 0x41, 0x80, 0x4F, 0x0B, 0x80, 0x78, 0x4A, - 0x24, 0x5B, 0x8C, 0x18, 0xDB, 0x8A, 0x0A, 0xF0, 0xC3, 0x15, 0x88, 0x08, 0xF1, 0xC5, 0xC7, 0x3C, - 0x13, 0x40, 0x94, 0x01, 0x81, 0x13, 0x20, 0xA0, 0x23, 0x02, 0x27, 0xE0, 0x58, 0x63, 0x08, 0xD9, - 0xE8, 0x41, 0x81, 0x5B, 0x42, 0x7A, 0x57, 0x86, 0x12, 0x46, 0x26, 0x79, 0x46, 0x06, 0x11, 0x00, - 0x00, 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x3C, 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, - 0xE4, 0x8C, 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0xA1, - 0x1C, 0x34, 0x1B, 0x24, 0x4A, 0x82, 0xE7, 0x27, 0x85, 0x50, 0x08, 0x0C, 0x3D, 0x12, 0xBC, 0xC4, - 0xA3, 0x18, 0x12, 0x08, 0x14, 0x86, 0xC1, 0x80, 0xC9, 0x31, 0x18, 0x0E, 0x84, 0x81, 0x80, 0xBA, - 0x91, 0x46, 0xB1, 0x51, 0x06, 0xD7, 0x62, 0x40, 0x9A, 0x91, 0xE2, 0x71, 0xA5, 0x37, 0x40, 0x33, - 0xDE, 0xE9, 0xF1, 0xE3, 0xA1, 0x20, 0x10, 0x0E, 0x52, 0x01, 0x63, 0xA9, 0x5E, 0x0C, 0x85, 0x03, - 0x76, 0x7A, 0x7D, 0x0B, 0x4E, 0x03, 0x75, 0x78, 0x77, 0x78, 0x06, 0x84, 0x51, 0x37, 0x8A, 0x77, - 0x02, 0x51, 0x6A, 0x05, 0x02, 0x04, 0x67, 0x67, 0x5B, 0x72, 0x47, 0x98, 0x98, 0x7C, 0x5C, 0x73, - 0x66, 0x58, 0x07, 0x8B, 0x0F, 0x00, 0x9F, 0x45, 0x02, 0x01, 0x03, 0xA3, 0x0C, 0x89, 0x03, 0x06, - 0x02, 0x00, 0x5C, 0x06, 0x01, 0x92, 0x52, 0x07, 0xAE, 0x59, 0x03, 0x00, 0xBD, 0xBD, 0x4C, 0x02, - 0x05, 0xAB, 0xB9, 0x70, 0x0C, 0xAC, 0x96, 0x00, 0x52, 0x45, 0x36, 0xC1, 0x51, 0x97, 0x0C, 0x66, - 0x5E, 0x00, 0x8C, 0x4C, 0x0A, 0x05, 0x5F, 0x68, 0x98, 0x4E, 0x56, 0x40, 0x7F, 0x3D, 0x67, 0x97, - 0x9D, 0x73, 0x39, 0x02, 0x74, 0x9C, 0x48, 0xA4, 0x76, 0x76, 0x66, 0x73, 0xA8, 0x2C, 0x05, 0x50, - 0x02, 0xA3, 0xA3, 0x59, 0x78, 0x5E, 0x92, 0xD4, 0x2C, 0xDB, 0xB0, 0x59, 0x76, 0x07, 0x00, 0x78, - 0x16, 0x09, 0x80, 0xF5, 0xE4, 0x05, 0xC1, 0x81, 0x5F, 0xB0, 0x10, 0x00, 0xA0, 0xEE, 0xC0, 0xC0, - 0x03, 0x8E, 0x68, 0x68, 0xB1, 0x72, 0xE5, 0x92, 0xAF, 0x5E, 0xF6, 0x0C, 0x10, 0xF0, 0x86, 0x62, - 0xFB, 0xCE, 0xC1, 0x03, 0x98, 0x00, 0x74, 0x42, 0x42, 0xE7, 0xC5, 0xB9, 0x4E, 0xFF, 0xC2, 0x9D, - 0x99, 0xA3, 0x60, 0x0A, 0x0A, 0x03, 0xED, 0xC0, 0xDD, 0xF1, 0x47, 0xCF, 0xCB, 0x2E, 0x97, 0x20, - 0x92, 0x0D, 0x64, 0x85, 0xA5, 0x65, 0x43, 0x2C, 0x3C, 0x19, 0x10, 0x30, 0x94, 0x2F, 0x27, 0xBE, - 0x9D, 0x87, 0x78, 0xCE, 0x54, 0x47, 0xC0, 0x98, 0xC6, 0x9D, 0x39, 0x2F, 0xC6, 0xB2, 0xF1, 0x87, - 0x29, 0x96, 0x62, 0xC6, 0xB6, 0x69, 0xE2, 0xC0, 0x2B, 0x4A, 0x2C, 0x58, 0x49, 0x47, 0xDA, 0x11, - 0x6A, 0x69, 0xC0, 0xB8, 0x10, 0x22, 0x1F, 0xDC, 0x0A, 0xF4, 0x6D, 0x64, 0x02, 0x06, 0xB1, 0x04, - 0x28, 0x39, 0xBB, 0xA1, 0xDD, 0x49, 0x4C, 0xE9, 0xD4, 0xB9, 0x4D, 0x0A, 0xA2, 0x40, 0x81, 0x91, - 0x81, 0x68, 0x2E, 0x35, 0x43, 0xA0, 0xC0, 0x50, 0x05, 0x1F, 0x6A, 0x39, 0xB9, 0x65, 0x47, 0x4A, - 0xBF, 0xBC, 0xF4, 0xF0, 0x04, 0xE3, 0x98, 0xA1, 0x96, 0x02, 0x5B, 0x5E, 0x71, 0xA5, 0x53, 0xA8, - 0x4E, 0x68, 0x16, 0x2B, 0x01, 0xFC, 0x42, 0x29, 0x4A, 0x21, 0xF4, 0xE8, 0x87, 0x0A, 0xA5, 0x04, - 0xDA, 0xDC, 0x94, 0x95, 0x6A, 0x03, 0xC2, 0x5A, 0x6E, 0xF0, 0x66, 0xC8, 0x0E, 0xC0, 0x99, 0x20, - 0xDF, 0x16, 0x93, 0xAC, 0x91, 0x64, 0x16, 0x0B, 0xED, 0x14, 0x70, 0xF2, 0xC2, 0x6B, 0x75, 0x27, - 0x68, 0x81, 0xDA, 0x90, 0xB4, 0x0B, 0xDC, 0x74, 0xC8, 0x8B, 0x67, 0xB0, 0xBC, 0x75, 0x2B, 0xCC, - 0x5D, 0xA1, 0x00, 0xD8, 0x09, 0xC4, 0x3D, 0x23, 0x92, 0xB0, 0x6B, 0x29, 0xDA, 0x6A, 0x55, 0x12, - 0x46, 0x7A, 0x41, 0xA5, 0x81, 0xF8, 0x62, 0x25, 0xE8, 0x4E, 0x2A, 0x60, 0x22, 0x52, 0x05, 0xB4, - 0xB4, 0x94, 0x14, 0xAC, 0x12, 0x05, 0xBF, 0xCD, 0xB4, 0x60, 0xA7, 0x6F, 0x66, 0x65, 0xE7, 0x57, - 0xC7, 0xA3, 0xC8, 0x67, 0x85, 0x16, 0x5B, 0x49, 0xF0, 0x84, 0x2A, 0x48, 0x19, 0x92, 0x47, 0x30, - 0x4E, 0x00, 0x60, 0xC9, 0x57, 0x71, 0x79, 0x03, 0x51, 0x30, 0xD3, 0x4C, 0xA0, 0xC0, 0x4E, 0xA4, - 0x1C, 0x45, 0x51, 0x2C, 0x7E, 0x39, 0xB8, 0x18, 0x3E, 0x04, 0xB5, 0x04, 0x14, 0x6C, 0xB3, 0xF8, - 0xF1, 0xC7, 0x3C, 0x00, 0xAA, 0xC6, 0xCB, 0x45, 0xFC, 0x21, 0xD5, 0x52, 0x72, 0x17, 0x95, 0x88, - 0xD8, 0x09, 0x08, 0x00, 0x80, 0x00, 0x02, 0x28, 0x94, 0x28, 0xC1, 0x8C, 0x20, 0x20, 0xD1, 0x5D, - 0x02, 0x27, 0xE8, 0x88, 0x82, 0x5B, 0x84, 0x2C, 0xE0, 0xD6, 0x19, 0x4C, 0x1C, 0xA9, 0xA4, 0x19, - 0x1B, 0x44, 0x00, 0x00, 0x21, 0xFE, 0x19, 0x42, 0x6F, 0x79, 0x27, 0x73, 0x20, 0x48, 0x61, 0x70, - 0x70, 0x79, 0x20, 0x48, 0x6F, 0x6C, 0x69, 0x64, 0x61, 0x79, 0x73, 0x20, 0x50, 0x61, 0x67, 0x65, - 0x00, 0x3B - -}; - -static const uint8_t bird_gif[] PROGMEM = { - 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x74, 0x00, 0x4E, 0x00, 0xCC, 0x13, 0x00, 0xFF, 0xFF, 0xFF, - 0xEF, 0xFF, 0xFF, 0xBD, 0xE7, 0xE7, 0xD6, 0xEF, 0xEF, 0x63, 0x63, 0x63, 0xAD, 0xAD, 0xAD, 0xCE, - 0xCE, 0xCE, 0xD6, 0xDE, 0xDE, 0x4A, 0x4A, 0x4A, 0x7B, 0x84, 0x84, 0x94, 0x9C, 0x9C, 0xE7, 0xE7, - 0xE7, 0x84, 0x94, 0x94, 0xB5, 0xC6, 0xC6, 0x73, 0x7B, 0x7B, 0x31, 0x31, 0x31, 0xF7, 0xF7, 0xF7, - 0x18, 0x10, 0x10, 0xCE, 0x63, 0x39, 0x6B, 0x39, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xFF, 0x0B, - 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00, - 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x4B, - 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0xAE, 0xEC, 0x68, 0x2C, - 0x6D, 0x2C, 0xCF, 0x74, 0x6D, 0x03, 0x46, 0x84, 0x40, 0x77, 0xEF, 0xFF, 0x40, 0x51, 0x42, 0x41, - 0x0C, 0x1A, 0x8F, 0x48, 0x13, 0xC1, 0xD0, 0x20, 0x00, 0x0E, 0x8E, 0x42, 0x72, 0x4A, 0xAD, 0x21, - 0x0E, 0xCD, 0x05, 0xE1, 0x80, 0xA8, 0x7A, 0xBF, 0x29, 0xC2, 0xA0, 0x91, 0x28, 0x34, 0x02, 0x5D, - 0xB0, 0x5A, 0xFD, 0x08, 0x34, 0x14, 0x84, 0x00, 0x7A, 0x4D, 0xF7, 0x22, 0xDC, 0x89, 0xB8, 0xC1, - 0xB9, 0x80, 0xD5, 0xFF, 0x40, 0x0B, 0x77, 0x0C, 0x0F, 0x05, 0x01, 0x0C, 0x0A, 0x0B, 0x0F, 0x08, - 0x06, 0x80, 0x8E, 0x37, 0x7B, 0x01, 0x09, 0x11, 0x03, 0x68, 0x5C, 0x4C, 0x0A, 0x8F, 0x9A, 0x33, - 0x06, 0x09, 0x01, 0x0E, 0x71, 0x68, 0x88, 0x92, 0x07, 0x9B, 0xA6, 0x2C, 0x0A, 0x86, 0x07, 0x95, - 0x05, 0x04, 0xA1, 0x5D, 0x8D, 0xA7, 0xB2, 0x26, 0x09, 0x06, 0x72, 0x72, 0x0E, 0x94, 0x01, 0xA9, - 0x04, 0x08, 0x52, 0xB3, 0xC0, 0x00, 0x09, 0x95, 0xB7, 0x0D, 0x86, 0x01, 0x04, 0x0A, 0xC3, 0x09, - 0x34, 0x43, 0xC1, 0x54, 0x0E, 0xB7, 0xD2, 0x87, 0xAE, 0xBB, 0x99, 0x32, 0x7B, 0x0E, 0xCF, 0x49, - 0x0B, 0xD1, 0xD3, 0x72, 0x0C, 0xDE, 0x57, 0x33, 0xBE, 0xCC, 0xDB, 0x47, 0x05, 0x0C, 0xDF, 0xD3, - 0x05, 0xD7, 0x31, 0x0C, 0xE1, 0xA5, 0xE7, 0x46, 0xBE, 0xEB, 0xD2, 0x04, 0x05, 0xBF, 0x2C, 0x5C, - 0x4D, 0xF3, 0x46, 0x0B, 0x11, 0x56, 0xD9, 0x3B, 0x14, 0x01, 0x14, 0x0F, 0x16, 0x04, 0x1A, 0x30, - 0x28, 0x00, 0x81, 0xA1, 0x3F, 0x1F, 0xAD, 0x02, 0x10, 0x5B, 0x87, 0x6F, 0x0E, 0x8B, 0x02, 0x0E, - 0x04, 0x5C, 0x41, 0x10, 0xF0, 0x61, 0x8F, 0x25, 0x03, 0x26, 0xDA, 0x43, 0xC4, 0x42, 0x8B, 0x00, - 0x05, 0x0E, 0x7C, 0xFF, 0xED, 0xF0, 0x68, 0x83, 0x8B, 0x44, 0x91, 0xDF, 0x06, 0xAC, 0x54, 0x01, - 0x21, 0xA1, 0x80, 0x07, 0x0F, 0x1A, 0x38, 0x70, 0xC7, 0x72, 0x46, 0xC2, 0x97, 0x03, 0x3F, 0xC5, - 0x52, 0xE1, 0x80, 0x81, 0x00, 0x01, 0x19, 0x1B, 0x3C, 0x38, 0xD8, 0x53, 0xC6, 0x81, 0x38, 0x21, - 0x61, 0x4A, 0xEB, 0xB7, 0x42, 0x01, 0x82, 0xA3, 0x58, 0x7D, 0xC9, 0x6B, 0x1A, 0x63, 0x0B, 0xD0, - 0x81, 0x11, 0x08, 0x74, 0x44, 0x61, 0xE0, 0x01, 0xD6, 0xA3, 0x05, 0x16, 0x2D, 0xE5, 0xDA, 0xC2, - 0x80, 0xB7, 0x90, 0x41, 0xCB, 0xA4, 0x39, 0xC1, 0xEF, 0x2C, 0x56, 0xAA, 0x6C, 0x57, 0x38, 0xA8, - 0x14, 0x35, 0xA8, 0x35, 0x14, 0x10, 0x10, 0x34, 0xB0, 0x9B, 0xD5, 0x4F, 0xDE, 0x14, 0x06, 0x8E, - 0xF5, 0x1D, 0xC8, 0x25, 0x85, 0x83, 0xC1, 0x84, 0x05, 0x20, 0x32, 0x30, 0xF4, 0x30, 0x2D, 0x39, - 0x8B, 0x07, 0x32, 0x42, 0xA1, 0x00, 0x72, 0xE4, 0x45, 0x08, 0x7C, 0x59, 0x36, 0x91, 0x18, 0x73, - 0xE6, 0x6F, 0x79, 0x38, 0x2B, 0x88, 0x7C, 0x54, 0xE7, 0xE0, 0x2D, 0xA3, 0x4B, 0x78, 0x7A, 0x79, - 0x7A, 0x1A, 0xCE, 0x04, 0x4C, 0x85, 0xAC, 0x66, 0x7D, 0x96, 0x80, 0xB9, 0xD8, 0x22, 0x4A, 0x4B, - 0x14, 0x00, 0x97, 0xF1, 0xD3, 0x12, 0x3B, 0x79, 0x9F, 0x45, 0xC0, 0x13, 0xB8, 0xB7, 0xE1, 0xC5, - 0x19, 0x33, 0xEB, 0x53, 0xD3, 0xA8, 0x72, 0x01, 0x0D, 0x44, 0x97, 0x5C, 0x90, 0x7B, 0x9B, 0x01, - 0x05, 0xA6, 0x89, 0xFB, 0x3D, 0x54, 0x20, 0x81, 0xDA, 0x8C, 0xD7, 0x91, 0x16, 0x22, 0x91, 0xF8, - 0x80, 0x9F, 0x86, 0x08, 0x1E, 0xF4, 0xF2, 0xD5, 0x7D, 0x96, 0x18, 0xCC, 0x47, 0xA3, 0xDB, 0x7B, - 0xCA, 0x60, 0x40, 0xCA, 0xF4, 0x58, 0x81, 0xE2, 0x42, 0x04, 0x11, 0x4C, 0x80, 0x53, 0x7C, 0x3F, - 0xC9, 0xB1, 0xC7, 0xFF, 0x7A, 0xC1, 0x18, 0xA0, 0x0E, 0x7E, 0xC4, 0x49, 0xA5, 0x99, 0x67, 0xD7, - 0xA5, 0xB4, 0x15, 0x04, 0x93, 0x48, 0xA0, 0xA1, 0x81, 0x7C, 0x49, 0xB3, 0xC7, 0x38, 0xF6, 0x11, - 0x13, 0x52, 0x7E, 0x12, 0xAE, 0x63, 0xC0, 0x55, 0x00, 0x82, 0x62, 0xD8, 0x08, 0x0B, 0x24, 0xA0, - 0xA1, 0x86, 0x57, 0x3C, 0xF0, 0xE0, 0x2D, 0x05, 0x68, 0x67, 0x4A, 0x27, 0xB7, 0x0C, 0x80, 0x95, - 0x7E, 0x41, 0x11, 0x80, 0x5E, 0x85, 0xBF, 0x9D, 0xD0, 0xC0, 0x04, 0x2F, 0x2E, 0x62, 0xCB, 0x34, - 0x03, 0xE4, 0xB1, 0xA2, 0x23, 0x5E, 0x41, 0xC8, 0x63, 0x50, 0x0E, 0x9A, 0x75, 0x5D, 0x68, 0x5B, - 0x9D, 0xA0, 0x45, 0x04, 0x38, 0x2D, 0x72, 0xCC, 0x34, 0x7B, 0x24, 0xF2, 0x88, 0x5B, 0x39, 0xEA, - 0x18, 0xE1, 0x78, 0xD2, 0x58, 0x05, 0x20, 0x6C, 0x2B, 0xD4, 0x78, 0x64, 0x89, 0x6E, 0xB8, 0xF2, - 0xC2, 0x1F, 0x4D, 0xBE, 0x44, 0x22, 0x99, 0x72, 0xE4, 0x01, 0x60, 0x19, 0x31, 0x68, 0xB1, 0xC4, - 0x78, 0x50, 0xF4, 0xE2, 0x9B, 0x43, 0x5E, 0x80, 0x99, 0xE3, 0x8E, 0x6C, 0x4E, 0xE3, 0x63, 0x7A, - 0xD9, 0x55, 0xD6, 0x82, 0x4E, 0x04, 0x30, 0xD0, 0xC0, 0x01, 0x7C, 0x2A, 0xE4, 0xA3, 0xA2, 0x47, - 0xDC, 0x37, 0xE8, 0x9C, 0xE3, 0xC9, 0x64, 0x9D, 0x72, 0x70, 0x54, 0x29, 0x03, 0x04, 0xDF, 0xE5, - 0xE1, 0x4A, 0x19, 0x06, 0xB0, 0xD9, 0xC4, 0x66, 0x48, 0x7C, 0x27, 0xCD, 0x88, 0x98, 0x92, 0x89, - 0xE2, 0x75, 0x69, 0x2D, 0x69, 0xC3, 0x02, 0x07, 0xA4, 0x03, 0x8A, 0x2B, 0x8E, 0xC2, 0x04, 0x05, - 0x03, 0x48, 0x3C, 0x17, 0x5E, 0xAB, 0x7E, 0x61, 0x04, 0x20, 0x03, 0x33, 0x21, 0x01, 0xC1, 0x02, - 0xDF, 0x81, 0x52, 0x8B, 0x34, 0xAD, 0xC8, 0x6A, 0x43, 0x3E, 0x48, 0x9E, 0xF5, 0x24, 0x45, 0xAF, - 0xF2, 0x96, 0x9D, 0xFF, 0x03, 0xF5, 0x51, 0xD1, 0xA2, 0x03, 0x90, 0xCA, 0xF1, 0x94, 0x3E, 0x37, - 0x68, 0x81, 0xA4, 0x98, 0xC0, 0x9A, 0xF8, 0xC0, 0x8F, 0xCA, 0x39, 0xA0, 0xCD, 0x1F, 0x0B, 0x10, - 0x21, 0x0D, 0x03, 0xB8, 0x7D, 0x74, 0x64, 0x98, 0xD2, 0x16, 0x8A, 0x0C, 0xBA, 0xCA, 0x29, 0xF5, - 0x48, 0x8B, 0x53, 0xA1, 0x19, 0x03, 0xA8, 0x18, 0x85, 0xB2, 0x2A, 0xB9, 0x63, 0x06, 0x45, 0x06, - 0x80, 0x48, 0x05, 0xC9, 0x6E, 0x9C, 0x4F, 0xE1, 0xA3, 0xC2, 0x77, 0xF0, 0x16, 0x95, 0x4B, 0xB7, - 0xF4, 0x12, 0xEA, 0x57, 0x59, 0x14, 0xB2, 0x46, 0x08, 0xB8, 0x8E, 0x08, 0x72, 0x06, 0xB3, 0x3E, - 0xA6, 0xF2, 0x28, 0x46, 0x8B, 0x2C, 0xEB, 0xED, 0x03, 0xF3, 0x56, 0x5C, 0xF0, 0x40, 0xE6, 0xED, - 0xA6, 0x9C, 0x7C, 0xD9, 0x02, 0xA2, 0x48, 0xCA, 0x98, 0x25, 0xD6, 0xCE, 0x4E, 0x14, 0x2B, 0x18, - 0xE7, 0xC0, 0xE5, 0xAE, 0x93, 0x00, 0xC2, 0x45, 0x01, 0xB3, 0xC0, 0x8C, 0x74, 0xFA, 0xF7, 0x80, - 0x84, 0xAC, 0xAE, 0x6C, 0xCF, 0x00, 0x04, 0xA4, 0x47, 0x2C, 0x02, 0xCE, 0x6A, 0xF2, 0x06, 0x9D, - 0x98, 0xE5, 0x3C, 0xB0, 0x98, 0xB5, 0x4D, 0xD3, 0x40, 0x04, 0x05, 0x28, 0x57, 0x40, 0x04, 0x0A, - 0x50, 0x2A, 0x4B, 0x02, 0x1F, 0x53, 0xBD, 0x74, 0x54, 0x59, 0xBF, 0x1B, 0x5A, 0x41, 0xAC, 0x65, - 0xA7, 0xF0, 0x33, 0x0C, 0x58, 0x6D, 0xB6, 0x69, 0x68, 0x4F, 0x2B, 0x87, 0x55, 0xB7, 0x38, 0x50, - 0xC8, 0x5D, 0x7E, 0x8A, 0x1D, 0x0C, 0x04, 0x8F, 0xCD, 0x1D, 0x94, 0xDD, 0x4F, 0xA1, 0xEC, 0xA1, - 0x7C, 0xAD, 0x8D, 0xC5, 0x52, 0x4D, 0xBE, 0x0A, 0x3E, 0x9E, 0x55, 0x32, 0xDA, 0xA3, 0x37, 0x03, - 0xBD, 0x44, 0x3D, 0x8F, 0x55, 0x34, 0x3B, 0x6E, 0x4F, 0x03, 0x99, 0x73, 0x89, 0x93, 0xE5, 0xFE, - 0x74, 0x13, 0xB7, 0xCB, 0xE6, 0xA4, 0x4B, 0x63, 0x90, 0x65, 0xED, 0x16, 0x25, 0x77, 0xE9, 0x54, - 0x67, 0x11, 0xDB, 0x89, 0x44, 0xB3, 0x6E, 0xF6, 0x89, 0x7E, 0x37, 0x05, 0x47, 0xE7, 0xB2, 0xFB, - 0xF5, 0x2D, 0x70, 0xDD, 0x80, 0x37, 0xDE, 0x0A, 0x8E, 0xFB, 0x06, 0x1C, 0x00, 0x4D, 0xE0, 0x1E, - 0x80, 0x0C, 0x73, 0xFB, 0x47, 0x00, 0xE8, 0x2C, 0x89, 0x6E, 0xCF, 0x0C, 0x66, 0x87, 0x64, 0x55, - 0x73, 0x87, 0xB5, 0xD2, 0x39, 0xF2, 0x54, 0xA3, 0xAD, 0x24, 0xEF, 0x09, 0xC4, 0x2E, 0x47, 0x0C, - 0x83, 0x4F, 0x44, 0x6E, 0x25, 0xA9, 0x0C, 0x8F, 0x43, 0xE0, 0xD3, 0xB4, 0x30, 0x50, 0x54, 0xF9, - 0x41, 0x57, 0xC9, 0x63, 0xE6, 0x03, 0x00, 0xC1, 0xED, 0xE9, 0xAB, 0x60, 0x4F, 0x62, 0x94, 0x41, - 0x2A, 0xFE, 0x01, 0x56, 0x11, 0x10, 0xB3, 0x65, 0x4F, 0x11, 0xCC, 0x37, 0x4A, 0x10, 0x2C, 0x8E, - 0x3C, 0x80, 0x40, 0x3A, 0x30, 0x20, 0x02, 0x96, 0x10, 0x3F, 0x13, 0x64, 0xA7, 0x1E, 0x17, 0x53, - 0x90, 0x02, 0x28, 0x87, 0x00, 0xB2, 0xC1, 0xE0, 0x29, 0x08, 0x24, 0x50, 0xC9, 0xFE, 0x37, 0x3C, - 0x28, 0x30, 0x67, 0x75, 0x01, 0x9C, 0x20, 0x4E, 0x0A, 0xE0, 0xAC, 0xAF, 0x21, 0x90, 0x3E, 0x0D, - 0x4C, 0x41, 0xBB, 0x42, 0x13, 0x05, 0x63, 0xA4, 0x64, 0x81, 0x43, 0x28, 0x40, 0xED, 0x44, 0x00, - 0x01, 0x2C, 0x78, 0x29, 0x85, 0x2C, 0x38, 0x56, 0x62, 0x1A, 0xC0, 0x1D, 0x35, 0x84, 0x00, 0x00, - 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, - 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, - 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, - 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, - 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, - 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, - 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, - 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, - 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, - 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, - 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, - 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, - 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, - 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, - 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, - 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, - 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, - 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, - 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, - 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, - 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, - 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, - 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, - 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, - 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, - 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, - 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, - 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, - 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, - 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, - 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, - 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, - 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, - 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, - 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, - 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, - 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, - 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, - 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, - 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, - 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, - 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, - 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, - 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, - 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, - 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, - 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, - 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, - 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, - 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, - 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, - 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, - 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, - 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, - 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, - 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, - 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, - 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, - 0x0D, 0x21, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, - 0x00, 0x6A, 0x00, 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, - 0xAE, 0x6C, 0xEB, 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, - 0x0A, 0xC7, 0x03, 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, - 0xA4, 0x10, 0xA8, 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, - 0x9E, 0x18, 0x02, 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, - 0xD4, 0x81, 0x01, 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, - 0x0D, 0x08, 0x05, 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, - 0x04, 0x06, 0x10, 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, - 0x93, 0x09, 0x0C, 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, - 0x0C, 0x39, 0x9A, 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, - 0xAB, 0x5B, 0x4A, 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, - 0x0D, 0x0D, 0x07, 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, - 0x0E, 0x7B, 0x04, 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, - 0x92, 0x0C, 0x0E, 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, - 0x5B, 0x03, 0x0E, 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, - 0x98, 0xBE, 0x73, 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, - 0xB0, 0x6A, 0xA3, 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, - 0xBC, 0xA5, 0x0C, 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, - 0x04, 0x32, 0x53, 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, - 0x67, 0x8E, 0xA2, 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, - 0x33, 0xA0, 0x2B, 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, - 0x0E, 0x10, 0xC0, 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, - 0x0A, 0x08, 0xF8, 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, - 0x1D, 0x8A, 0x47, 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, - 0x22, 0x22, 0x82, 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, - 0x6B, 0x50, 0xE0, 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, - 0xA3, 0x2D, 0x60, 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, - 0x94, 0x14, 0x7F, 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, - 0x05, 0x30, 0x4A, 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, - 0x53, 0x20, 0xC1, 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, - 0x10, 0x03, 0x80, 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, - 0x26, 0x0F, 0x28, 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, - 0xC6, 0x0A, 0x02, 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, - 0xA0, 0xC0, 0x28, 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, - 0x42, 0x01, 0x5A, 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, - 0x88, 0x33, 0x14, 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, - 0x6A, 0xC4, 0x80, 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, - 0x28, 0xC2, 0xE2, 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, - 0x21, 0xA4, 0x0C, 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, - 0x4A, 0x93, 0x29, 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, - 0x94, 0x0C, 0x38, 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, - 0x56, 0x74, 0x54, 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, - 0x99, 0x83, 0x8A, 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, - 0x10, 0x02, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, - 0x6A, 0x00, 0x2E, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x00, 0x40, 0x62, 0xB9, 0x28, 0x08, 0x41, 0x28, - 0x4B, 0xE9, 0xBE, 0x70, 0x2C, 0xCF, 0x74, 0x6D, 0xDF, 0xE5, 0xF1, 0x3C, 0x69, 0x52, 0x24, 0x0F, - 0x82, 0xE1, 0x60, 0x00, 0x26, 0x5A, 0xB8, 0xA4, 0x72, 0xC9, 0x94, 0xE9, 0x22, 0x12, 0xC9, 0x64, - 0xF2, 0x18, 0x04, 0xAE, 0xD7, 0x01, 0xB0, 0xD0, 0xEC, 0x7A, 0xBF, 0x31, 0x48, 0x61, 0x12, 0x95, - 0x32, 0x02, 0x8E, 0x06, 0x36, 0x70, 0x50, 0x21, 0xC1, 0xF0, 0x78, 0x72, 0x91, 0x20, 0x4B, 0x55, - 0x85, 0xF5, 0xB5, 0x81, 0xE0, 0xCA, 0xFF, 0x80, 0x32, 0x0D, 0x0F, 0x53, 0x11, 0x11, 0x04, 0x07, - 0x7A, 0x57, 0x0E, 0x04, 0x6F, 0x81, 0x8F, 0x7F, 0x0B, 0x2A, 0x06, 0x94, 0x6A, 0x8A, 0x01, 0x06, - 0x04, 0x05, 0x07, 0x0B, 0x0B, 0x44, 0x94, 0xA0, 0x43, 0x24, 0x90, 0xA4, 0x37, 0x05, 0x04, 0x96, - 0x97, 0x58, 0x45, 0x09, 0x0A, 0x0C, 0x0C, 0x0A, 0x05, 0x0D, 0xB3, 0x05, 0x0A, 0x09, 0x0C, 0x05, - 0x06, 0xA3, 0x4D, 0x9F, 0xA0, 0x0B, 0xBB, 0xA5, 0x33, 0x6D, 0x08, 0x0C, 0x89, 0xAA, 0xC7, 0x8A, - 0x07, 0xAE, 0x3E, 0xC0, 0x32, 0x10, 0x07, 0x3F, 0x2A, 0x0E, 0x8C, 0x2A, 0x08, 0xD6, 0x29, 0x0E, - 0xB9, 0xCD, 0xC1, 0x22, 0x10, 0x45, 0xD2, 0xB8, 0x07, 0x56, 0x97, 0x22, 0xC8, 0x01, 0x0D, 0x0C, - 0x3E, 0x9C, 0x25, 0xCF, 0xA7, 0x04, 0xD9, 0xE2, 0xC8, 0x03, 0xD0, 0x09, 0x04, 0xD6, 0x09, 0xBA, - 0xDC, 0x30, 0x10, 0x0B, 0x06, 0xB6, 0x2A, 0x04, 0x12, 0xDC, 0x52, 0x40, 0x90, 0x60, 0x81, 0x5C, - 0x07, 0x20, 0xA8, 0x1A, 0xD0, 0x20, 0x01, 0x35, 0x07, 0x3C, 0x1C, 0x18, 0x30, 0x87, 0xCC, 0x00, - 0x03, 0x02, 0x0F, 0x12, 0x34, 0xD8, 0xA6, 0xCF, 0x44, 0xA7, 0x8F, 0x9D, 0x0E, 0x88, 0xAC, 0x75, - 0x6B, 0x22, 0xC5, 0x4B, 0x44, 0x4E, 0xFF, 0x26, 0x63, 0x80, 0x20, 0xE3, 0x81, 0x8E, 0x5D, 0x0E, - 0xA4, 0x33, 0xA6, 0x92, 0x8D, 0x03, 0x04, 0x35, 0x2F, 0x35, 0xC0, 0x98, 0xE0, 0x25, 0x4C, 0x26, - 0x07, 0x7C, 0xE4, 0xBC, 0x82, 0x40, 0xE1, 0x50, 0x3D, 0xCA, 0x52, 0x38, 0xFA, 0x89, 0xE3, 0x47, - 0xCE, 0x1F, 0x00, 0x8E, 0xAA, 0x02, 0xC2, 0x80, 0xE9, 0x92, 0x86, 0x2A, 0x0D, 0x3C, 0xA0, 0x29, - 0x55, 0xD1, 0x00, 0x8C, 0x06, 0xAC, 0x26, 0x31, 0x80, 0xC0, 0x24, 0x32, 0x04, 0x09, 0xBA, 0x9A, - 0x1B, 0x94, 0x80, 0xA3, 0x58, 0x18, 0x5A, 0xCF, 0x1C, 0x13, 0x78, 0x69, 0x9C, 0xDA, 0x2C, 0x04, - 0x22, 0x34, 0x78, 0x6B, 0x03, 0x82, 0x02, 0x44, 0x97, 0x5E, 0xD5, 0x1D, 0x60, 0xF7, 0xEE, 0xB9, - 0x07, 0x61, 0xF9, 0xD6, 0x58, 0xC0, 0x20, 0xDB, 0x1A, 0x82, 0x0B, 0x09, 0x17, 0xBE, 0xFB, 0x55, - 0x81, 0xE2, 0x1B, 0x99, 0x10, 0x39, 0xF6, 0x2A, 0x99, 0xB0, 0x61, 0x3D, 0x0E, 0x2F, 0xDF, 0x18, - 0x94, 0x87, 0xF3, 0x00, 0x01, 0x02, 0x24, 0x7F, 0x7E, 0x8C, 0x60, 0xA9, 0x68, 0x17, 0x6D, 0xCC, - 0x62, 0x91, 0x8C, 0x1A, 0x75, 0xE7, 0x2B, 0x30, 0xBA, 0xF2, 0xF1, 0xF9, 0xDA, 0x45, 0x26, 0xAE, - 0x59, 0x4E, 0xD7, 0x4E, 0xED, 0x19, 0xF7, 0x8C, 0xA3, 0x5A, 0xF7, 0xF6, 0x16, 0xF1, 0xC3, 0x68, - 0x70, 0xE1, 0xC3, 0x8B, 0xAF, 0xA1, 0x31, 0xF4, 0xB4, 0xD2, 0xD7, 0x10, 0x60, 0xE9, 0x21, 0x3C, - 0x3C, 0xFA, 0x64, 0xE3, 0x32, 0x6A, 0xD2, 0x56, 0xF0, 0xC0, 0x0F, 0x5F, 0x3A, 0xA9, 0x02, 0x70, - 0xEF, 0x4E, 0x5C, 0x3A, 0x68, 0xD7, 0xE5, 0x54, 0x72, 0xB7, 0xF2, 0xD5, 0xBC, 0xD5, 0xA0, 0x34, - 0xD7, 0xDB, 0x6E, 0xAF, 0x5A, 0x95, 0x03, 0xDE, 0x2F, 0x98, 0x73, 0xDB, 0x70, 0x01, 0xC4, 0xF2, - 0x96, 0x45, 0xB3, 0x41, 0x67, 0x5B, 0xFF, 0x7F, 0xE6, 0x00, 0x20, 0x51, 0x0C, 0xF2, 0xD0, 0x47, - 0x9C, 0x7A, 0xEA, 0x91, 0x07, 0x20, 0x4C, 0x05, 0xC8, 0xA5, 0x9E, 0x70, 0xA7, 0x31, 0x78, 0x92, - 0x24, 0x89, 0xB9, 0x70, 0x4C, 0x26, 0x41, 0x04, 0xA4, 0x40, 0x03, 0x19, 0x32, 0x72, 0xC8, 0x85, - 0x1D, 0xB9, 0x92, 0x20, 0x7F, 0xEE, 0x9D, 0x94, 0xE1, 0x49, 0x0C, 0xDD, 0x84, 0x16, 0x79, 0x11, - 0xF4, 0x11, 0x0B, 0x42, 0x62, 0x41, 0x70, 0xCB, 0x73, 0x1E, 0x0E, 0xE5, 0x20, 0x70, 0x7B, 0x10, - 0x40, 0x58, 0x5E, 0xC4, 0xE4, 0x23, 0x42, 0x02, 0x86, 0x34, 0xA2, 0x98, 0x24, 0x0A, 0x00, 0x19, - 0x63, 0x4E, 0xFD, 0x10, 0x43, 0x93, 0x32, 0x79, 0xF1, 0x90, 0x42, 0x88, 0x2E, 0x2C, 0xF0, 0x80, - 0x21, 0x0F, 0x30, 0x00, 0x5F, 0x30, 0x62, 0xF4, 0xB1, 0x61, 0x90, 0x47, 0x39, 0x18, 0xCB, 0x3F, - 0xEF, 0xF8, 0x60, 0xC0, 0x2F, 0x36, 0x3C, 0xB1, 0x22, 0x53, 0x99, 0x20, 0x90, 0x08, 0x9A, 0x5D, - 0x79, 0xD9, 0x80, 0x00, 0x29, 0xB4, 0xD6, 0x04, 0x59, 0x2C, 0xFC, 0x24, 0x13, 0x2A, 0x78, 0x76, - 0xF5, 0x95, 0x03, 0x0C, 0xA0, 0xA6, 0xA3, 0x17, 0x6E, 0x3D, 0xB2, 0xC0, 0x0F, 0x0A, 0x10, 0xB9, - 0xDA, 0x39, 0x08, 0x08, 0x90, 0x86, 0x00, 0x4E, 0x2E, 0x17, 0x86, 0x3B, 0xA5, 0x4D, 0xAA, 0x87, - 0x42, 0xAF, 0x0C, 0xE2, 0x00, 0xA6, 0x63, 0x8A, 0xF6, 0xA8, 0x0A, 0x91, 0x06, 0xF0, 0x4B, 0x9E, - 0xCE, 0x29, 0xF2, 0x17, 0x4B, 0x96, 0x16, 0x50, 0xA9, 0x9F, 0x9A, 0x02, 0x50, 0x00, 0x23, 0x81, - 0x9E, 0x1A, 0x41, 0x94, 0x47, 0x31, 0x10, 0xE6, 0x01, 0xD3, 0x98, 0xA5, 0x10, 0x2A, 0x2D, 0xF1, - 0x21, 0x46, 0x40, 0xB5, 0xDA, 0x8A, 0xD8, 0x02, 0x0D, 0x21, 0x9A, 0x80, 0x99, 0x98, 0xE0, 0x63, - 0xCE, 0x10, 0x01, 0xC8, 0x7A, 0xC2, 0x79, 0x11, 0x50, 0x65, 0x26, 0x2B, 0x9F, 0x64, 0xF9, 0xD1, - 0xE8, 0x93, 0x29, 0x32, 0x30, 0x84, 0x03, 0x0A, 0x28, 0x04, 0x2C, 0x46, 0x0B, 0x5C, 0x91, 0xAE, - 0x22, 0x64, 0x21, 0xB0, 0x13, 0x30, 0x99, 0xDC, 0xB4, 0xD3, 0xB3, 0xE9, 0x00, 0x50, 0x6A, 0xB2, - 0x00, 0xB4, 0xD1, 0x42, 0x50, 0x42, 0x00, 0xF6, 0x55, 0x51, 0xAA, 0x6A, 0x82, 0x09, 0x22, 0x08, - 0x38, 0xB0, 0x4D, 0xB7, 0x88, 0x2C, 0x60, 0x0D, 0x8B, 0xF8, 0xBE, 0x90, 0x89, 0x02, 0x0E, 0xE0, - 0x03, 0x81, 0xC0, 0x99, 0xDC, 0xAA, 0x2A, 0x44, 0xB3, 0xF8, 0xE9, 0x16, 0x04, 0x08, 0xD8, 0xC2, - 0x1C, 0x97, 0x0D, 0xCB, 0xE0, 0xC9, 0x28, 0x3A, 0x28, 0xF3, 0x5F, 0x6B, 0xBF, 0xD9, 0x72, 0xC4, - 0x62, 0x1D, 0x7F, 0x1B, 0x72, 0x0D, 0xCA, 0xBC, 0xD4, 0x86, 0x2D, 0x3E, 0xB9, 0xBC, 0x5C, 0x08, - 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, 0x6A, 0x00, - 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, 0xAE, 0x6C, 0xEB, - 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, 0x0A, 0xC7, 0x03, - 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, 0xA4, 0x10, 0xA8, - 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, 0x9E, 0x18, 0x02, - 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, 0xD4, 0x81, 0x01, - 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, 0x0D, 0x08, 0x05, - 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, 0x04, 0x06, 0x10, - 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, 0x93, 0x09, 0x0C, - 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, 0x0C, 0x39, 0x9A, - 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, 0xAB, 0x5B, 0x4A, - 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, 0x0D, 0x0D, 0x07, - 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, 0x0E, 0x7B, 0x04, - 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, 0x92, 0x0C, 0x0E, - 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, 0x5B, 0x03, 0x0E, - 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, 0x98, 0xBE, 0x73, - 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, 0xB0, 0x6A, 0xA3, - 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, 0xBC, 0xA5, 0x0C, - 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, 0x04, 0x32, 0x53, - 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, 0x67, 0x8E, 0xA2, - 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, 0x33, 0xA0, 0x2B, - 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, 0x0E, 0x10, 0xC0, - 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, 0x0A, 0x08, 0xF8, - 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, 0x1D, 0x8A, 0x47, - 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, 0x22, 0x22, 0x82, - 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, 0x6B, 0x50, 0xE0, - 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, 0xA3, 0x2D, 0x60, - 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, 0x94, 0x14, 0x7F, - 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, 0x05, 0x30, 0x4A, - 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, 0x53, 0x20, 0xC1, - 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, 0x10, 0x03, 0x80, - 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, 0x26, 0x0F, 0x28, - 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, 0xC6, 0x0A, 0x02, - 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, 0xA0, 0xC0, 0x28, - 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, 0x42, 0x01, 0x5A, - 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, 0x88, 0x33, 0x14, - 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, 0x6A, 0xC4, 0x80, - 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, 0x28, 0xC2, 0xE2, - 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, 0x21, 0xA4, 0x0C, - 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, 0x4A, 0x93, 0x29, - 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, 0x94, 0x0C, 0x38, - 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, 0x56, 0x74, 0x54, - 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, 0x99, 0x83, 0x8A, - 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, 0x10, 0x02, 0x00, - 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, - 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, - 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, - 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, - 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, - 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, - 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, - 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, - 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, - 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, - 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, - 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, - 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, - 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, - 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, - 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, - 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, - 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, - 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, - 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, - 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, - 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, - 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, - 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, - 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, - 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, - 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, - 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, - 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, - 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, - 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, - 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, - 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, - 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, - 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, - 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, - 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, - 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, - 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, - 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, - 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, - 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, - 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, - 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, - 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, - 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, - 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, - 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, - 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, - 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, - 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, - 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, - 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, - 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, - 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, - 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, - 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, - 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, - 0x0D, 0x21, 0x00, 0x00, 0x3B}; +#include + +static const uint8_t firebase_png[] PROGMEM = { + 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49, 0x48, 0x44, 0x52, + 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x02, 0x58, 0x08, 0x06, 0x00, 0x00, 0x00, 0x9A, 0x76, 0x82, + 0x70, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xAE, 0xCE, 0x1C, 0xE9, 0x00, 0x00, + 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41, 0x00, 0x00, 0xB1, 0x8F, 0x0B, 0xFC, 0x61, 0x05, 0x00, 0x00, + 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0E, 0xC3, 0x00, 0x00, 0x0E, 0xC3, 0x01, 0xC7, + 0x6F, 0xA8, 0x64, 0x00, 0x00, 0x55, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5E, 0xED, 0xDD, 0x59, + 0x90, 0x1D, 0xF5, 0x81, 0xE7, 0x7B, 0x3F, 0xF4, 0xC3, 0x84, 0x91, 0x40, 0x6E, 0xEF, 0xC6, 0x8B, + 0x30, 0x92, 0x4A, 0x1B, 0x58, 0x98, 0xCD, 0xA0, 0xA5, 0x4A, 0x12, 0x20, 0x6C, 0x9A, 0xB6, 0xBA, + 0x01, 0x63, 0x4F, 0x3F, 0x8C, 0x1E, 0x26, 0xC2, 0xF7, 0xE5, 0xC6, 0x25, 0xE2, 0xDE, 0x97, 0x3B, + 0x7D, 0x67, 0xAC, 0x6E, 0x63, 0x63, 0x83, 0x8D, 0xBC, 0xB1, 0x99, 0xA5, 0x10, 0x08, 0xED, 0x52, + 0x69, 0xAD, 0x92, 0xA0, 0xBB, 0xAB, 0xA7, 0xED, 0x6E, 0x77, 0xB7, 0x81, 0x42, 0x9B, 0x99, 0x89, + 0x89, 0xDB, 0x9A, 0xB9, 0x0E, 0x2F, 0x2C, 0x76, 0x61, 0x16, 0x49, 0x85, 0xA4, 0xFC, 0xDF, 0xFF, + 0x3F, 0x4F, 0xE6, 0xA9, 0x3C, 0x79, 0x7E, 0xE7, 0x9C, 0xCC, 0x3C, 0x99, 0x75, 0xCE, 0xC9, 0xFA, + 0x7E, 0x22, 0x7E, 0xA1, 0x6E, 0x2F, 0x42, 0xC2, 0x94, 0xE2, 0xFF, 0x8D, 0x7F, 0x65, 0x9E, 0xF7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x82, 0x79, 0x6E, 0xCD, 0x80, 0xBF, 0xC3, 0x5F, 0x58, 0x12, 0xFC, + 0x4B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1F, 0x73, 0x78, 0xCD, 0x3A, 0xEF, 0xB9, 0x35, 0x63, 0xE6, + 0xB9, 0x9B, 0x4D, 0x75, 0xCF, 0xAE, 0xF1, 0xE7, 0x3D, 0x7B, 0xD3, 0xA0, 0x0B, 0x92, 0xE0, 0x3F, + 0x0A, 0x00, 0x00, 0x00, 0x00, 0xD9, 0x98, 0x91, 0x35, 0xB3, 0xEB, 0xC2, 0x23, 0x12, 0x1F, 0xD1, + 0x79, 0x87, 0xD7, 0x6C, 0x08, 0xFE, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x90, 0x8E, 0xFB, 0x16, 0x2B, + 0xEF, 0xD9, 0x35, 0xE3, 0x95, 0xE0, 0xB8, 0xD1, 0x98, 0x03, 0x57, 0x19, 0xB3, 0x7B, 0xAE, 0x31, + 0x3B, 0x3E, 0x65, 0xCC, 0xB6, 0x8F, 0x1A, 0xB3, 0xF3, 0xD3, 0xC6, 0x0C, 0x2D, 0x34, 0x66, 0x78, + 0xD9, 0x64, 0x84, 0x3C, 0x7B, 0xD3, 0x60, 0xF0, 0x5F, 0x07, 0x00, 0x00, 0x00, 0x80, 0xE4, 0xAA, + 0x37, 0x1F, 0x2E, 0x3C, 0x76, 0x7C, 0xC2, 0x98, 0xED, 0x1F, 0xAB, 0x84, 0x87, 0xDA, 0x2E, 0x1B, + 0x26, 0x87, 0x6F, 0xA8, 0x84, 0xC8, 0xA1, 0x9B, 0xD6, 0x06, 0x3F, 0x05, 0x00, 0x00, 0x00, 0x00, + 0xB4, 0xE6, 0x9E, 0xF9, 0xF0, 0xE3, 0x63, 0xCF, 0xA2, 0x4A, 0x78, 0x34, 0x8B, 0x8F, 0x70, 0xDB, + 0x3F, 0x6E, 0xCC, 0xC8, 0x0A, 0xF7, 0xAD, 0x58, 0xE3, 0x66, 0xB4, 0x7F, 0x56, 0xF0, 0x53, 0x01, + 0x00, 0x00, 0x00, 0x40, 0x73, 0xDE, 0x73, 0x37, 0x9F, 0x34, 0xFB, 0xAF, 0x48, 0x1E, 0x1F, 0xE1, + 0x76, 0x5E, 0x62, 0xCC, 0xE1, 0xD5, 0x76, 0x37, 0xAE, 0x0F, 0x7E, 0x2A, 0x00, 0x00, 0x00, 0x00, + 0x68, 0xCC, 0x3D, 0x78, 0x6E, 0x0E, 0xAF, 0x4A, 0x1F, 0x1F, 0xFE, 0x3E, 0x62, 0xCC, 0xBE, 0xCF, + 0x18, 0xEF, 0xF0, 0x4D, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x68, 0xCD, 0xFF, 0x8C, 0x8F, 0xBD, + 0x97, 0x67, 0x8B, 0x0F, 0xB7, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x20, 0x19, 0x1B, + 0x20, 0xEB, 0xCD, 0xAE, 0x4F, 0xC7, 0xE2, 0xA2, 0xD5, 0x82, 0xF8, 0x08, 0xB7, 0x67, 0xB1, 0x31, + 0xCF, 0xDE, 0x64, 0xDC, 0x6D, 0x4A, 0xF0, 0xD3, 0x02, 0x00, 0x00, 0x00, 0x40, 0x3D, 0xEF, 0xB9, + 0x9B, 0x07, 0x75, 0x64, 0x34, 0x5A, 0x2C, 0x3E, 0xC2, 0x1D, 0x1A, 0xE0, 0xB5, 0xBC, 0x00, 0x00, + 0x00, 0x00, 0x9A, 0xF3, 0x0E, 0x2E, 0x1B, 0xD5, 0xA1, 0xA1, 0x26, 0xC2, 0x23, 0xDC, 0xD0, 0x02, + 0x6E, 0x41, 0x00, 0x00, 0x00, 0x00, 0x34, 0xE7, 0x1D, 0xB8, 0x76, 0x5C, 0xC7, 0x46, 0x7C, 0x22, + 0x3A, 0xE2, 0x1B, 0x59, 0x6E, 0xBC, 0xC3, 0x37, 0x8E, 0x06, 0x3F, 0x35, 0x00, 0x00, 0x00, 0x00, + 0x4C, 0x72, 0x6F, 0xAE, 0x32, 0xFB, 0x96, 0xD8, 0x78, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x0D, 0xB5, + 0x5D, 0x73, 0x2A, 0xB7, 0x20, 0xCF, 0xAD, 0x19, 0x08, 0xFE, 0x12, 0x00, 0x00, 0x00, 0x00, 0x50, + 0xE1, 0xBF, 0x01, 0x6B, 0x77, 0x9F, 0x8D, 0x07, 0x15, 0x1D, 0xE1, 0x44, 0x68, 0x34, 0xDB, 0xF0, + 0xF5, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xE7, 0x7F, 0x02, 0xFA, 0xAE, 0xB9, 0x36, 0x1C, + 0x54, 0x78, 0xB8, 0x89, 0xC0, 0x68, 0xB5, 0x5D, 0x97, 0x1A, 0xF3, 0xEC, 0x8D, 0xC6, 0x3C, 0xB7, + 0x9A, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0x93, 0x6C, 0x80, 0xAC, 0xD7, 0xE1, 0xE1, 0x26, 0xE2, + 0xA2, 0xE5, 0x3E, 0x5C, 0xD9, 0x81, 0xAB, 0x8C, 0xF7, 0xEC, 0x0D, 0x27, 0x83, 0xBF, 0x0C, 0x00, + 0x00, 0x00, 0x00, 0xBC, 0xE7, 0x3D, 0xDE, 0xF0, 0x8A, 0x06, 0x6F, 0xC0, 0x52, 0x71, 0xD1, 0x6A, + 0x41, 0x7C, 0xB8, 0xED, 0xF8, 0x44, 0xE5, 0x16, 0xE4, 0xF0, 0x8D, 0xEB, 0x82, 0xBF, 0x14, 0x00, + 0x00, 0x00, 0x80, 0xE9, 0xCE, 0x3B, 0x70, 0xFD, 0xC9, 0xDC, 0xE3, 0x23, 0x1C, 0xB7, 0x20, 0x00, + 0x00, 0x00, 0x00, 0xA2, 0xCC, 0xFE, 0x2B, 0x6D, 0x2C, 0x14, 0x10, 0x1F, 0x6E, 0xEE, 0x16, 0xE4, + 0xF0, 0x2A, 0x77, 0x0B, 0xB2, 0x3E, 0xF8, 0xCB, 0x01, 0x00, 0x00, 0x00, 0x98, 0xAE, 0x6C, 0x18, + 0x2C, 0x31, 0x7B, 0x2E, 0xB3, 0xB1, 0x50, 0x40, 0x7C, 0x84, 0xDB, 0x77, 0xB9, 0x7B, 0x23, 0xD6, + 0xB8, 0x7B, 0xDD, 0x6F, 0xF0, 0x97, 0x05, 0x00, 0x00, 0x00, 0x30, 0x1D, 0x99, 0x43, 0x37, 0xAD, + 0x9D, 0x7C, 0x03, 0x96, 0x8A, 0x8B, 0x56, 0x13, 0xC1, 0x11, 0xDF, 0xF6, 0x8F, 0x71, 0x0B, 0x02, + 0x00, 0x00, 0x00, 0x20, 0x78, 0x03, 0xD6, 0xF6, 0x8F, 0xDB, 0x50, 0x50, 0x71, 0xD1, 0x6A, 0x22, + 0x36, 0x1A, 0x8D, 0x5B, 0x10, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB3, 0x37, 0x0D, 0xEA, 0xB8, 0x68, + 0x35, 0x11, 0x19, 0xAD, 0x76, 0xA8, 0xDF, 0x3D, 0x90, 0x3E, 0x18, 0xFC, 0xA5, 0x01, 0x00, 0x00, + 0x00, 0x4C, 0x37, 0xDE, 0x81, 0x6B, 0x46, 0x75, 0x60, 0x34, 0x9B, 0x88, 0x8B, 0x56, 0xDB, 0xFA, + 0x21, 0x63, 0x86, 0xE6, 0x57, 0x5E, 0xCB, 0x3B, 0xB2, 0x66, 0x76, 0xF0, 0x97, 0x07, 0x00, 0x00, + 0x00, 0x30, 0x9D, 0x98, 0x03, 0x57, 0xDB, 0x40, 0x50, 0x91, 0xD1, 0x68, 0x22, 0x2E, 0x5A, 0xCD, + 0xC5, 0x47, 0x38, 0x6E, 0x41, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC9, 0xDD, 0x44, 0x98, 0x7D, 0x9F, + 0xB1, 0x91, 0xA0, 0x42, 0x43, 0x4D, 0xC4, 0x45, 0xAB, 0x45, 0xE3, 0xC3, 0x6D, 0xF7, 0xDC, 0xCA, + 0x2D, 0xC8, 0x73, 0xAB, 0x07, 0x82, 0x5F, 0x06, 0x00, 0x00, 0x00, 0x80, 0xE9, 0xC0, 0x3C, 0xB7, + 0x66, 0xC0, 0xEC, 0x9E, 0x67, 0x43, 0x41, 0xC5, 0x46, 0x7C, 0x22, 0x2E, 0x5A, 0x2D, 0x1E, 0x1F, + 0xE1, 0x86, 0xAF, 0x73, 0x0F, 0xA4, 0x8F, 0x06, 0xBF, 0x0C, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x81, + 0xF7, 0xEC, 0x4D, 0x77, 0x99, 0x9D, 0x97, 0xD8, 0x58, 0x50, 0xC1, 0x11, 0x9D, 0x88, 0x8B, 0x56, + 0x53, 0xE1, 0x11, 0x6E, 0xD7, 0xA7, 0xB9, 0x05, 0x01, 0x00, 0x00, 0x00, 0xA6, 0x1B, 0xEF, 0xF0, + 0x8D, 0x1B, 0x74, 0x70, 0x44, 0x27, 0xE2, 0xA2, 0xD5, 0x54, 0x74, 0xC4, 0xC7, 0x2D, 0x08, 0x00, + 0x00, 0x00, 0x30, 0xBD, 0x78, 0x07, 0xAF, 0x6F, 0xF1, 0x06, 0x2C, 0x11, 0x17, 0xAD, 0xA6, 0x62, + 0x43, 0xCD, 0x7D, 0xF6, 0x88, 0xBB, 0x05, 0x39, 0x7C, 0xE3, 0xBA, 0xE0, 0x97, 0x03, 0x00, 0x00, + 0x00, 0xA0, 0xCC, 0xBC, 0x03, 0xD7, 0x9D, 0xD4, 0xE1, 0xE1, 0x26, 0xE2, 0xA2, 0xD5, 0x54, 0x68, + 0x34, 0xDB, 0xFE, 0x2B, 0xDD, 0x1B, 0xB1, 0x4E, 0x06, 0xBF, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x65, + 0xD6, 0xF8, 0x0D, 0x58, 0x22, 0x2E, 0x5A, 0x4D, 0x05, 0x46, 0xAB, 0xB9, 0x5B, 0x90, 0xC3, 0x37, + 0x70, 0x0B, 0x02, 0x00, 0x00, 0x00, 0x94, 0x9D, 0xFF, 0x06, 0xAC, 0xA1, 0x05, 0x36, 0x1E, 0x3A, + 0x14, 0x1F, 0xFE, 0x3E, 0x68, 0x5C, 0x04, 0x79, 0x87, 0x6E, 0x18, 0x37, 0xA3, 0xFD, 0xB3, 0x82, + 0x5F, 0x1A, 0x00, 0x00, 0x00, 0x80, 0xB2, 0x71, 0xB7, 0x0E, 0x66, 0xD7, 0x1C, 0x1B, 0x10, 0x1D, + 0x8C, 0x0F, 0x37, 0xF7, 0xD7, 0x3D, 0xB4, 0xD2, 0x98, 0xC3, 0xAB, 0xD7, 0x07, 0xBF, 0x34, 0x00, + 0x00, 0x00, 0x00, 0x65, 0x63, 0x03, 0x64, 0xBD, 0xD9, 0x7E, 0x71, 0x25, 0x00, 0x3A, 0x15, 0x1F, + 0xE1, 0xF6, 0x5E, 0xC6, 0x2D, 0x08, 0x00, 0x00, 0x00, 0x50, 0x66, 0xDE, 0xC8, 0xCA, 0xA1, 0xAE, + 0x88, 0x0F, 0xB7, 0xE0, 0x16, 0xC4, 0x3B, 0xBC, 0x7A, 0x43, 0xF0, 0xCB, 0x03, 0x00, 0x00, 0x00, + 0x50, 0x26, 0xDE, 0xC1, 0x6B, 0xC7, 0xBA, 0x22, 0x3E, 0xC2, 0xED, 0xEE, 0xAB, 0x3C, 0x90, 0x3E, + 0xB2, 0x66, 0x76, 0xF0, 0x4B, 0x04, 0x00, 0x00, 0x00, 0x50, 0x16, 0x66, 0xFF, 0x67, 0x75, 0x5C, + 0xB4, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0xD1, 0x11, 0xDF, 0xC8, 0x0A, 0xE3, 0x1D, 0x5A, 0x3D, 0x18, + 0xFC, 0x12, 0x01, 0x00, 0x00, 0x00, 0x94, 0x81, 0xBB, 0x65, 0x30, 0xFB, 0x2E, 0xD7, 0x81, 0xD1, + 0x6C, 0x32, 0x2C, 0x92, 0x4C, 0xC4, 0x86, 0x1A, 0xB7, 0x20, 0x00, 0x00, 0x00, 0x40, 0xF9, 0x98, + 0xE7, 0x56, 0x0F, 0x98, 0x5D, 0x97, 0xEA, 0xC8, 0x68, 0x34, 0x19, 0x16, 0x49, 0x26, 0x42, 0xA3, + 0xD9, 0x0E, 0x7E, 0xCE, 0x78, 0x87, 0x6F, 0x18, 0x0D, 0x7E, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x7A, + 0x9D, 0xFF, 0x06, 0xAC, 0x1D, 0x9F, 0xD0, 0xA1, 0xA1, 0x26, 0xC3, 0x22, 0xC9, 0x44, 0x60, 0xB4, + 0xDA, 0xCE, 0x4B, 0x82, 0x5B, 0x90, 0xD5, 0x03, 0xC1, 0x2F, 0x17, 0x00, 0x00, 0x00, 0x40, 0x2F, + 0xF3, 0x9E, 0xBD, 0x61, 0x50, 0x86, 0x86, 0x9A, 0x0C, 0x8B, 0x24, 0x13, 0x71, 0x91, 0x74, 0x07, + 0xAF, 0x35, 0xDE, 0xE1, 0x55, 0xDC, 0x82, 0x00, 0x00, 0x00, 0x00, 0x65, 0xE0, 0x1D, 0xBC, 0x6E, + 0x54, 0xC6, 0x46, 0x7C, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, 0x6D, 0xF9, 0x80, 0x31, 0x3B, + 0x67, 0xBB, 0x0F, 0x26, 0x34, 0xE6, 0xD0, 0xAA, 0xB5, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, 0x40, + 0xAF, 0xF2, 0x0E, 0x5C, 0x33, 0x2E, 0x83, 0x23, 0x3A, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, + 0x5C, 0x7C, 0x84, 0xDB, 0x77, 0x85, 0xFB, 0x5C, 0x90, 0x93, 0xC1, 0x2F, 0x19, 0x00, 0x00, 0x00, + 0x40, 0x2F, 0x72, 0x9F, 0x36, 0xDE, 0xF2, 0x0D, 0x58, 0x32, 0x2C, 0x92, 0x4C, 0x44, 0x45, 0xD2, + 0x45, 0xE3, 0xC3, 0x6D, 0xDB, 0xC7, 0x2A, 0xB7, 0x20, 0x87, 0x57, 0xAD, 0x0B, 0x7E, 0xE9, 0x00, + 0x00, 0x00, 0x00, 0x7A, 0x8D, 0xFF, 0x06, 0xAC, 0xDD, 0x73, 0xEB, 0xA3, 0x23, 0x9C, 0x0C, 0x8B, + 0x24, 0x13, 0x51, 0x91, 0x74, 0xF1, 0xF8, 0x08, 0xC7, 0x2D, 0x08, 0x00, 0x00, 0x00, 0xD0, 0xDB, + 0xCC, 0xE1, 0x1B, 0xD7, 0x35, 0x7C, 0x05, 0xAF, 0x0C, 0x8B, 0x24, 0x13, 0x51, 0x91, 0x74, 0x2A, + 0x3C, 0xC2, 0x6D, 0xB5, 0xBF, 0xA6, 0x43, 0x03, 0xEE, 0x26, 0x64, 0x7D, 0xF0, 0xCB, 0x07, 0x00, + 0x00, 0x00, 0xD0, 0x4B, 0xFC, 0x57, 0xF0, 0xF6, 0x42, 0x7C, 0x84, 0xDB, 0xB3, 0xD8, 0x7D, 0x3A, + 0xFA, 0xB8, 0xFB, 0xD6, 0xB1, 0xE0, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x57, 0x78, 0xC3, 0xCB, + 0xEB, 0xDF, 0x80, 0x25, 0xC3, 0x22, 0xC9, 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x0D, 0x35, 0x6E, 0x41, + 0x00, 0x00, 0x00, 0x80, 0xDE, 0xE5, 0x1D, 0xBC, 0x76, 0xAC, 0x67, 0xE2, 0x23, 0xDC, 0x9E, 0x45, + 0xC6, 0x3B, 0xB4, 0x6A, 0xDC, 0x8C, 0xF4, 0xCF, 0x0E, 0x7E, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x7A, + 0x81, 0xD9, 0x7F, 0x45, 0x6F, 0xC5, 0x87, 0xBF, 0xF7, 0x1B, 0x33, 0xB2, 0xCC, 0x46, 0xC8, 0xCA, + 0xC1, 0xE0, 0xB7, 0x01, 0x00, 0x00, 0x00, 0xA0, 0xDB, 0x99, 0xC3, 0x37, 0x2E, 0x71, 0xB7, 0x09, + 0x3D, 0x17, 0x1F, 0x6E, 0xEE, 0xCD, 0x5D, 0x87, 0x57, 0xD9, 0x10, 0xE9, 0xCD, 0x5B, 0x10, 0xF7, + 0xEB, 0xB6, 0x1B, 0x08, 0xC6, 0x4D, 0x0E, 0x00, 0x00, 0x00, 0xCA, 0xCF, 0x1C, 0xBA, 0x69, 0xAD, + 0xFF, 0x06, 0x2C, 0x19, 0x16, 0x49, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x5A, 0x10, 0x1F, + 0xE1, 0x7A, 0xEC, 0x16, 0xC4, 0xFF, 0xCC, 0x95, 0x91, 0xFE, 0xF5, 0xDE, 0xA1, 0x81, 0x93, 0xFE, + 0x73, 0x2C, 0x91, 0xF9, 0xFF, 0x9A, 0xFD, 0xF7, 0x78, 0xB8, 0x1E, 0x00, 0x00, 0x00, 0xA5, 0x55, + 0x79, 0x03, 0xD6, 0x47, 0x6D, 0x10, 0xA8, 0xB8, 0x68, 0x35, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, + 0xD5, 0x62, 0xF1, 0xE1, 0xB6, 0xF3, 0x53, 0xC1, 0x2D, 0xC8, 0xEA, 0x81, 0xE0, 0xB7, 0xD4, 0xB5, + 0xCC, 0xA1, 0xFE, 0xB5, 0xDE, 0xC8, 0xC0, 0x78, 0x3C, 0x3C, 0xE2, 0xAB, 0xFC, 0x67, 0xFA, 0xD7, + 0x06, 0xFF, 0x35, 0x00, 0x00, 0x00, 0xA0, 0x3C, 0xBC, 0x67, 0x6F, 0x18, 0xD4, 0x71, 0xD1, 0x6A, + 0x22, 0x2A, 0x92, 0x4E, 0xC6, 0x45, 0xAB, 0x89, 0xF8, 0x08, 0x77, 0xF0, 0x1A, 0xE3, 0x1D, 0x5E, + 0x39, 0x1A, 0xFC, 0x96, 0xBA, 0x92, 0x19, 0xE9, 0x5F, 0x57, 0x8D, 0x8C, 0x91, 0xE5, 0xFE, 0x43, + 0xF4, 0x66, 0xC7, 0xC7, 0x6B, 0xE7, 0xFE, 0x35, 0xF7, 0xEF, 0xF9, 0xFF, 0x99, 0x7E, 0x37, 0x3E, + 0xF1, 0x1D, 0x00, 0x00, 0x00, 0xE5, 0xE2, 0x1D, 0xB8, 0x7A, 0x54, 0x07, 0x46, 0xB3, 0x89, 0xA8, + 0x48, 0x3A, 0x19, 0x17, 0xAD, 0x26, 0xA2, 0x23, 0xBA, 0x2E, 0xBF, 0x05, 0xB1, 0x21, 0x31, 0xBB, + 0x7A, 0xF3, 0x31, 0x34, 0xBF, 0xF2, 0x6B, 0xDE, 0x3C, 0x4B, 0xCF, 0xFD, 0x7B, 0x43, 0x7D, 0x7E, + 0x80, 0x78, 0x23, 0x2B, 0x78, 0xCB, 0x17, 0x00, 0x00, 0x00, 0xCA, 0xC5, 0xEC, 0xBF, 0xD2, 0x86, + 0x81, 0x8A, 0x8C, 0x46, 0x13, 0x51, 0x91, 0x74, 0x32, 0x2E, 0x5A, 0x2D, 0x12, 0x1A, 0xCD, 0xE6, + 0x6E, 0x41, 0x0E, 0xAD, 0x1A, 0x0B, 0x7E, 0x5B, 0x5D, 0xC5, 0xC6, 0xC7, 0x90, 0x1F, 0x1F, 0xBB, + 0x3E, 0xAD, 0xA3, 0xA3, 0x66, 0x17, 0x55, 0xB6, 0xF3, 0x92, 0x4A, 0x84, 0x0C, 0xAF, 0xE8, 0xEA, + 0x9B, 0x1D, 0x00, 0x00, 0x00, 0x20, 0x31, 0xFF, 0x81, 0xE8, 0xBD, 0x97, 0xDB, 0x38, 0x50, 0xA1, + 0xA1, 0x26, 0xA2, 0x22, 0xE9, 0x64, 0x5C, 0xB4, 0x9A, 0x08, 0x8D, 0x46, 0x73, 0xCF, 0xB1, 0xB8, + 0x5B, 0x90, 0xC3, 0xAB, 0xBA, 0xEA, 0xDB, 0x96, 0x6C, 0x44, 0x0C, 0xF8, 0xF1, 0xE1, 0xDE, 0xD8, + 0x25, 0x83, 0x23, 0xBA, 0x20, 0x3E, 0x62, 0x11, 0xE2, 0x7E, 0x8E, 0xE0, 0xA7, 0x03, 0x00, 0x00, + 0x00, 0x7A, 0x97, 0x79, 0x6E, 0xF5, 0x80, 0x7F, 0x30, 0x96, 0xB1, 0x11, 0x9F, 0x88, 0x8A, 0xA4, + 0x93, 0x71, 0xD1, 0x6A, 0x22, 0x32, 0x5A, 0x6D, 0xDF, 0x12, 0xE3, 0x1D, 0x5E, 0x75, 0x32, 0xF8, + 0xED, 0x75, 0x05, 0xEF, 0xD0, 0xC0, 0xA8, 0x39, 0x70, 0x55, 0x10, 0x18, 0xCD, 0x16, 0x8B, 0x8F, + 0x70, 0xFB, 0xAF, 0xE4, 0x16, 0x04, 0x00, 0x00, 0x00, 0xE5, 0xE0, 0x3D, 0x7B, 0xC3, 0x5D, 0x66, + 0xC7, 0xA7, 0x6C, 0x24, 0xA8, 0xE0, 0x88, 0x4E, 0x44, 0x45, 0xD2, 0xC9, 0xB8, 0x68, 0x35, 0x11, + 0x17, 0x49, 0x16, 0xDC, 0x82, 0x78, 0x87, 0x56, 0xDD, 0x15, 0xFC, 0x16, 0x3B, 0xAA, 0x7A, 0xFB, + 0xE1, 0x1E, 0x30, 0x97, 0xD1, 0x11, 0x4E, 0x84, 0x47, 0xB8, 0xED, 0x17, 0x73, 0x0B, 0x02, 0x00, + 0x00, 0x80, 0x72, 0xF0, 0x0E, 0xDF, 0xB8, 0x41, 0x07, 0x47, 0x74, 0x22, 0x2A, 0x92, 0x4E, 0xC6, + 0x45, 0xAB, 0x89, 0xB0, 0x48, 0xB3, 0x3D, 0x0B, 0x8D, 0x37, 0xB2, 0x72, 0xBC, 0x1B, 0x3E, 0x4B, + 0x23, 0xD9, 0xED, 0x87, 0x88, 0x8E, 0xF8, 0xB8, 0x05, 0x01, 0x00, 0x00, 0x40, 0x19, 0x78, 0x07, + 0xAF, 0x6B, 0xF1, 0x06, 0x2C, 0x11, 0x15, 0x49, 0x27, 0xE3, 0xA2, 0xD5, 0x44, 0x50, 0xA4, 0xDA, + 0x1F, 0x57, 0xFE, 0xDA, 0x23, 0x2B, 0xEC, 0x56, 0xAE, 0x0F, 0x7E, 0x9B, 0x1D, 0xE1, 0x3E, 0xC7, + 0xC3, 0xBF, 0xFD, 0x70, 0x7F, 0x1F, 0x65, 0x78, 0xB8, 0x89, 0xD8, 0x50, 0xF3, 0x7F, 0x4F, 0xFD, + 0xC6, 0x1C, 0xE4, 0xB3, 0x41, 0x00, 0x00, 0x00, 0xD0, 0xC3, 0xBC, 0x03, 0x9F, 0x3B, 0x59, 0x1F, + 0x1D, 0xE1, 0x22, 0x31, 0x91, 0x76, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xD9, 0xF8, 0x08, + 0xD7, 0x05, 0xB7, 0x20, 0xFE, 0xA7, 0x9A, 0xBB, 0x07, 0xFC, 0x65, 0x78, 0xB8, 0x89, 0xD0, 0x68, + 0xB6, 0xBD, 0x97, 0xB9, 0x5B, 0x90, 0xAE, 0x7A, 0xBE, 0x05, 0x00, 0x00, 0x00, 0x48, 0xA5, 0xF1, + 0x1B, 0xB0, 0x44, 0x54, 0x24, 0x9D, 0x8C, 0x8B, 0x56, 0x53, 0x41, 0x91, 0x66, 0x91, 0xF8, 0x70, + 0x73, 0xBF, 0x8E, 0xE1, 0xA5, 0xEE, 0x13, 0xC5, 0x37, 0x04, 0xBF, 0xD5, 0x29, 0x65, 0xC2, 0x0F, + 0x1D, 0x74, 0x7F, 0x2F, 0xF3, 0x88, 0x0F, 0x37, 0xF7, 0x7B, 0xF2, 0x9F, 0x05, 0x59, 0xCE, 0x87, + 0x13, 0x02, 0x00, 0x00, 0xA0, 0xF7, 0xF8, 0x6F, 0xC0, 0x72, 0x1F, 0x8A, 0x57, 0xB6, 0xF8, 0x08, + 0xB7, 0x6B, 0x8E, 0x31, 0x87, 0x56, 0xBA, 0x43, 0xFB, 0x94, 0x7F, 0x90, 0x5F, 0xF3, 0xDB, 0x0F, + 0x11, 0x17, 0x49, 0xB7, 0x67, 0xB1, 0xF1, 0x86, 0x97, 0x73, 0x0B, 0x02, 0x00, 0x00, 0x80, 0xDE, + 0x63, 0x0E, 0xDD, 0xB4, 0xD6, 0xFF, 0x60, 0xBC, 0x32, 0xC6, 0x47, 0x38, 0x77, 0x0B, 0x72, 0x68, + 0xE5, 0x60, 0xF0, 0x5B, 0x9E, 0x12, 0xCD, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0xDD, 0x33, 0x17, 0xDA, + 0xDF, 0x93, 0xFD, 0x7B, 0x66, 0x7F, 0x4F, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0xE7, 0x98, 0xC3, + 0x37, 0xAE, 0xF7, 0x5F, 0x5B, 0x5B, 0xD6, 0xF8, 0x70, 0x0B, 0x6F, 0x41, 0x0E, 0xF7, 0x2F, 0x09, + 0x7E, 0xDB, 0x85, 0x72, 0xCF, 0x9C, 0xF8, 0xB7, 0x1F, 0xEE, 0x66, 0x29, 0xEF, 0xF8, 0x08, 0xB7, + 0x7B, 0x9E, 0xF1, 0x46, 0x96, 0x8F, 0x9B, 0xA1, 0xCE, 0xBF, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, + 0xCC, 0x1B, 0x59, 0x39, 0x54, 0xEA, 0xF8, 0x08, 0x77, 0xE0, 0x6A, 0x77, 0x0B, 0x32, 0x25, 0xAF, + 0xB0, 0x35, 0x23, 0xFD, 0xEB, 0xCD, 0xC8, 0x72, 0xFB, 0xD7, 0xB5, 0xBF, 0xC6, 0x22, 0xE2, 0xC3, + 0x6D, 0xF3, 0xFB, 0xC2, 0x5B, 0x90, 0x8E, 0xBE, 0xE5, 0x0B, 0x00, 0x00, 0x00, 0x48, 0xC5, 0xDB, + 0x7F, 0xED, 0x58, 0xE9, 0xE3, 0xC3, 0x6D, 0xC7, 0x27, 0xC3, 0x67, 0x41, 0x0A, 0xFD, 0x20, 0x3F, + 0xFF, 0xF6, 0x63, 0x64, 0x60, 0xBC, 0xFE, 0xF6, 0x43, 0x44, 0x45, 0xD2, 0xC5, 0xE3, 0x23, 0x1C, + 0xB7, 0x20, 0x00, 0x00, 0x00, 0xE8, 0x35, 0x66, 0xDF, 0x12, 0x1D, 0x15, 0x49, 0x27, 0xE3, 0xA2, + 0xD5, 0x54, 0x50, 0xA4, 0x99, 0x08, 0x8C, 0x56, 0x73, 0x37, 0x06, 0x53, 0x70, 0x0B, 0xA2, 0x6F, + 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8F, 0x70, 0xDC, 0x82, 0x00, 0x00, 0x00, 0xA0, 0x97, 0x98, + 0x91, 0x35, 0xB3, 0xDD, 0xE7, 0x4A, 0xC8, 0xB0, 0x48, 0x32, 0x19, 0x17, 0xAD, 0x16, 0x8F, 0x89, + 0xB4, 0x13, 0x71, 0xD1, 0x6A, 0xEE, 0xA0, 0xEE, 0xB6, 0xED, 0x63, 0x95, 0x5B, 0x90, 0x43, 0xC5, + 0x7C, 0x90, 0x9F, 0xBE, 0xFD, 0x10, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0xE2, 0xE3, 0x16, 0x04, 0x00, + 0x00, 0x00, 0xBD, 0xC2, 0x8C, 0xAC, 0x1E, 0x30, 0x3B, 0x2F, 0xD1, 0x71, 0xD1, 0x6A, 0x32, 0x2E, + 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0x30, 0x3E, 0xC2, 0xED, 0xFD, 0x8C, 0xBB, + 0x05, 0x29, 0xE4, 0x15, 0xB6, 0xEE, 0xF3, 0x46, 0xCC, 0xF0, 0xF5, 0xF6, 0xAF, 0x33, 0x45, 0xF1, + 0x11, 0xEE, 0xE0, 0xE7, 0x6C, 0x84, 0xAC, 0xE8, 0xC8, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x89, + 0x99, 0xC3, 0xAB, 0xD7, 0x9B, 0xED, 0x17, 0xEB, 0xC0, 0x68, 0x36, 0x19, 0x17, 0xAD, 0xA6, 0x82, + 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x5A, 0x3C, 0x3E, 0xDC, 0xB6, 0x7E, 0x38, 0x7C, 0x16, 0x24, 0xD7, + 0x57, 0xD8, 0xDA, 0x9F, 0x6F, 0xB6, 0xFF, 0xDA, 0x5D, 0xF7, 0x4A, 0xE3, 0xA9, 0x8C, 0x0F, 0xB7, + 0x9D, 0xB3, 0xED, 0xEF, 0x67, 0x85, 0xFB, 0x3D, 0x4D, 0xF9, 0x67, 0x9D, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x79, 0x87, 0x57, 0x6F, 0x90, 0x81, 0xD1, 0x6C, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, + 0x89, 0xB8, 0x68, 0x35, 0x15, 0x1F, 0xE1, 0x82, 0x5B, 0x10, 0xF7, 0x2D, 0x53, 0xC1, 0xDF, 0x8A, + 0xB6, 0x79, 0x87, 0x06, 0x06, 0x27, 0x6F, 0x3F, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8C, 0x24, 0x73, + 0xB7, 0x20, 0xC3, 0x2B, 0xA6, 0xF4, 0xB3, 0x4E, 0x00, 0x00, 0x00, 0x80, 0x54, 0xBC, 0x83, 0x9F, + 0x1B, 0x95, 0x91, 0xD1, 0x68, 0x32, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0x35, + 0x15, 0x1D, 0xD1, 0xB9, 0x5F, 0x97, 0x7F, 0x63, 0xB0, 0x32, 0x97, 0x87, 0xB7, 0x6B, 0x6F, 0x3F, + 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8B, 0xA4, 0xE3, 0x16, 0x04, 0x00, 0x00, 0x00, 0xDD, 0xCE, 0xDB, + 0x7F, 0xD5, 0xB8, 0x0C, 0x0D, 0xB5, 0xBA, 0xB0, 0x48, 0x32, 0x15, 0x14, 0x69, 0x26, 0xE2, 0xA2, + 0xD5, 0x54, 0x70, 0xA8, 0x0D, 0x2D, 0x30, 0xDE, 0xC8, 0xCA, 0xF1, 0x3C, 0x6E, 0x41, 0xFC, 0xDB, + 0x8F, 0x03, 0xD7, 0xDA, 0x9F, 0x57, 0x44, 0x45, 0xD2, 0xA9, 0xA8, 0x48, 0x3B, 0xF7, 0x96, 0xAF, + 0xE1, 0x65, 0xDC, 0x82, 0x34, 0x60, 0xC6, 0xFE, 0xC3, 0x2C, 0xF3, 0xF2, 0xBF, 0x5F, 0x67, 0x4E, + 0x7C, 0x65, 0x7D, 0x64, 0x6B, 0xDD, 0xBF, 0x1E, 0xFC, 0x47, 0x00, 0x00, 0x00, 0x50, 0x14, 0x77, + 0xF0, 0x4E, 0xFC, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, + 0x0A, 0x8D, 0x46, 0x73, 0xBF, 0xC6, 0x1C, 0x6E, 0x41, 0xDC, 0xA7, 0xAB, 0xFB, 0xB7, 0x1F, 0xEE, + 0x59, 0x1A, 0x15, 0x16, 0x49, 0xA6, 0x62, 0x22, 0xCB, 0xB6, 0x7F, 0xD4, 0xFE, 0x7E, 0x96, 0xDB, + 0x2D, 0x2D, 0xF4, 0xB3, 0x4E, 0x7A, 0x8D, 0x0B, 0x0C, 0xEF, 0xC4, 0x97, 0x07, 0xCD, 0x2F, 0xBE, + 0x62, 0xE4, 0x4E, 0x7C, 0xC9, 0xF8, 0xFF, 0x3E, 0x21, 0x02, 0x00, 0x00, 0x50, 0x1C, 0xFF, 0x0D, + 0x58, 0xBB, 0xE6, 0xE8, 0xE0, 0x88, 0xAE, 0x2E, 0x2C, 0x92, 0x4C, 0x05, 0x45, 0x9A, 0x89, 0xB8, + 0x68, 0x35, 0x15, 0x19, 0xAD, 0xE6, 0xBF, 0xC2, 0x76, 0xE5, 0x78, 0x3B, 0xDF, 0xB6, 0xE4, 0x1D, + 0x1A, 0x18, 0x35, 0xFB, 0xAF, 0xB4, 0x3F, 0x9F, 0x08, 0x8B, 0x24, 0x53, 0x21, 0x91, 0x69, 0x33, + 0x2B, 0xDB, 0x7F, 0x85, 0xF1, 0x86, 0x97, 0x4F, 0xC9, 0x27, 0xBE, 0xF7, 0x02, 0x73, 0xFC, 0xDF, + 0x2F, 0xF1, 0x7E, 0xF1, 0xE5, 0xF1, 0xDA, 0xE0, 0xB8, 0xDD, 0x98, 0xE3, 0x5F, 0xF4, 0xC3, 0x23, + 0xFA, 0xAF, 0xFB, 0xFF, 0x39, 0xFB, 0x9F, 0x0F, 0xFE, 0xAB, 0x00, 0x00, 0x00, 0xC8, 0x93, 0x39, + 0x7C, 0xE3, 0xBA, 0x96, 0xAF, 0xE0, 0x95, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, + 0xAB, 0xA9, 0xB8, 0x48, 0xBA, 0xE1, 0xEB, 0x8D, 0xFB, 0x16, 0xAA, 0xE0, 0x6F, 0x4B, 0x2A, 0x36, + 0x5C, 0x06, 0xEC, 0xB2, 0xDF, 0x7E, 0xC8, 0x90, 0xC8, 0xB2, 0x20, 0x3E, 0xDC, 0xB8, 0x05, 0xA9, + 0xAA, 0x89, 0x0F, 0x17, 0x1D, 0x2F, 0xD9, 0xFF, 0xAD, 0x5E, 0xB0, 0xB1, 0xF8, 0xFC, 0x92, 0xC9, + 0xBD, 0x70, 0xB5, 0xFD, 0xD7, 0x57, 0x55, 0xFE, 0x7D, 0x22, 0x04, 0x00, 0x00, 0xA0, 0x38, 0xFE, + 0x2B, 0x78, 0x55, 0x74, 0x84, 0x93, 0x71, 0xD1, 0x6A, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, + 0xA9, 0xA8, 0x48, 0xBC, 0x59, 0x95, 0x07, 0xC7, 0xDD, 0xB7, 0x50, 0x65, 0xB8, 0x05, 0xF1, 0x86, + 0x57, 0x64, 0xBF, 0xFD, 0x90, 0x21, 0x91, 0x65, 0x91, 0xF8, 0x08, 0xC7, 0x2D, 0x48, 0x6D, 0x7C, + 0x1C, 0xB9, 0xB1, 0x36, 0x3A, 0xD4, 0x5C, 0x98, 0x1C, 0xFD, 0x42, 0x25, 0x42, 0x4E, 0x7C, 0x85, + 0x1B, 0x24, 0x00, 0x00, 0x80, 0xBC, 0x79, 0x07, 0x97, 0x35, 0x7E, 0x03, 0x96, 0x8C, 0x8B, 0x56, + 0x53, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0x85, 0x1F, 0x16, 0x68, 0xE7, + 0x6E, 0x41, 0x46, 0x06, 0x86, 0x82, 0xBF, 0x35, 0x89, 0xB4, 0x75, 0xFB, 0x21, 0x43, 0x22, 0xCB, + 0x44, 0x7C, 0xB8, 0x6D, 0xFD, 0xD0, 0xB4, 0xBE, 0x05, 0xA9, 0x89, 0x0F, 0x77, 0xEB, 0xA1, 0x82, + 0xA3, 0xD1, 0x5C, 0xAC, 0xF8, 0x37, 0x26, 0x5F, 0x29, 0xE4, 0xD3, 0xF2, 0x01, 0x00, 0x00, 0xA6, + 0x2D, 0x6F, 0xFF, 0x35, 0x63, 0xC4, 0x47, 0xB0, 0xED, 0x1F, 0xB7, 0x87, 0x75, 0xFF, 0x16, 0x24, + 0xF1, 0x81, 0xDD, 0x1B, 0x59, 0x31, 0xE6, 0x3F, 0xC4, 0xAF, 0x02, 0xA3, 0xD9, 0x64, 0x48, 0x64, + 0x99, 0x08, 0x8F, 0xE8, 0xF6, 0x2C, 0xB2, 0x51, 0xB5, 0x7C, 0x2C, 0xF8, 0xE5, 0x4E, 0x1B, 0x6D, + 0xC5, 0x47, 0xB8, 0x63, 0x7F, 0xE2, 0x3F, 0x94, 0x1E, 0xFC, 0x94, 0x00, 0x00, 0x00, 0xC8, 0x83, + 0xD9, 0xF7, 0x19, 0xE2, 0xC3, 0xED, 0x99, 0x60, 0xFB, 0xAF, 0x32, 0xDE, 0xF0, 0x40, 0xA2, 0x6F, + 0xBD, 0xB1, 0xA1, 0xB2, 0xCE, 0xBF, 0xFD, 0x70, 0x7F, 0xCF, 0x54, 0x64, 0x34, 0x9A, 0x0C, 0x89, + 0x2C, 0x13, 0xC1, 0x11, 0x9F, 0xFB, 0x7B, 0xEB, 0xDF, 0x82, 0x2C, 0xCF, 0xF5, 0x13, 0xDF, 0xBB, + 0x59, 0x2E, 0xF1, 0xE1, 0xF6, 0xC2, 0xD5, 0xEE, 0xDB, 0xB0, 0x4E, 0x06, 0x3F, 0x2D, 0x00, 0x00, + 0x00, 0xDA, 0x65, 0x0E, 0xDF, 0xB8, 0xC4, 0x0C, 0x2D, 0x9C, 0xBE, 0xF1, 0x11, 0x46, 0x47, 0xF0, + 0x7F, 0x7B, 0x6E, 0xDB, 0x3F, 0xEE, 0xBE, 0x0D, 0x2B, 0xD1, 0x2D, 0x88, 0x37, 0xBC, 0xE2, 0x64, + 0xEA, 0xDB, 0x0F, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, 0xD1, 0xDC, 0x2D, 0xC8, 0xF0, 0xB2, 0x69, + 0x71, 0x90, 0xCE, 0x2D, 0x3E, 0xC2, 0x1D, 0xBB, 0xC5, 0x04, 0x3F, 0x35, 0x00, 0x00, 0x00, 0xDA, + 0x65, 0x0E, 0xAD, 0x5A, 0x5B, 0xF3, 0x06, 0x2C, 0x19, 0x17, 0xAD, 0xA6, 0x82, 0x22, 0xCD, 0x44, + 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0xAB, 0x8F, 0x0F, 0x3F, 0x3C, 0xC2, 0x6D, 0xB2, 0xDB, 0x7B, + 0x85, 0x39, 0x3F, 0x3C, 0xD0, 0xF4, 0xC0, 0x9E, 0xE9, 0xF6, 0x43, 0x86, 0x44, 0x96, 0x89, 0xC8, + 0x68, 0x36, 0xF7, 0xF7, 0x79, 0x1A, 0xDC, 0x82, 0xE4, 0x1E, 0x1F, 0xCF, 0x7F, 0xC6, 0x98, 0x23, + 0x37, 0x18, 0xF3, 0xF2, 0x9D, 0x7C, 0x9E, 0x0A, 0x00, 0x00, 0x40, 0x1E, 0xFC, 0x37, 0x60, 0x6D, + 0xFB, 0xC8, 0xF4, 0x8D, 0x8F, 0x68, 0x78, 0xB8, 0xB9, 0xF8, 0x70, 0xDB, 0xFC, 0x21, 0xF7, 0x6D, + 0x58, 0xEE, 0x16, 0xA4, 0xE1, 0x81, 0xDD, 0xBF, 0xFD, 0xD8, 0xB3, 0xD0, 0xFE, 0x7C, 0x22, 0x34, + 0xD4, 0x64, 0x48, 0x64, 0x99, 0x08, 0x8C, 0x24, 0x1B, 0x9A, 0x5F, 0xEA, 0x5B, 0x90, 0x42, 0xE2, + 0xC3, 0x6D, 0xEC, 0x3A, 0x17, 0x20, 0xD3, 0xE6, 0xDB, 0xD7, 0x00, 0x00, 0x00, 0x0A, 0xE5, 0x1D, + 0x5A, 0x3D, 0x38, 0xED, 0xE2, 0x23, 0x12, 0x20, 0xD5, 0xE8, 0x88, 0xC4, 0xC7, 0xF9, 0x70, 0x43, + 0x97, 0x9B, 0x73, 0x07, 0xF5, 0x2D, 0xC8, 0xF9, 0x91, 0xFE, 0xF5, 0x66, 0x78, 0x99, 0xFD, 0xB9, + 0xDC, 0xAF, 0x49, 0xC4, 0x46, 0x7C, 0x32, 0x24, 0xB2, 0x4C, 0x84, 0x45, 0xD2, 0xB9, 0xDF, 0xF7, + 0xF0, 0xF5, 0xEE, 0x16, 0xA4, 0xAD, 0x4F, 0x7C, 0xEF, 0x46, 0x85, 0xC5, 0x87, 0xDB, 0x0B, 0x57, + 0x19, 0x73, 0xE2, 0xCE, 0xD2, 0xFD, 0x3D, 0x03, 0x00, 0x00, 0xE8, 0x08, 0x6F, 0xDF, 0x55, 0xA3, + 0x3A, 0x2E, 0x5A, 0x4D, 0x05, 0x45, 0x9A, 0xC5, 0xC2, 0x22, 0xC9, 0x64, 0x54, 0x24, 0x5D, 0x24, + 0x3E, 0x82, 0xD5, 0xDC, 0x78, 0x84, 0xD1, 0xF1, 0x74, 0x64, 0x9B, 0x3F, 0x64, 0xCE, 0x1F, 0x5C, + 0x6E, 0xCE, 0x0D, 0xF7, 0xDF, 0x15, 0xFC, 0xED, 0xF2, 0x99, 0xA1, 0xFE, 0x59, 0xE7, 0x47, 0x56, + 0x8C, 0x9B, 0xDD, 0x7D, 0xF6, 0x60, 0x2F, 0x62, 0x23, 0x3E, 0x19, 0x12, 0x59, 0x26, 0xA2, 0x22, + 0xED, 0x76, 0xCF, 0x35, 0xDE, 0xC8, 0xB2, 0x71, 0xF7, 0x7B, 0x08, 0x7E, 0x3B, 0x3D, 0xAF, 0xD0, + 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x9F, 0x07, 0x02, 0x00, 0x00, 0x90, 0x07, 0xB3, 0xEF, 0x0A, + 0x7B, 0xB8, 0x57, 0x81, 0xD1, 0x6C, 0x2A, 0x28, 0xD2, 0x4C, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, 0x48, + 0xBA, 0x48, 0x78, 0x44, 0x6F, 0x3E, 0xE2, 0xB7, 0x1E, 0x7E, 0x78, 0xBC, 0xCF, 0x9C, 0x7B, 0x6A, + 0x72, 0xE7, 0x77, 0xCE, 0x77, 0xB7, 0x20, 0x35, 0x07, 0xF6, 0xF3, 0x07, 0xFB, 0xD7, 0x7B, 0xC3, + 0xCB, 0x8C, 0xE7, 0x6E, 0x3F, 0x5A, 0x05, 0x88, 0x0C, 0x89, 0x2C, 0x13, 0x31, 0x91, 0x76, 0x9B, + 0x66, 0xD8, 0x1F, 0xED, 0xAF, 0xA9, 0x44, 0xB7, 0x20, 0x53, 0x11, 0x1F, 0x6E, 0xDE, 0xD1, 0x5B, + 0xA6, 0xDD, 0x6B, 0x8C, 0x01, 0x00, 0x00, 0x72, 0x67, 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x8B, 0xED, + 0x01, 0x5F, 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x58, 0x24, 0x99, 0x8C, 0x8A, 0xA4, + 0x8B, 0xC4, 0x47, 0x83, 0x00, 0x09, 0xE3, 0xE3, 0x5C, 0x24, 0x3E, 0xCE, 0x6E, 0x0C, 0xF6, 0xD4, + 0xFB, 0xCD, 0xF9, 0x03, 0xCB, 0x8D, 0x8B, 0x0E, 0xFF, 0xEF, 0x99, 0x0D, 0x91, 0x73, 0xC3, 0x2B, + 0xC6, 0xBD, 0x5D, 0x7D, 0xF6, 0xBF, 0x7F, 0x91, 0x3F, 0xFF, 0x50, 0xAF, 0x42, 0x44, 0x86, 0x44, + 0x96, 0x89, 0x98, 0x48, 0x3B, 0x17, 0x1F, 0xE1, 0x4A, 0x72, 0x0B, 0x32, 0x55, 0xF1, 0xE1, 0xEF, + 0xE8, 0xE7, 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xBB, 0xCC, 0xC8, 0xEA, 0x01, 0xB3, 0xEB, 0x52, + 0x7B, 0xC8, 0x57, 0xA1, 0xA1, 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, + 0x4B, 0x1F, 0x1F, 0xD5, 0xF0, 0x78, 0xD2, 0x6D, 0x96, 0xBF, 0x73, 0x3B, 0xE6, 0x9B, 0xB3, 0x07, + 0x2A, 0xB7, 0x20, 0x2E, 0x44, 0xCE, 0x1F, 0x5C, 0x66, 0xFF, 0xFB, 0x7F, 0xDC, 0x3C, 0x40, 0x64, + 0x48, 0x64, 0x99, 0x88, 0x89, 0xB4, 0x8B, 0xC6, 0x87, 0x9B, 0xFB, 0xB5, 0x1E, 0xBC, 0xB6, 0xA7, + 0x6F, 0x41, 0xA6, 0x34, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0xEC, 0x5F, 0x33, 0xF8, 0xCB, 0x03, 0x00, + 0x00, 0x20, 0x0B, 0xEF, 0xD0, 0xAA, 0xBB, 0xCC, 0xF6, 0x4F, 0xD8, 0x83, 0xBE, 0x8A, 0x8D, 0xF8, + 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, 0x74, 0xB1, 0xF8, 0x08, 0x02, 0x24, + 0x49, 0x7C, 0xBC, 0x6B, 0xE3, 0xE3, 0xDD, 0xC1, 0x59, 0x93, 0xDB, 0xF8, 0x7E, 0x73, 0x6E, 0xEF, + 0xF5, 0xE6, 0xDC, 0x81, 0x81, 0x51, 0xF7, 0xED, 0x58, 0xE7, 0xB7, 0x5F, 0x62, 0xFF, 0xBB, 0x36, + 0x3E, 0xDC, 0x54, 0x84, 0xC8, 0x90, 0xC8, 0x32, 0x11, 0x13, 0x69, 0x17, 0x8F, 0x8F, 0x70, 0x3B, + 0x3E, 0xE9, 0x02, 0xC4, 0xBD, 0xE5, 0x6B, 0x76, 0xF0, 0x8F, 0x43, 0xCF, 0x98, 0xF2, 0xF8, 0x70, + 0x1B, 0x5B, 0x66, 0xCC, 0x89, 0xAF, 0xAC, 0x0D, 0x7E, 0x09, 0x00, 0x00, 0x00, 0xC8, 0xC2, 0x3B, + 0xBC, 0x7A, 0x83, 0x8E, 0x8D, 0xF8, 0x54, 0x50, 0xA4, 0x99, 0x88, 0x8B, 0x56, 0x93, 0x51, 0x91, + 0x74, 0x3A, 0x3E, 0xEA, 0x02, 0xC4, 0x86, 0x47, 0xF8, 0xCC, 0x47, 0x3C, 0x3E, 0x26, 0xDC, 0x9E, + 0xA8, 0xCC, 0xFD, 0xFF, 0x67, 0xB7, 0x7C, 0xDA, 0x4C, 0x3C, 0xD3, 0x6F, 0xCE, 0x0D, 0xD9, 0x10, + 0x79, 0xCA, 0xFD, 0x77, 0x2F, 0xD2, 0x11, 0xB2, 0x49, 0x85, 0x44, 0x96, 0x89, 0x98, 0x48, 0x3B, + 0x15, 0x1E, 0xD1, 0x1D, 0xBC, 0xD6, 0xBD, 0x96, 0x77, 0x30, 0xF8, 0xC7, 0xA1, 0x27, 0x74, 0x24, + 0x3E, 0xDC, 0x5E, 0xBC, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0xB4, 0xCB, 0x3B, 0x78, 0x4D, 0x82, + 0x37, 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0xE1, 0x11, + 0x2E, 0x1E, 0x1F, 0xE1, 0xED, 0x47, 0xE4, 0x99, 0x0F, 0x17, 0x1F, 0xD1, 0xF0, 0x98, 0x78, 0x3C, + 0x98, 0xFB, 0xBF, 0x1F, 0x9B, 0x65, 0x4E, 0x3F, 0x72, 0x9D, 0x39, 0xF3, 0xF0, 0x25, 0x7E, 0x80, + 0x9C, 0xF3, 0x1F, 0x58, 0x8F, 0x05, 0x88, 0x8B, 0x8F, 0x5C, 0x02, 0x44, 0xC4, 0x44, 0xDA, 0xA9, + 0xE0, 0x88, 0xAF, 0xC7, 0x6E, 0x41, 0x3A, 0x16, 0x1F, 0xC1, 0xBC, 0x5F, 0xDC, 0x39, 0x14, 0xFC, + 0x52, 0x00, 0x00, 0x00, 0x90, 0x85, 0xB7, 0xFF, 0xEA, 0x93, 0x3A, 0x3A, 0xC2, 0xA9, 0xA0, 0x48, + 0x33, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x78, 0xB8, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, + 0xDE, 0x7E, 0xD4, 0x7E, 0xEB, 0x55, 0x34, 0x3E, 0xCE, 0xD8, 0xE8, 0x38, 0xF3, 0xF8, 0xFB, 0x82, + 0x55, 0x22, 0xE4, 0xF4, 0xFD, 0x17, 0x99, 0x53, 0xF7, 0x5E, 0x6C, 0x4E, 0xDD, 0x7D, 0x91, 0x39, + 0x6B, 0xFF, 0x33, 0x75, 0xB7, 0x20, 0x36, 0x3C, 0xDC, 0xDA, 0x0F, 0x10, 0x11, 0x13, 0x69, 0xA7, + 0x62, 0xA3, 0xD1, 0x7A, 0xE4, 0x16, 0xA4, 0xD3, 0xF1, 0xE1, 0xE6, 0x1D, 0xFB, 0x53, 0xDE, 0x84, + 0x05, 0x00, 0x00, 0xD0, 0x8E, 0xE6, 0x6F, 0xC0, 0x52, 0x41, 0x91, 0x66, 0x22, 0x2E, 0x5A, 0x4D, + 0x46, 0x45, 0xD2, 0xC5, 0xA2, 0x23, 0xBA, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDC, 0x7E, 0xD4, 0x7C, + 0xDB, 0x55, 0x18, 0x1F, 0x8F, 0xD9, 0xF0, 0xB0, 0x3B, 0x1D, 0xFC, 0x78, 0xE6, 0x91, 0xF7, 0xF9, + 0xE1, 0x11, 0xEE, 0xF4, 0x7D, 0x36, 0x42, 0x36, 0x4E, 0x46, 0x88, 0xF7, 0x74, 0x25, 0x3E, 0xAA, + 0x01, 0x92, 0x39, 0x42, 0x44, 0x4C, 0xA4, 0x9D, 0x8A, 0x8C, 0x66, 0xDB, 0x7E, 0x71, 0xD7, 0xDF, + 0x82, 0x74, 0x43, 0x7C, 0xF8, 0x3B, 0x76, 0x0B, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xC8, 0xCA, 0x7F, + 0x03, 0xD6, 0xEE, 0x79, 0xF6, 0xE0, 0x5F, 0xFE, 0xF8, 0x70, 0x3F, 0x36, 0xBF, 0xFD, 0xB0, 0xF1, + 0xE1, 0x02, 0x24, 0x88, 0x0F, 0x17, 0x1E, 0xA7, 0x1F, 0x9D, 0xDC, 0xA9, 0x7B, 0x67, 0xD5, 0x04, + 0x88, 0xDB, 0xBB, 0x3F, 0x0E, 0x02, 0xE4, 0xA9, 0x0B, 0xED, 0xCF, 0x67, 0xE3, 0x23, 0x1E, 0x21, + 0x32, 0x30, 0x9A, 0x4D, 0xC4, 0x44, 0xDA, 0xA9, 0xC0, 0x48, 0xB2, 0x7D, 0x57, 0x18, 0x6F, 0x78, + 0x79, 0x57, 0x7E, 0xD0, 0x5E, 0xD7, 0xC4, 0x87, 0x9B, 0x7B, 0x13, 0xD6, 0xCB, 0x77, 0xF6, 0xDC, + 0x43, 0xFB, 0x00, 0x00, 0x00, 0x5D, 0xC1, 0x1C, 0x5A, 0xB5, 0xD6, 0xEC, 0x9C, 0x6D, 0x0F, 0xFF, + 0x25, 0x8E, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x88, 0xDD, 0x7E, 0xB8, 0xD7, 0xEC, 0x46, 0x6F, + 0x3F, 0xE2, 0xF1, 0x71, 0xFA, 0x81, 0xDA, 0xDB, 0x8F, 0x70, 0xEE, 0x16, 0xE4, 0xDC, 0x93, 0x76, + 0x1B, 0x2F, 0xF2, 0x23, 0xA4, 0x26, 0x40, 0x5C, 0x50, 0xA4, 0x8A, 0x10, 0x11, 0x13, 0x69, 0xA7, + 0xC2, 0x22, 0xE9, 0xB6, 0x7D, 0x24, 0xB8, 0x05, 0x59, 0x3A, 0x10, 0xFC, 0xE3, 0xD1, 0x15, 0xBA, + 0x2A, 0x3E, 0xDC, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0xB3, 0xAB, 0xFE, 0x1E, 0x01, 0x00, 0x00, 0xF4, + 0x0C, 0x73, 0x78, 0xF5, 0x7A, 0xB3, 0xF5, 0xC3, 0x36, 0x00, 0x4A, 0x1C, 0x1F, 0xC1, 0xD4, 0xED, + 0xC7, 0x59, 0x3F, 0x40, 0x6C, 0x7C, 0xB8, 0xDB, 0x8F, 0xC8, 0xB7, 0x5E, 0x55, 0xC3, 0xE3, 0xC7, + 0x95, 0xA9, 0xDB, 0x0F, 0x7F, 0x5F, 0xBF, 0xD0, 0xBC, 0xFB, 0x48, 0x25, 0x40, 0xCE, 0xB5, 0x75, + 0x0B, 0x22, 0x62, 0x22, 0xED, 0x54, 0x54, 0xA4, 0x9D, 0xBB, 0x05, 0x39, 0xB8, 0xAC, 0x6B, 0x6E, + 0x41, 0xBA, 0x2E, 0x3E, 0xDC, 0x78, 0x13, 0x16, 0x00, 0x00, 0x40, 0x76, 0xDE, 0xC8, 0x8A, 0xA1, + 0xD2, 0xC7, 0x47, 0xC3, 0xDB, 0x8F, 0x59, 0xD5, 0xF8, 0xA8, 0xDE, 0x7E, 0x84, 0xF1, 0x11, 0x84, + 0x87, 0x1F, 0x1F, 0x3F, 0xD2, 0xB7, 0x1F, 0x2E, 0x3E, 0xDC, 0x4E, 0x7F, 0xEB, 0x42, 0x73, 0xB6, + 0xAD, 0x5B, 0x10, 0x11, 0x13, 0x69, 0xA7, 0x62, 0x22, 0xCB, 0xB6, 0xD9, 0x18, 0x1D, 0x5E, 0xD6, + 0x15, 0xB7, 0x20, 0x5D, 0x19, 0x1F, 0xC1, 0xBC, 0x13, 0x5F, 0xEE, 0xA9, 0xD7, 0x16, 0x03, 0x00, + 0x00, 0x74, 0x0D, 0x6F, 0xDF, 0x55, 0x63, 0x65, 0xBF, 0xF9, 0x70, 0xAB, 0xBF, 0xFD, 0x88, 0x04, + 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x70, 0x44, 0x02, 0xE4, 0x94, 0x7B, 0xE8, 0xDC, 0xED, 0xDB, 0xE2, + 0xF6, 0x23, 0x88, 0x8F, 0x70, 0x13, 0x0F, 0x64, 0xBD, 0x05, 0x11, 0x31, 0x91, 0x76, 0x2A, 0x24, + 0x32, 0xED, 0x82, 0xCA, 0xF6, 0x5C, 0xD6, 0xF1, 0x5B, 0x90, 0x6E, 0x8E, 0x0F, 0x37, 0xEF, 0xF8, + 0x9F, 0x75, 0xE5, 0xB3, 0x32, 0x00, 0x00, 0x00, 0x5D, 0xCF, 0xEC, 0xBD, 0xDC, 0x86, 0x40, 0x89, + 0xE3, 0x23, 0xC1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xC1, 0xB7, 0x5E, 0x9D, 0x0A, 0x03, 0xE4, 0x07, + 0xAD, 0xE3, 0xC3, 0xED, 0xF4, 0x3D, 0x2D, 0x6E, 0x41, 0xE4, 0x44, 0x4C, 0xA4, 0x9D, 0x0C, 0x89, + 0x2C, 0x0B, 0xE2, 0xC3, 0xCD, 0xFD, 0xFD, 0xF5, 0x6F, 0x41, 0x96, 0xAF, 0x0B, 0xFE, 0x31, 0x99, + 0x52, 0xDD, 0x1E, 0x1F, 0xFE, 0x8E, 0xFF, 0x29, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x48, 0xCB, 0xBD, + 0x72, 0xD5, 0xEC, 0x59, 0x64, 0x63, 0x40, 0x05, 0x45, 0x9A, 0x89, 0xB8, 0x68, 0xB5, 0xBA, 0xA0, + 0x48, 0x33, 0x11, 0x1A, 0x8D, 0x16, 0x0F, 0x90, 0xE0, 0xF6, 0xE3, 0x6C, 0x92, 0xDB, 0x8F, 0x87, + 0xED, 0xEE, 0x69, 0x1D, 0x1F, 0xE1, 0xC2, 0x5B, 0x90, 0x64, 0x6F, 0xC4, 0x12, 0x31, 0x91, 0x76, + 0x32, 0x24, 0xB2, 0x2C, 0x12, 0x1F, 0xE1, 0x86, 0x16, 0x1A, 0xEF, 0xE0, 0xD2, 0x93, 0xC1, 0x3F, + 0x2A, 0x53, 0xA6, 0x27, 0xE2, 0xC3, 0xED, 0xC8, 0x6A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0x90, 0x96, + 0xFF, 0x0A, 0xDE, 0x9D, 0x9F, 0xB2, 0x41, 0xA0, 0xA2, 0x22, 0xE9, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, + 0x8A, 0xA4, 0x13, 0x91, 0xA1, 0x66, 0x83, 0xA3, 0x1A, 0x1F, 0x36, 0x3C, 0x12, 0xDF, 0x7E, 0x44, + 0xBF, 0xF5, 0xEA, 0xFB, 0xB1, 0xDB, 0x0F, 0x11, 0x1D, 0xD1, 0x25, 0xBF, 0x05, 0x11, 0x31, 0x91, + 0x76, 0x32, 0x24, 0xB2, 0x4C, 0xC4, 0x87, 0x9B, 0xFB, 0x7B, 0x3D, 0xC5, 0xB7, 0x20, 0x3D, 0x13, + 0x1F, 0x3F, 0xBF, 0xDC, 0x98, 0xB1, 0x15, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x20, 0x2D, 0x73, 0x78, + 0xE5, 0x7A, 0xB3, 0xED, 0xA3, 0x36, 0x0A, 0x54, 0x58, 0x24, 0x99, 0x88, 0x8B, 0x56, 0xAB, 0x0B, + 0x8A, 0x34, 0x8B, 0x45, 0x46, 0xB3, 0x45, 0x03, 0xC4, 0xAE, 0x12, 0x1F, 0x36, 0x0E, 0xC2, 0x00, + 0x69, 0xF4, 0xDA, 0xDD, 0x46, 0xB7, 0x1F, 0x22, 0x38, 0xD4, 0x26, 0x7E, 0x50, 0x09, 0x90, 0x9A, + 0x67, 0x41, 0x82, 0x10, 0xA9, 0xDC, 0x82, 0x88, 0x98, 0x48, 0x3B, 0x19, 0x12, 0x59, 0x26, 0xC2, + 0x23, 0xBA, 0x29, 0xBC, 0x05, 0xE9, 0xA9, 0xF8, 0x70, 0x7B, 0xF1, 0x3A, 0x63, 0x7F, 0xBD, 0x77, + 0x05, 0xBF, 0x7C, 0x00, 0x00, 0x00, 0x24, 0xE1, 0x1D, 0x5E, 0xB9, 0x41, 0x87, 0x45, 0x92, 0x89, + 0xB8, 0x68, 0x35, 0x19, 0x15, 0x49, 0x17, 0x0B, 0x8C, 0x66, 0x8B, 0xC5, 0x47, 0xE5, 0xF6, 0x23, + 0x12, 0x1F, 0xCD, 0x6E, 0x3F, 0xC2, 0x00, 0x89, 0xDE, 0x7E, 0x88, 0xD0, 0x68, 0xB8, 0x6F, 0x5C, + 0x68, 0xCE, 0x3E, 0xD1, 0xE0, 0x16, 0x64, 0x93, 0x88, 0x89, 0xB4, 0x93, 0x21, 0x91, 0x65, 0x22, + 0x38, 0xE2, 0x73, 0x7F, 0xDF, 0x0F, 0x5E, 0x57, 0xF8, 0x2D, 0x48, 0xCF, 0xC5, 0x47, 0x30, 0xEF, + 0xC4, 0x9D, 0x1B, 0x82, 0xDF, 0x02, 0x00, 0x00, 0x00, 0x92, 0xF0, 0x0E, 0x5E, 0x3D, 0xAA, 0xE3, + 0xA2, 0xD5, 0x44, 0x5C, 0xB4, 0x5A, 0x5D, 0x50, 0xA4, 0x59, 0x2C, 0x30, 0x9A, 0xAD, 0x41, 0x7C, + 0xF8, 0xB7, 0x1F, 0x2E, 0x3E, 0xD4, 0xED, 0x47, 0x10, 0x1F, 0xD5, 0xDB, 0x8F, 0x87, 0xEC, 0xBE, + 0x91, 0x21, 0x3E, 0x82, 0x85, 0xB7, 0x20, 0xE7, 0x9F, 0x72, 0x7F, 0xDD, 0x20, 0x42, 0x9E, 0x9E, + 0x69, 0x7F, 0x2D, 0x2E, 0x20, 0x82, 0xA9, 0xB8, 0x68, 0x35, 0x19, 0x12, 0x59, 0x26, 0x62, 0xA3, + 0xD1, 0x76, 0xCD, 0x31, 0xDE, 0xF0, 0xD2, 0x71, 0x33, 0xD4, 0x3F, 0x2B, 0xF8, 0xC7, 0x26, 0x57, + 0xBD, 0x1A, 0x1F, 0x7E, 0x80, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x74, 0xBC, 0xFD, 0x9F, 0x1D, + 0xD7, 0x81, 0xD1, 0x6C, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xC5, 0x02, 0xA3, 0xD5, 0xEA, + 0x02, 0x24, 0x88, 0x8F, 0xF8, 0xED, 0x47, 0x10, 0x1F, 0xF2, 0xD9, 0x8F, 0xFB, 0x83, 0xDB, 0x0F, + 0x11, 0x17, 0x89, 0x16, 0xBB, 0x05, 0x39, 0x1F, 0xC4, 0x47, 0x5B, 0x01, 0x22, 0x43, 0x22, 0xCB, + 0x44, 0x64, 0x34, 0x9B, 0x7B, 0x66, 0xC5, 0xDD, 0x82, 0x1C, 0x5C, 0x9A, 0xFB, 0x07, 0xEF, 0xF5, + 0x72, 0x7C, 0xB8, 0x79, 0xC7, 0xFE, 0x64, 0x3C, 0xF8, 0xAD, 0x00, 0x00, 0x00, 0xA0, 0x15, 0x33, + 0xDA, 0x3F, 0x2B, 0xFD, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x8B, 0xC5, 0x45, + 0x92, 0xC5, 0xE3, 0x23, 0x7A, 0xFB, 0x11, 0xC4, 0x47, 0xCD, 0x9B, 0xAF, 0x1A, 0xDD, 0x7E, 0xA8, + 0xB0, 0x48, 0xB1, 0x33, 0xDF, 0xBB, 0x70, 0xF2, 0x59, 0x90, 0xA7, 0x6C, 0x7C, 0xB4, 0x13, 0x21, + 0x32, 0x24, 0xB2, 0x4C, 0x04, 0x46, 0x92, 0x15, 0x70, 0x0B, 0xD2, 0xEB, 0xF1, 0xE1, 0xEF, 0xC8, + 0x4D, 0xC6, 0x8C, 0xFD, 0x87, 0x42, 0x6E, 0x86, 0x00, 0x00, 0x00, 0x4A, 0xC7, 0x7F, 0x03, 0xD6, + 0xAE, 0x4F, 0xDB, 0x48, 0x50, 0xA1, 0xA1, 0x26, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, + 0x8B, 0x56, 0xB3, 0xD1, 0x31, 0x19, 0x20, 0x17, 0x55, 0x02, 0x24, 0xB8, 0xFD, 0xA8, 0xBE, 0x76, + 0xB7, 0x7A, 0xFB, 0xF1, 0xBE, 0xC6, 0xB7, 0x1F, 0x22, 0x28, 0xB2, 0xEC, 0xEC, 0x63, 0x2E, 0x42, + 0x2A, 0x01, 0xE2, 0xDF, 0x82, 0x64, 0x89, 0x10, 0x19, 0x12, 0x59, 0x26, 0xC2, 0x22, 0xE9, 0x72, + 0xBE, 0x05, 0x29, 0x45, 0x7C, 0xB8, 0xBD, 0x34, 0xC0, 0x9B, 0xB0, 0x00, 0x00, 0x00, 0x92, 0x32, + 0x87, 0x57, 0xAD, 0x4B, 0xFE, 0x0A, 0x5E, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x61, + 0x91, 0x74, 0xF1, 0xF8, 0xC8, 0x74, 0xFB, 0xA1, 0x63, 0x22, 0xFD, 0x66, 0x9A, 0x33, 0xF7, 0xCF, + 0x34, 0x67, 0x9F, 0x9C, 0x8C, 0x90, 0xD4, 0x01, 0x22, 0x43, 0x22, 0xCB, 0x44, 0x54, 0xA4, 0xDD, + 0xCE, 0xD9, 0xC6, 0x1B, 0xBE, 0xBE, 0xED, 0x5B, 0x90, 0xD2, 0xC4, 0x87, 0x1B, 0x6F, 0xC2, 0x02, + 0x00, 0x00, 0x48, 0xCE, 0xB8, 0x57, 0xF0, 0xCA, 0xD8, 0x88, 0x4F, 0xC4, 0x45, 0xAB, 0xC9, 0xA8, + 0x48, 0x3A, 0x11, 0x16, 0x49, 0xE6, 0x6E, 0x3F, 0xEC, 0x8F, 0x7E, 0x7C, 0xC4, 0x6E, 0x3F, 0xEA, + 0x9F, 0xFD, 0x68, 0x70, 0xFB, 0x71, 0x5F, 0xFB, 0xDF, 0x7A, 0x55, 0xD9, 0xCC, 0xEA, 0xDE, 0x0D, + 0x6E, 0x41, 0xCE, 0x35, 0xBA, 0x05, 0x51, 0xE1, 0xE1, 0x26, 0x43, 0x22, 0xCB, 0x44, 0x4C, 0x64, + 0xDA, 0x7B, 0x8D, 0x39, 0x70, 0xB5, 0x7B, 0x2D, 0xEF, 0x60, 0xF0, 0x8F, 0x50, 0x6A, 0xA5, 0x8A, + 0x0F, 0xB7, 0xE7, 0xAF, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x49, 0x79, 0x07, 0xAF, 0x4B, 0xF0, + 0x06, 0x2C, 0x11, 0x17, 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x62, 0x51, 0x91, 0x66, 0xE1, 0xCD, 0x47, + 0x83, 0xDB, 0x8F, 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0x78, 0x30, 0xAF, 0x6F, 0xBD, 0x9A, 0x8C, 0x0F, + 0xB7, 0x4C, 0xB7, 0x20, 0x32, 0x24, 0xB2, 0x4C, 0x85, 0x44, 0x96, 0xD9, 0xF8, 0x70, 0xDB, 0xFE, + 0x71, 0xF7, 0x6D, 0x58, 0xC6, 0x8C, 0x5C, 0x9B, 0xFA, 0x13, 0xC0, 0x4B, 0x17, 0x1F, 0xC1, 0xBC, + 0x13, 0x77, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x80, 0x24, 0xBC, 0x7D, 0x57, 0x8E, 0xE9, 0xE8, 0x08, + 0x27, 0xE2, 0xA2, 0xD5, 0x64, 0x54, 0x24, 0x9D, 0x88, 0x8A, 0xA4, 0xF3, 0x6F, 0x3F, 0x82, 0xF8, + 0x88, 0xDD, 0x7E, 0xA8, 0x67, 0x3F, 0xEA, 0x3F, 0x74, 0xD0, 0xC6, 0x47, 0x2E, 0xB7, 0x1F, 0xB5, + 0xF1, 0x11, 0xEE, 0xDD, 0x47, 0x5A, 0x3C, 0x0B, 0xD2, 0x0B, 0xF1, 0xF1, 0x74, 0xB0, 0xFD, 0xE9, + 0x6F, 0x41, 0xCA, 0x1A, 0x1F, 0x6E, 0xDE, 0xB1, 0x5B, 0xA6, 0xE4, 0x83, 0x1A, 0x01, 0x00, 0x00, + 0x7A, 0x9E, 0xD9, 0x7B, 0x99, 0x8D, 0x06, 0x15, 0x1E, 0x6E, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, + 0xD2, 0xC5, 0x82, 0x22, 0xED, 0xC2, 0xF0, 0x68, 0x70, 0xFB, 0x51, 0xF7, 0xEC, 0x47, 0x10, 0x20, + 0x95, 0xDB, 0x0F, 0x1B, 0x1F, 0xB9, 0xDC, 0x7E, 0xE8, 0xF8, 0x70, 0x3B, 0x7D, 0xEF, 0x4C, 0x73, + 0xAE, 0xD1, 0x2D, 0x88, 0x1F, 0x1D, 0x3D, 0x12, 0x1F, 0xF6, 0xFF, 0xF6, 0xB6, 0x7F, 0xDC, 0x05, + 0x48, 0xE2, 0x5B, 0x90, 0x32, 0xC7, 0x87, 0xBF, 0x23, 0x37, 0x99, 0xE0, 0xB7, 0x0A, 0x00, 0x00, + 0x80, 0x46, 0xCC, 0xE1, 0xFE, 0x25, 0x66, 0x68, 0xBE, 0x0D, 0x87, 0x72, 0xC4, 0x47, 0xCB, 0xDB, + 0x0F, 0x11, 0x1F, 0x95, 0xDB, 0x0F, 0x1B, 0x1E, 0xB9, 0xDC, 0x7E, 0xE8, 0xF0, 0x88, 0x2E, 0xBC, + 0x05, 0x69, 0xF8, 0x2C, 0x88, 0x0C, 0x89, 0x2C, 0x53, 0x21, 0x91, 0x65, 0x22, 0x3E, 0xEC, 0x8F, + 0xFE, 0xF6, 0x7C, 0xC6, 0x9C, 0x3F, 0x70, 0xFD, 0x50, 0xF0, 0x8F, 0x53, 0x43, 0xA5, 0x8F, 0x0F, + 0x37, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x9A, 0xFF, 0x0A, 0x5E, 0xF9, 0x06, 0x2C, 0x11, 0x17, + 0xAD, 0x26, 0xA3, 0x22, 0xE9, 0x44, 0x50, 0xA4, 0x9A, 0x8D, 0x8F, 0x30, 0x3C, 0xC2, 0xF8, 0x48, + 0x7A, 0xFB, 0xF1, 0x63, 0x1B, 0x1E, 0x2E, 0x40, 0x7E, 0xD8, 0xEE, 0xED, 0x87, 0x0E, 0x8E, 0xF8, + 0xDC, 0x2D, 0x48, 0xE3, 0x67, 0x41, 0x54, 0x48, 0x64, 0x99, 0x0A, 0x89, 0x2C, 0x6B, 0x12, 0x1F, + 0x4F, 0xBD, 0xD7, 0x9C, 0xDF, 0xF2, 0x21, 0x73, 0x7E, 0xFF, 0x32, 0x73, 0x76, 0xFF, 0xD2, 0x86, + 0x07, 0xEF, 0x69, 0x11, 0x1F, 0x6E, 0x2F, 0x5E, 0xE7, 0x02, 0x64, 0x5D, 0xF0, 0xDB, 0x06, 0x00, + 0x00, 0x80, 0xE2, 0xBF, 0x01, 0x6B, 0xEB, 0x87, 0x6C, 0x40, 0xF4, 0x7E, 0x7C, 0x64, 0xB9, 0xFD, + 0xA8, 0xC6, 0x87, 0xBB, 0xFD, 0xF8, 0x56, 0x3B, 0xB7, 0x1F, 0x3A, 0x36, 0x1A, 0x6D, 0xE2, 0x21, + 0x75, 0x0B, 0x32, 0xC3, 0x9F, 0x0E, 0x8A, 0x34, 0x53, 0x21, 0x91, 0x65, 0x2D, 0xE2, 0xC3, 0x6D, + 0xE3, 0x05, 0xE6, 0xFC, 0xEE, 0x25, 0xE6, 0xDC, 0xDE, 0x65, 0xF2, 0x01, 0xEC, 0x69, 0x13, 0x1F, + 0x6E, 0xCF, 0x5F, 0x69, 0xCC, 0x89, 0x3B, 0x73, 0xFF, 0x94, 0x78, 0x00, 0x00, 0x80, 0x52, 0xF1, + 0x0E, 0xAD, 0x1C, 0xEC, 0xF9, 0xF8, 0xC8, 0x78, 0xFB, 0x71, 0xEA, 0x51, 0x1B, 0x1D, 0xB9, 0xDC, + 0x7E, 0xE8, 0xC8, 0x68, 0xB6, 0xD3, 0xF7, 0xC4, 0x6F, 0x41, 0x2A, 0xF1, 0xD1, 0x7E, 0x80, 0xA8, + 0x90, 0xC8, 0xB2, 0x64, 0xF1, 0x71, 0xEE, 0x49, 0xBB, 0x4D, 0x1F, 0x76, 0x01, 0x62, 0xCE, 0x0E, + 0xD5, 0xDE, 0x82, 0x4C, 0xAB, 0xF8, 0x08, 0xE6, 0x9D, 0xF8, 0x32, 0x6F, 0xC2, 0x02, 0x00, 0x00, + 0x68, 0xC6, 0xDB, 0x77, 0x45, 0xE4, 0x15, 0xBC, 0x22, 0x2E, 0x5A, 0x4D, 0x46, 0x45, 0xD2, 0xA9, + 0xA0, 0x48, 0xB3, 0x20, 0x3E, 0x82, 0xA5, 0xBB, 0xFD, 0x88, 0xC4, 0x47, 0x5B, 0xB7, 0x1F, 0x3A, + 0x30, 0x92, 0x6C, 0xE2, 0x81, 0xE8, 0x2D, 0x88, 0x8D, 0x8F, 0xB6, 0x23, 0x44, 0x85, 0x44, 0x96, + 0x25, 0x8F, 0x8F, 0xB3, 0x83, 0x76, 0x4F, 0x5C, 0x60, 0xDE, 0xDD, 0xB1, 0xC4, 0x4C, 0xEC, 0x5E, + 0x5E, 0x3D, 0x7C, 0x4F, 0xC7, 0xF8, 0x70, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x2D, 0x98, 0x7D, + 0xF6, 0x70, 0xD7, 0xEB, 0xF1, 0x91, 0xE6, 0xF6, 0x23, 0x8C, 0x8F, 0x5C, 0x6E, 0x3F, 0x74, 0x58, + 0x24, 0x5D, 0xE5, 0x16, 0x64, 0xA6, 0x8D, 0x10, 0x1B, 0x20, 0x4F, 0xB5, 0x1B, 0x20, 0x2A, 0x24, + 0xB2, 0x2C, 0x43, 0x7C, 0x3C, 0x7E, 0x81, 0x39, 0x33, 0xF8, 0x41, 0x17, 0x20, 0xE6, 0xF4, 0x8E, + 0xA5, 0x03, 0xD3, 0x35, 0x3E, 0xFC, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x00, 0x34, 0x62, + 0x46, 0xFB, 0x67, 0x99, 0x3D, 0x0B, 0x75, 0x5C, 0xB4, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, + 0x66, 0x91, 0xF8, 0x08, 0xA6, 0x6E, 0x3F, 0xAA, 0x01, 0x52, 0x73, 0xFB, 0x31, 0xAB, 0xFE, 0xF6, + 0xE3, 0x9B, 0x2A, 0x2E, 0x5A, 0x4D, 0x47, 0x45, 0x9A, 0xBD, 0xF3, 0xD7, 0x33, 0xCC, 0x99, 0x1F, + 0x4E, 0x06, 0x48, 0xF6, 0x5B, 0x10, 0x15, 0x12, 0x59, 0x96, 0x31, 0x3E, 0x1E, 0x9D, 0x61, 0x4E, + 0xFF, 0xD8, 0xEE, 0x99, 0x45, 0x66, 0xE2, 0xC0, 0xAA, 0x93, 0xD3, 0x36, 0x3E, 0xDC, 0x8E, 0xAC, + 0x32, 0xE6, 0xF8, 0x1D, 0x4B, 0x82, 0x2F, 0x31, 0x00, 0x00, 0x00, 0x44, 0x99, 0x91, 0xFE, 0x01, + 0xB3, 0xF3, 0x12, 0x1D, 0x18, 0xCD, 0x26, 0xA3, 0x22, 0xE9, 0x54, 0x50, 0xA4, 0x59, 0x2C, 0x3E, + 0x12, 0xDC, 0x7E, 0x4C, 0xB8, 0x00, 0x79, 0xDC, 0xDD, 0x7E, 0xC4, 0xE2, 0xC3, 0xED, 0x7B, 0x59, + 0xBE, 0xF5, 0x4A, 0x07, 0x45, 0x9A, 0xB9, 0xF8, 0xF0, 0x77, 0xF7, 0x0C, 0x7B, 0x90, 0x6F, 0xE7, + 0x16, 0x44, 0x85, 0x44, 0x96, 0xB5, 0x17, 0x1F, 0xA7, 0x1E, 0x76, 0x01, 0x32, 0xDB, 0x98, 0x63, + 0x77, 0x9A, 0x69, 0x1B, 0x1F, 0x3F, 0xBF, 0xCC, 0x98, 0x17, 0x3F, 0x67, 0xCC, 0x89, 0x2F, 0xAD, + 0x0D, 0xBE, 0xC4, 0x00, 0x00, 0x00, 0x10, 0xE5, 0x1D, 0x5A, 0x75, 0x97, 0xD9, 0x7E, 0xB1, 0x8E, + 0x8C, 0x46, 0x93, 0x51, 0x91, 0x74, 0x2A, 0x28, 0xD2, 0x2C, 0x16, 0x1F, 0x2A, 0x40, 0x1A, 0x3E, + 0xFB, 0x61, 0xE3, 0x23, 0x97, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0x56, 0x8D, 0x8F, 0x60, 0x67, 0xBE, + 0x5F, 0x09, 0x90, 0x73, 0xD1, 0x5B, 0x90, 0x20, 0x44, 0x74, 0x74, 0x84, 0x53, 0x21, 0x91, 0x65, + 0x39, 0xC4, 0xC7, 0xD3, 0x1F, 0x33, 0xDE, 0xD1, 0xDB, 0xA7, 0x77, 0x7C, 0xB8, 0x3D, 0xFF, 0x59, + 0xDE, 0x84, 0x05, 0x00, 0x00, 0xD0, 0x88, 0x19, 0x59, 0xB9, 0x5E, 0x46, 0x46, 0xA3, 0xC9, 0xA8, + 0x48, 0x3A, 0x15, 0x14, 0x69, 0x56, 0x1F, 0x1E, 0xD5, 0xF8, 0xB0, 0xE1, 0x31, 0x79, 0xFB, 0x11, + 0xF9, 0xD6, 0xAB, 0xEA, 0xED, 0xC7, 0x45, 0x95, 0xDB, 0x0F, 0xBB, 0xF6, 0x6E, 0x3F, 0x74, 0x50, + 0xA4, 0x59, 0x3C, 0x3E, 0xFC, 0x65, 0xBA, 0x05, 0x51, 0x21, 0x91, 0x65, 0xC4, 0x47, 0xFB, 0x0B, + 0xE2, 0x23, 0x98, 0xF7, 0x8B, 0x3B, 0x5B, 0x7E, 0x30, 0x23, 0x00, 0x00, 0xC0, 0xB4, 0xE4, 0x1D, + 0xB8, 0x7A, 0x54, 0x86, 0x86, 0x9A, 0x8C, 0x8A, 0xA4, 0x53, 0x41, 0x91, 0x66, 0xB1, 0xF8, 0x88, + 0x07, 0x88, 0x5D, 0xF5, 0x5B, 0xAF, 0xC2, 0x00, 0xA9, 0x3E, 0x78, 0x6E, 0xE3, 0xC3, 0x06, 0x48, + 0xFB, 0xB7, 0x1F, 0x3A, 0x28, 0xD2, 0x4C, 0xC6, 0x47, 0xB0, 0xF0, 0x16, 0xC4, 0xBD, 0x92, 0xB7, + 0xF5, 0x2D, 0x88, 0x0A, 0x89, 0x2C, 0x23, 0x3E, 0xDA, 0x5F, 0x6D, 0x7C, 0xF8, 0x01, 0x72, 0xF4, + 0xD6, 0xB1, 0xE0, 0x4B, 0x0C, 0x00, 0x00, 0x00, 0x51, 0xDE, 0xFE, 0x2B, 0x4F, 0xCA, 0xD8, 0x88, + 0x4F, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, 0xB3, 0x58, 0x78, 0x88, 0xF8, 0x08, 0x6F, 0x3F, 0x6A, + 0x1E, 0x3C, 0xF7, 0x6F, 0x3F, 0x2E, 0x9A, 0xBC, 0xFD, 0x08, 0xE3, 0x23, 0x0C, 0x90, 0xFB, 0xD3, + 0xDC, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x1D, 0x35, 0x73, 0xB7, 0x20, 0x8F, 0x4D, 0xDE, 0x82, + 0xF8, 0x11, 0x62, 0x63, 0xA3, 0x3E, 0x40, 0x54, 0x48, 0x64, 0x19, 0xF1, 0xD1, 0xFE, 0xEA, 0xE3, + 0xC3, 0xDF, 0xB1, 0x2F, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x00, 0x25, 0xD1, 0x1B, 0xB0, 0x64, 0x54, + 0x24, 0x9D, 0x0A, 0x8A, 0x34, 0x8B, 0x85, 0x47, 0x93, 0xF8, 0xA8, 0x3E, 0x78, 0x5E, 0xBD, 0xFD, + 0xB0, 0xF1, 0x11, 0xDE, 0x7E, 0xC4, 0xE3, 0xE3, 0x21, 0xBB, 0xBB, 0x55, 0x68, 0xA8, 0xE9, 0xA0, + 0x48, 0x33, 0x19, 0x1C, 0x62, 0xA7, 0xBF, 0x3B, 0x23, 0x78, 0x16, 0xA4, 0xC1, 0xB7, 0x62, 0x3D, + 0xAD, 0x42, 0x22, 0xCB, 0x88, 0x8F, 0xF6, 0x27, 0xC2, 0x23, 0x1C, 0x6F, 0xC2, 0x02, 0x00, 0x00, + 0xA8, 0xE7, 0xBF, 0x01, 0x6B, 0xD7, 0x1C, 0x1D, 0x1D, 0xE1, 0x64, 0x54, 0x24, 0x9D, 0x0A, 0x8A, + 0x34, 0x8B, 0x85, 0x47, 0x38, 0x15, 0x20, 0xF1, 0xD7, 0xEE, 0x3E, 0x39, 0x19, 0x1F, 0xF2, 0xCD, + 0x57, 0x89, 0x6F, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0A, 0x8D, 0x66, 0x7B, 0x37, 0x7E, 0x0B, 0x12, + 0x46, 0x88, 0x8B, 0x8F, 0x70, 0x32, 0x2A, 0x92, 0x8E, 0xF8, 0x68, 0x7F, 0x22, 0x3A, 0xA2, 0x7B, + 0xF1, 0x7A, 0x63, 0x5E, 0xBE, 0xB3, 0xE6, 0x53, 0xE1, 0x01, 0x00, 0x00, 0xA6, 0x3D, 0x73, 0xA8, + 0x7F, 0xAD, 0xD9, 0xF1, 0x49, 0x1D, 0x1E, 0x6E, 0x32, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, 0xC5, + 0xA2, 0x23, 0xBA, 0x78, 0x7C, 0x44, 0x6F, 0x3F, 0x82, 0xF8, 0x98, 0xBC, 0xFD, 0x10, 0xDF, 0x7A, + 0x95, 0xF8, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xA9, 0xC0, 0x68, 0x35, 0x77, 0x0B, 0x52, 0xF7, 0xE1, + 0x84, 0x36, 0x3A, 0xF2, 0x09, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xE0, 0x88, 0xEF, 0x85, 0xAB, 0x79, + 0x13, 0x16, 0x00, 0x00, 0x40, 0x9C, 0xFF, 0x06, 0xAC, 0xAD, 0x1F, 0xEC, 0xB9, 0xF8, 0x68, 0x74, + 0xFB, 0xE1, 0xE2, 0xE3, 0x6C, 0x2C, 0x3E, 0xB2, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x15, 0x17, + 0x49, 0xF7, 0xEE, 0x8F, 0x2B, 0x01, 0xE2, 0xBF, 0x96, 0xF7, 0x29, 0x1B, 0x1F, 0x6E, 0xD1, 0x08, + 0x91, 0x71, 0xD1, 0x6A, 0xC4, 0x47, 0xFB, 0x13, 0xB1, 0xD1, 0x60, 0xDE, 0x89, 0x2F, 0x0D, 0x06, + 0x5F, 0x6A, 0x00, 0x00, 0x00, 0x70, 0xBC, 0xE1, 0xE5, 0x43, 0x3D, 0x15, 0x1F, 0x6E, 0xF1, 0xF8, + 0x88, 0xDE, 0x7E, 0xB8, 0xF8, 0x68, 0x75, 0xFB, 0xF1, 0xA0, 0x9D, 0x0C, 0x8E, 0xE8, 0x74, 0x50, + 0xA4, 0x99, 0x8A, 0x8A, 0x34, 0x3B, 0xFD, 0xED, 0xE0, 0x16, 0xE4, 0x49, 0x1B, 0x20, 0x36, 0x0A, + 0xEA, 0x02, 0x24, 0x75, 0x84, 0x10, 0x1F, 0xED, 0x4F, 0x87, 0x46, 0xA3, 0x79, 0x47, 0x6F, 0x1D, + 0x0D, 0xBE, 0xD4, 0x00, 0x00, 0x00, 0xE0, 0x78, 0x7B, 0xAF, 0xA8, 0x7F, 0x05, 0xAF, 0x8C, 0x8A, + 0xA4, 0x53, 0x41, 0x91, 0x66, 0x22, 0x38, 0xA2, 0xB3, 0xD1, 0xE1, 0x7E, 0xAC, 0xBB, 0xFD, 0xB0, + 0xF1, 0x71, 0x6E, 0xE3, 0x45, 0xC9, 0x6E, 0x3F, 0xEE, 0x6B, 0x75, 0xFB, 0xA1, 0x83, 0x22, 0xCD, + 0x54, 0x50, 0x64, 0xD9, 0xBB, 0xF6, 0xD0, 0x1F, 0x06, 0x48, 0x7B, 0xB7, 0x20, 0xC4, 0x47, 0xFB, + 0xD3, 0x91, 0xD1, 0x74, 0xC7, 0x6E, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0x00, 0x51, 0x66, 0xEF, 0xE2, + 0xDE, 0x89, 0x0F, 0xB7, 0x30, 0x3C, 0xC2, 0xF8, 0x08, 0x03, 0x24, 0x88, 0x8F, 0x78, 0x80, 0xD4, + 0xC5, 0x47, 0xCB, 0xDB, 0x0F, 0x1D, 0x14, 0x69, 0xA6, 0x42, 0x22, 0xDB, 0x2E, 0x30, 0xA7, 0xBF, + 0x6D, 0xA3, 0x60, 0x70, 0x32, 0x42, 0x6A, 0x02, 0xC4, 0x85, 0x45, 0xA2, 0x08, 0x21, 0x3E, 0xDA, + 0x9F, 0x88, 0x8B, 0x24, 0x73, 0x6F, 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x1B, 0x00, 0x00, + 0xC0, 0xF4, 0x66, 0x46, 0xFA, 0x67, 0xD7, 0xBC, 0x82, 0x57, 0x46, 0x45, 0xD2, 0xA9, 0xA0, 0x48, + 0x33, 0x11, 0x1B, 0xF1, 0xD9, 0xE8, 0x70, 0x3F, 0xD6, 0xDF, 0x7E, 0xD8, 0xF0, 0x10, 0xB7, 0x1F, + 0xF2, 0x43, 0x07, 0x9B, 0xDE, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x76, 0x41, 0x75, + 0xE1, 0x2D, 0xC8, 0xB9, 0x4C, 0xB7, 0x20, 0xC4, 0x47, 0xFB, 0x13, 0x61, 0x91, 0x74, 0x63, 0xCB, + 0x79, 0x13, 0x16, 0x00, 0x00, 0x40, 0xC8, 0x7F, 0x05, 0x6F, 0xF8, 0x06, 0x2C, 0x19, 0x15, 0x49, + 0xA7, 0x82, 0x22, 0xCD, 0x62, 0xA1, 0xD1, 0x68, 0x61, 0x78, 0x84, 0xF1, 0xE1, 0xF6, 0xD4, 0x85, + 0x35, 0xDF, 0x7A, 0x15, 0x0F, 0x90, 0x53, 0x2E, 0x40, 0xC2, 0xDB, 0x8F, 0x1F, 0xD9, 0xC9, 0xF0, + 0x70, 0xD3, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x6C, 0x32, 0x3E, 0xDC, 0x4E, 0x7D, 0xD3, 0xC5, + 0x41, 0x96, 0x5B, 0x10, 0xE2, 0xA3, 0xFD, 0x89, 0xA8, 0x48, 0xB3, 0x17, 0x3F, 0xC7, 0x9B, 0xB0, + 0x00, 0x00, 0x00, 0x42, 0xFE, 0x1B, 0xB0, 0xB6, 0x7D, 0xC4, 0x1E, 0xEE, 0x55, 0x54, 0x24, 0x9D, + 0x0A, 0x8A, 0x34, 0x13, 0xA1, 0xA1, 0x66, 0xA3, 0xC3, 0xFD, 0x58, 0x7B, 0xFB, 0x61, 0xE3, 0x23, + 0xCD, 0xED, 0xC7, 0xB7, 0x1A, 0xDD, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, 0x56, 0x1B, + 0x1F, 0xE1, 0x26, 0x7E, 0x94, 0xF6, 0x16, 0x84, 0xF8, 0x68, 0x7F, 0x22, 0x28, 0x32, 0x8C, 0x37, + 0x61, 0x01, 0x00, 0x00, 0x04, 0xBC, 0x91, 0x81, 0x0D, 0x3A, 0x2A, 0x92, 0x4E, 0x05, 0x45, 0x9A, + 0xC5, 0x22, 0xA3, 0xD9, 0xC2, 0xF0, 0x88, 0xC4, 0x47, 0xA2, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x68, + 0xD7, 0xA3, 0xF1, 0xE1, 0xD6, 0xF2, 0x16, 0x84, 0xF8, 0xC8, 0x79, 0x3A, 0x26, 0xB2, 0xCC, 0x3B, + 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x00, 0x38, 0xDE, 0x81, 0xAB, 0x47, 0x75, 0x58, 0x24, 0x99, + 0x0A, 0x8A, 0x34, 0x13, 0x91, 0xD1, 0x62, 0xD5, 0x00, 0x09, 0xE3, 0xA3, 0xED, 0xDB, 0x0F, 0x1D, + 0x14, 0x69, 0xA6, 0x43, 0x22, 0xCB, 0x74, 0x78, 0x44, 0x17, 0xDE, 0x82, 0xB8, 0x78, 0x68, 0x7C, + 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x12, 0x59, 0xE7, 0x1D, 0xBB, 0x65, 0x3C, 0xF8, 0x92, 0x03, + 0x00, 0x00, 0x98, 0xDE, 0xBC, 0x7D, 0x57, 0x8C, 0xEB, 0xB8, 0x68, 0x35, 0x15, 0x14, 0x69, 0xA6, + 0x03, 0xA3, 0xE1, 0x6A, 0x6E, 0x3F, 0x6C, 0x7C, 0x34, 0xBB, 0xFD, 0x08, 0xE3, 0xA3, 0xE5, 0xED, + 0x87, 0x0E, 0x8A, 0x34, 0xD3, 0x21, 0x91, 0x65, 0x3A, 0x38, 0xE2, 0xF3, 0x6F, 0x41, 0x1E, 0x6F, + 0x76, 0x0B, 0x42, 0x7C, 0xB4, 0x3F, 0x1D, 0x11, 0x6D, 0xCD, 0xBD, 0x09, 0x6B, 0xEC, 0x8B, 0xB3, + 0x82, 0x2F, 0x3B, 0x00, 0x00, 0x80, 0xE9, 0xCB, 0x0C, 0x2D, 0xB0, 0x07, 0x7C, 0x15, 0x18, 0xCD, + 0xA6, 0x82, 0x22, 0xCD, 0x44, 0x60, 0x24, 0x58, 0x18, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xB9, 0x1F, + 0xC9, 0x6E, 0x3F, 0x74, 0x50, 0xA4, 0x99, 0x0E, 0x89, 0x2C, 0xD3, 0xB1, 0xD1, 0x68, 0x67, 0xBE, + 0x2F, 0x9E, 0x05, 0xF1, 0x43, 0x24, 0x12, 0x1E, 0x6E, 0xC4, 0x47, 0x86, 0x89, 0x78, 0xC8, 0x63, + 0x63, 0xCB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x80, 0xFF, 0x06, 0xAC, 0x9D, 0xB3, 0xED, 0xE1, 0x5E, + 0x45, 0x46, 0xA3, 0xA9, 0xA0, 0x48, 0x33, 0x1D, 0x17, 0x4D, 0x17, 0xB9, 0xF9, 0xF0, 0xE3, 0x43, + 0xDC, 0x7E, 0x4C, 0xB8, 0x3D, 0x1E, 0xB9, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xE5, 0x89, 0x0F, + 0x7F, 0x77, 0xAB, 0x5B, 0x90, 0x4A, 0x68, 0x18, 0x1B, 0x19, 0xC4, 0x47, 0xD6, 0x89, 0x70, 0xC8, + 0x65, 0x8B, 0x8D, 0x79, 0xF1, 0x5A, 0xE3, 0xFD, 0xE2, 0x4B, 0x77, 0x05, 0x5F, 0x7A, 0x00, 0x00, + 0x00, 0xD3, 0x93, 0x0D, 0x90, 0x75, 0x66, 0xC7, 0x27, 0xEC, 0x21, 0x5F, 0x85, 0x86, 0x9A, 0x0A, + 0x8A, 0x34, 0x13, 0x71, 0x91, 0x64, 0x61, 0x7C, 0xC4, 0x6E, 0x3F, 0x12, 0x3F, 0xFB, 0xF1, 0xCD, + 0x12, 0xC5, 0x47, 0xB0, 0x33, 0xDF, 0x8B, 0x3E, 0x0B, 0x52, 0x89, 0x8C, 0x70, 0x2E, 0x40, 0xC2, + 0xF0, 0x20, 0x3E, 0x92, 0x4E, 0x85, 0x43, 0x1E, 0xB3, 0xF1, 0xE1, 0x66, 0x7F, 0xED, 0xDE, 0x89, + 0x3B, 0x36, 0x04, 0x5F, 0x7A, 0x00, 0x00, 0x00, 0xD3, 0x93, 0xFF, 0x0A, 0x5E, 0x19, 0x1A, 0x6A, + 0x2A, 0x28, 0xD2, 0x4C, 0x84, 0x45, 0xAB, 0xD9, 0xF0, 0xA8, 0xC6, 0x87, 0x0D, 0x8F, 0xC9, 0xDB, + 0x8F, 0xD8, 0xB7, 0x5E, 0x45, 0x6F, 0x3F, 0xEC, 0x1A, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, + 0x12, 0x59, 0xA6, 0xC3, 0x22, 0xF1, 0xAA, 0xB7, 0x20, 0x36, 0x40, 0x36, 0xBA, 0xC0, 0x08, 0x82, + 0x23, 0x12, 0x1E, 0xC4, 0x47, 0xD2, 0xA9, 0x70, 0xC8, 0x63, 0x41, 0x7C, 0x04, 0xF3, 0x4E, 0xFC, + 0x39, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x9B, 0x77, 0xF0, 0xBA, 0x84, 0x6F, 0xC0, 0x52, 0x41, + 0x91, 0x66, 0xB1, 0xB0, 0x48, 0x3A, 0x17, 0x20, 0xE1, 0xCD, 0x87, 0x5D, 0xF5, 0x5B, 0xAF, 0xE4, + 0xB3, 0x1F, 0x17, 0xB5, 0xB8, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x04, 0x45, + 0x86, 0x9D, 0xFE, 0xCE, 0x7B, 0xFD, 0xB0, 0x08, 0x23, 0xA4, 0x1A, 0x1C, 0x2E, 0x3E, 0x82, 0x28, + 0x21, 0x3E, 0x5A, 0x4D, 0x85, 0x43, 0x1E, 0xAB, 0x8D, 0x0F, 0x3F, 0x40, 0x8E, 0x7D, 0x81, 0x37, + 0x61, 0x01, 0x00, 0x80, 0xE9, 0xCD, 0xDB, 0xFB, 0xD9, 0x31, 0x1D, 0x1C, 0xD1, 0xA9, 0xA0, 0x48, + 0xB3, 0x58, 0x54, 0x24, 0x5D, 0x2C, 0x3E, 0xC2, 0xDB, 0x8F, 0xBA, 0xF8, 0x88, 0xDE, 0x7E, 0x84, + 0xF1, 0x11, 0x06, 0xC8, 0x86, 0xF0, 0xF6, 0x43, 0x07, 0x45, 0x9A, 0xE9, 0x90, 0xC8, 0x32, 0x1D, + 0x13, 0xA9, 0xF7, 0x57, 0xEF, 0xF5, 0xF7, 0xEE, 0xA3, 0x93, 0x01, 0x12, 0x9F, 0x1F, 0x27, 0x2E, + 0x3C, 0x88, 0x8F, 0x06, 0x53, 0xE1, 0x90, 0xC7, 0xEA, 0xE3, 0xC3, 0xDF, 0x91, 0x1B, 0x4C, 0xF0, + 0xA5, 0x07, 0x00, 0x00, 0x30, 0x3D, 0x99, 0x3D, 0xF6, 0x50, 0x24, 0xA3, 0x23, 0x9C, 0x0A, 0x8A, + 0x34, 0x8B, 0x45, 0x45, 0xD2, 0x35, 0x88, 0x8F, 0xEA, 0x83, 0xE7, 0xEA, 0xF6, 0x23, 0x1E, 0x1F, + 0x0F, 0xD9, 0xDD, 0x5D, 0xEE, 0xF8, 0x70, 0x73, 0xB7, 0x20, 0x7E, 0x60, 0xD8, 0x9D, 0x7B, 0xD2, + 0x86, 0x87, 0xDD, 0xB9, 0x68, 0x7C, 0xD8, 0xF0, 0x38, 0x6B, 0xC3, 0x83, 0xF8, 0x88, 0x4F, 0x85, + 0x43, 0x1E, 0x8B, 0x45, 0x47, 0x74, 0x2F, 0xAD, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xFA, 0x32, + 0x87, 0xFB, 0x97, 0x98, 0xDD, 0xF3, 0xEC, 0x81, 0x5F, 0x85, 0x87, 0x9B, 0x0A, 0x8A, 0x34, 0x8B, + 0x45, 0x45, 0x9A, 0xD9, 0xE8, 0xA8, 0x0B, 0x90, 0x26, 0xDF, 0x7A, 0x25, 0xDF, 0x7C, 0x75, 0xBF, + 0xBB, 0xFD, 0xD0, 0x41, 0x91, 0x66, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x45, 0xE2, 0x23, + 0x9C, 0xBB, 0x05, 0xF1, 0x43, 0x63, 0xD0, 0xC6, 0x88, 0x0D, 0x90, 0xB3, 0xB1, 0x6F, 0xB9, 0x7A, + 0xF7, 0x31, 0xE2, 0xA3, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x88, 0x8E, 0xE8, 0x5E, 0xBC, 0xD6, 0x06, + 0xC8, 0x1D, 0xEB, 0x82, 0x2F, 0x41, 0x00, 0x00, 0x80, 0xE9, 0xC5, 0x7F, 0x05, 0x6F, 0xC3, 0x37, + 0x60, 0xA9, 0xA0, 0x48, 0x33, 0x11, 0x15, 0x49, 0xF7, 0x8C, 0x88, 0x8F, 0xE8, 0xED, 0x87, 0x8B, + 0x8F, 0x9A, 0x00, 0x11, 0xDF, 0x7A, 0xE5, 0xDF, 0x7E, 0xE8, 0xA0, 0x48, 0x33, 0x1D, 0x12, 0x59, + 0x26, 0x42, 0x22, 0xCB, 0x44, 0x7C, 0xBC, 0xBD, 0xFE, 0xBD, 0xE6, 0xD4, 0x3D, 0x36, 0x42, 0x5C, + 0x68, 0xB8, 0xE0, 0x70, 0x21, 0x12, 0xFC, 0xE8, 0xFE, 0xB5, 0x09, 0x17, 0x1F, 0x36, 0x3C, 0x4E, + 0x3F, 0x42, 0x7C, 0x54, 0xA6, 0xC2, 0x21, 0x8F, 0x89, 0xE0, 0x88, 0xCF, 0xFD, 0xBE, 0x4E, 0xDC, + 0xB1, 0x3E, 0xF8, 0x12, 0x04, 0x00, 0x00, 0x98, 0x5E, 0xFC, 0x37, 0x60, 0x6D, 0xF9, 0x80, 0x3D, + 0xF4, 0x77, 0x5F, 0x7C, 0x34, 0xBA, 0xFD, 0x50, 0xAF, 0xDD, 0xD5, 0xB7, 0x1F, 0xED, 0x7F, 0xEB, + 0x95, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0x0D, 0xE2, 0x23, 0xDC, 0x99, 0x07, 0x6D, 0x6C, + 0x3C, 0x3E, 0xA3, 0x12, 0x22, 0x41, 0x78, 0x4C, 0x3C, 0x7A, 0x81, 0x7F, 0xEB, 0x41, 0x7C, 0x84, + 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x6C, 0x34, 0x98, 0x77, 0xE2, 0x0E, 0xDE, 0x84, 0x05, 0x00, 0x00, + 0xA6, 0x27, 0xEF, 0xD0, 0xCA, 0xC1, 0xAE, 0x8B, 0x8F, 0x5C, 0x6E, 0x3F, 0x2E, 0x6A, 0xFB, 0xF6, + 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0xD6, 0xD7, 0xEC, 0xBF, 0xF6, + 0x4D, 0x17, 0x1D, 0x33, 0xFC, 0x9D, 0xB1, 0xE1, 0xE1, 0xE6, 0x7F, 0xCB, 0x55, 0x18, 0x1F, 0x4F, + 0x11, 0x1F, 0xC5, 0x4C, 0x87, 0x46, 0xA3, 0x79, 0xC7, 0xBE, 0x70, 0x32, 0xF8, 0x12, 0x04, 0x00, + 0x00, 0x98, 0x5E, 0xBC, 0xBD, 0x57, 0xC4, 0x5E, 0xC1, 0xAB, 0x82, 0x22, 0xCD, 0x44, 0x54, 0x24, + 0x5D, 0x24, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0xA3, 0xFE, 0xD9, 0x0F, 0x75, 0xFB, 0x61, 0xE3, 0xE3, + 0xBE, 0xF6, 0x6E, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x4B, 0x10, 0x1F, 0x6F, 0x7D, + 0xED, 0x02, 0xF3, 0xD6, 0x7F, 0xB9, 0xC0, 0x9C, 0xFA, 0xA1, 0x0D, 0x0D, 0x77, 0xE3, 0xF1, 0x63, + 0x1B, 0x1F, 0x41, 0x78, 0xBC, 0xF3, 0x90, 0xFD, 0x91, 0xF8, 0x28, 0x68, 0x3A, 0x32, 0x9A, 0xEE, + 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x4C, 0x4F, 0x66, 0xAF, 0x3D, 0xF0, 0x75, 0x53, 0x7C, + 0x04, 0x01, 0xD2, 0xEC, 0xF6, 0x23, 0x1E, 0x20, 0x75, 0xF1, 0xF1, 0x60, 0x7B, 0x0F, 0x9E, 0xEB, + 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x96, 0x22, 0x3E, 0xDE, 0xFC, 0xCF, 0xF6, 0xC7, 0xBB, 0x6D, + 0x84, 0x04, 0xD1, 0xE1, 0xEF, 0x41, 0xE2, 0x43, 0x87, 0x43, 0x1E, 0x13, 0x71, 0x91, 0x64, 0x47, + 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xFD, 0x98, 0xD1, 0xFE, 0x59, 0x66, 0x68, 0x81, 0x0D, + 0x80, 0xEE, 0x8A, 0x0F, 0xF7, 0xA3, 0xBA, 0xFD, 0x50, 0xCF, 0x7E, 0xD4, 0x7E, 0xE8, 0xA0, 0x0D, + 0x8F, 0x87, 0xDB, 0xBB, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x2C, 0x65, 0x7C, 0xB8, + 0xFD, 0xE1, 0xFF, 0xB1, 0xFF, 0xFF, 0x77, 0x66, 0x98, 0xB7, 0x1F, 0x98, 0x69, 0x67, 0xE3, 0x63, + 0x23, 0xF1, 0x51, 0xCC, 0x44, 0x58, 0x24, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x2F, 0xAD, 0x0D, 0xBE, + 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0xFF, 0x0D, 0x58, 0x3B, 0x67, 0xDB, 0x08, 0x50, 0x41, 0x91, + 0x66, 0x22, 0x2A, 0x92, 0x2E, 0x1A, 0x1F, 0x41, 0x80, 0x34, 0xBB, 0xFD, 0x70, 0xF1, 0x11, 0x0F, + 0x90, 0x6A, 0x7C, 0xB4, 0x79, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, 0x64, 0x59, 0xC6, 0xF8, + 0x78, 0xE3, 0x2F, 0x67, 0x98, 0xF1, 0xFF, 0x3C, 0xC3, 0xBC, 0xF5, 0x23, 0xFB, 0x7B, 0x7A, 0x92, + 0xF8, 0x28, 0x66, 0x22, 0x2A, 0xD2, 0xEC, 0xF9, 0x2B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x7E, + 0xBC, 0x43, 0xAB, 0xEE, 0x32, 0xDB, 0x3E, 0x6A, 0x43, 0x40, 0x45, 0x45, 0xD2, 0x89, 0xA8, 0x48, + 0x3A, 0x11, 0x1F, 0xEE, 0xC7, 0xD4, 0xB7, 0x1F, 0x61, 0x7C, 0xB8, 0xDB, 0x8F, 0x7B, 0xB3, 0xDD, + 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x4E, 0x7C, 0xFC, 0xA7, 0x19, 0xE6, 0xF7, + 0xFF, 0xF7, 0x0C, 0xF3, 0xE6, 0x03, 0xC4, 0x47, 0x31, 0x13, 0x41, 0x91, 0x61, 0xDE, 0x2F, 0xEE, + 0x18, 0x0A, 0xBE, 0x14, 0x01, 0x00, 0x00, 0xA6, 0x07, 0x33, 0xD2, 0xBF, 0x5E, 0x47, 0x45, 0xD2, + 0x89, 0xA8, 0x48, 0xBA, 0x78, 0x7C, 0xB8, 0x85, 0xE1, 0x11, 0xC6, 0x47, 0xAB, 0xDB, 0x0F, 0xFF, + 0x5B, 0xAF, 0x82, 0xF8, 0x70, 0xFB, 0xA1, 0x9D, 0x88, 0x8B, 0x56, 0xD3, 0x21, 0x91, 0x65, 0x22, + 0x24, 0xB2, 0x2C, 0x87, 0xF8, 0x78, 0xE3, 0xDB, 0x36, 0x3E, 0x5E, 0x22, 0x3E, 0xF2, 0x9F, 0x8E, + 0x89, 0x2C, 0xF3, 0x8E, 0xDE, 0x3C, 0x16, 0x7C, 0x29, 0x02, 0x00, 0x00, 0x4C, 0x0F, 0xDE, 0x81, + 0xAB, 0x46, 0x75, 0x58, 0x24, 0x99, 0x88, 0x8A, 0xA4, 0x6B, 0x10, 0x1F, 0xEE, 0xC7, 0x54, 0xB7, + 0x1F, 0xD1, 0xF8, 0x70, 0xB7, 0x1F, 0xDF, 0x4A, 0x7F, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, + 0x64, 0x19, 0xF1, 0x91, 0xC3, 0x54, 0x38, 0xE4, 0x31, 0x1D, 0x12, 0x99, 0xC7, 0x9B, 0xB0, 0x00, + 0x00, 0xC0, 0x74, 0xE3, 0xED, 0xFF, 0xEC, 0x49, 0x1D, 0x17, 0xAD, 0x26, 0xA2, 0x22, 0xE9, 0xE2, + 0xE1, 0x11, 0x2E, 0x0C, 0x8F, 0x30, 0x3E, 0x9A, 0xDD, 0x7E, 0x3C, 0x76, 0x91, 0x39, 0xFD, 0xA8, + 0x0D, 0x8E, 0x36, 0x6F, 0x3F, 0x74, 0x48, 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, + 0x0A, 0x87, 0x3C, 0x26, 0x02, 0xA2, 0xDD, 0xB9, 0x37, 0x61, 0x1D, 0xBF, 0x63, 0x49, 0xF0, 0xE5, + 0x08, 0x00, 0x00, 0x50, 0x7E, 0x66, 0x68, 0xBE, 0x8D, 0x02, 0x15, 0x18, 0xCD, 0x26, 0xA2, 0x22, + 0xE9, 0x54, 0x78, 0x44, 0x96, 0xE8, 0xF6, 0x23, 0x88, 0x8F, 0x76, 0x6F, 0x3F, 0x74, 0x48, 0x64, + 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0x26, 0xE2, 0x21, 0x8F, 0xBD, + 0x78, 0x1D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xD3, 0x87, 0xFF, 0x06, 0xAC, 0x5D, 0x9F, 0xB6, 0x61, + 0xA0, 0x22, 0xA3, 0xD1, 0x44, 0x54, 0x24, 0x9D, 0x08, 0x8E, 0xEA, 0x92, 0xDE, 0x7E, 0x3C, 0x6E, + 0x03, 0x24, 0x8C, 0x8F, 0x68, 0x80, 0xFC, 0x80, 0xF8, 0x20, 0x3E, 0x54, 0x38, 0xE4, 0x31, 0x11, + 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x3E, 0xCC, 0xA1, 0xFE, 0xB5, + 0x66, 0xC7, 0xC7, 0x6D, 0x1C, 0xA8, 0xD0, 0x50, 0x13, 0x51, 0x91, 0x74, 0x2A, 0x3A, 0x62, 0x53, + 0xB7, 0x1F, 0xD1, 0x00, 0xF1, 0xE3, 0xA3, 0xD1, 0xED, 0xC7, 0x37, 0x75, 0x68, 0xA8, 0xE9, 0x90, + 0xC8, 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x44, 0x43, 0xCE, + 0xE3, 0x4D, 0x58, 0x00, 0x00, 0x60, 0xDA, 0xF0, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0x36, 0x10, 0x54, + 0x6C, 0xC4, 0x27, 0xA2, 0x22, 0xE9, 0x44, 0x6C, 0xD4, 0x2C, 0xC1, 0xED, 0x87, 0xFB, 0xD6, 0xAB, + 0x89, 0xC7, 0x2E, 0x9C, 0xBC, 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0x7B, 0xC9, 0x6F, 0x3F, 0x74, 0x48, + 0x64, 0x99, 0x08, 0x89, 0x2C, 0x23, 0x3E, 0x72, 0x98, 0x0A, 0x87, 0x3C, 0xA6, 0x83, 0x21, 0xEF, + 0x79, 0x47, 0xFF, 0x64, 0x34, 0xF8, 0x92, 0x04, 0x00, 0x00, 0x28, 0x37, 0x6F, 0x78, 0xE9, 0x90, + 0x8E, 0x8D, 0xF8, 0x44, 0x54, 0x24, 0x9D, 0x0A, 0x8E, 0xF8, 0xE2, 0x01, 0xA2, 0x9E, 0xFD, 0x78, + 0xDC, 0xC6, 0x47, 0x9B, 0xB7, 0x1F, 0x3A, 0x24, 0xB2, 0x4C, 0x84, 0x44, 0x96, 0x11, 0x1F, 0x39, + 0x4C, 0x85, 0x43, 0x1E, 0xD3, 0xB1, 0x50, 0xC8, 0x8E, 0x7D, 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, + 0xE9, 0xC1, 0xDB, 0xBB, 0x24, 0xC1, 0x2B, 0x78, 0x45, 0x54, 0x24, 0x9D, 0x8A, 0x8D, 0xE8, 0x6C, + 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, 0x47, 0xEC, 0x5B, 0xAF, 0x9E, 0xB8, 0x70, 0xF2, + 0xF6, 0xC3, 0x2E, 0xCB, 0xED, 0x87, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, + 0x53, 0xE1, 0x90, 0xC7, 0x44, 0x24, 0x14, 0xB6, 0x45, 0x95, 0x37, 0x61, 0xBD, 0x7C, 0xE7, 0xEC, + 0xE0, 0xCB, 0x12, 0x00, 0x00, 0xA0, 0xBC, 0xCC, 0x1E, 0x7B, 0xF8, 0x91, 0xD1, 0x11, 0x4E, 0x44, + 0x45, 0xD2, 0xA9, 0xE0, 0x88, 0x2F, 0x1A, 0x20, 0x76, 0xD5, 0x6F, 0xBD, 0x8A, 0x06, 0x88, 0x8B, + 0x0F, 0xFF, 0xF6, 0xE3, 0xC2, 0xFA, 0xDB, 0x8F, 0x87, 0xEC, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, + 0x32, 0x11, 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xB3, + 0x5F, 0x7F, 0x6E, 0x2F, 0x7E, 0xCE, 0x05, 0xC8, 0x40, 0xF0, 0x65, 0x09, 0x00, 0x00, 0x50, 0x4E, + 0x66, 0xA4, 0x7F, 0x76, 0xF3, 0x57, 0xF0, 0x8A, 0xA8, 0x48, 0x3A, 0x15, 0x1B, 0xF1, 0xC5, 0xE2, + 0x23, 0xBC, 0xFD, 0xA8, 0x7D, 0xF0, 0xDC, 0xC6, 0x47, 0xF4, 0xF6, 0x23, 0xFE, 0xAD, 0x57, 0xF7, + 0xB7, 0xBE, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, + 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x16, 0xC4, 0x87, 0x1F, 0x20, 0xD7, 0xF0, 0x26, 0x2C, 0x00, 0x00, + 0x50, 0x7E, 0xFE, 0x2B, 0x78, 0x1B, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, 0xA9, 0xD8, 0x88, 0xAF, + 0x41, 0x7C, 0x54, 0x1F, 0x3C, 0x77, 0xB3, 0xF1, 0x51, 0x73, 0xFB, 0x11, 0x7F, 0xF0, 0xDC, 0xDD, + 0x7E, 0xDC, 0xAD, 0xA3, 0x23, 0x9C, 0x0E, 0x89, 0x2C, 0x13, 0x21, 0x91, 0x65, 0xC4, 0x47, 0x0E, + 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0xB5, 0x48, 0x7C, 0x04, 0xF3, 0x4E, 0x7C, 0x69, 0x30, + 0xF8, 0xD2, 0x04, 0x00, 0x00, 0x28, 0x27, 0xFF, 0x0D, 0x58, 0x5B, 0x3F, 0x64, 0xA3, 0x61, 0x8A, + 0xE3, 0xC3, 0x4D, 0x05, 0x48, 0xCD, 0xB7, 0x5E, 0xD9, 0xF8, 0x70, 0xB7, 0x1F, 0x41, 0x7C, 0x64, + 0xB9, 0xFD, 0xD0, 0x21, 0x91, 0x65, 0x22, 0x24, 0xB2, 0x8C, 0xF8, 0xC8, 0x61, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x56, 0x1F, 0x1F, 0x6E, 0xDE, 0xF1, 0x3F, 0xE5, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0xDC, 0xBC, 0x91, 0x81, 0x0D, 0x1D, 0x89, 0x0F, 0xB7, 0x78, 0x7C, 0x54, 0x6F, 0x3F, 0x2E, + 0xAC, 0xC6, 0xC7, 0xE4, 0xED, 0x47, 0x2C, 0x3E, 0x12, 0xDC, 0x7E, 0xE8, 0x90, 0xC8, 0x32, 0x11, + 0x12, 0x59, 0x46, 0x7C, 0xE4, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xF1, 0xE1, + 0xEF, 0xD8, 0x2D, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x94, 0x9B, 0x77, 0xE0, 0xAA, 0xD8, 0x1B, 0xB0, + 0x44, 0x54, 0x24, 0x9D, 0x8A, 0x8C, 0x46, 0xB3, 0xD1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0x44, 0x02, + 0x24, 0x8C, 0x0F, 0xF9, 0xB9, 0x1F, 0xDF, 0x69, 0x7C, 0xFB, 0xA1, 0x43, 0x22, 0xCB, 0x44, 0x48, + 0x64, 0x59, 0x34, 0x3A, 0x88, 0x8F, 0x8C, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x11, + 0x1D, 0xD1, 0xB9, 0x37, 0x61, 0x8D, 0x7D, 0x71, 0x56, 0xF0, 0xE5, 0x09, 0x00, 0x00, 0x50, 0x3E, + 0xDE, 0xBE, 0x25, 0xE3, 0x53, 0x1E, 0x1F, 0x6E, 0xF1, 0xF8, 0x48, 0x7B, 0xFB, 0xF1, 0xA0, 0x9D, + 0x08, 0x0F, 0x37, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x52, 0xC4, 0x47, 0x18, 0x20, 0x2E, + 0x3E, 0xFE, 0x40, 0x7C, 0x44, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x38, 0xE2, + 0x1B, 0x5B, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB9, 0x4D, 0xBE, 0x01, 0x4B, 0x44, 0x45, 0xD2, + 0xA9, 0xC0, 0x68, 0x36, 0x1B, 0x1D, 0xEE, 0x47, 0x75, 0xFB, 0x11, 0x0D, 0x90, 0xA6, 0xB7, 0x1F, + 0xF7, 0xE9, 0xDB, 0x0F, 0x1D, 0x12, 0x59, 0x26, 0x42, 0x22, 0xCB, 0x22, 0xF1, 0x11, 0xAE, 0x3E, + 0x3E, 0xEC, 0x5C, 0x78, 0x84, 0xB7, 0x1F, 0xC4, 0x47, 0x6C, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, + 0xA2, 0x26, 0x62, 0x43, 0xED, 0xC5, 0x6B, 0x8C, 0xF7, 0x8B, 0x2F, 0xDD, 0x15, 0x7C, 0x79, 0x02, + 0x00, 0x00, 0x94, 0x8B, 0xFF, 0x06, 0xAC, 0x9D, 0x9F, 0xD2, 0x51, 0x91, 0x74, 0xF1, 0xB8, 0x48, + 0xB2, 0x30, 0x3C, 0xC2, 0xF8, 0xF0, 0x03, 0x64, 0x66, 0x35, 0x3E, 0x6A, 0xDF, 0x7C, 0x95, 0xFC, + 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0xB2, 0x16, 0xF1, 0xF1, 0x76, 0x24, 0x3E, 0xE2, + 0x37, 0x1F, 0x6F, 0x04, 0xF1, 0xF1, 0x07, 0xE2, 0xA3, 0xA0, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x34, + 0x9A, 0xCC, 0x3B, 0x71, 0xC7, 0x86, 0xE0, 0x4B, 0x14, 0x00, 0x00, 0xA0, 0x5C, 0x6C, 0x80, 0xAC, + 0x33, 0xDB, 0x2F, 0xD6, 0x61, 0x91, 0x64, 0x2A, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0xF6, + 0xF6, 0xC3, 0xC6, 0x47, 0x83, 0x67, 0x3F, 0xEA, 0x3E, 0x74, 0xD0, 0xBD, 0xF9, 0x4A, 0xDC, 0x7E, + 0xE8, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0xD6, 0x22, 0x3E, 0xA2, 0x37, 0x1F, 0x61, 0x7C, 0x84, + 0x37, 0x1F, 0xC4, 0x47, 0x38, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x91, 0xD1, 0x6C, + 0xDE, 0x89, 0x3F, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x9C, 0xFC, 0x57, 0xF0, 0xAA, 0xB0, 0x48, + 0xB2, 0x78, 0x58, 0x24, 0x5D, 0x18, 0x1E, 0x61, 0x7C, 0x3C, 0x3D, 0xB3, 0xE6, 0xF6, 0xA3, 0xEE, + 0xD9, 0x0F, 0x1B, 0x20, 0xA7, 0xA2, 0x01, 0xF2, 0x23, 0xBB, 0x1E, 0x8C, 0x0F, 0xB7, 0xBA, 0x00, + 0x69, 0x10, 0x1F, 0xE3, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0xC0, + 0x68, 0x35, 0xEF, 0xD8, 0x17, 0xC6, 0x83, 0x2F, 0x51, 0x00, 0x00, 0x80, 0x72, 0xF1, 0x0E, 0x5C, + 0x33, 0x2A, 0xE3, 0xA2, 0xD5, 0x54, 0x58, 0x24, 0x99, 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, + 0xF1, 0x11, 0xBD, 0xFD, 0x88, 0xC5, 0x47, 0xDD, 0xED, 0xC7, 0xB7, 0x6A, 0x6F, 0x3F, 0x74, 0x48, + 0x64, 0x99, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x56, 0x17, 0x1F, 0xEA, 0x8D, 0x57, 0xC4, 0x47, + 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x71, 0x91, 0x68, 0x47, 0x56, 0xF3, 0x26, + 0x2C, 0x00, 0x00, 0x50, 0x4E, 0xDE, 0xDE, 0x25, 0x63, 0x32, 0x30, 0x9A, 0x2D, 0x1E, 0x15, 0x69, + 0x16, 0x86, 0x47, 0x18, 0x1F, 0x69, 0x6F, 0x3F, 0x7E, 0x68, 0x57, 0xB6, 0xF8, 0x70, 0x37, 0x1F, + 0x2E, 0x3E, 0xDC, 0x43, 0xE7, 0xC4, 0x87, 0x9D, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, + 0xA8, 0x48, 0xB3, 0x97, 0x56, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x4E, 0x66, 0xCF, 0x42, 0x1D, + 0x19, 0x8D, 0xA6, 0xA2, 0x22, 0xE5, 0x2A, 0x01, 0x32, 0xB3, 0xED, 0xDB, 0x0F, 0x1D, 0x12, 0x59, + 0x26, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0xB5, 0x8C, 0x8F, 0xBF, 0x9C, 0xFC, 0xAC, 0x8F, 0x3F, + 0xDC, 0x4B, 0x7C, 0x14, 0x33, 0x15, 0x09, 0x45, 0x4D, 0x04, 0x45, 0xDA, 0xBD, 0x78, 0x8D, 0x0D, + 0x90, 0x3B, 0xD6, 0x05, 0x5F, 0xA6, 0x00, 0x00, 0x00, 0xE5, 0x60, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, + 0xE6, 0xE8, 0xD0, 0x50, 0x13, 0x31, 0x91, 0x6A, 0xD5, 0xDB, 0x8F, 0x20, 0x3E, 0x9A, 0xDD, 0x7E, + 0x84, 0xF1, 0xD1, 0xE0, 0xF6, 0x43, 0x87, 0x44, 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, + 0x0D, 0xE3, 0x23, 0x08, 0x90, 0xE8, 0x07, 0x0D, 0x12, 0x1F, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, + 0xA2, 0x26, 0x62, 0x22, 0xCB, 0x9E, 0xB7, 0x7F, 0x3F, 0x4E, 0xDC, 0xB1, 0x3E, 0xF8, 0x52, 0x05, + 0x00, 0x00, 0x28, 0x07, 0xFF, 0x15, 0xBC, 0x49, 0xDF, 0x80, 0xA5, 0x82, 0x22, 0xC3, 0xFC, 0xF8, + 0x88, 0xDD, 0x7E, 0x54, 0x03, 0xA4, 0xD5, 0xED, 0xC7, 0x3D, 0xBD, 0x1B, 0x1F, 0x95, 0xD7, 0xED, + 0x12, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x24, 0xDA, 0x18, 0x6F, + 0xC2, 0x02, 0x00, 0x00, 0xA5, 0xE3, 0xBF, 0x01, 0x6B, 0xEB, 0x07, 0x75, 0x70, 0x44, 0x27, 0x42, + 0x22, 0xF5, 0xC2, 0x9B, 0x8F, 0x26, 0xB7, 0x1F, 0x13, 0x2E, 0x40, 0x1E, 0x8B, 0xDC, 0x7E, 0x84, + 0xF1, 0xE1, 0xF6, 0xBD, 0xCA, 0xB7, 0x5E, 0xE9, 0x90, 0xC8, 0x32, 0x11, 0x12, 0x59, 0x26, 0xC2, + 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x11, 0xD1, 0xCE, + 0xBC, 0x63, 0x5F, 0x38, 0x19, 0x7C, 0xA9, 0x02, 0x00, 0x00, 0x94, 0x83, 0x37, 0xBC, 0x62, 0x50, + 0x06, 0x47, 0x74, 0x2A, 0x26, 0xB2, 0x2C, 0x8C, 0x8F, 0xD8, 0xED, 0x47, 0xE2, 0x67, 0x3F, 0xBE, + 0xC9, 0xB7, 0x5D, 0x25, 0x9B, 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, + 0x2A, 0x12, 0x8A, 0x9A, 0x0E, 0x88, 0xB6, 0x77, 0x64, 0xB5, 0x09, 0xBE, 0x54, 0x01, 0x00, 0x00, + 0xCA, 0xC1, 0xDB, 0x7B, 0x79, 0xF3, 0x57, 0xF0, 0xAA, 0x90, 0x48, 0xBB, 0x4D, 0x6E, 0x93, 0xE1, + 0x31, 0x79, 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xFC, 0xF6, 0x43, 0x87, 0x44, + 0x96, 0x89, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0x0D, 0xE3, 0xC3, 0x3D, 0x70, 0x1E, 0x8B, 0x8F, + 0xF1, 0xFF, 0x32, 0xCB, 0x9C, 0xFF, 0xD7, 0x5B, 0x83, 0xF8, 0x58, 0x65, 0x0F, 0xFA, 0x2A, 0x28, + 0xD2, 0x4C, 0x84, 0x43, 0x1E, 0x93, 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x84, 0x43, 0x5E, 0x3B, 0xB2, 0x92, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF1, 0xF6, 0x2C, + 0x1A, 0x97, 0xE1, 0xE1, 0xA6, 0x62, 0x22, 0xCB, 0x6C, 0x78, 0x44, 0x6F, 0x3F, 0xAA, 0xDF, 0x7A, + 0x15, 0x06, 0x48, 0xCD, 0x6B, 0x77, 0x2F, 0x94, 0xB7, 0x1F, 0xEF, 0x7C, 0x23, 0xAF, 0xDB, 0x0F, + 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x2D, 0x6D, 0x7C, 0x9C, 0xFB, 0xE9, 0x17, 0x2A, 0xF1, 0x71, + 0xD4, 0xFE, 0x28, 0x83, 0x22, 0xCD, 0x44, 0x38, 0xE4, 0x31, 0x19, 0x0E, 0x79, 0x4C, 0x85, 0x43, + 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x44, 0x34, 0xE4, 0x39, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xCA, 0xC4, + 0x0C, 0xF5, 0xCF, 0x32, 0x43, 0x7D, 0x53, 0x1A, 0x1F, 0xE1, 0xED, 0x47, 0xCD, 0x83, 0xE7, 0xCD, + 0x9E, 0xFD, 0x70, 0xF1, 0x71, 0x7F, 0x5E, 0xB7, 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, + 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x82, 0x21, 0xEF, 0xB9, 0xFF, + 0x6D, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0x0B, 0xFF, 0x0D, 0x58, 0x3B, 0x3E, 0x39, 0xE5, 0xF1, + 0x51, 0x7D, 0xF0, 0x5C, 0xDD, 0x7E, 0xC4, 0x1E, 0x3C, 0x7F, 0xE7, 0x41, 0x1B, 0x1F, 0x5F, 0x57, + 0x31, 0x91, 0x76, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x62, 0xA1, 0xA0, 0x79, 0x27, 0xEE, 0xE0, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0x1C, 0xBC, 0xE1, 0xFE, 0xBB, 0xCC, 0xB6, 0x8F, 0x14, 0x13, 0x1F, 0xCF, 0x54, 0xE2, 0xA3, + 0x2E, 0x40, 0xE2, 0xAF, 0xDD, 0x75, 0xB7, 0x1F, 0x41, 0x7C, 0xC4, 0x6F, 0x3F, 0xDE, 0x79, 0xD8, + 0xC6, 0xC7, 0x77, 0xF3, 0xF8, 0xD6, 0x2B, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, + 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0xD3, 0xA1, 0x50, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, + 0x82, 0x2F, 0x59, 0x00, 0x00, 0x80, 0xDE, 0xE6, 0xBF, 0x82, 0xB7, 0xA8, 0xF8, 0x08, 0x02, 0xA4, + 0xE1, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0x8A, 0xC7, 0x47, 0x2E, 0xB7, 0x1F, 0x22, 0x24, + 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0xA6, + 0x23, 0xA1, 0xD0, 0x1D, 0xB9, 0x91, 0x37, 0x61, 0x01, 0x00, 0x80, 0x72, 0xF0, 0x0E, 0x5C, 0x33, + 0xF9, 0x06, 0x2C, 0x19, 0x12, 0x59, 0x36, 0x19, 0x1F, 0x8D, 0x6E, 0x3F, 0xAA, 0xAF, 0xDD, 0xAD, + 0xDE, 0x7E, 0x5C, 0x14, 0xBB, 0xFD, 0xB0, 0xE1, 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, + 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x38, 0x98, + 0x8A, 0xBD, 0x34, 0x60, 0xCC, 0xF1, 0x3B, 0x96, 0x04, 0x5F, 0xB6, 0x00, 0x00, 0x00, 0xBD, 0xCB, + 0xDB, 0x77, 0xC5, 0xC9, 0x42, 0xE2, 0xA3, 0xAD, 0xDB, 0x8F, 0x20, 0x3E, 0x1E, 0x68, 0xF7, 0xF6, + 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, + 0x50, 0xD4, 0x44, 0x18, 0x4C, 0xD5, 0xDC, 0x9B, 0xB0, 0x4E, 0x7C, 0x69, 0x6D, 0xF0, 0x65, 0x0B, + 0x00, 0x00, 0xD0, 0xBB, 0xCC, 0xEE, 0xBE, 0x48, 0x3C, 0xB4, 0xBB, 0xDA, 0xF8, 0x70, 0x3F, 0xAA, + 0xDB, 0x8F, 0xFA, 0x67, 0x3F, 0xA2, 0xB7, 0x1F, 0x41, 0x7C, 0xB8, 0xDD, 0xDB, 0xCE, 0xED, 0x87, + 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, + 0xA8, 0x89, 0x28, 0x98, 0xCA, 0xBD, 0x70, 0x25, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xCF, 0x1C, + 0xE8, 0x5F, 0x62, 0x76, 0xCE, 0x0E, 0xE2, 0xA1, 0xDD, 0x45, 0xE2, 0x23, 0x08, 0x90, 0x66, 0xB7, + 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xE1, 0x6E, 0x3F, 0x64, 0x58, 0x24, 0x99, 0x08, 0x89, 0x2C, + 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x20, + 0xE8, 0xC0, 0xBC, 0xE3, 0xB7, 0x0F, 0x05, 0x5F, 0xBA, 0x00, 0x00, 0x00, 0xBD, 0xC9, 0x1C, 0x5C, + 0xB6, 0xD6, 0x6C, 0xFF, 0x58, 0x10, 0x10, 0xED, 0xAC, 0x3E, 0x3E, 0xDC, 0x8F, 0xEA, 0xF6, 0x43, + 0x3D, 0xFB, 0x51, 0xF9, 0xD0, 0xC1, 0x0B, 0x27, 0x03, 0xE4, 0x21, 0xBB, 0xCC, 0xB7, 0x1F, 0x22, + 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0xA6, 0x63, 0xA0, 0x13, 0xF3, 0x8E, 0xDE, 0xC2, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x33, 0x23, + 0xCB, 0xD7, 0x9B, 0xCD, 0xEF, 0xB3, 0xB1, 0xA0, 0xA2, 0x22, 0xE9, 0x62, 0xF1, 0xE1, 0x16, 0x86, + 0x47, 0x18, 0x1F, 0xB1, 0xDB, 0x8F, 0xBA, 0x67, 0x3F, 0x1E, 0xB5, 0xF1, 0xE1, 0x02, 0xA4, 0xED, + 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, + 0x45, 0x42, 0x51, 0xD3, 0x21, 0xD0, 0xB1, 0x1D, 0xBD, 0x99, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, + 0xE6, 0x1D, 0xB8, 0x7E, 0xA8, 0x36, 0x26, 0xD2, 0x4E, 0xC7, 0x87, 0xFB, 0xB1, 0xE9, 0xED, 0x47, + 0x2C, 0x3E, 0xEA, 0x6E, 0x3F, 0xEE, 0xC9, 0x72, 0xFB, 0x21, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, + 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0x22, 0x00, 0x3A, 0x3D, 0xF7, + 0x26, 0xAC, 0x97, 0xEF, 0x9C, 0x1D, 0x7C, 0xF9, 0x02, 0x00, 0x00, 0xF4, 0x1E, 0x6F, 0xEF, 0x65, + 0xA3, 0xF5, 0x51, 0x91, 0x74, 0xB1, 0xF0, 0x08, 0x17, 0x86, 0x47, 0x18, 0x1F, 0x4D, 0x6F, 0x3F, + 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x4E, 0x06, 0x46, 0xB3, 0x89, 0x90, 0xC8, + 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xFC, 0x77, 0xC3, 0x5E, 0xFC, 0x9C, 0x31, 0xC7, 0x6E, 0x1B, 0x08, 0xBE, 0x7C, 0x01, 0x00, 0x00, + 0x7A, 0x8F, 0xD9, 0x63, 0x0F, 0x5B, 0x32, 0x2E, 0x5A, 0x4D, 0x84, 0x47, 0x64, 0xC9, 0x6E, 0x3F, + 0x2A, 0xF1, 0xD1, 0xFE, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, + 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xFE, 0xDD, 0x32, 0xDE, 0x84, 0x05, 0x00, + 0x00, 0x7A, 0x99, 0x19, 0xE9, 0x9F, 0x6D, 0x76, 0xCF, 0xB3, 0xC1, 0xA0, 0x02, 0xA3, 0xD9, 0x74, + 0x74, 0xF8, 0x4B, 0x7C, 0xFB, 0x31, 0xD3, 0x9C, 0x09, 0xE3, 0xA3, 0xAD, 0xDB, 0x0F, 0x11, 0x12, + 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xFE, 0x2E, 0x9B, 0x77, 0xE2, 0xF6, 0xC1, 0xE0, 0x4B, 0x18, 0x00, 0x00, 0xA0, 0xB7, 0xD8, + 0x00, 0x19, 0x48, 0xFF, 0x06, 0x2C, 0x11, 0x1D, 0xB1, 0xA9, 0xDB, 0x8F, 0x6A, 0x80, 0x84, 0xF1, + 0x91, 0xCB, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, + 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7F, 0xB7, 0xCD, 0x3B, 0xFA, 0x85, 0xD1, 0xE0, 0x4B, + 0x18, 0x00, 0x00, 0xA0, 0xB7, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0x3E, 0x60, 0xA3, 0x41, 0x85, + 0x86, 0x9A, 0x0E, 0x8E, 0xEA, 0x12, 0xDC, 0x7E, 0x4C, 0x3C, 0x31, 0xD3, 0x4C, 0x3C, 0x16, 0xB9, + 0xFD, 0x08, 0xE3, 0xC3, 0xED, 0xFB, 0xC4, 0x47, 0x65, 0x22, 0x1C, 0xF2, 0x98, 0x0C, 0x87, 0x3C, + 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0xB0, 0xDF, 0x95, 0x3B, 0x76, 0x0B, 0x6F, + 0xC2, 0x02, 0x00, 0x00, 0xBD, 0xC9, 0x1B, 0x59, 0xB1, 0xA1, 0x3E, 0x32, 0x1A, 0x4D, 0x04, 0x47, + 0x7C, 0xF1, 0x00, 0xA9, 0x7B, 0xF6, 0xC3, 0xC6, 0x47, 0xB3, 0xDB, 0x8F, 0x6F, 0xA8, 0xD0, 0x50, + 0x13, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, + 0x14, 0x35, 0x71, 0xC8, 0xEF, 0xE6, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xAB, 0xBC, 0x7D, 0x57, + 0x24, 0x7C, 0x03, 0x96, 0x88, 0x8D, 0xE8, 0x6C, 0x70, 0x54, 0xE3, 0xC3, 0x86, 0xC7, 0xE4, 0xED, + 0x47, 0xE4, 0x5B, 0xAF, 0x06, 0x6D, 0x7C, 0x44, 0x6F, 0x3F, 0xEC, 0x6A, 0x6E, 0x3F, 0x36, 0x24, + 0xBD, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, + 0x54, 0x24, 0x14, 0x35, 0x71, 0xC0, 0xEF, 0xF6, 0x8D, 0x2D, 0xE5, 0x4D, 0x58, 0x00, 0x00, 0xA0, + 0x37, 0x79, 0x7B, 0x2F, 0x1B, 0xAF, 0x8F, 0x8D, 0xF8, 0x62, 0xB1, 0xA1, 0x16, 0x0D, 0x10, 0xBB, + 0xEA, 0xB7, 0x5E, 0x85, 0x01, 0x62, 0xE3, 0x63, 0xF2, 0xF6, 0x63, 0x66, 0x1B, 0xB7, 0x1F, 0x22, + 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0x26, 0x0E, 0xF7, 0xBD, 0xB0, 0x17, 0xAF, 0x31, 0xDE, 0x2F, 0x6E, 0xBF, 0x2B, 0xF8, 0x32, 0x06, + 0x00, 0x00, 0xE8, 0x1D, 0xAD, 0xDF, 0x80, 0x15, 0x0B, 0x0D, 0xB5, 0x58, 0x7C, 0x84, 0xB7, 0x1F, + 0x93, 0x0F, 0x9E, 0xDB, 0xF8, 0x88, 0xDF, 0x7E, 0x84, 0xF1, 0x11, 0x06, 0x48, 0xA2, 0xDB, 0x0F, + 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, + 0x51, 0x13, 0x07, 0xFB, 0x1E, 0x9A, 0x77, 0xFC, 0x8E, 0x0D, 0xC1, 0x97, 0x31, 0x00, 0x00, 0x40, + 0x6F, 0xF0, 0xDF, 0x80, 0xB5, 0x73, 0xB6, 0x8D, 0x08, 0x15, 0x1E, 0x6E, 0xB1, 0xD0, 0x50, 0x6B, + 0x10, 0x1F, 0xD5, 0x07, 0xCF, 0x37, 0xCE, 0xAC, 0xBF, 0xFD, 0x08, 0xE2, 0xA3, 0x7A, 0xFB, 0xF1, + 0xA0, 0xDD, 0xD7, 0x55, 0x70, 0x44, 0x27, 0x42, 0x22, 0xCB, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, + 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xFA, 0x50, 0xDF, 0x4B, 0xF3, 0x8E, 0xDE, 0xCA, + 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x6F, 0x31, 0x23, 0xCB, 0xD7, 0x35, 0x7E, 0x05, 0x6F, 0x2C, 0x34, + 0x1A, 0x4D, 0x05, 0x48, 0xF5, 0x5B, 0xAF, 0x6C, 0x7C, 0x84, 0xB7, 0x1F, 0x41, 0x7C, 0xC8, 0x37, + 0x5F, 0x7D, 0xB7, 0xD5, 0xED, 0x87, 0x08, 0x89, 0x2C, 0x13, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, + 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0xE9, 0x03, 0x7D, 0xAF, 0xCD, 0x3B, 0xFA, 0xF9, 0xF1, + 0xE0, 0x4B, 0x19, 0x00, 0x00, 0xA0, 0x37, 0xD8, 0x00, 0x59, 0x5F, 0x1F, 0x1E, 0x29, 0xE2, 0xC3, + 0x2D, 0x1E, 0x1F, 0xD5, 0xDB, 0x8F, 0xC9, 0xF8, 0xA8, 0x79, 0xF3, 0x55, 0xEA, 0xDB, 0x0F, 0x11, + 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, + 0xD3, 0x87, 0xF9, 0x9E, 0x9C, 0x7B, 0x13, 0xD6, 0xD8, 0x17, 0x67, 0x05, 0x5F, 0xCE, 0x00, 0x00, + 0x00, 0xDD, 0xCF, 0x3B, 0x70, 0xD5, 0x50, 0xBB, 0xF1, 0xA1, 0x6F, 0x3F, 0x6C, 0x7C, 0xD4, 0xDD, + 0x7E, 0x5C, 0x98, 0xE1, 0xF6, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, + 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBE, 0x97, 0x37, 0xB6, 0x9C, 0x37, 0x61, + 0x01, 0x00, 0x80, 0xDE, 0xE2, 0xED, 0xBD, 0x7C, 0x2C, 0x73, 0x7C, 0xB8, 0xC5, 0xE3, 0xC3, 0x0F, + 0x90, 0x19, 0x39, 0xDD, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xC0, 0xF7, 0xFA, 0x78, 0x13, 0x16, 0x00, 0x00, + 0xE8, 0x35, 0x66, 0x68, 0x81, 0x0D, 0x89, 0xEC, 0xF1, 0xE1, 0x7E, 0xAC, 0xBD, 0xFD, 0xB0, 0xF1, + 0x11, 0xFB, 0xF6, 0xAB, 0xA6, 0xB7, 0x1F, 0xF7, 0x35, 0xBA, 0xFD, 0x10, 0x21, 0x91, 0x65, 0x22, + 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x78, 0x2F, + 0xC3, 0x9E, 0xBF, 0x9C, 0x37, 0x61, 0x01, 0x00, 0x80, 0xDE, 0x61, 0x0E, 0xF4, 0x2F, 0x31, 0xBB, + 0x2E, 0xB5, 0x11, 0x91, 0x21, 0x3E, 0xDC, 0xC2, 0xF0, 0x08, 0xE3, 0xE3, 0xE9, 0x19, 0x35, 0xB7, + 0x1F, 0xB5, 0x6F, 0xBE, 0x12, 0xF1, 0xF1, 0x80, 0x1D, 0xF1, 0x91, 0xCF, 0x64, 0x38, 0xE4, 0x31, + 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x07, 0xF7, 0x12, 0xCD, 0x3B, 0xFE, 0x67, 0xBC, + 0x09, 0x0B, 0x00, 0x00, 0xF4, 0x06, 0xFF, 0x15, 0xBC, 0xFE, 0x1B, 0xB0, 0x44, 0x5C, 0xB4, 0x9A, + 0x8D, 0x0E, 0xF7, 0xE3, 0x64, 0x80, 0x04, 0xF1, 0xD1, 0xE0, 0xD9, 0x0F, 0xF9, 0xA1, 0x83, 0xF7, + 0xAA, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, + 0x4C, 0x45, 0x42, 0x51, 0xD3, 0x87, 0xF6, 0x32, 0xCD, 0x3B, 0xFA, 0xF9, 0x93, 0xC1, 0x97, 0x34, + 0x00, 0x00, 0x40, 0x77, 0xF3, 0xDF, 0x80, 0xB5, 0xE5, 0xFD, 0xF5, 0x71, 0x91, 0x64, 0x61, 0x78, + 0x84, 0xF1, 0x11, 0xBB, 0xFD, 0xA8, 0x7B, 0xF6, 0xC3, 0x06, 0xC8, 0x29, 0x17, 0x20, 0x4D, 0x6F, + 0x3F, 0x44, 0x48, 0x64, 0x99, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1F, 0xD8, 0x4B, 0xB7, 0x23, 0xAB, 0x4C, 0xF0, 0x25, 0x0D, 0x00, 0x00, 0xD0, + 0xDD, 0xBC, 0xE1, 0x65, 0x83, 0x32, 0x2E, 0x5A, 0xCD, 0x46, 0x87, 0xFB, 0xB1, 0x12, 0x20, 0x33, + 0xF4, 0xED, 0x47, 0x2C, 0x3E, 0x5A, 0xDF, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, + 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA8, 0x97, 0x75, 0x63, 0xCB, + 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0D, 0xDE, 0xDE, 0xCB, 0x46, 0xEB, 0xE2, 0x22, 0xC9, 0xAA, + 0xB7, 0x1F, 0x41, 0x7C, 0x24, 0xBD, 0xFD, 0x08, 0x03, 0xE4, 0x07, 0x76, 0xC4, 0x47, 0x7B, 0x93, + 0xE1, 0x90, 0xC7, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0xBA, 0x7F, + 0x5D, 0x68, 0xCC, 0x0B, 0x57, 0x1B, 0x73, 0xFC, 0x8E, 0x75, 0xC1, 0x97, 0x35, 0x00, 0x00, 0x40, + 0xF7, 0xF2, 0xF6, 0x2C, 0x18, 0x97, 0x81, 0xD1, 0x6C, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0x59, 0x6F, + 0x3F, 0xEE, 0x89, 0xDE, 0x7E, 0x88, 0x90, 0xC8, 0x32, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2E, 0x3E, 0xDC, 0x7E, 0x6E, + 0xFF, 0x99, 0x38, 0x71, 0xDB, 0xFA, 0xE0, 0xCB, 0x1A, 0x00, 0x00, 0xA0, 0x3B, 0x99, 0xA1, 0xFE, + 0x59, 0x66, 0xF7, 0xDC, 0xFA, 0xC0, 0x68, 0xB5, 0xF0, 0xE6, 0x23, 0x97, 0xDB, 0x0F, 0x11, 0x12, + 0x59, 0x26, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x2E, 0x8C, 0x8F, 0x60, 0xDE, 0x89, 0xDB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, + 0x6E, 0x66, 0x64, 0xE9, 0x80, 0xD9, 0xF1, 0x71, 0x1D, 0x19, 0xCD, 0x16, 0xC6, 0x47, 0xDB, 0xB7, + 0x1F, 0x22, 0x24, 0xB2, 0x4C, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, + 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x5D, 0x2C, 0x3E, 0xFC, 0x00, 0x39, 0x7A, 0x33, 0x6F, 0xC2, + 0x02, 0x00, 0x00, 0xDD, 0xCD, 0x1B, 0x5E, 0x7E, 0x97, 0xD9, 0xFA, 0x21, 0x1D, 0x19, 0x8D, 0x16, + 0x8F, 0x8F, 0x66, 0xB7, 0x1F, 0x61, 0x7C, 0xC8, 0xDB, 0x0F, 0x11, 0x12, 0x59, 0x26, 0xC2, 0xC3, + 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, + 0xC4, 0x87, 0xBF, 0x23, 0x37, 0xF0, 0x26, 0x2C, 0x00, 0x00, 0xD0, 0xDD, 0xFC, 0x57, 0xF0, 0xAA, + 0xC8, 0x68, 0x34, 0x1B, 0x1D, 0x8D, 0x6E, 0x3F, 0xAA, 0x01, 0xD2, 0xEA, 0xF6, 0xE3, 0x1B, 0xC4, + 0x47, 0xA6, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, + 0x65, 0x9D, 0x0A, 0x8F, 0x70, 0x2F, 0xF5, 0xBB, 0x07, 0xD1, 0x97, 0x04, 0x5F, 0xDE, 0x00, 0x00, + 0x00, 0xDD, 0xC7, 0x3B, 0x70, 0x75, 0xF2, 0x37, 0x60, 0x45, 0xE3, 0xC3, 0x86, 0x47, 0xA3, 0xDB, + 0x8F, 0x09, 0x17, 0x20, 0x8F, 0x45, 0x6E, 0x3F, 0xC2, 0xF8, 0x70, 0xDB, 0xE0, 0xBE, 0xF5, 0x4A, + 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xD1, 0x11, 0x9D, 0x7B, 0x13, 0xD6, 0x89, 0x3F, 0x5F, 0x1B, + 0x7C, 0x79, 0x03, 0x00, 0x00, 0x74, 0x1F, 0x6F, 0xDF, 0xE5, 0x27, 0x65, 0x6C, 0xC4, 0x17, 0xC4, + 0x47, 0xA3, 0xDB, 0x8F, 0xC4, 0xCF, 0x7E, 0x7C, 0x43, 0x84, 0x44, 0x96, 0x89, 0xF0, 0x70, 0x23, + 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xC1, + 0x11, 0x1F, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0xDD, 0x2E, 0xD1, 0x1B, 0xB0, 0xE2, 0xF1, 0x51, 0x73, + 0xFB, 0x11, 0xF9, 0xD6, 0xAB, 0xF8, 0xED, 0x87, 0x5D, 0xED, 0xED, 0x47, 0x4E, 0xDF, 0x7A, 0x25, + 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, + 0xB2, 0x4E, 0xC5, 0x46, 0x83, 0x79, 0xC7, 0x6F, 0x1F, 0x0A, 0xBE, 0xBC, 0x01, 0x00, 0x00, 0xBA, + 0x8B, 0x39, 0x70, 0xFD, 0x12, 0xB3, 0xF3, 0x53, 0x3A, 0x3A, 0xC2, 0x45, 0xE2, 0xA3, 0x1A, 0x20, + 0x76, 0xD5, 0x6F, 0xBD, 0x0A, 0x03, 0xA4, 0xE6, 0xB5, 0xBB, 0x33, 0xC5, 0xED, 0xC7, 0xCC, 0x7C, + 0x6E, 0x3F, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, + 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0xC8, 0x68, 0x36, 0xEF, 0xC8, 0x9A, 0xB1, 0xE0, 0x4B, 0x1C, 0x00, + 0x00, 0xA0, 0xBB, 0x98, 0x83, 0xCB, 0xD6, 0x9A, 0xED, 0x1F, 0xD5, 0xE1, 0xE1, 0x16, 0x09, 0x8F, + 0x68, 0x7C, 0x84, 0xB7, 0x1F, 0x35, 0x0F, 0x9E, 0x37, 0x7A, 0xF6, 0xC3, 0x0F, 0x10, 0x1B, 0x1F, + 0xDF, 0xCD, 0xE1, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, + 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x08, 0x8C, 0x96, 0x3B, 0xBA, 0x86, 0x37, 0x61, 0x01, + 0x00, 0x80, 0xEE, 0xE4, 0xBF, 0x01, 0x6B, 0xF3, 0xAC, 0x4C, 0xF1, 0x51, 0x7D, 0xF0, 0x5C, 0xDD, + 0x7E, 0x04, 0xF1, 0x51, 0xB9, 0xFD, 0xB0, 0xF1, 0xF1, 0xA0, 0xDD, 0xD7, 0x45, 0x50, 0xA4, 0x99, + 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, + 0xCB, 0x3A, 0x15, 0x17, 0x49, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB7, 0xF2, 0x0E, 0x7C, 0x6E, + 0x28, 0x49, 0x7C, 0xD4, 0x05, 0x48, 0xFC, 0xB5, 0xBB, 0xEE, 0xF6, 0x23, 0x88, 0x8F, 0xDA, 0x37, + 0x5F, 0xD9, 0xF0, 0xC8, 0xE3, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x0A, 0x8B, 0xA4, 0x7B, 0xE1, 0x5A, 0x63, + 0x8E, 0xDD, 0x36, 0x10, 0x7C, 0x99, 0x03, 0x00, 0x00, 0x74, 0x0F, 0x6F, 0xEF, 0x65, 0xF5, 0xAF, + 0xE0, 0x8D, 0x44, 0x87, 0x8C, 0x8F, 0xE8, 0xED, 0x47, 0x10, 0x1F, 0x35, 0x6F, 0xBE, 0xAA, 0xDE, + 0x7E, 0x04, 0xF1, 0xD1, 0xEE, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, + 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x15, 0x69, 0xF6, 0xFC, 0x67, 0x79, + 0x13, 0x16, 0x00, 0x00, 0xE8, 0x4E, 0x66, 0x8F, 0x3D, 0xEC, 0xB4, 0x88, 0x0F, 0x37, 0x75, 0xFB, + 0x51, 0x7D, 0xED, 0x6E, 0xF5, 0xF6, 0xE3, 0xC2, 0xC8, 0xED, 0x47, 0x10, 0x1F, 0xED, 0xDE, 0x7E, + 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0x62, 0x07, + 0xF4, 0x32, 0x4F, 0x05, 0x45, 0x86, 0x79, 0x27, 0x6E, 0x1B, 0x0C, 0xBE, 0xCC, 0x01, 0x00, 0x00, + 0xBA, 0x83, 0x19, 0xE9, 0x9F, 0x5D, 0xF3, 0x0A, 0xDE, 0x48, 0x70, 0x44, 0x97, 0xFE, 0xF6, 0x63, + 0xE6, 0x64, 0x80, 0x3C, 0x60, 0xA7, 0xC2, 0x22, 0xC9, 0x44, 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, + 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0x89, 0x90, 0xC8, 0x3A, 0xEF, + 0xC8, 0xE7, 0x47, 0x83, 0x2F, 0x75, 0x00, 0x00, 0x80, 0xEE, 0x60, 0x46, 0x96, 0x0E, 0x54, 0xDF, + 0x80, 0x15, 0x09, 0x8E, 0xF8, 0xD4, 0xED, 0x47, 0xFD, 0xB3, 0x1F, 0xE1, 0xED, 0x47, 0x24, 0x3E, + 0xDC, 0xEE, 0xCD, 0x78, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, + 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x44, 0x44, 0x5B, 0xE3, 0x4D, 0x58, 0x00, 0x00, + 0xA0, 0xDB, 0x78, 0xC3, 0xCB, 0xEF, 0x32, 0x5B, 0xDE, 0x2F, 0xA3, 0x23, 0x5C, 0xB3, 0xDB, 0x8F, + 0xDA, 0x37, 0x5F, 0x89, 0xF8, 0xC8, 0x7A, 0xFB, 0x21, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, + 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x05, 0x44, 0xBB, 0x73, 0x6F, + 0xC2, 0x7A, 0xF9, 0xCE, 0xD9, 0xC1, 0x97, 0x3B, 0x00, 0x00, 0x40, 0xE7, 0x79, 0x23, 0xCB, 0x36, + 0xA8, 0xE8, 0x88, 0x4E, 0xDD, 0x7E, 0xD4, 0x3F, 0xFB, 0xE1, 0x3E, 0x74, 0xD0, 0xBD, 0x7A, 0x37, + 0x12, 0x20, 0xEE, 0x43, 0x07, 0xB3, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, + 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x53, 0xF1, 0x90, 0xC7, 0x5E, 0xBC, + 0x9E, 0x37, 0x61, 0x01, 0x00, 0x80, 0xEE, 0xE2, 0xED, 0xBD, 0x62, 0x54, 0x45, 0x47, 0xB8, 0x66, + 0xB7, 0x1F, 0xD5, 0x67, 0x3F, 0xFC, 0xD7, 0xEE, 0x06, 0xF1, 0xE1, 0xD6, 0xCE, 0xED, 0x87, 0x08, + 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, + 0x3A, 0x15, 0x0E, 0x79, 0xED, 0x85, 0xAB, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x2E, 0xDE, 0xDE, + 0xC5, 0xE3, 0x2A, 0x3C, 0xC2, 0x35, 0xBD, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC5, 0x87, 0xBA, 0xFD, + 0xB8, 0x27, 0xE5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x15, 0x0D, 0x39, 0xCF, 0x3B, 0xB6, 0x96, 0x37, 0x61, + 0x01, 0x00, 0x80, 0xEE, 0xE1, 0xBF, 0x01, 0x2B, 0x12, 0x1C, 0xD1, 0xB5, 0xBC, 0xFD, 0xB0, 0xF1, + 0x31, 0xF1, 0xD8, 0x8C, 0xDA, 0xDB, 0x8F, 0x30, 0x40, 0x7E, 0x60, 0xA7, 0x22, 0xA3, 0xD1, 0x44, + 0x78, 0xB8, 0x11, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0x89, 0x58, 0x28, 0x62, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0E, 0xFE, + 0x1B, 0xB0, 0x76, 0x7C, 0x52, 0xC6, 0x87, 0x5B, 0xCB, 0xDB, 0x8F, 0x30, 0x3E, 0xDA, 0xBD, 0xFD, + 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, + 0x7A, 0x59, 0x27, 0x42, 0xA1, 0xA8, 0x79, 0x47, 0x6F, 0x1E, 0x0F, 0xBE, 0xE4, 0x01, 0x00, 0x00, + 0x3A, 0xCB, 0x8C, 0x2C, 0x5F, 0x67, 0xB6, 0x7D, 0xA4, 0x75, 0x7C, 0xC8, 0xDB, 0x8F, 0x19, 0xF9, + 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, + 0xC4, 0x21, 0xBD, 0xAC, 0x13, 0x91, 0x50, 0xE8, 0xDC, 0x9B, 0xB0, 0xC6, 0xBE, 0x38, 0x2B, 0xF8, + 0xB2, 0x07, 0x00, 0x00, 0xE8, 0x1C, 0x1B, 0x20, 0xEB, 0x55, 0x7C, 0xB8, 0xA9, 0xDB, 0x0F, 0x3F, + 0x40, 0x44, 0x7C, 0x64, 0xBE, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, + 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA1, 0xE8, 0xF1, 0x26, 0x2C, 0x00, + 0x00, 0xD0, 0x2D, 0xBC, 0x03, 0x57, 0x0D, 0x35, 0x8C, 0x0F, 0x1B, 0x1E, 0xF2, 0xF6, 0xE3, 0x09, + 0x1B, 0x1F, 0x2E, 0x40, 0x1E, 0x8D, 0xDC, 0x7E, 0x84, 0xF1, 0xE1, 0xB6, 0x81, 0xF8, 0xA8, 0x9B, + 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xA9, + 0x38, 0x98, 0x8A, 0xBD, 0x70, 0xB5, 0xF1, 0x7E, 0x71, 0xFB, 0x5D, 0xC1, 0x97, 0x3D, 0x00, 0x00, + 0x40, 0xE7, 0x78, 0x7B, 0x2F, 0x1B, 0x6B, 0x18, 0x20, 0x6E, 0x91, 0xDB, 0x0F, 0x17, 0x1F, 0x67, + 0x07, 0x67, 0xD4, 0xDE, 0x7E, 0xA8, 0x67, 0x3F, 0xBE, 0x21, 0x62, 0x23, 0x3E, 0x11, 0x1E, 0x6E, + 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x2A, + 0x0C, 0xA6, 0x70, 0xDE, 0xF1, 0xDB, 0x36, 0x04, 0x5F, 0xF6, 0x00, 0x00, 0x00, 0x9D, 0x63, 0x86, + 0xE6, 0xEB, 0xF8, 0xA8, 0xB9, 0xFD, 0x08, 0xBF, 0xF5, 0xCA, 0xC6, 0x47, 0x1E, 0xB7, 0x1F, 0x22, + 0x3C, 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, + 0xEB, 0x44, 0x10, 0x4C, 0xF5, 0xBC, 0xE3, 0x7F, 0xC6, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x67, 0x99, + 0x91, 0xFE, 0xD9, 0x66, 0xE7, 0x25, 0x3A, 0x40, 0xEC, 0xA2, 0xDF, 0x7A, 0x75, 0xEE, 0xC9, 0x19, + 0xE6, 0xAC, 0x8D, 0x8F, 0xC9, 0xDB, 0x8F, 0x19, 0xFA, 0xD9, 0x8F, 0x56, 0xB7, 0x1F, 0x22, 0x3C, + 0xDC, 0x88, 0x8F, 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, + 0x44, 0x0C, 0x74, 0x62, 0xBC, 0x09, 0x0B, 0x00, 0x00, 0x74, 0x9C, 0xFF, 0x0A, 0xDE, 0xD8, 0x1B, + 0xB0, 0x6A, 0xBE, 0xF5, 0xCA, 0xEE, 0x9C, 0x0B, 0x10, 0x17, 0x1F, 0xF1, 0xDB, 0x8F, 0x68, 0x7C, + 0x84, 0x01, 0x72, 0x7F, 0x8B, 0xDB, 0x0F, 0x11, 0x1E, 0x6E, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, + 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0x22, 0x04, 0x3A, 0xB6, 0x97, 0x56, 0x99, + 0xE0, 0x4B, 0x1F, 0x00, 0x00, 0xA0, 0x33, 0xFC, 0x37, 0x60, 0x6D, 0xFE, 0xE3, 0x86, 0xF1, 0x51, + 0xB9, 0xFD, 0xB0, 0xF1, 0xD1, 0xE0, 0xF6, 0xC3, 0xC5, 0x47, 0xF5, 0xF6, 0xE3, 0x41, 0xBB, 0xAF, + 0x8B, 0xE8, 0x08, 0x27, 0xC2, 0xC3, 0x8D, 0xF8, 0x48, 0x33, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, + 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x45, 0x40, 0x27, 0x37, 0xB6, 0x8C, 0x37, 0x61, 0x01, 0x00, + 0x80, 0xCE, 0xF2, 0x86, 0x97, 0x0D, 0x36, 0xBC, 0xFD, 0x08, 0xE2, 0xA3, 0xE6, 0xF6, 0x23, 0x88, + 0x8F, 0x9A, 0xDB, 0x8F, 0xF0, 0xD9, 0x8F, 0xEF, 0x36, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, 0x46, 0x7C, + 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0xA7, 0x02, 0xA0, + 0xD3, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0xF2, 0x07, 0x00, 0x00, 0x98, 0x7A, + 0xDE, 0xDE, 0xCB, 0x46, 0x1B, 0xDE, 0x7E, 0x6C, 0xBC, 0xA0, 0x26, 0x3E, 0xEA, 0x3E, 0x74, 0x30, + 0xE9, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x75, 0xF8, 0xEF, 0xF8, 0x16, 0xD8, 0x5F, 0x9B, 0xFD, 0xDF, 0xE1, + 0xC4, 0x6D, 0xEB, 0x83, 0x2F, 0x7F, 0x00, 0x00, 0x80, 0xA9, 0xE7, 0xED, 0x9E, 0x3F, 0xAE, 0x6F, + 0x3F, 0x6C, 0x7C, 0x84, 0xDF, 0x7A, 0x55, 0x73, 0xFB, 0x31, 0x33, 0xDD, 0xED, 0x87, 0x08, 0x0F, + 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, 0xE4, 0xB1, 0x78, 0x20, 0x14, 0x39, 0x71, 0x48, 0x2F, 0xEB, + 0xE4, 0xE1, 0xBF, 0xD3, 0xB3, 0xF1, 0x11, 0xCC, 0x3B, 0xBE, 0x96, 0x37, 0x61, 0x01, 0x00, 0x80, + 0xCE, 0x30, 0x43, 0xFD, 0xB3, 0xCC, 0xEE, 0xB9, 0x32, 0x3E, 0x72, 0xB9, 0xFD, 0x10, 0xE1, 0xE1, + 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, + 0x0F, 0xFF, 0x9D, 0xDE, 0x64, 0x7C, 0xF8, 0x01, 0x72, 0xF4, 0xE6, 0x93, 0xC1, 0x1F, 0x01, 0x00, + 0x00, 0x00, 0x53, 0xCB, 0x7F, 0x03, 0xD6, 0xF6, 0x8B, 0x6B, 0x03, 0x24, 0x8C, 0x0F, 0xF9, 0xEC, + 0x47, 0x83, 0xDB, 0x8F, 0x7B, 0xC5, 0xED, 0x87, 0x08, 0x0F, 0x37, 0xE2, 0x23, 0xCD, 0x54, 0x38, + 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x6A, 0xE3, + 0xC3, 0xDF, 0x91, 0x1B, 0x78, 0x13, 0x16, 0x00, 0x00, 0xE8, 0x0C, 0x33, 0xB2, 0x7C, 0x9D, 0xD9, + 0xFA, 0xC1, 0xC8, 0xED, 0x87, 0x8D, 0x8F, 0xD8, 0xED, 0x47, 0xED, 0x9B, 0xAF, 0x44, 0x7C, 0x3C, + 0x60, 0x47, 0x7C, 0x14, 0x30, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x11, 0x1F, 0x6E, 0x2F, 0xF5, 0xF3, 0x26, 0x2C, 0x00, 0x00, 0xD0, + 0x19, 0xE6, 0xE0, 0xF2, 0xF5, 0xD5, 0xDB, 0x0F, 0x1B, 0x1F, 0xD1, 0xDB, 0x0F, 0xF5, 0xEC, 0xC7, + 0xE9, 0x78, 0x80, 0xB8, 0x0F, 0x1D, 0x8C, 0xDF, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, + 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, + 0x84, 0x47, 0x38, 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x00, 0x00, 0x00, 0x60, + 0xEA, 0x78, 0xFB, 0xAE, 0x1E, 0xAD, 0x89, 0x8F, 0x24, 0xCF, 0x7E, 0xB8, 0x35, 0xBA, 0xFD, 0x10, + 0xE1, 0xE1, 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, + 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x88, 0x8E, 0xE8, 0xDC, 0x3F, 0x67, 0xBC, 0x09, 0x0B, 0x00, + 0x00, 0x74, 0x82, 0xB7, 0xF7, 0xF2, 0x93, 0x7E, 0x7C, 0x34, 0xBA, 0xFD, 0x88, 0xC6, 0x87, 0xBA, + 0xFD, 0xF8, 0x76, 0xE4, 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, + 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x38, 0xC4, 0xBC, + 0xE3, 0xB7, 0x0F, 0x05, 0x7F, 0x0C, 0x00, 0x00, 0x00, 0x4C, 0x1D, 0x6F, 0xE7, 0x9C, 0xF4, 0xB7, + 0x1F, 0x61, 0x80, 0xFC, 0xC0, 0x8E, 0xF8, 0xC8, 0x71, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, + 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x36, 0xD4, 0xBC, 0x23, 0x6B, 0xC6, + 0x82, 0x3F, 0x06, 0x00, 0x00, 0x00, 0xA6, 0x86, 0x39, 0x70, 0xFD, 0x12, 0x6F, 0xFB, 0x27, 0xB2, + 0xDF, 0x7E, 0xDC, 0x13, 0xDC, 0x7E, 0x88, 0xF0, 0x70, 0x23, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, + 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x87, 0x46, 0xC3, + 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x30, 0xD5, 0xCC, 0xC1, 0x65, 0x6B, 0xBD, 0xAD, 0x1F, 0x6E, 0xEF, + 0xF6, 0x43, 0x84, 0x87, 0x1B, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, + 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x30, 0x5A, 0xCD, 0xBD, 0x09, 0xEB, 0xF8, + 0x1D, 0x4B, 0x82, 0x3F, 0x0E, 0x00, 0x00, 0x00, 0x8A, 0x77, 0xFE, 0xE0, 0xD2, 0xF5, 0xDE, 0xA6, + 0x0B, 0x33, 0xDE, 0x7E, 0x10, 0x1F, 0xF9, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, + 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC4, 0x45, 0x92, 0xBD, 0x70, 0x0D, 0x6F, 0xC2, + 0x02, 0x00, 0x00, 0x53, 0xEB, 0xFC, 0xFE, 0x6B, 0x06, 0xB3, 0xDD, 0x7E, 0xCC, 0x90, 0xE1, 0xE1, + 0x46, 0x7C, 0xA4, 0x99, 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, + 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x8B, 0xA4, 0x7B, 0xFE, 0x0A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xA6, + 0xD6, 0xF9, 0xDD, 0x8B, 0x47, 0xA3, 0xB7, 0x1F, 0xD5, 0x00, 0x89, 0xC5, 0x47, 0xDD, 0xED, 0xC7, + 0xDD, 0xC4, 0x47, 0xFB, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, + 0xE4, 0xE1, 0xBF, 0xD3, 0x13, 0x51, 0x91, 0x72, 0xDE, 0xB1, 0xB5, 0xBC, 0x09, 0x0B, 0x00, 0x00, + 0x4C, 0x1D, 0x6F, 0xF7, 0x42, 0x79, 0xFB, 0x31, 0xE1, 0x02, 0xE4, 0xD1, 0xC8, 0xED, 0x47, 0x18, + 0x1F, 0x6E, 0xF7, 0xEB, 0x6F, 0xBD, 0x22, 0x3E, 0xD2, 0x4C, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x07, 0x45, 0xDA, 0x79, 0x47, 0x3E, + 0x3F, 0x1A, 0xFC, 0x71, 0x00, 0x00, 0x00, 0x50, 0x2C, 0x33, 0xD2, 0x3F, 0xDB, 0xDB, 0x31, 0x27, + 0xDD, 0xB3, 0x1F, 0x0F, 0xCE, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, + 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x98, 0xC8, 0xB4, 0xA3, + 0x6B, 0x78, 0x13, 0x16, 0x00, 0x00, 0x98, 0x1A, 0x66, 0xFF, 0xD2, 0x81, 0xF3, 0x5B, 0x3E, 0x6C, + 0x03, 0x24, 0xF2, 0xAD, 0x57, 0xCD, 0x6E, 0x3F, 0x1E, 0xB2, 0xF1, 0x21, 0x6E, 0x3F, 0x88, 0x8F, + 0x34, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, + 0xD3, 0x13, 0x11, 0xD1, 0xCE, 0xDC, 0x9B, 0xB0, 0x5E, 0xBE, 0x73, 0x76, 0xF0, 0xC7, 0x02, 0x00, + 0x00, 0x40, 0x71, 0xCE, 0xED, 0x5F, 0x7A, 0xD7, 0xF9, 0x4D, 0xEF, 0x9B, 0x7C, 0xF6, 0xA3, 0xE6, + 0xC1, 0xF3, 0x19, 0xB5, 0xCF, 0x7E, 0xB8, 0xF8, 0x78, 0xA0, 0xFE, 0xF6, 0x83, 0xF8, 0x48, 0x33, + 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, + 0x11, 0x10, 0xED, 0xCE, 0xBD, 0x09, 0xEB, 0xD8, 0x6D, 0x03, 0xC1, 0x1F, 0x0B, 0x00, 0x00, 0x00, + 0xC5, 0x39, 0x7F, 0x60, 0xD9, 0x86, 0x9A, 0x07, 0xCF, 0xA3, 0xB7, 0x1F, 0xD1, 0xF8, 0x78, 0xD8, + 0x86, 0x87, 0x0B, 0x90, 0xEF, 0xD4, 0xDE, 0x7E, 0x10, 0x1F, 0x69, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x21, 0x8F, 0xF1, + 0x26, 0x2C, 0x00, 0x00, 0x30, 0x55, 0xCE, 0xEF, 0x5E, 0x32, 0xEA, 0xC7, 0x47, 0x83, 0xDB, 0x0F, + 0x17, 0x1F, 0xA7, 0xC2, 0xF8, 0x70, 0xB7, 0x1F, 0x7F, 0x4D, 0x7C, 0x64, 0x9B, 0x0A, 0x87, 0x3C, + 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x08, 0x87, 0x1C, + 0xE7, 0x9D, 0xB8, 0x6D, 0x30, 0xF8, 0x63, 0x01, 0x00, 0x00, 0xA0, 0x38, 0xE7, 0x76, 0x2E, 0x3A, + 0x59, 0x73, 0xFB, 0x11, 0xC4, 0x47, 0xF5, 0xD9, 0x8F, 0x30, 0x3E, 0x62, 0xB7, 0x1F, 0xC4, 0x47, + 0x9A, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, + 0xE9, 0xE9, 0x68, 0xC8, 0x73, 0xDE, 0xD1, 0x5B, 0x79, 0x13, 0x16, 0x00, 0x00, 0x28, 0xDE, 0xF9, + 0xED, 0x73, 0xAA, 0xF1, 0x51, 0xF7, 0xA1, 0x83, 0x8F, 0xCC, 0x90, 0xB7, 0x1F, 0xC4, 0x47, 0x9A, + 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, + 0xE9, 0x60, 0xC8, 0x7D, 0x47, 0x3F, 0xCF, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xB1, 0xCE, 0xEE, 0x5F, + 0x3A, 0x70, 0x6E, 0xCB, 0x27, 0x63, 0xB7, 0x1F, 0x33, 0x2B, 0xCF, 0x7E, 0x44, 0xE3, 0xC3, 0xED, + 0xDE, 0xCA, 0xED, 0x07, 0xF1, 0x91, 0x66, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, + 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0x22, 0x14, 0x8A, 0x9A, 0x7B, 0x13, 0xD6, 0xD8, 0x17, + 0x67, 0x05, 0x7F, 0x3C, 0x00, 0x00, 0x00, 0xE4, 0xEF, 0xDC, 0xDE, 0xE5, 0xEB, 0xCE, 0x6D, 0xFA, + 0x48, 0xEC, 0xF6, 0x63, 0x46, 0x35, 0x3E, 0xAA, 0x01, 0xF2, 0x23, 0x3B, 0xE2, 0x23, 0xE5, 0x54, + 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x44, + 0x24, 0x14, 0xB9, 0x17, 0xAF, 0xE3, 0x4D, 0x58, 0x00, 0x00, 0xA0, 0x58, 0xE7, 0xF7, 0x2E, 0x5F, + 0x5F, 0xF7, 0xEC, 0xC7, 0x8F, 0x27, 0x03, 0xA4, 0x7A, 0xFB, 0xF1, 0xED, 0x0B, 0x88, 0x8F, 0x54, + 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, + 0x13, 0x81, 0x50, 0xF4, 0x5E, 0xB8, 0xCA, 0x78, 0xBF, 0xB8, 0xFD, 0xAE, 0xE0, 0x8F, 0x07, 0x00, + 0x00, 0x80, 0xFC, 0x9D, 0xDB, 0x7D, 0xD5, 0x50, 0xCD, 0x9B, 0xAF, 0xC2, 0xF8, 0x88, 0x06, 0xC8, + 0x8F, 0x66, 0x10, 0x1F, 0xA9, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0xE2, 0x60, 0x8A, 0xE6, 0x1D, 0xBF, 0x6D, 0x43, 0xF0, 0xC7, + 0x03, 0x00, 0x00, 0x40, 0xFE, 0xCE, 0xED, 0xB8, 0x6C, 0x6C, 0xF2, 0xF6, 0xE3, 0x02, 0x79, 0xFB, + 0xF1, 0x76, 0xE4, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x06, 0x53, 0x35, 0xDE, 0x84, 0x05, 0x00, + 0x00, 0x0A, 0x75, 0x76, 0xDB, 0xFC, 0xE0, 0xF6, 0xC3, 0xC6, 0x87, 0x78, 0xF6, 0xE3, 0xED, 0x1F, + 0x4C, 0xDE, 0x7E, 0x10, 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, + 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0xA3, 0x60, 0x2A, 0xE7, 0x1D, 0xBD, 0x79, 0x3C, 0xF8, + 0xE3, 0x01, 0x00, 0x00, 0x20, 0x5F, 0x66, 0xA8, 0x7F, 0xF6, 0xD9, 0xCD, 0x97, 0x04, 0xF1, 0x51, + 0x7B, 0xFB, 0x71, 0x2A, 0xBC, 0xFD, 0xF8, 0x66, 0xE5, 0xF6, 0x83, 0xF8, 0x68, 0x35, 0x15, 0x0E, + 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x04, + 0x53, 0xBE, 0x97, 0x56, 0xF2, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x8C, 0xB3, 0x43, 0x4B, 0x07, 0xDE, + 0xDD, 0xF8, 0xE1, 0x6A, 0x80, 0x9C, 0xB6, 0x01, 0x52, 0xF3, 0xEC, 0xC7, 0xF7, 0x2B, 0xB7, 0x1F, + 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, + 0xF0, 0xDF, 0xE9, 0x89, 0x10, 0xE8, 0xD4, 0xC6, 0x96, 0xF1, 0x26, 0x2C, 0x00, 0x00, 0x50, 0x0C, + 0x1B, 0x20, 0xEB, 0x27, 0x06, 0xDF, 0x57, 0x73, 0xFB, 0x11, 0x7D, 0xFE, 0xC3, 0xDD, 0x7E, 0x10, + 0x1F, 0xAD, 0xA6, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, + 0x7F, 0xA7, 0x27, 0x22, 0xA0, 0x93, 0x7B, 0xE1, 0x2A, 0x63, 0x8E, 0xDF, 0xB1, 0x2E, 0xF8, 0x63, + 0x02, 0x00, 0x00, 0x20, 0x3F, 0xEF, 0xEE, 0x59, 0x3A, 0xE8, 0xDF, 0x7E, 0x88, 0xF8, 0x70, 0xB7, + 0x1F, 0xC4, 0x47, 0xAB, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, + 0xF2, 0xF0, 0xDF, 0xE9, 0x89, 0x00, 0xE8, 0xF4, 0xDC, 0x3F, 0x17, 0x27, 0x6E, 0x5B, 0x1F, 0xFC, + 0x31, 0x01, 0x00, 0x00, 0x90, 0x9F, 0x89, 0x6D, 0x8B, 0x47, 0xEB, 0xDE, 0x7C, 0x15, 0xDE, 0x7E, + 0xDC, 0x4D, 0x7C, 0x34, 0x9F, 0x0A, 0x87, 0x3C, 0x16, 0x0F, 0x84, 0x22, 0x27, 0x0E, 0xE9, 0x65, + 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xE2, 0xF0, 0xDF, 0x25, 0xF3, 0x8E, 0xAF, 0xE5, 0x4D, 0x58, 0x00, + 0x00, 0x20, 0x7F, 0x13, 0x5B, 0xFA, 0xC6, 0xE5, 0xC3, 0xE7, 0xF7, 0xBB, 0x6F, 0xBD, 0x22, 0x3E, + 0x1A, 0x4F, 0x85, 0x43, 0x1E, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, + 0x4E, 0x4F, 0x1F, 0xFC, 0xBB, 0x65, 0xDE, 0xD1, 0x9B, 0x4F, 0x06, 0x7F, 0x4C, 0x00, 0x00, 0x00, + 0xE4, 0xC3, 0x0C, 0xF5, 0xCF, 0x7A, 0xF7, 0x99, 0x39, 0x95, 0xF8, 0xB0, 0x8B, 0x3E, 0x7C, 0xFE, + 0xD6, 0x5F, 0x11, 0x1F, 0x8D, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, + 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFD, 0x5D, 0xB5, 0x97, 0x56, 0x9A, 0xE0, 0x8F, 0x0A, + 0x00, 0x00, 0x80, 0x7C, 0xB8, 0x37, 0x60, 0x4D, 0x6C, 0xFC, 0x98, 0x0D, 0x90, 0x0B, 0xCC, 0xE9, + 0x47, 0xEC, 0xDC, 0xED, 0x87, 0x0B, 0x90, 0xFB, 0x6D, 0x80, 0x10, 0x1F, 0x0D, 0xA6, 0xC2, 0x21, + 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xFB, + 0xDD, 0x38, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x7C, 0xDD, 0xC4, 0x13, 0x1F, + 0x30, 0xA7, 0xFD, 0x00, 0x09, 0xBE, 0xFD, 0xEA, 0xE1, 0x99, 0xFE, 0xED, 0x07, 0xF1, 0xA1, 0xA6, + 0xC2, 0x21, 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, + 0x0E, 0xFA, 0xDD, 0x3A, 0xDE, 0x84, 0x05, 0x00, 0x00, 0xF2, 0x36, 0x31, 0xB4, 0x74, 0x7D, 0x78, + 0xFB, 0x71, 0xCA, 0xCD, 0xDD, 0x7E, 0x7C, 0x67, 0x06, 0xF1, 0x21, 0xA7, 0xC2, 0x21, 0x8F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF9, 0xDD, 0x3C, + 0xF7, 0xCF, 0x3D, 0x6F, 0xC2, 0x02, 0x00, 0x00, 0x79, 0x9A, 0xD8, 0x79, 0xD5, 0x68, 0xF5, 0xDB, + 0xAF, 0xDC, 0x0D, 0x88, 0x7B, 0xF6, 0xE3, 0x6B, 0xC4, 0x47, 0xFD, 0x54, 0x38, 0xE4, 0x31, 0x15, + 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, 0x01, 0xBF, 0x07, 0xC6, + 0x9B, 0xB0, 0x00, 0x00, 0x40, 0xAE, 0x26, 0xB6, 0x5D, 0x76, 0xB2, 0x7A, 0x03, 0xF2, 0xF0, 0x0C, + 0xF3, 0xF6, 0x7D, 0xC1, 0xED, 0x87, 0x8D, 0x8F, 0x3F, 0x10, 0x1F, 0xC1, 0x54, 0x38, 0xE4, 0x31, + 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0xE1, 0xBE, 0x17, + 0xE6, 0x1D, 0x59, 0x33, 0x16, 0xFC, 0x71, 0x01, 0x00, 0x00, 0xD0, 0xBE, 0x09, 0xFF, 0x0D, 0x58, + 0x93, 0xB7, 0x1F, 0x6F, 0x7E, 0x6D, 0xF2, 0xE6, 0xE3, 0x0D, 0xE2, 0xC3, 0x4E, 0x85, 0x43, 0x1E, + 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xEC, 0x7B, + 0x66, 0x47, 0x6E, 0xE0, 0x4D, 0x58, 0x00, 0x00, 0x20, 0x1F, 0x13, 0x43, 0xD7, 0x2F, 0x99, 0x78, + 0xFA, 0x13, 0xE6, 0xCC, 0xA3, 0x95, 0xCF, 0xFF, 0x70, 0xB7, 0x1F, 0x95, 0xF8, 0xB8, 0xC0, 0xBF, + 0xF9, 0x78, 0x83, 0xF8, 0x28, 0x68, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, + 0xDF, 0xE9, 0x89, 0x03, 0x7D, 0xAF, 0xED, 0xA5, 0x7E, 0xF7, 0x20, 0xFA, 0x92, 0xE0, 0x8F, 0x0D, + 0x00, 0x00, 0x80, 0xEC, 0xCE, 0x0C, 0x2D, 0x5B, 0x3B, 0xF1, 0xE4, 0x87, 0x2B, 0x9F, 0x01, 0xF2, + 0x60, 0xE5, 0xB5, 0xBB, 0xD5, 0xDB, 0x8F, 0xAF, 0xD9, 0xF8, 0xF8, 0x47, 0xE2, 0x23, 0xFF, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, 0xF3, 0xBD, 0x38, + 0xF7, 0x26, 0xAC, 0x13, 0x7F, 0xBE, 0x36, 0xF8, 0x63, 0x03, 0x00, 0x00, 0x20, 0x3B, 0xF7, 0x06, + 0xAC, 0x89, 0xC7, 0x2F, 0xF2, 0x03, 0xE4, 0xED, 0x6F, 0x55, 0x9E, 0xFB, 0x20, 0x3E, 0xDC, 0x54, + 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xC4, + 0x41, 0xBE, 0x57, 0xE7, 0xBE, 0x26, 0x78, 0x13, 0x16, 0x00, 0x00, 0xC8, 0xC3, 0xD9, 0x5D, 0xD7, + 0x0C, 0x4E, 0x3C, 0x36, 0xC3, 0x9C, 0x71, 0xCF, 0x7E, 0x04, 0x6F, 0xBD, 0xFA, 0xC3, 0x7A, 0xE2, + 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0x27, 0x0E, + 0xF1, 0x3D, 0xBB, 0xF9, 0xFE, 0xBC, 0xE3, 0xB7, 0x0D, 0x05, 0x7F, 0x6C, 0x00, 0x00, 0x00, 0x64, + 0xF7, 0xEE, 0xB6, 0xC5, 0xA3, 0x13, 0x8F, 0xCF, 0x30, 0xEF, 0x7C, 0xBB, 0x72, 0xFB, 0xF1, 0xE6, + 0x5F, 0x5D, 0x44, 0x7C, 0x14, 0x32, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, + 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x57, 0x89, 0x0F, 0x3F, 0x40, 0x8E, 0xDC, 0xCC, 0x9B, 0xB0, + 0x00, 0x00, 0x40, 0xFB, 0xCE, 0x6D, 0x5F, 0x60, 0x26, 0x1E, 0xB9, 0xC0, 0xBC, 0xE5, 0x5E, 0xBB, + 0xFB, 0xD7, 0xC4, 0x47, 0x31, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, + 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0xE1, 0xEF, 0xE8, 0x4D, 0xBC, 0x09, 0x0B, 0x00, + 0x00, 0xB4, 0xC7, 0x0C, 0x5D, 0x3B, 0xFB, 0xDC, 0xB6, 0x4B, 0xCD, 0x3B, 0xDF, 0xB4, 0x01, 0xF2, + 0x75, 0xE2, 0xA3, 0x98, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, + 0xA7, 0x0E, 0xF1, 0xBD, 0xBA, 0x58, 0x7C, 0xB8, 0xBD, 0xB4, 0xC2, 0x98, 0x97, 0xBF, 0x38, 0x3B, + 0xF8, 0xE3, 0x03, 0x00, 0x00, 0x20, 0xBD, 0xB3, 0xFB, 0x97, 0x0E, 0xBC, 0xFB, 0xD8, 0x87, 0xCC, + 0xDB, 0x77, 0x5F, 0x64, 0xCE, 0x13, 0x1F, 0x05, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x89, 0xF8, 0x70, 0x7B, 0xE1, 0x6A, 0x63, + 0x8E, 0xDD, 0x36, 0x10, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDE, 0x99, 0x5D, 0x9F, 0xBB, 0xEB, + 0xD4, 0x86, 0x0F, 0x98, 0xF3, 0xFF, 0x44, 0x7C, 0xE4, 0x3F, 0x15, 0x09, 0x45, 0x4D, 0x1C, 0xD2, + 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0x27, 0xC2, 0x23, 0x98, 0xF7, 0xAF, + 0x4B, 0xCC, 0xE9, 0x9F, 0xDD, 0xCA, 0x9B, 0xB0, 0x00, 0x00, 0x40, 0x76, 0xAF, 0x3D, 0x70, 0xED, + 0x86, 0xF1, 0xDD, 0xAB, 0xCD, 0xD9, 0x17, 0xBF, 0x44, 0x7C, 0xE4, 0x3A, 0x15, 0x09, 0x45, 0x4D, + 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xD4, 0x21, 0xBE, 0x57, 0xA7, 0xC3, 0xC3, 0xED, + 0xD4, 0xB3, 0xF3, 0xCC, 0xEF, 0x77, 0xCC, 0x31, 0xBF, 0xDB, 0x77, 0xD3, 0x60, 0xF0, 0xC7, 0x07, + 0x00, 0x00, 0x40, 0x7A, 0xAF, 0xEF, 0xB9, 0x75, 0xF8, 0xF7, 0x07, 0x6F, 0x35, 0xBF, 0xDF, 0xB7, + 0xD2, 0xBC, 0x79, 0xE0, 0x32, 0x73, 0xFE, 0x9F, 0x55, 0x54, 0x24, 0x9D, 0x08, 0x87, 0x3C, 0x26, + 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, + 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0x4E, 0x87, 0xC7, 0x99, 0xBF, 0xEB, 0x33, 0xE3, 0xBB, + 0xE6, 0x9A, 0xDF, 0x6D, 0xB3, 0xF1, 0xE1, 0xB6, 0x67, 0x39, 0xAF, 0xE2, 0x05, 0x00, 0x00, 0xD9, + 0xFD, 0xF3, 0xFF, 0xFE, 0x17, 0x17, 0xFE, 0x76, 0xFB, 0xEA, 0xFB, 0x7E, 0xB7, 0x6D, 0xF1, 0x5B, + 0xBF, 0xDF, 0xB9, 0xD8, 0xB8, 0xBD, 0x7D, 0xE8, 0x72, 0xFF, 0x5B, 0x2D, 0x74, 0x64, 0x34, 0x9A, + 0x08, 0x87, 0x3C, 0x26, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xA9, 0x43, 0x7C, 0xAF, 0xAE, 0x3E, 0x3C, 0xCE, 0xFE, + 0x43, 0x9F, 0x79, 0x73, 0xEF, 0x64, 0x78, 0xBC, 0xBE, 0x75, 0xCE, 0xF8, 0xEF, 0xB6, 0x5D, 0xBA, + 0x7E, 0xB4, 0xFF, 0x3D, 0x7F, 0x14, 0xFC, 0xF1, 0x01, 0x00, 0x00, 0x90, 0xDD, 0x7F, 0xBF, 0xFB, + 0x33, 0x17, 0xBF, 0xB6, 0x79, 0xF1, 0x96, 0x30, 0x42, 0xC6, 0x77, 0x2F, 0x36, 0xA7, 0xFF, 0xC6, + 0x1E, 0xD4, 0x65, 0x6C, 0xC4, 0x27, 0xC2, 0x21, 0x8F, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, 0xF2, + 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, 0xDF, + 0xAB, 0xAB, 0x0D, 0x8F, 0xF3, 0xFF, 0x34, 0xDF, 0xBC, 0xB5, 0x3F, 0x72, 0xE3, 0x61, 0xF7, 0xEA, + 0x33, 0x73, 0x7E, 0x34, 0x3E, 0xF4, 0xA9, 0x59, 0xC1, 0x1F, 0x17, 0x00, 0x00, 0x00, 0xF9, 0xF9, + 0xEF, 0xDF, 0x5D, 0xF2, 0x99, 0xD7, 0xB6, 0x2C, 0xFA, 0x59, 0x18, 0x22, 0x6F, 0xEC, 0xB9, 0xCC, + 0x4C, 0xFC, 0xBD, 0x0B, 0x02, 0x15, 0x1E, 0x6E, 0xB1, 0x68, 0xC8, 0x6B, 0x32, 0x1C, 0xF2, 0x98, + 0x0A, 0x87, 0x3C, 0xA6, 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, + 0x3A, 0xC4, 0xF7, 0xEA, 0x26, 0xC3, 0xC3, 0xFB, 0xE7, 0xF9, 0xE6, 0x9D, 0x91, 0x79, 0x35, 0xE1, + 0xF1, 0xDA, 0xE6, 0x4B, 0xF7, 0x8F, 0x6F, 0xE9, 0xE3, 0xB5, 0xBB, 0x00, 0x00, 0xA0, 0x78, 0xFF, + 0xEB, 0xA1, 0xCB, 0xBE, 0xF8, 0xBB, 0x6D, 0x8B, 0x7E, 0x19, 0x86, 0x88, 0x7B, 0x3E, 0xE4, 0xEC, + 0x4F, 0x5D, 0x1C, 0x10, 0x1F, 0xF5, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, + 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x75, 0x93, 0xF1, 0x51, 0x7D, 0xC0, 0x3C, 0x08, 0x8F, 0xD7, + 0xB7, 0x5E, 0x3A, 0xF6, 0xDA, 0x96, 0x4B, 0x79, 0xDD, 0x2E, 0x00, 0x00, 0x98, 0x5A, 0xA3, 0xFD, + 0xFD, 0x7F, 0xF4, 0xAB, 0x27, 0x2E, 0xFB, 0x3F, 0xA2, 0xCF, 0x87, 0xBC, 0x35, 0xEC, 0x1E, 0x54, + 0x17, 0xD1, 0x90, 0xD7, 0x64, 0x38, 0xE4, 0x31, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, + 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x75, 0x88, 0xEF, 0xD5, 0x55, 0xC2, 0x23, 0xFE, + 0x80, 0xB9, 0x8D, 0x8E, 0x5F, 0xBE, 0xBE, 0x7D, 0xEE, 0xBA, 0xE0, 0x8F, 0x00, 0x00, 0x00, 0x80, + 0xCE, 0xF8, 0xD5, 0x23, 0x57, 0x7E, 0xE0, 0x37, 0x4F, 0x2E, 0xDE, 0x30, 0x19, 0x22, 0x8B, 0xCC, + 0xE9, 0xBF, 0xB9, 0xCC, 0x78, 0xFF, 0x2A, 0x02, 0xA2, 0x9D, 0xC9, 0x70, 0xC8, 0x63, 0x2A, 0x1C, + 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, 0x77, 0x7A, 0xEA, 0x10, + 0xDF, 0xAB, 0x6B, 0xFC, 0x80, 0x39, 0xCF, 0x79, 0x00, 0x00, 0x80, 0xAE, 0x72, 0xF2, 0x91, 0xC5, + 0xF3, 0x5F, 0x7D, 0x66, 0xF1, 0x0E, 0x17, 0x20, 0x6E, 0xE3, 0xBB, 0x17, 0x99, 0x33, 0x7F, 0x67, + 0x0F, 0xE2, 0x2A, 0x26, 0xD2, 0x4E, 0x86, 0x43, 0x1E, 0x8B, 0x47, 0x43, 0x5E, 0x53, 0x91, 0x50, + 0xD4, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1D, 0xE2, 0x7B, 0x73, 0xEA, 0x01, + 0xF3, 0xDF, 0x6D, 0xBD, 0x74, 0xF0, 0xBF, 0x7D, 0x67, 0xDE, 0x07, 0x82, 0x2F, 0x73, 0x00, 0x00, + 0x80, 0xEE, 0xF3, 0xAB, 0x8D, 0x8B, 0xD6, 0xBC, 0xFA, 0xCC, 0xC2, 0x9F, 0x87, 0x21, 0xF2, 0xC6, + 0x9E, 0xC5, 0xE6, 0xDD, 0x7F, 0xB0, 0x87, 0x7D, 0x15, 0x16, 0x49, 0x26, 0xC3, 0x21, 0x8F, 0xA9, + 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, + 0x83, 0x7C, 0xAF, 0xCD, 0xFB, 0xE7, 0x05, 0x75, 0x0F, 0x98, 0xDB, 0x8D, 0xFE, 0x7F, 0x8F, 0x5E, + 0x3A, 0x27, 0xF8, 0xB2, 0x06, 0x00, 0x00, 0xE8, 0x6E, 0xFE, 0xF3, 0x21, 0x83, 0x8B, 0xFF, 0xE2, + 0x77, 0xDB, 0x16, 0xFE, 0x32, 0x0C, 0x91, 0x37, 0x0F, 0x2C, 0x36, 0x67, 0x7F, 0x6A, 0x0F, 0xFE, + 0x2A, 0x32, 0x1A, 0x4D, 0x86, 0x43, 0x1E, 0x53, 0xE1, 0x90, 0xC7, 0x54, 0x24, 0x14, 0x35, 0x71, + 0x48, 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x87, 0xF9, 0x5E, 0xDB, 0xE9, 0xBF, 0xE9, 0xAB, + 0x79, 0xC0, 0xFC, 0xB5, 0x67, 0xE6, 0x1C, 0xE3, 0x01, 0x73, 0x00, 0x00, 0xD0, 0xB3, 0x6C, 0x88, + 0xFC, 0xBB, 0x57, 0x37, 0x2F, 0xBA, 0xE7, 0x77, 0xDB, 0x16, 0xBD, 0x15, 0x86, 0xC8, 0xDB, 0x87, + 0x12, 0x3E, 0xA8, 0x2E, 0xC3, 0x21, 0x8F, 0xA9, 0x70, 0xC8, 0x63, 0x2A, 0x12, 0x8A, 0x9A, 0x38, + 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xC3, 0x7C, 0x2F, 0x6D, 0xE2, 0xEF, 0xE7, 0xF3, + 0x80, 0x39, 0x00, 0x00, 0x28, 0xAF, 0x93, 0xF7, 0x2E, 0xFC, 0xC8, 0x2B, 0x9B, 0x16, 0x3F, 0x1A, + 0x46, 0x88, 0x7B, 0x3E, 0xA4, 0xE9, 0x83, 0xEA, 0x32, 0x1C, 0xF2, 0x98, 0x0A, 0x87, 0x3C, 0xA6, + 0x22, 0xA1, 0xA8, 0x89, 0x43, 0x7A, 0x59, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x3E, 0xD0, 0xF7, 0xCA, + 0xCE, 0xFE, 0xC3, 0x7C, 0xF3, 0xE6, 0x5E, 0xF7, 0xED, 0x56, 0x95, 0xF8, 0xE0, 0x01, 0x73, 0x00, + 0x00, 0x50, 0x6A, 0xFF, 0xE3, 0xFE, 0xCF, 0x2C, 0x7A, 0x75, 0xF3, 0xA2, 0xE7, 0xA2, 0x21, 0x32, + 0xF1, 0xF7, 0x36, 0x0C, 0x88, 0x8F, 0x84, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, + 0x7D, 0xA8, 0xEF, 0x85, 0x9D, 0xFF, 0xA7, 0x05, 0xE6, 0xED, 0x83, 0x7D, 0x41, 0x78, 0x04, 0x37, + 0x1F, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0xA6, 0x8B, 0x5F, 0x3E, 0xB6, 0xF8, 0x96, 0xD7, 0xB7, 0x2E, + 0x7C, 0x39, 0x0C, 0x11, 0xF7, 0xA0, 0xBA, 0xFF, 0x7C, 0x88, 0x0C, 0x87, 0x3C, 0xA6, 0xC2, 0x21, + 0x8F, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xF6, + 0xDD, 0x3E, 0xF7, 0x80, 0xF9, 0xA9, 0x67, 0xA3, 0xE1, 0xE1, 0xC7, 0x07, 0x0F, 0x98, 0x03, 0x00, + 0x80, 0xE9, 0xC7, 0x3D, 0xA8, 0xFE, 0xDB, 0xA7, 0x17, 0x7F, 0xF5, 0xF5, 0xAD, 0x8B, 0x7E, 0xE3, + 0x22, 0xE4, 0x77, 0x3B, 0x16, 0x9A, 0x37, 0xF7, 0x2F, 0x32, 0xE7, 0xFE, 0xD1, 0x1D, 0xEC, 0x55, + 0x44, 0x64, 0x5D, 0x3C, 0x1A, 0xF2, 0x9A, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, + 0xFC, 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xED, 0xAB, 0x3C, 0x60, 0x3E, 0x19, 0x1E, 0xAF, 0x3D, 0x33, + 0x97, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x7E, 0xF5, 0xC8, 0xBC, 0x0F, 0xFC, 0xE6, 0xE9, 0x85, 0xF7, + 0xBD, 0xBE, 0x75, 0xC1, 0x5B, 0x2E, 0x42, 0xDC, 0xDE, 0x1E, 0x59, 0x6C, 0xBC, 0x7F, 0x51, 0x31, + 0x91, 0x76, 0x2A, 0x1C, 0xF2, 0x98, 0x8A, 0x84, 0xA2, 0x26, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, + 0x77, 0x7A, 0xFA, 0x70, 0xDF, 0xCD, 0xAB, 0x3C, 0x60, 0x1E, 0x3E, 0xE7, 0x61, 0xC3, 0x63, 0xCB, + 0x5C, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x88, 0x1B, 0xFB, 0x4F, 0x9F, 0xB9, 0xF8, 0x95, 0xCD, 0x0B, + 0xB7, 0x84, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCD, 0xA9, 0xE7, 0xDA, 0x09, 0x11, 0x15, 0x0E, 0x79, + 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC0, 0xEF, + 0xD6, 0xD5, 0x3E, 0x60, 0x3E, 0xD7, 0xBC, 0xBE, 0x75, 0xEE, 0xB8, 0xFD, 0x91, 0x07, 0xCC, 0x01, + 0x00, 0x00, 0x9A, 0xF9, 0x9F, 0x0F, 0x2D, 0x5A, 0xFA, 0xEA, 0xE6, 0x85, 0x3F, 0x0B, 0x43, 0x64, + 0x7C, 0x68, 0x91, 0x39, 0x33, 0xEA, 0x0E, 0xFE, 0x2A, 0x32, 0x1A, 0x2D, 0x1E, 0x0D, 0x79, 0x4D, + 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xC8, 0xEF, 0xC6, + 0xD5, 0x3F, 0x60, 0x6E, 0xB7, 0x75, 0x0E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA4, 0xF1, 0xBF, 0x1E, + 0x5A, 0xF0, 0xC5, 0xD7, 0xB6, 0x2E, 0xF8, 0x65, 0x18, 0x22, 0x6F, 0xEC, 0x5D, 0x64, 0xCE, 0xFE, + 0xC4, 0x45, 0x80, 0x0A, 0x8E, 0xE8, 0xE2, 0xD1, 0x90, 0xD7, 0x54, 0x24, 0x14, 0x35, 0x71, 0x48, + 0x2F, 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x07, 0xFD, 0x6E, 0x9B, 0x7E, 0xC0, 0x7C, 0x2E, 0x0F, + 0x98, 0x03, 0x00, 0x00, 0x64, 0xE5, 0x1E, 0x54, 0xFF, 0xF5, 0xC6, 0x45, 0x7F, 0x19, 0x7D, 0x3E, + 0xC4, 0x3D, 0xA8, 0x7E, 0xFE, 0x67, 0x2A, 0x3C, 0xDC, 0x54, 0x38, 0xE4, 0x31, 0x15, 0x09, 0x45, + 0x4D, 0x1C, 0xD2, 0xCB, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0xF4, 0x61, 0xBF, 0xDB, 0xC6, 0x03, 0xE6, + 0x00, 0x00, 0x00, 0x05, 0x72, 0x0F, 0xAA, 0xFF, 0xFA, 0xC9, 0x85, 0x1B, 0xC2, 0x08, 0x71, 0x7B, + 0xE7, 0x70, 0xFC, 0xF9, 0x10, 0x15, 0x0E, 0x79, 0x4C, 0x45, 0x42, 0x51, 0x13, 0x87, 0xF4, 0xB2, + 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x7D, 0xD8, 0xEF, 0xA6, 0xF1, 0x80, 0x39, 0x00, 0x00, 0xC0, 0x14, + 0x3A, 0xF9, 0xC8, 0xE2, 0xF9, 0xBF, 0xDD, 0xB4, 0x60, 0x47, 0x18, 0x21, 0xE1, 0x83, 0xEA, 0x3A, + 0x1C, 0xF2, 0x58, 0x3C, 0x10, 0x8A, 0x9C, 0x38, 0xA4, 0x97, 0x75, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, + 0x03, 0x7F, 0xB7, 0x8C, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x3A, 0xE8, 0x57, 0x1B, 0x17, 0xAD, 0x79, + 0x65, 0xD3, 0x82, 0x9F, 0x57, 0x42, 0x64, 0x81, 0x19, 0x1F, 0x5A, 0x68, 0xCE, 0x8C, 0xBA, 0x43, + 0xBC, 0x8A, 0x88, 0xAC, 0x8B, 0x07, 0x42, 0x91, 0x13, 0x87, 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, + 0x3D, 0x7D, 0xE8, 0xEF, 0x86, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x40, 0x97, 0xA8, 0x7C, 0x90, 0xE1, + 0xC2, 0xAF, 0xBE, 0xB6, 0x75, 0xFE, 0x2F, 0x5D, 0x84, 0xB8, 0xBD, 0xB9, 0x7F, 0xA1, 0x39, 0xFB, + 0x13, 0x77, 0xA0, 0x57, 0x41, 0x91, 0x66, 0xF1, 0x40, 0x28, 0x72, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, + 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFE, 0x9D, 0x5E, 0xA3, 0x07, 0xCC, 0x4F, 0x7E, 0xE7, 0x53, 0xF3, + 0x83, 0x2F, 0x01, 0x00, 0x00, 0x00, 0x74, 0xC2, 0x60, 0xFF, 0xA7, 0xFE, 0xDD, 0xAB, 0x9B, 0x16, + 0xDC, 0xF3, 0xFA, 0xD6, 0xF9, 0x6F, 0x85, 0x21, 0xF2, 0xF6, 0x88, 0x7B, 0x50, 0x5D, 0x85, 0x45, + 0x92, 0xA9, 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x0F, 0xFF, + 0x9D, 0x9E, 0x7A, 0xC0, 0xFC, 0xB7, 0x1B, 0xE7, 0xDE, 0x10, 0xFC, 0x23, 0x0F, 0x00, 0x00, 0x80, + 0x6E, 0xF0, 0xFF, 0x7E, 0x63, 0xF1, 0x87, 0x7F, 0xF3, 0xD4, 0x82, 0x47, 0xC3, 0x08, 0x71, 0x3B, + 0xF5, 0xDC, 0x22, 0xE3, 0xFD, 0x8B, 0x8A, 0x8C, 0x46, 0x53, 0x91, 0x50, 0xD4, 0xC4, 0x21, 0xBD, + 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0x1F, 0xFE, 0x3B, 0xB9, 0xF8, 0x03, 0xE6, 0xEE, 0x39, 0x8F, + 0x57, 0x9F, 0xBE, 0xF4, 0x3F, 0x06, 0xFF, 0x88, 0x03, 0x00, 0x00, 0xA0, 0x1B, 0xFD, 0x8F, 0xFB, + 0x17, 0x2C, 0x7A, 0x75, 0xF3, 0x82, 0x9F, 0x85, 0x11, 0xF2, 0xFB, 0x5D, 0x0B, 0xCC, 0xE9, 0xBF, + 0x75, 0x07, 0x61, 0x15, 0x1C, 0xD1, 0xA9, 0x48, 0x28, 0x6A, 0xB1, 0x03, 0x7A, 0x99, 0x27, 0x0F, + 0xFF, 0x9D, 0x9E, 0x0E, 0x80, 0x4E, 0xAD, 0xEE, 0x01, 0xF3, 0xCD, 0x73, 0xDE, 0xB2, 0x3F, 0xF2, + 0x80, 0x39, 0x00, 0x00, 0x40, 0x2F, 0xF9, 0xE5, 0xC3, 0xF3, 0x6F, 0x79, 0x75, 0xCB, 0x82, 0x97, + 0xC3, 0x10, 0x71, 0x0F, 0xAA, 0x4F, 0xFC, 0x57, 0x77, 0xF8, 0x27, 0x3E, 0xA6, 0x6C, 0xF2, 0xF0, + 0xDF, 0xE9, 0xE9, 0x08, 0xE8, 0xC4, 0x1A, 0x3D, 0x60, 0x3E, 0xBE, 0xA5, 0x6F, 0x76, 0xF0, 0x8F, + 0x31, 0x00, 0x00, 0x00, 0x7A, 0x49, 0xF8, 0xA0, 0x7A, 0xF4, 0xF9, 0x10, 0xF7, 0xA0, 0xFA, 0xB9, + 0x7F, 0x74, 0x21, 0x40, 0x7C, 0x14, 0x3A, 0x79, 0xF8, 0xEF, 0xF4, 0x74, 0x08, 0x4C, 0xF5, 0x1A, + 0x3D, 0x60, 0xFE, 0xEB, 0xC7, 0x3E, 0x7D, 0x55, 0xF0, 0x8F, 0x2E, 0x00, 0x00, 0x00, 0x7A, 0x99, + 0xFB, 0x20, 0xC3, 0xDF, 0x6C, 0x9C, 0x7F, 0x5F, 0xED, 0x83, 0xEA, 0x0B, 0xCD, 0xF9, 0x9F, 0xA9, + 0x48, 0x28, 0x6A, 0xE2, 0x90, 0x5E, 0xD6, 0xC9, 0xC3, 0x7F, 0xA7, 0xA7, 0x63, 0x60, 0xAA, 0x17, + 0x7F, 0xC0, 0xFC, 0xF5, 0x6D, 0x73, 0x4E, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x40, 0x49, 0xFD, 0xDB, + 0x83, 0x7D, 0x7D, 0xAF, 0x6C, 0x5E, 0xB0, 0xA5, 0x12, 0x21, 0xF3, 0xCD, 0xEF, 0x77, 0xCD, 0x37, + 0xA7, 0x9E, 0x5B, 0x68, 0xBC, 0x7F, 0x51, 0xC1, 0x90, 0xE7, 0xC4, 0x21, 0xBD, 0xAC, 0x93, 0x87, + 0xFF, 0x4E, 0x4F, 0xC7, 0xC0, 0x54, 0x8E, 0x07, 0xCC, 0x01, 0x00, 0x00, 0xA6, 0xB1, 0xFF, 0xF9, + 0xD0, 0xBC, 0xA5, 0xAF, 0x6E, 0xEE, 0xFB, 0x99, 0x8B, 0x90, 0x30, 0x44, 0xCE, 0x8C, 0xBA, 0x03, + 0xB4, 0x8A, 0x87, 0x76, 0x17, 0x3B, 0xA0, 0x97, 0x79, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0x20, 0x98, + 0xAA, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xAA, 0x7E, 0xF5, 0x58, 0xDF, 0x5F, 0x54, 0x3E, 0xC8, + 0xB0, 0x12, 0x22, 0xE3, 0x43, 0xF6, 0xC0, 0xF8, 0x13, 0x77, 0x98, 0x56, 0x21, 0x91, 0x65, 0xB1, + 0x03, 0x7A, 0x99, 0x27, 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x82, 0xA9, 0x18, 0x0F, 0x98, 0x03, 0x00, + 0x00, 0x40, 0x72, 0x0F, 0xAA, 0xFF, 0x7A, 0x63, 0xDF, 0x5F, 0xBE, 0xBE, 0xB5, 0xEF, 0xAD, 0x30, + 0x44, 0xDE, 0xDC, 0x6F, 0x0F, 0x90, 0x6D, 0x3F, 0x1F, 0x22, 0x0E, 0xE9, 0x65, 0x9D, 0x3C, 0xFC, + 0x77, 0x7A, 0x3A, 0x0C, 0x8A, 0x1E, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x20, 0x11, 0xFF, 0x41, 0xF5, + 0xA7, 0xFA, 0x1E, 0x0D, 0x23, 0xC4, 0xCD, 0x3D, 0xA8, 0x9E, 0xED, 0xF9, 0x10, 0x71, 0x48, 0x2F, + 0xEB, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x71, 0x50, 0xF4, 0xCE, 0xFC, 0xDD, 0x7C, 0x1E, 0x30, 0x07, + 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x41, 0xF5, 0x57, 0x9F, 0x99, 0x3F, 0x12, 0x46, 0x48, 0xFA, 0x07, + 0xD5, 0xC5, 0x21, 0xBD, 0xAC, 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x41, 0x91, 0x73, 0xCF, 0x79, + 0xF0, 0x80, 0x39, 0x00, 0x00, 0x00, 0xDA, 0xF2, 0xAB, 0x27, 0xFA, 0xD6, 0x44, 0x1F, 0x54, 0x77, + 0xCF, 0x87, 0xB4, 0x7E, 0x50, 0x3D, 0x76, 0x40, 0x2F, 0xF3, 0xE4, 0xE1, 0xBF, 0xD3, 0xD3, 0x81, + 0x50, 0xD4, 0xCE, 0xFD, 0x94, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x90, 0xA3, 0xCA, 0x07, 0x19, 0xF6, + 0x7D, 0x35, 0xFA, 0xA0, 0xBA, 0x7B, 0x3E, 0x44, 0x3F, 0xA8, 0x1E, 0x3B, 0xA0, 0x97, 0x79, 0xF2, + 0xF0, 0xDF, 0xE9, 0xE9, 0x48, 0x28, 0x62, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x42, 0xB9, 0xE7, + 0x43, 0x5E, 0xDD, 0xD4, 0x77, 0x4F, 0xF4, 0x41, 0xF5, 0xB7, 0x0E, 0x46, 0x1F, 0x54, 0x17, 0x87, + 0xF4, 0xB2, 0x4E, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0A, 0x79, 0x2F, 0x7C, 0xC0, 0x3C, 0xFA, 0x9C, + 0x87, 0x1D, 0x0F, 0x98, 0x03, 0x00, 0x00, 0xA0, 0x18, 0x47, 0xBF, 0xB1, 0xF8, 0xC3, 0xAF, 0x6C, + 0xEE, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0x3B, 0x87, 0xEC, 0xC1, 0xF4, 0x5F, 0xC4, 0x41, 0xBD, 0x8C, + 0x93, 0x87, 0xFF, 0x4E, 0x4F, 0xC7, 0x42, 0xDE, 0x53, 0x0F, 0x98, 0xFF, 0xFA, 0xE1, 0x4B, 0x6F, + 0x0E, 0xFE, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xE3, 0x3F, 0xA8, 0xEE, 0x9E, 0x0F, 0xD9, 0xDE, + 0x67, 0xDC, 0x7E, 0xBF, 0xB3, 0xCF, 0x9C, 0x7A, 0xCE, 0x1E, 0x54, 0xD5, 0xA1, 0xBD, 0x2C, 0x93, + 0x87, 0xFF, 0x4E, 0xAF, 0x3E, 0x14, 0xF2, 0x9E, 0x7A, 0xC0, 0xFC, 0xD7, 0x83, 0x73, 0xFE, 0xB7, + 0xE0, 0x1F, 0x05, 0x00, 0x00, 0x00, 0x60, 0xEA, 0xFC, 0xF2, 0xE1, 0xB9, 0xB7, 0xBC, 0xB6, 0xB5, + 0xEF, 0x97, 0x61, 0x88, 0x8C, 0xEF, 0x9E, 0x6F, 0x26, 0xFE, 0xAB, 0x3D, 0x18, 0xAB, 0x03, 0x7C, + 0x2F, 0x4F, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x0C, 0x79, 0x4D, 0x3D, 0x60, 0xFE, 0xDA, 0xA6, 0x39, + 0x77, 0xF3, 0x80, 0x39, 0x00, 0x00, 0x00, 0x3A, 0xCA, 0x7F, 0x50, 0xFD, 0xC9, 0xBE, 0xAF, 0xBE, + 0xBE, 0x65, 0xDE, 0x5B, 0x61, 0x88, 0xBC, 0xB9, 0x6F, 0xBE, 0x39, 0xFB, 0x13, 0x7B, 0x48, 0x56, + 0x87, 0xF9, 0x5E, 0x9B, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x1A, 0xF2, 0x98, 0x7A, 0xC0, 0xFC, 0xD5, + 0xCD, 0x73, 0x37, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0xBA, 0x8A, 0x7B, 0x50, 0xFD, 0xB7, 0x9B, + 0xFA, 0xEE, 0x09, 0x23, 0xC4, 0xED, 0xED, 0x61, 0xF7, 0xA0, 0xBA, 0x38, 0xD4, 0xF7, 0xCA, 0xE4, + 0xE1, 0xBF, 0xD3, 0xD3, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0x3D, 0xC9, 0x3D, + 0x1F, 0xF2, 0xCA, 0xA6, 0xBE, 0x2D, 0xD1, 0x10, 0x71, 0xCF, 0x87, 0xF4, 0xDC, 0x83, 0xEA, 0xF2, + 0xF0, 0xDF, 0xE9, 0xE9, 0x78, 0x68, 0x77, 0x3C, 0x60, 0x0E, 0x00, 0x00, 0x80, 0x9E, 0x57, 0xF9, + 0x20, 0xC3, 0x79, 0x35, 0x0F, 0xAA, 0x9F, 0xFE, 0x5B, 0x7B, 0xE0, 0x55, 0x87, 0xFD, 0x6E, 0x9B, + 0x3C, 0xFC, 0x77, 0x7A, 0xF5, 0xE1, 0xD0, 0xEE, 0x78, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xA5, 0xF3, + 0xAB, 0xC7, 0xFA, 0xFE, 0x22, 0xFE, 0xA0, 0x7A, 0x57, 0x3F, 0x1F, 0x22, 0x0F, 0xFF, 0x9D, 0x9E, + 0x0E, 0x88, 0xAC, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0x94, 0x9A, 0x7B, 0x50, 0xFD, 0xB5, 0x2D, + 0xF3, 0xBE, 0x1E, 0x7F, 0x50, 0xFD, 0xDC, 0x3F, 0xDA, 0xC3, 0xB5, 0x8A, 0x80, 0x4E, 0x4D, 0x1E, + 0xFE, 0x3B, 0x3D, 0x1D, 0x11, 0x59, 0xC6, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x98, 0x56, 0xDC, 0x83, + 0xEA, 0xBF, 0x79, 0xAA, 0xEF, 0xC7, 0x61, 0x84, 0xB8, 0x75, 0xCD, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, + 0xE9, 0xE9, 0x90, 0x48, 0xBB, 0x46, 0x0F, 0x98, 0xBF, 0xB6, 0xE5, 0xD2, 0x81, 0xE0, 0x7F, 0x1A, + 0x00, 0x00, 0x00, 0xA0, 0xBC, 0xFC, 0x0F, 0x32, 0xDC, 0xD4, 0x37, 0x12, 0x46, 0x48, 0xF8, 0x41, + 0x86, 0x1D, 0x7B, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x13, 0x69, 0xA7, 0x1E, 0x30, 0x7F, + 0xE5, 0xC9, 0x39, 0xB7, 0x07, 0xFF, 0x53, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x87, 0x7B, 0x50, 0xFD, + 0xB5, 0x2D, 0xF3, 0x8E, 0x85, 0x21, 0xE2, 0x9E, 0x0F, 0x39, 0x33, 0x6A, 0x0F, 0xDF, 0x2A, 0x12, + 0x8A, 0x9A, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x26, 0xD2, 0x4C, 0x3D, 0x60, 0xFE, 0xCA, 0xA6, 0xB9, + 0xFF, 0x57, 0xF0, 0xB7, 0x1E, 0x00, 0x00, 0x00, 0x98, 0x9E, 0xC2, 0x0F, 0x32, 0x8C, 0x3E, 0xA8, + 0xFE, 0xC6, 0x9E, 0x29, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, 0x3D, 0x1D, 0x14, 0x49, 0x17, 0x7F, + 0xC0, 0xDC, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x98, 0xF0, 0x83, 0x0C, 0xE3, 0x0F, 0xAA, + 0x17, 0xF6, 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2A, 0x92, 0x8C, 0x07, 0xCC, 0x01, 0x00, + 0x00, 0x80, 0x0C, 0x5E, 0x79, 0x72, 0xCE, 0xA5, 0xF1, 0x0F, 0x32, 0x74, 0x0F, 0xAA, 0xE7, 0xFA, + 0x7C, 0x88, 0x3C, 0xFC, 0x77, 0x7A, 0x3A, 0x2C, 0x5A, 0x8D, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, + 0x1C, 0xFC, 0x7A, 0x63, 0xDF, 0x55, 0xAF, 0x6E, 0x9E, 0xF7, 0x4F, 0x61, 0x84, 0x84, 0x0F, 0xAA, + 0xCB, 0xA0, 0x48, 0x33, 0x79, 0xF8, 0xEF, 0xF4, 0xEA, 0xC3, 0x22, 0xC9, 0x78, 0xC0, 0x1C, 0x00, + 0x00, 0x00, 0xC8, 0xD9, 0x2F, 0x1F, 0x9E, 0x7B, 0x4B, 0xFC, 0x83, 0x0C, 0x33, 0x3F, 0xA8, 0x2E, + 0x0F, 0xFF, 0x9D, 0x9E, 0x8E, 0x8B, 0x66, 0xE3, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, 0x40, 0xFE, + 0x07, 0x19, 0x6E, 0xEE, 0xFB, 0x3F, 0xE3, 0xCF, 0x87, 0xA4, 0x7A, 0x50, 0x5D, 0x1E, 0xFE, 0x3B, + 0x3D, 0x1D, 0x18, 0x8D, 0xA6, 0x1E, 0x30, 0xFF, 0xED, 0xC6, 0x4B, 0xBF, 0xC5, 0x03, 0xE6, 0x00, + 0x00, 0x00, 0x40, 0x01, 0xC2, 0x07, 0xD5, 0xC3, 0x08, 0x71, 0x7B, 0xEB, 0x40, 0x82, 0x07, 0xD5, + 0xE5, 0xE1, 0xBF, 0xD3, 0xD3, 0x91, 0xA1, 0xE6, 0x9E, 0xF3, 0x88, 0x3F, 0x60, 0xFE, 0xCA, 0x53, + 0x73, 0xB6, 0xF2, 0x80, 0x39, 0x00, 0x00, 0x00, 0x30, 0x05, 0xDC, 0x07, 0x19, 0xBE, 0xBE, 0x75, + 0xDE, 0xFE, 0x68, 0x88, 0xBC, 0x73, 0xA8, 0xC1, 0x83, 0xEA, 0xF2, 0xF0, 0xDF, 0xE9, 0xE9, 0xD0, + 0x88, 0x4F, 0x3D, 0x60, 0xFE, 0xDA, 0xE6, 0x39, 0x3F, 0xE1, 0x01, 0x73, 0x00, 0x00, 0x00, 0xA0, + 0x03, 0xDC, 0x07, 0x19, 0xC6, 0x1F, 0x54, 0x3F, 0xFD, 0xB7, 0xF6, 0xF0, 0x5E, 0x82, 0xF8, 0x70, + 0x0F, 0x98, 0xD7, 0x3C, 0xE7, 0xC1, 0x03, 0xE6, 0x00, 0x00, 0x00, 0x40, 0x77, 0x88, 0x7F, 0x90, + 0xE1, 0xF8, 0xEE, 0x3E, 0x33, 0xF1, 0xF7, 0xEE, 0x20, 0xAF, 0x02, 0xA0, 0x93, 0xAB, 0x0F, 0x8D, + 0xF8, 0xDC, 0x03, 0xE6, 0x6F, 0x0C, 0xD5, 0x3F, 0x60, 0x3E, 0xDA, 0xFF, 0x9E, 0x3F, 0x0A, 0x7E, + 0xBB, 0x00, 0x00, 0x00, 0x00, 0x3A, 0xCD, 0x7F, 0x50, 0x7D, 0xCB, 0xBC, 0xAF, 0x57, 0x1E, 0x54, + 0xB7, 0x07, 0x78, 0xBB, 0x37, 0xF7, 0xF5, 0xD9, 0x03, 0xBD, 0x3B, 0xD8, 0xAB, 0x18, 0x98, 0xEA, + 0xD5, 0xC7, 0x46, 0x74, 0xEE, 0x83, 0x04, 0x79, 0xC0, 0x1C, 0x00, 0x00, 0x00, 0xE8, 0x31, 0xEE, + 0x41, 0xF5, 0x57, 0x36, 0xCD, 0xDB, 0x12, 0x46, 0x88, 0xDB, 0xDB, 0xC3, 0xF3, 0xED, 0x01, 0x5F, + 0x45, 0xC1, 0x54, 0x4D, 0x47, 0x87, 0x1B, 0x0F, 0x98, 0x03, 0x00, 0x00, 0x00, 0x25, 0xF0, 0x6F, + 0x1B, 0xFA, 0xFA, 0x5E, 0xDB, 0x32, 0xF7, 0x27, 0x61, 0x84, 0xFC, 0x7E, 0xE7, 0x3C, 0x73, 0xEA, + 0xD9, 0xF9, 0xF6, 0xC0, 0xAF, 0x02, 0xA1, 0xC8, 0x35, 0x0E, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, + 0x00, 0x4A, 0xE6, 0x57, 0x4F, 0x5C, 0xBA, 0xC6, 0x86, 0xC8, 0xB1, 0x68, 0x88, 0x9C, 0xF9, 0x3B, + 0x17, 0x01, 0x2A, 0x16, 0xF2, 0x5E, 0x7D, 0x78, 0xB8, 0xF1, 0x80, 0x39, 0x00, 0x00, 0x00, 0x50, + 0x62, 0xEE, 0x01, 0xEE, 0xDF, 0x3E, 0x39, 0xF7, 0xAB, 0xAF, 0x6F, 0x9B, 0x37, 0x1E, 0x86, 0x88, + 0x7B, 0x50, 0xBD, 0xD8, 0xE7, 0x43, 0xEA, 0xC3, 0x83, 0x07, 0xCC, 0x01, 0x00, 0x00, 0x80, 0x69, + 0xA4, 0xF2, 0x41, 0x86, 0x73, 0xEF, 0x79, 0x7D, 0xCB, 0xDC, 0x9A, 0x07, 0xD5, 0xCF, 0xFD, 0x34, + 0xEF, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, 0xA6, 0xB1, 0x57, 0x9E, 0x9C, + 0x73, 0xA9, 0x7A, 0x50, 0x3D, 0x9F, 0x10, 0xA9, 0x0D, 0x0F, 0x1E, 0x30, 0x07, 0x00, 0x00, 0x00, + 0xE0, 0x7B, 0x6D, 0x47, 0xDF, 0x40, 0xE5, 0x83, 0x0C, 0x27, 0x43, 0xE4, 0x8D, 0x3D, 0x7D, 0xFE, + 0x33, 0x22, 0xD9, 0xDE, 0x9A, 0x55, 0x79, 0xB8, 0xDC, 0x3D, 0xE3, 0x11, 0xBF, 0xF1, 0xE0, 0x01, + 0x73, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x57, 0x9E, 0x99, 0x73, 0xDB, 0xEB, 0xDB, 0xE7, 0x9E, 0x8C, + 0x86, 0x48, 0x18, 0x23, 0xEF, 0x1C, 0x9A, 0x6F, 0x4E, 0xFF, 0xCD, 0x7C, 0xFF, 0x79, 0x91, 0xF8, + 0x0D, 0x89, 0xFB, 0xFF, 0xDD, 0xBF, 0xEE, 0xFE, 0xFD, 0x77, 0x0E, 0xF5, 0xD5, 0x3C, 0xDF, 0x11, + 0xCE, 0x3D, 0x60, 0x6E, 0x7F, 0xEE, 0x75, 0xC1, 0x5F, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xDC, + 0x1B, 0xB3, 0x5E, 0x79, 0x66, 0xEE, 0x70, 0x3C, 0x44, 0x5A, 0x2E, 0x16, 0x1D, 0x95, 0xCD, 0x19, + 0xFA, 0xF5, 0xA3, 0x97, 0xDE, 0x1C, 0xFC, 0xD4, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xB9, 0x87, 0xD5, + 0x7F, 0xB3, 0x71, 0xDE, 0x9D, 0xAF, 0x3E, 0x3D, 0xEF, 0xA1, 0x57, 0x37, 0xCF, 0x7D, 0x59, 0x46, + 0x47, 0xB8, 0x20, 0x38, 0x5E, 0xDB, 0x3C, 0xF7, 0xD8, 0xAB, 0xCF, 0xCC, 0x7D, 0xDA, 0xDD, 0x76, + 0xFC, 0xB7, 0xEF, 0xCC, 0xFB, 0x40, 0xF0, 0x53, 0x01, 0x00, 0x00, 0x00, 0x40, 0x3A, 0xEE, 0x35, + 0xB9, 0xFE, 0x07, 0x1B, 0xEE, 0xE8, 0x1B, 0x88, 0xEF, 0xDF, 0x36, 0xCC, 0xEE, 0x0B, 0xFE, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xD0, 0x15, 0xDE, 0xF3, 0x9E, 0xFF, 0x1F, 0x5B, 0xE2, 0x94, 0x1D, 0x86, + 0x86, 0x23, 0x09, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82}; + +static const uint8_t tree_gif[] PROGMEM = { + + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x28, 0x00, 0x3C, 0x00, 0x83, 0x0B, 0x00, 0x00, 0xFF, 0xFF, + 0x00, 0x21, 0x00, 0x00, 0x4A, 0x00, 0x00, 0x6B, 0x00, 0x00, 0x94, 0x00, 0x00, 0xB5, 0x00, 0x00, + 0xDE, 0x00, 0x00, 0xFF, 0x00, 0x6B, 0x00, 0x00, 0xFF, 0x33, 0x33, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x99, 0x00, 0xCC, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0xA0, 0x0F, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, + 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, + 0x8C, 0xCA, 0xE8, 0x85, 0xE8, 0xA5, 0xAC, 0x67, 0xEA, 0x8A, 0xE5, 0x2B, 0x2F, 0xE3, 0x31, 0xCE, + 0xAF, 0x41, 0x1C, 0xB8, 0x1B, 0x24, 0x80, 0x04, 0xAF, 0x87, 0x02, 0x26, 0x88, 0xA1, 0x07, 0x60, + 0xB9, 0x44, 0x82, 0x04, 0x02, 0x80, 0x61, 0x30, 0x70, 0x6E, 0x0C, 0x86, 0x03, 0x60, 0x20, 0xB0, + 0x6A, 0xA8, 0xD3, 0x03, 0x21, 0xEC, 0xAD, 0x18, 0x12, 0xE8, 0xF4, 0xB1, 0x4C, 0x51, 0xA0, 0x07, + 0xEA, 0x07, 0x5B, 0xF2, 0x70, 0x13, 0x76, 0xD4, 0xA8, 0xBC, 0xBC, 0xEA, 0x1F, 0x06, 0x77, 0x51, + 0x73, 0x50, 0x0A, 0x80, 0x7F, 0x04, 0x4C, 0x4D, 0x65, 0x06, 0x0A, 0x3B, 0x3B, 0x62, 0x5A, 0x53, + 0x65, 0x05, 0x02, 0x04, 0x68, 0x0C, 0x6A, 0x00, 0x5D, 0x5E, 0x0F, 0x0F, 0x6A, 0x98, 0x6A, 0x09, + 0x7B, 0x56, 0x9D, 0x09, 0x0C, 0xA7, 0xA7, 0x7F, 0x06, 0x9D, 0xA3, 0x44, 0x02, 0x01, 0x03, 0x90, + 0x0C, 0x87, 0x03, 0x06, 0x02, 0x05, 0x56, 0x06, 0x01, 0x02, 0x53, 0xB1, 0xB3, 0x04, 0x79, 0xAF, + 0x55, 0x48, 0x51, 0xB0, 0x87, 0xC0, 0x7F, 0x07, 0x95, 0x05, 0x85, 0x44, 0xB6, 0x00, 0x05, 0x53, + 0x96, 0x6A, 0x60, 0x02, 0x0A, 0x48, 0x89, 0x00, 0x07, 0xA1, 0x69, 0x7D, 0x2B, 0x3D, 0x9D, 0x41, + 0xA1, 0x04, 0xA0, 0xDD, 0x9D, 0x38, 0x02, 0xE1, 0x6A, 0x07, 0x62, 0x0C, 0x77, 0xE6, 0xAD, 0x2F, + 0x05, 0x01, 0xB6, 0x90, 0x07, 0xA8, 0xA7, 0x54, 0xB5, 0xBC, 0x06, 0x33, 0x50, 0x53, 0x3A, 0x00, + 0x39, 0x62, 0x10, 0x6B, 0xDF, 0xBE, 0x19, 0x03, 0x18, 0x40, 0xA9, 0x15, 0x4B, 0xCC, 0x0E, 0x77, + 0x3B, 0x04, 0xC4, 0x02, 0x38, 0x43, 0x21, 0x96, 0x2C, 0xD3, 0xD6, 0x81, 0x01, 0x26, 0x2A, 0xFB, + 0xDE, 0x07, 0x7C, 0x0A, 0xB7, 0x71, 0x1B, 0x79, 0xEE, 0xC5, 0x83, 0x72, 0xDD, 0x84, 0xBC, 0x4B, + 0x13, 0xA4, 0x13, 0x15, 0x17, 0xAB, 0x18, 0x78, 0x4A, 0x43, 0x40, 0x81, 0x43, 0x76, 0x8E, 0xB6, + 0x04, 0x7C, 0x19, 0x02, 0x98, 0xC4, 0x86, 0x35, 0xBD, 0xE1, 0x1C, 0x90, 0x4D, 0x62, 0xBF, 0x14, + 0xFC, 0x7E, 0x02, 0x1A, 0x60, 0xD3, 0xD1, 0x9D, 0x3B, 0x3A, 0x09, 0xFC, 0x44, 0xB1, 0xD0, 0x96, + 0x8E, 0x43, 0x8D, 0x9E, 0xDA, 0xDB, 0x22, 0x11, 0x8A, 0x42, 0x10, 0x5C, 0x00, 0x1A, 0x2D, 0x38, + 0xF2, 0x0E, 0xA0, 0x4A, 0x03, 0x4E, 0xA2, 0xF0, 0xF4, 0x80, 0x17, 0x95, 0x8C, 0x23, 0xD1, 0xD8, + 0x12, 0x00, 0x92, 0x03, 0xAB, 0x99, 0x23, 0x71, 0x3E, 0x8D, 0xEB, 0x6E, 0x18, 0x07, 0x66, 0x23, + 0x05, 0x3E, 0x72, 0xE4, 0x06, 0x0D, 0x81, 0x02, 0xE4, 0x36, 0x5D, 0xD9, 0xA5, 0xC0, 0xAD, 0x59, + 0xA2, 0x86, 0x6E, 0xD6, 0xC4, 0x73, 0xEB, 0x15, 0xA5, 0xC5, 0xDE, 0x14, 0xF4, 0x62, 0x07, 0xC0, + 0xE9, 0x9D, 0xCC, 0x58, 0x02, 0x14, 0xA0, 0x84, 0x45, 0x83, 0x68, 0x7A, 0x8D, 0x81, 0x66, 0xC3, + 0xE9, 0xD0, 0xA6, 0x3E, 0x03, 0xF3, 0x80, 0x7D, 0x90, 0xD8, 0x58, 0xA2, 0x59, 0x2D, 0x90, 0x68, + 0xD6, 0x64, 0x17, 0x76, 0x5A, 0x23, 0xBF, 0x13, 0x58, 0x89, 0x7A, 0xC3, 0xF0, 0x8F, 0xB6, 0xB8, + 0x4B, 0xD3, 0x74, 0x52, 0x50, 0x92, 0xC2, 0x03, 0xD1, 0x78, 0xD7, 0x89, 0x4C, 0x23, 0x26, 0x6E, + 0x82, 0xCC, 0x15, 0x5E, 0x05, 0x08, 0x30, 0x06, 0x8A, 0x75, 0x64, 0xFA, 0x42, 0xF1, 0x12, 0xAD, + 0x60, 0xDE, 0x51, 0x0A, 0x94, 0xBA, 0x5E, 0x2C, 0x8C, 0x86, 0xDD, 0x3D, 0xDE, 0x8F, 0x0A, 0x70, + 0x51, 0x5F, 0xFE, 0xF2, 0x84, 0xD1, 0xD0, 0xA6, 0x68, 0xB7, 0x96, 0x62, 0x14, 0x0C, 0xC1, 0xB7, + 0x90, 0x68, 0x72, 0xD1, 0x7C, 0xD9, 0x3D, 0xA3, 0x94, 0x35, 0xDE, 0x54, 0x06, 0x92, 0x51, 0x50, + 0x68, 0xC2, 0xC5, 0x44, 0xB7, 0x30, 0x70, 0xDE, 0x6A, 0x49, 0x69, 0x86, 0xC5, 0x2D, 0xA3, 0x29, + 0x04, 0x05, 0x2F, 0xD9, 0xC4, 0x02, 0x0C, 0x6C, 0x0C, 0x48, 0xB0, 0x94, 0x01, 0xDA, 0x3C, 0xF2, + 0x56, 0x21, 0xFA, 0xE8, 0xA3, 0xA1, 0x55, 0x12, 0xE9, 0xF4, 0x56, 0x42, 0xF8, 0x50, 0x00, 0x40, + 0x08, 0x08, 0xD4, 0x88, 0x80, 0x05, 0x33, 0x66, 0x10, 0xA2, 0x0C, 0xDC, 0xA0, 0xB0, 0xA3, 0x0B, + 0x71, 0xCD, 0xB1, 0x80, 0x75, 0x69, 0x20, 0x41, 0xE4, 0x91, 0x6B, 0x64, 0x10, 0x01, 0x00, 0x21, + 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x3C, 0x00, + 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, 0xE4, 0x8C, + 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0x31, 0x1C, 0x34, + 0x1B, 0x24, 0x4C, 0x82, 0xE7, 0x28, 0x5E, 0x02, 0x78, 0x7A, 0x30, 0x8E, 0x47, 0x62, 0x48, 0x20, + 0x60, 0xD8, 0x06, 0x4A, 0x8E, 0xC1, 0x70, 0x60, 0x0C, 0x04, 0xD1, 0xCD, 0x60, 0x60, 0x3B, 0x10, + 0xBA, 0x59, 0x8B, 0x21, 0x41, 0x2E, 0x0F, 0xC3, 0x16, 0xF2, 0xC0, 0xAC, 0x40, 0x4F, 0x1E, 0x80, + 0x04, 0x81, 0x70, 0xD8, 0x0A, 0x14, 0x0F, 0xF7, 0x42, 0x00, 0xA0, 0xD6, 0x09, 0x0A, 0x81, 0x81, + 0x68, 0x00, 0x85, 0x85, 0x7F, 0x07, 0x07, 0x0A, 0x06, 0x7A, 0x06, 0x00, 0x74, 0x74, 0x5E, 0x8A, + 0x36, 0x68, 0x05, 0x7C, 0x66, 0x3D, 0x64, 0x58, 0x61, 0x0F, 0x0F, 0x66, 0x64, 0x99, 0x64, 0x79, + 0x9C, 0x9E, 0xA0, 0x48, 0x4E, 0x9D, 0xA3, 0x4A, 0x02, 0x01, 0x37, 0x90, 0x55, 0x04, 0x5C, 0x02, + 0x05, 0x59, 0x06, 0x01, 0x02, 0x4F, 0x89, 0x55, 0x76, 0xAC, 0x50, 0xAB, 0x0A, 0xAD, 0x7F, 0xB1, + 0x75, 0x07, 0x02, 0x04, 0x05, 0x00, 0xBE, 0x39, 0x06, 0x77, 0x05, 0x36, 0x04, 0x9F, 0x5B, 0xCC, + 0x00, 0x4A, 0x82, 0x81, 0x07, 0x9F, 0x65, 0x86, 0x85, 0x40, 0x9D, 0x0A, 0x9F, 0x0C, 0xD0, 0x9F, + 0x00, 0x9D, 0x39, 0x02, 0xDE, 0x66, 0xB0, 0x73, 0xE2, 0x09, 0xE4, 0xAA, 0x2F, 0x05, 0x01, 0xCC, + 0x5E, 0xA7, 0x56, 0x75, 0xD2, 0xB8, 0x8C, 0x2F, 0x4C, 0x36, 0x06, 0xB1, 0x73, 0xE1, 0x88, 0xC9, + 0x92, 0x45, 0x43, 0x96, 0x00, 0x2E, 0x37, 0xE8, 0x79, 0x99, 0x53, 0xEC, 0x86, 0x0D, 0x06, 0x05, + 0xF3, 0x51, 0x61, 0x57, 0xE6, 0x9E, 0xBF, 0x35, 0x0C, 0xDE, 0x81, 0xE8, 0x64, 0x10, 0xFB, 0x5B, + 0xB6, 0x6C, 0xF5, 0x56, 0x94, 0x22, 0x13, 0xA7, 0xE2, 0x9C, 0x04, 0xDF, 0xCA, 0x74, 0xB2, 0xB2, + 0xC2, 0x40, 0x2A, 0x92, 0x72, 0x20, 0x45, 0x52, 0xE0, 0x45, 0x1A, 0x01, 0x2B, 0xCA, 0x3E, 0xC4, + 0x3A, 0x38, 0x60, 0xDB, 0x23, 0x86, 0xD6, 0x14, 0x0C, 0x20, 0xC0, 0x84, 0xCB, 0x8A, 0x7C, 0x3C, + 0x1F, 0x25, 0x94, 0xA9, 0x80, 0x21, 0x17, 0xA2, 0x5B, 0x4E, 0x34, 0x91, 0xE5, 0x2F, 0x99, 0x4C, + 0xA0, 0x89, 0xEC, 0x5C, 0xC1, 0xB5, 0x89, 0xC3, 0x15, 0x2B, 0xCC, 0x10, 0xD6, 0xF9, 0x38, 0x67, + 0xA8, 0xB1, 0x01, 0xE5, 0x40, 0xD4, 0x7B, 0x42, 0xF1, 0x63, 0x02, 0x66, 0x02, 0x12, 0xA4, 0xFA, + 0x90, 0x2A, 0x54, 0xB6, 0x44, 0xEB, 0xDA, 0x96, 0x19, 0x9A, 0x53, 0x43, 0x01, 0xBB, 0x64, 0x84, + 0xAE, 0xC3, 0xBB, 0xB0, 0xCC, 0x31, 0x40, 0x5D, 0x35, 0xD8, 0x62, 0x82, 0x6B, 0x68, 0xAC, 0xA6, + 0x43, 0xF1, 0xD2, 0x01, 0x20, 0xE9, 0x8A, 0x25, 0x05, 0x96, 0x36, 0xD8, 0x8A, 0xD7, 0xD8, 0x46, + 0xD0, 0x85, 0xEB, 0x7E, 0x72, 0x31, 0x10, 0x54, 0x9F, 0x85, 0x00, 0xF1, 0xA6, 0x1C, 0x94, 0x2C, + 0x34, 0xB2, 0x17, 0x9F, 0x5B, 0xB8, 0x14, 0x80, 0xFC, 0x41, 0x28, 0x63, 0xC7, 0x03, 0x9A, 0x4A, + 0x32, 0x9C, 0x2C, 0x2B, 0x2E, 0x40, 0x72, 0x63, 0x59, 0x48, 0x85, 0x47, 0x8D, 0xD8, 0xC8, 0xD9, + 0xE2, 0xF0, 0x55, 0x99, 0x4A, 0xE3, 0x82, 0x07, 0x41, 0x3F, 0x25, 0x92, 0xAE, 0xD7, 0x4C, 0x3C, + 0xE7, 0xAC, 0x02, 0x04, 0x58, 0xC4, 0xC4, 0xAD, 0x9C, 0x1B, 0xB1, 0x3F, 0xE1, 0x42, 0x3D, 0x4B, + 0x9E, 0x85, 0xCB, 0x57, 0xA6, 0x30, 0x4B, 0x97, 0x88, 0x26, 0xA2, 0x03, 0x7F, 0x8B, 0x72, 0x2D, + 0x90, 0x79, 0x02, 0xFD, 0x59, 0x36, 0xB2, 0xF3, 0x41, 0x2A, 0x65, 0xAD, 0x75, 0x64, 0x3A, 0x0C, + 0x48, 0xB4, 0x15, 0x35, 0x13, 0xE0, 0xC2, 0xC0, 0x2D, 0xB1, 0x15, 0x95, 0x0C, 0x13, 0x97, 0x59, + 0x73, 0x90, 0x01, 0xF5, 0xAC, 0x36, 0x8D, 0x79, 0x12, 0x40, 0xB8, 0x45, 0x22, 0xB8, 0xF8, 0xC4, + 0x0C, 0x7D, 0xB3, 0x31, 0x96, 0xCF, 0x00, 0x01, 0x76, 0x41, 0x80, 0x4F, 0x0B, 0x80, 0x78, 0x4A, + 0x24, 0x5B, 0x8C, 0x18, 0xDB, 0x8A, 0x0A, 0xF0, 0xC3, 0x15, 0x88, 0x08, 0xF1, 0xC5, 0xC7, 0x3C, + 0x13, 0x40, 0x94, 0x01, 0x81, 0x13, 0x20, 0xA0, 0x23, 0x02, 0x27, 0xE0, 0x58, 0x63, 0x08, 0xD9, + 0xE8, 0x41, 0x81, 0x5B, 0x42, 0x7A, 0x57, 0x86, 0x12, 0x46, 0x26, 0x79, 0x46, 0x06, 0x11, 0x00, + 0x00, 0x21, 0xF9, 0x04, 0x09, 0x14, 0x00, 0x0B, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x3C, 0x00, 0x03, 0x04, 0xFB, 0x70, 0xC9, 0x49, 0x6B, 0x75, 0x36, 0xEB, 0xBD, 0x31, 0xFF, 0xA0, + 0xE4, 0x8C, 0xA4, 0x17, 0x9E, 0x57, 0x89, 0xAE, 0xA9, 0xC9, 0xAE, 0xE3, 0x31, 0xBE, 0xAF, 0xA1, + 0x1C, 0x34, 0x1B, 0x24, 0x4A, 0x82, 0xE7, 0x27, 0x85, 0x50, 0x08, 0x0C, 0x3D, 0x12, 0xBC, 0xC4, + 0xA3, 0x18, 0x12, 0x08, 0x14, 0x86, 0xC1, 0x80, 0xC9, 0x31, 0x18, 0x0E, 0x84, 0x81, 0x80, 0xBA, + 0x91, 0x46, 0xB1, 0x51, 0x06, 0xD7, 0x62, 0x40, 0x9A, 0x91, 0xE2, 0x71, 0xA5, 0x37, 0x40, 0x33, + 0xDE, 0xE9, 0xF1, 0xE3, 0xA1, 0x20, 0x10, 0x0E, 0x52, 0x01, 0x63, 0xA9, 0x5E, 0x0C, 0x85, 0x03, + 0x76, 0x7A, 0x7D, 0x0B, 0x4E, 0x03, 0x75, 0x78, 0x77, 0x78, 0x06, 0x84, 0x51, 0x37, 0x8A, 0x77, + 0x02, 0x51, 0x6A, 0x05, 0x02, 0x04, 0x67, 0x67, 0x5B, 0x72, 0x47, 0x98, 0x98, 0x7C, 0x5C, 0x73, + 0x66, 0x58, 0x07, 0x8B, 0x0F, 0x00, 0x9F, 0x45, 0x02, 0x01, 0x03, 0xA3, 0x0C, 0x89, 0x03, 0x06, + 0x02, 0x00, 0x5C, 0x06, 0x01, 0x92, 0x52, 0x07, 0xAE, 0x59, 0x03, 0x00, 0xBD, 0xBD, 0x4C, 0x02, + 0x05, 0xAB, 0xB9, 0x70, 0x0C, 0xAC, 0x96, 0x00, 0x52, 0x45, 0x36, 0xC1, 0x51, 0x97, 0x0C, 0x66, + 0x5E, 0x00, 0x8C, 0x4C, 0x0A, 0x05, 0x5F, 0x68, 0x98, 0x4E, 0x56, 0x40, 0x7F, 0x3D, 0x67, 0x97, + 0x9D, 0x73, 0x39, 0x02, 0x74, 0x9C, 0x48, 0xA4, 0x76, 0x76, 0x66, 0x73, 0xA8, 0x2C, 0x05, 0x50, + 0x02, 0xA3, 0xA3, 0x59, 0x78, 0x5E, 0x92, 0xD4, 0x2C, 0xDB, 0xB0, 0x59, 0x76, 0x07, 0x00, 0x78, + 0x16, 0x09, 0x80, 0xF5, 0xE4, 0x05, 0xC1, 0x81, 0x5F, 0xB0, 0x10, 0x00, 0xA0, 0xEE, 0xC0, 0xC0, + 0x03, 0x8E, 0x68, 0x68, 0xB1, 0x72, 0xE5, 0x92, 0xAF, 0x5E, 0xF6, 0x0C, 0x10, 0xF0, 0x86, 0x62, + 0xFB, 0xCE, 0xC1, 0x03, 0x98, 0x00, 0x74, 0x42, 0x42, 0xE7, 0xC5, 0xB9, 0x4E, 0xFF, 0xC2, 0x9D, + 0x99, 0xA3, 0x60, 0x0A, 0x0A, 0x03, 0xED, 0xC0, 0xDD, 0xF1, 0x47, 0xCF, 0xCB, 0x2E, 0x97, 0x20, + 0x92, 0x0D, 0x64, 0x85, 0xA5, 0x65, 0x43, 0x2C, 0x3C, 0x19, 0x10, 0x30, 0x94, 0x2F, 0x27, 0xBE, + 0x9D, 0x87, 0x78, 0xCE, 0x54, 0x47, 0xC0, 0x98, 0xC6, 0x9D, 0x39, 0x2F, 0xC6, 0xB2, 0xF1, 0x87, + 0x29, 0x96, 0x62, 0xC6, 0xB6, 0x69, 0xE2, 0xC0, 0x2B, 0x4A, 0x2C, 0x58, 0x49, 0x47, 0xDA, 0x11, + 0x6A, 0x69, 0xC0, 0xB8, 0x10, 0x22, 0x1F, 0xDC, 0x0A, 0xF4, 0x6D, 0x64, 0x02, 0x06, 0xB1, 0x04, + 0x28, 0x39, 0xBB, 0xA1, 0xDD, 0x49, 0x4C, 0xE9, 0xD4, 0xB9, 0x4D, 0x0A, 0xA2, 0x40, 0x81, 0x91, + 0x81, 0x68, 0x2E, 0x35, 0x43, 0xA0, 0xC0, 0x50, 0x05, 0x1F, 0x6A, 0x39, 0xB9, 0x65, 0x47, 0x4A, + 0xBF, 0xBC, 0xF4, 0xF0, 0x04, 0xE3, 0x98, 0xA1, 0x96, 0x02, 0x5B, 0x5E, 0x71, 0xA5, 0x53, 0xA8, + 0x4E, 0x68, 0x16, 0x2B, 0x01, 0xFC, 0x42, 0x29, 0x4A, 0x21, 0xF4, 0xE8, 0x87, 0x0A, 0xA5, 0x04, + 0xDA, 0xDC, 0x94, 0x95, 0x6A, 0x03, 0xC2, 0x5A, 0x6E, 0xF0, 0x66, 0xC8, 0x0E, 0xC0, 0x99, 0x20, + 0xDF, 0x16, 0x93, 0xAC, 0x91, 0x64, 0x16, 0x0B, 0xED, 0x14, 0x70, 0xF2, 0xC2, 0x6B, 0x75, 0x27, + 0x68, 0x81, 0xDA, 0x90, 0xB4, 0x0B, 0xDC, 0x74, 0xC8, 0x8B, 0x67, 0xB0, 0xBC, 0x75, 0x2B, 0xCC, + 0x5D, 0xA1, 0x00, 0xD8, 0x09, 0xC4, 0x3D, 0x23, 0x92, 0xB0, 0x6B, 0x29, 0xDA, 0x6A, 0x55, 0x12, + 0x46, 0x7A, 0x41, 0xA5, 0x81, 0xF8, 0x62, 0x25, 0xE8, 0x4E, 0x2A, 0x60, 0x22, 0x52, 0x05, 0xB4, + 0xB4, 0x94, 0x14, 0xAC, 0x12, 0x05, 0xBF, 0xCD, 0xB4, 0x60, 0xA7, 0x6F, 0x66, 0x65, 0xE7, 0x57, + 0xC7, 0xA3, 0xC8, 0x67, 0x85, 0x16, 0x5B, 0x49, 0xF0, 0x84, 0x2A, 0x48, 0x19, 0x92, 0x47, 0x30, + 0x4E, 0x00, 0x60, 0xC9, 0x57, 0x71, 0x79, 0x03, 0x51, 0x30, 0xD3, 0x4C, 0xA0, 0xC0, 0x4E, 0xA4, + 0x1C, 0x45, 0x51, 0x2C, 0x7E, 0x39, 0xB8, 0x18, 0x3E, 0x04, 0xB5, 0x04, 0x14, 0x6C, 0xB3, 0xF8, + 0xF1, 0xC7, 0x3C, 0x00, 0xAA, 0xC6, 0xCB, 0x45, 0xFC, 0x21, 0xD5, 0x52, 0x72, 0x17, 0x95, 0x88, + 0xD8, 0x09, 0x08, 0x00, 0x80, 0x00, 0x02, 0x28, 0x94, 0x28, 0xC1, 0x8C, 0x20, 0x20, 0xD1, 0x5D, + 0x02, 0x27, 0xE8, 0x88, 0x82, 0x5B, 0x84, 0x2C, 0xE0, 0xD6, 0x19, 0x4C, 0x1C, 0xA9, 0xA4, 0x19, + 0x1B, 0x44, 0x00, 0x00, 0x21, 0xFE, 0x19, 0x42, 0x6F, 0x79, 0x27, 0x73, 0x20, 0x48, 0x61, 0x70, + 0x70, 0x79, 0x20, 0x48, 0x6F, 0x6C, 0x69, 0x64, 0x61, 0x79, 0x73, 0x20, 0x50, 0x61, 0x67, 0x65, + 0x00, 0x3B + +}; + +static const uint8_t bird_gif[] PROGMEM = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x74, 0x00, 0x4E, 0x00, 0xCC, 0x13, 0x00, 0xFF, 0xFF, 0xFF, + 0xEF, 0xFF, 0xFF, 0xBD, 0xE7, 0xE7, 0xD6, 0xEF, 0xEF, 0x63, 0x63, 0x63, 0xAD, 0xAD, 0xAD, 0xCE, + 0xCE, 0xCE, 0xD6, 0xDE, 0xDE, 0x4A, 0x4A, 0x4A, 0x7B, 0x84, 0x84, 0x94, 0x9C, 0x9C, 0xE7, 0xE7, + 0xE7, 0x84, 0x94, 0x94, 0xB5, 0xC6, 0xC6, 0x73, 0x7B, 0x7B, 0x31, 0x31, 0x31, 0xF7, 0xF7, 0xF7, + 0x18, 0x10, 0x10, 0xCE, 0x63, 0x39, 0x6B, 0x39, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xFF, 0x0B, + 0x4E, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2E, 0x30, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x4B, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0xAE, 0xEC, 0x68, 0x2C, + 0x6D, 0x2C, 0xCF, 0x74, 0x6D, 0x03, 0x46, 0x84, 0x40, 0x77, 0xEF, 0xFF, 0x40, 0x51, 0x42, 0x41, + 0x0C, 0x1A, 0x8F, 0x48, 0x13, 0xC1, 0xD0, 0x20, 0x00, 0x0E, 0x8E, 0x42, 0x72, 0x4A, 0xAD, 0x21, + 0x0E, 0xCD, 0x05, 0xE1, 0x80, 0xA8, 0x7A, 0xBF, 0x29, 0xC2, 0xA0, 0x91, 0x28, 0x34, 0x02, 0x5D, + 0xB0, 0x5A, 0xFD, 0x08, 0x34, 0x14, 0x84, 0x00, 0x7A, 0x4D, 0xF7, 0x22, 0xDC, 0x89, 0xB8, 0xC1, + 0xB9, 0x80, 0xD5, 0xFF, 0x40, 0x0B, 0x77, 0x0C, 0x0F, 0x05, 0x01, 0x0C, 0x0A, 0x0B, 0x0F, 0x08, + 0x06, 0x80, 0x8E, 0x37, 0x7B, 0x01, 0x09, 0x11, 0x03, 0x68, 0x5C, 0x4C, 0x0A, 0x8F, 0x9A, 0x33, + 0x06, 0x09, 0x01, 0x0E, 0x71, 0x68, 0x88, 0x92, 0x07, 0x9B, 0xA6, 0x2C, 0x0A, 0x86, 0x07, 0x95, + 0x05, 0x04, 0xA1, 0x5D, 0x8D, 0xA7, 0xB2, 0x26, 0x09, 0x06, 0x72, 0x72, 0x0E, 0x94, 0x01, 0xA9, + 0x04, 0x08, 0x52, 0xB3, 0xC0, 0x00, 0x09, 0x95, 0xB7, 0x0D, 0x86, 0x01, 0x04, 0x0A, 0xC3, 0x09, + 0x34, 0x43, 0xC1, 0x54, 0x0E, 0xB7, 0xD2, 0x87, 0xAE, 0xBB, 0x99, 0x32, 0x7B, 0x0E, 0xCF, 0x49, + 0x0B, 0xD1, 0xD3, 0x72, 0x0C, 0xDE, 0x57, 0x33, 0xBE, 0xCC, 0xDB, 0x47, 0x05, 0x0C, 0xDF, 0xD3, + 0x05, 0xD7, 0x31, 0x0C, 0xE1, 0xA5, 0xE7, 0x46, 0xBE, 0xEB, 0xD2, 0x04, 0x05, 0xBF, 0x2C, 0x5C, + 0x4D, 0xF3, 0x46, 0x0B, 0x11, 0x56, 0xD9, 0x3B, 0x14, 0x01, 0x14, 0x0F, 0x16, 0x04, 0x1A, 0x30, + 0x28, 0x00, 0x81, 0xA1, 0x3F, 0x1F, 0xAD, 0x02, 0x10, 0x5B, 0x87, 0x6F, 0x0E, 0x8B, 0x02, 0x0E, + 0x04, 0x5C, 0x41, 0x10, 0xF0, 0x61, 0x8F, 0x25, 0x03, 0x26, 0xDA, 0x43, 0xC4, 0x42, 0x8B, 0x00, + 0x05, 0x0E, 0x7C, 0xFF, 0xED, 0xF0, 0x68, 0x83, 0x8B, 0x44, 0x91, 0xDF, 0x06, 0xAC, 0x54, 0x01, + 0x21, 0xA1, 0x80, 0x07, 0x0F, 0x1A, 0x38, 0x70, 0xC7, 0x72, 0x46, 0xC2, 0x97, 0x03, 0x3F, 0xC5, + 0x52, 0xE1, 0x80, 0x81, 0x00, 0x01, 0x19, 0x1B, 0x3C, 0x38, 0xD8, 0x53, 0xC6, 0x81, 0x38, 0x21, + 0x61, 0x4A, 0xEB, 0xB7, 0x42, 0x01, 0x82, 0xA3, 0x58, 0x7D, 0xC9, 0x6B, 0x1A, 0x63, 0x0B, 0xD0, + 0x81, 0x11, 0x08, 0x74, 0x44, 0x61, 0xE0, 0x01, 0xD6, 0xA3, 0x05, 0x16, 0x2D, 0xE5, 0xDA, 0xC2, + 0x80, 0xB7, 0x90, 0x41, 0xCB, 0xA4, 0x39, 0xC1, 0xEF, 0x2C, 0x56, 0xAA, 0x6C, 0x57, 0x38, 0xA8, + 0x14, 0x35, 0xA8, 0x35, 0x14, 0x10, 0x10, 0x34, 0xB0, 0x9B, 0xD5, 0x4F, 0xDE, 0x14, 0x06, 0x8E, + 0xF5, 0x1D, 0xC8, 0x25, 0x85, 0x83, 0xC1, 0x84, 0x05, 0x20, 0x32, 0x30, 0xF4, 0x30, 0x2D, 0x39, + 0x8B, 0x07, 0x32, 0x42, 0xA1, 0x00, 0x72, 0xE4, 0x45, 0x08, 0x7C, 0x59, 0x36, 0x91, 0x18, 0x73, + 0xE6, 0x6F, 0x79, 0x38, 0x2B, 0x88, 0x7C, 0x54, 0xE7, 0xE0, 0x2D, 0xA3, 0x4B, 0x78, 0x7A, 0x79, + 0x7A, 0x1A, 0xCE, 0x04, 0x4C, 0x85, 0xAC, 0x66, 0x7D, 0x96, 0x80, 0xB9, 0xD8, 0x22, 0x4A, 0x4B, + 0x14, 0x00, 0x97, 0xF1, 0xD3, 0x12, 0x3B, 0x79, 0x9F, 0x45, 0xC0, 0x13, 0xB8, 0xB7, 0xE1, 0xC5, + 0x19, 0x33, 0xEB, 0x53, 0xD3, 0xA8, 0x72, 0x01, 0x0D, 0x44, 0x97, 0x5C, 0x90, 0x7B, 0x9B, 0x01, + 0x05, 0xA6, 0x89, 0xFB, 0x3D, 0x54, 0x20, 0x81, 0xDA, 0x8C, 0xD7, 0x91, 0x16, 0x22, 0x91, 0xF8, + 0x80, 0x9F, 0x86, 0x08, 0x1E, 0xF4, 0xF2, 0xD5, 0x7D, 0x96, 0x18, 0xCC, 0x47, 0xA3, 0xDB, 0x7B, + 0xCA, 0x60, 0x40, 0xCA, 0xF4, 0x58, 0x81, 0xE2, 0x42, 0x04, 0x11, 0x4C, 0x80, 0x53, 0x7C, 0x3F, + 0xC9, 0xB1, 0xC7, 0xFF, 0x7A, 0xC1, 0x18, 0xA0, 0x0E, 0x7E, 0xC4, 0x49, 0xA5, 0x99, 0x67, 0xD7, + 0xA5, 0xB4, 0x15, 0x04, 0x93, 0x48, 0xA0, 0xA1, 0x81, 0x7C, 0x49, 0xB3, 0xC7, 0x38, 0xF6, 0x11, + 0x13, 0x52, 0x7E, 0x12, 0xAE, 0x63, 0xC0, 0x55, 0x00, 0x82, 0x62, 0xD8, 0x08, 0x0B, 0x24, 0xA0, + 0xA1, 0x86, 0x57, 0x3C, 0xF0, 0xE0, 0x2D, 0x05, 0x68, 0x67, 0x4A, 0x27, 0xB7, 0x0C, 0x80, 0x95, + 0x7E, 0x41, 0x11, 0x80, 0x5E, 0x85, 0xBF, 0x9D, 0xD0, 0xC0, 0x04, 0x2F, 0x2E, 0x62, 0xCB, 0x34, + 0x03, 0xE4, 0xB1, 0xA2, 0x23, 0x5E, 0x41, 0xC8, 0x63, 0x50, 0x0E, 0x9A, 0x75, 0x5D, 0x68, 0x5B, + 0x9D, 0xA0, 0x45, 0x04, 0x38, 0x2D, 0x72, 0xCC, 0x34, 0x7B, 0x24, 0xF2, 0x88, 0x5B, 0x39, 0xEA, + 0x18, 0xE1, 0x78, 0xD2, 0x58, 0x05, 0x20, 0x6C, 0x2B, 0xD4, 0x78, 0x64, 0x89, 0x6E, 0xB8, 0xF2, + 0xC2, 0x1F, 0x4D, 0xBE, 0x44, 0x22, 0x99, 0x72, 0xE4, 0x01, 0x60, 0x19, 0x31, 0x68, 0xB1, 0xC4, + 0x78, 0x50, 0xF4, 0xE2, 0x9B, 0x43, 0x5E, 0x80, 0x99, 0xE3, 0x8E, 0x6C, 0x4E, 0xE3, 0x63, 0x7A, + 0xD9, 0x55, 0xD6, 0x82, 0x4E, 0x04, 0x30, 0xD0, 0xC0, 0x01, 0x7C, 0x2A, 0xE4, 0xA3, 0xA2, 0x47, + 0xDC, 0x37, 0xE8, 0x9C, 0xE3, 0xC9, 0x64, 0x9D, 0x72, 0x70, 0x54, 0x29, 0x03, 0x04, 0xDF, 0xE5, + 0xE1, 0x4A, 0x19, 0x06, 0xB0, 0xD9, 0xC4, 0x66, 0x48, 0x7C, 0x27, 0xCD, 0x88, 0x98, 0x92, 0x89, + 0xE2, 0x75, 0x69, 0x2D, 0x69, 0xC3, 0x02, 0x07, 0xA4, 0x03, 0x8A, 0x2B, 0x8E, 0xC2, 0x04, 0x05, + 0x03, 0x48, 0x3C, 0x17, 0x5E, 0xAB, 0x7E, 0x61, 0x04, 0x20, 0x03, 0x33, 0x21, 0x01, 0xC1, 0x02, + 0xDF, 0x81, 0x52, 0x8B, 0x34, 0xAD, 0xC8, 0x6A, 0x43, 0x3E, 0x48, 0x9E, 0xF5, 0x24, 0x45, 0xAF, + 0xF2, 0x96, 0x9D, 0xFF, 0x03, 0xF5, 0x51, 0xD1, 0xA2, 0x03, 0x90, 0xCA, 0xF1, 0x94, 0x3E, 0x37, + 0x68, 0x81, 0xA4, 0x98, 0xC0, 0x9A, 0xF8, 0xC0, 0x8F, 0xCA, 0x39, 0xA0, 0xCD, 0x1F, 0x0B, 0x10, + 0x21, 0x0D, 0x03, 0xB8, 0x7D, 0x74, 0x64, 0x98, 0xD2, 0x16, 0x8A, 0x0C, 0xBA, 0xCA, 0x29, 0xF5, + 0x48, 0x8B, 0x53, 0xA1, 0x19, 0x03, 0xA8, 0x18, 0x85, 0xB2, 0x2A, 0xB9, 0x63, 0x06, 0x45, 0x06, + 0x80, 0x48, 0x05, 0xC9, 0x6E, 0x9C, 0x4F, 0xE1, 0xA3, 0xC2, 0x77, 0xF0, 0x16, 0x95, 0x4B, 0xB7, + 0xF4, 0x12, 0xEA, 0x57, 0x59, 0x14, 0xB2, 0x46, 0x08, 0xB8, 0x8E, 0x08, 0x72, 0x06, 0xB3, 0x3E, + 0xA6, 0xF2, 0x28, 0x46, 0x8B, 0x2C, 0xEB, 0xED, 0x03, 0xF3, 0x56, 0x5C, 0xF0, 0x40, 0xE6, 0xED, + 0xA6, 0x9C, 0x7C, 0xD9, 0x02, 0xA2, 0x48, 0xCA, 0x98, 0x25, 0xD6, 0xCE, 0x4E, 0x14, 0x2B, 0x18, + 0xE7, 0xC0, 0xE5, 0xAE, 0x93, 0x00, 0xC2, 0x45, 0x01, 0xB3, 0xC0, 0x8C, 0x74, 0xFA, 0xF7, 0x80, + 0x84, 0xAC, 0xAE, 0x6C, 0xCF, 0x00, 0x04, 0xA4, 0x47, 0x2C, 0x02, 0xCE, 0x6A, 0xF2, 0x06, 0x9D, + 0x98, 0xE5, 0x3C, 0xB0, 0x98, 0xB5, 0x4D, 0xD3, 0x40, 0x04, 0x05, 0x28, 0x57, 0x40, 0x04, 0x0A, + 0x50, 0x2A, 0x4B, 0x02, 0x1F, 0x53, 0xBD, 0x74, 0x54, 0x59, 0xBF, 0x1B, 0x5A, 0x41, 0xAC, 0x65, + 0xA7, 0xF0, 0x33, 0x0C, 0x58, 0x6D, 0xB6, 0x69, 0x68, 0x4F, 0x2B, 0x87, 0x55, 0xB7, 0x38, 0x50, + 0xC8, 0x5D, 0x7E, 0x8A, 0x1D, 0x0C, 0x04, 0x8F, 0xCD, 0x1D, 0x94, 0xDD, 0x4F, 0xA1, 0xEC, 0xA1, + 0x7C, 0xAD, 0x8D, 0xC5, 0x52, 0x4D, 0xBE, 0x0A, 0x3E, 0x9E, 0x55, 0x32, 0xDA, 0xA3, 0x37, 0x03, + 0xBD, 0x44, 0x3D, 0x8F, 0x55, 0x34, 0x3B, 0x6E, 0x4F, 0x03, 0x99, 0x73, 0x89, 0x93, 0xE5, 0xFE, + 0x74, 0x13, 0xB7, 0xCB, 0xE6, 0xA4, 0x4B, 0x63, 0x90, 0x65, 0xED, 0x16, 0x25, 0x77, 0xE9, 0x54, + 0x67, 0x11, 0xDB, 0x89, 0x44, 0xB3, 0x6E, 0xF6, 0x89, 0x7E, 0x37, 0x05, 0x47, 0xE7, 0xB2, 0xFB, + 0xF5, 0x2D, 0x70, 0xDD, 0x80, 0x37, 0xDE, 0x0A, 0x8E, 0xFB, 0x06, 0x1C, 0x00, 0x4D, 0xE0, 0x1E, + 0x80, 0x0C, 0x73, 0xFB, 0x47, 0x00, 0xE8, 0x2C, 0x89, 0x6E, 0xCF, 0x0C, 0x66, 0x87, 0x64, 0x55, + 0x73, 0x87, 0xB5, 0xD2, 0x39, 0xF2, 0x54, 0xA3, 0xAD, 0x24, 0xEF, 0x09, 0xC4, 0x2E, 0x47, 0x0C, + 0x83, 0x4F, 0x44, 0x6E, 0x25, 0xA9, 0x0C, 0x8F, 0x43, 0xE0, 0xD3, 0xB4, 0x30, 0x50, 0x54, 0xF9, + 0x41, 0x57, 0xC9, 0x63, 0xE6, 0x03, 0x00, 0xC1, 0xED, 0xE9, 0xAB, 0x60, 0x4F, 0x62, 0x94, 0x41, + 0x2A, 0xFE, 0x01, 0x56, 0x11, 0x10, 0xB3, 0x65, 0x4F, 0x11, 0xCC, 0x37, 0x4A, 0x10, 0x2C, 0x8E, + 0x3C, 0x80, 0x40, 0x3A, 0x30, 0x20, 0x02, 0x96, 0x10, 0x3F, 0x13, 0x64, 0xA7, 0x1E, 0x17, 0x53, + 0x90, 0x02, 0x28, 0x87, 0x00, 0xB2, 0xC1, 0xE0, 0x29, 0x08, 0x24, 0x50, 0xC9, 0xFE, 0x37, 0x3C, + 0x28, 0x30, 0x67, 0x75, 0x01, 0x9C, 0x20, 0x4E, 0x0A, 0xE0, 0xAC, 0xAF, 0x21, 0x90, 0x3E, 0x0D, + 0x4C, 0x41, 0xBB, 0x42, 0x13, 0x05, 0x63, 0xA4, 0x64, 0x81, 0x43, 0x28, 0x40, 0xED, 0x44, 0x00, + 0x01, 0x2C, 0x78, 0x29, 0x85, 0x2C, 0x38, 0x56, 0x62, 0x1A, 0xC0, 0x1D, 0x35, 0x84, 0x00, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, + 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, + 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, + 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, + 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, + 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, + 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, + 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, + 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, + 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, + 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, + 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, + 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, + 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, + 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, + 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, + 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, + 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, + 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, + 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, + 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, + 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, + 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, + 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, + 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, + 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, + 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, + 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, + 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, + 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, + 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, + 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, + 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, + 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, + 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, + 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, + 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, + 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, + 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, + 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, + 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, + 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, + 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, + 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, + 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, + 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, + 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, + 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, + 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, + 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, + 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, + 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, + 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, + 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, + 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, + 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, + 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, + 0x0D, 0x21, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, + 0x00, 0x6A, 0x00, 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, + 0xAE, 0x6C, 0xEB, 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, + 0x0A, 0xC7, 0x03, 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, + 0xA4, 0x10, 0xA8, 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, + 0x9E, 0x18, 0x02, 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, + 0xD4, 0x81, 0x01, 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, + 0x0D, 0x08, 0x05, 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, + 0x04, 0x06, 0x10, 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, + 0x93, 0x09, 0x0C, 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, + 0x0C, 0x39, 0x9A, 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, + 0xAB, 0x5B, 0x4A, 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, + 0x0D, 0x0D, 0x07, 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, + 0x0E, 0x7B, 0x04, 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, + 0x92, 0x0C, 0x0E, 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, + 0x5B, 0x03, 0x0E, 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, + 0x98, 0xBE, 0x73, 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, + 0xB0, 0x6A, 0xA3, 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, + 0xBC, 0xA5, 0x0C, 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, + 0x04, 0x32, 0x53, 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, + 0x67, 0x8E, 0xA2, 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, + 0x33, 0xA0, 0x2B, 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, + 0x0E, 0x10, 0xC0, 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, + 0x0A, 0x08, 0xF8, 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, + 0x1D, 0x8A, 0x47, 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, + 0x22, 0x22, 0x82, 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, + 0x6B, 0x50, 0xE0, 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, + 0xA3, 0x2D, 0x60, 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, + 0x94, 0x14, 0x7F, 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, + 0x05, 0x30, 0x4A, 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, + 0x53, 0x20, 0xC1, 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, + 0x10, 0x03, 0x80, 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, + 0x26, 0x0F, 0x28, 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, + 0xC6, 0x0A, 0x02, 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, + 0xA0, 0xC0, 0x28, 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, + 0x42, 0x01, 0x5A, 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, + 0x88, 0x33, 0x14, 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, + 0x6A, 0xC4, 0x80, 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, + 0x28, 0xC2, 0xE2, 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, + 0x21, 0xA4, 0x0C, 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, + 0x4A, 0x93, 0x29, 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, + 0x94, 0x0C, 0x38, 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, + 0x56, 0x74, 0x54, 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, + 0x99, 0x83, 0x8A, 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, + 0x10, 0x02, 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, + 0x6A, 0x00, 0x2E, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x00, 0x40, 0x62, 0xB9, 0x28, 0x08, 0x41, 0x28, + 0x4B, 0xE9, 0xBE, 0x70, 0x2C, 0xCF, 0x74, 0x6D, 0xDF, 0xE5, 0xF1, 0x3C, 0x69, 0x52, 0x24, 0x0F, + 0x82, 0xE1, 0x60, 0x00, 0x26, 0x5A, 0xB8, 0xA4, 0x72, 0xC9, 0x94, 0xE9, 0x22, 0x12, 0xC9, 0x64, + 0xF2, 0x18, 0x04, 0xAE, 0xD7, 0x01, 0xB0, 0xD0, 0xEC, 0x7A, 0xBF, 0x31, 0x48, 0x61, 0x12, 0x95, + 0x32, 0x02, 0x8E, 0x06, 0x36, 0x70, 0x50, 0x21, 0xC1, 0xF0, 0x78, 0x72, 0x91, 0x20, 0x4B, 0x55, + 0x85, 0xF5, 0xB5, 0x81, 0xE0, 0xCA, 0xFF, 0x80, 0x32, 0x0D, 0x0F, 0x53, 0x11, 0x11, 0x04, 0x07, + 0x7A, 0x57, 0x0E, 0x04, 0x6F, 0x81, 0x8F, 0x7F, 0x0B, 0x2A, 0x06, 0x94, 0x6A, 0x8A, 0x01, 0x06, + 0x04, 0x05, 0x07, 0x0B, 0x0B, 0x44, 0x94, 0xA0, 0x43, 0x24, 0x90, 0xA4, 0x37, 0x05, 0x04, 0x96, + 0x97, 0x58, 0x45, 0x09, 0x0A, 0x0C, 0x0C, 0x0A, 0x05, 0x0D, 0xB3, 0x05, 0x0A, 0x09, 0x0C, 0x05, + 0x06, 0xA3, 0x4D, 0x9F, 0xA0, 0x0B, 0xBB, 0xA5, 0x33, 0x6D, 0x08, 0x0C, 0x89, 0xAA, 0xC7, 0x8A, + 0x07, 0xAE, 0x3E, 0xC0, 0x32, 0x10, 0x07, 0x3F, 0x2A, 0x0E, 0x8C, 0x2A, 0x08, 0xD6, 0x29, 0x0E, + 0xB9, 0xCD, 0xC1, 0x22, 0x10, 0x45, 0xD2, 0xB8, 0x07, 0x56, 0x97, 0x22, 0xC8, 0x01, 0x0D, 0x0C, + 0x3E, 0x9C, 0x25, 0xCF, 0xA7, 0x04, 0xD9, 0xE2, 0xC8, 0x03, 0xD0, 0x09, 0x04, 0xD6, 0x09, 0xBA, + 0xDC, 0x30, 0x10, 0x0B, 0x06, 0xB6, 0x2A, 0x04, 0x12, 0xDC, 0x52, 0x40, 0x90, 0x60, 0x81, 0x5C, + 0x07, 0x20, 0xA8, 0x1A, 0xD0, 0x20, 0x01, 0x35, 0x07, 0x3C, 0x1C, 0x18, 0x30, 0x87, 0xCC, 0x00, + 0x03, 0x02, 0x0F, 0x12, 0x34, 0xD8, 0xA6, 0xCF, 0x44, 0xA7, 0x8F, 0x9D, 0x0E, 0x88, 0xAC, 0x75, + 0x6B, 0x22, 0xC5, 0x4B, 0x44, 0x4E, 0xFF, 0x26, 0x63, 0x80, 0x20, 0xE3, 0x81, 0x8E, 0x5D, 0x0E, + 0xA4, 0x33, 0xA6, 0x92, 0x8D, 0x03, 0x04, 0x35, 0x2F, 0x35, 0xC0, 0x98, 0xE0, 0x25, 0x4C, 0x26, + 0x07, 0x7C, 0xE4, 0xBC, 0x82, 0x40, 0xE1, 0x50, 0x3D, 0xCA, 0x52, 0x38, 0xFA, 0x89, 0xE3, 0x47, + 0xCE, 0x1F, 0x00, 0x8E, 0xAA, 0x02, 0xC2, 0x80, 0xE9, 0x92, 0x86, 0x2A, 0x0D, 0x3C, 0xA0, 0x29, + 0x55, 0xD1, 0x00, 0x8C, 0x06, 0xAC, 0x26, 0x31, 0x80, 0xC0, 0x24, 0x32, 0x04, 0x09, 0xBA, 0x9A, + 0x1B, 0x94, 0x80, 0xA3, 0x58, 0x18, 0x5A, 0xCF, 0x1C, 0x13, 0x78, 0x69, 0x9C, 0xDA, 0x2C, 0x04, + 0x22, 0x34, 0x78, 0x6B, 0x03, 0x82, 0x02, 0x44, 0x97, 0x5E, 0xD5, 0x1D, 0x60, 0xF7, 0xEE, 0xB9, + 0x07, 0x61, 0xF9, 0xD6, 0x58, 0xC0, 0x20, 0xDB, 0x1A, 0x82, 0x0B, 0x09, 0x17, 0xBE, 0xFB, 0x55, + 0x81, 0xE2, 0x1B, 0x99, 0x10, 0x39, 0xF6, 0x2A, 0x99, 0xB0, 0x61, 0x3D, 0x0E, 0x2F, 0xDF, 0x18, + 0x94, 0x87, 0xF3, 0x00, 0x01, 0x02, 0x24, 0x7F, 0x7E, 0x8C, 0x60, 0xA9, 0x68, 0x17, 0x6D, 0xCC, + 0x62, 0x91, 0x8C, 0x1A, 0x75, 0xE7, 0x2B, 0x30, 0xBA, 0xF2, 0xF1, 0xF9, 0xDA, 0x45, 0x26, 0xAE, + 0x59, 0x4E, 0xD7, 0x4E, 0xED, 0x19, 0xF7, 0x8C, 0xA3, 0x5A, 0xF7, 0xF6, 0x16, 0xF1, 0xC3, 0x68, + 0x70, 0xE1, 0xC3, 0x8B, 0xAF, 0xA1, 0x31, 0xF4, 0xB4, 0xD2, 0xD7, 0x10, 0x60, 0xE9, 0x21, 0x3C, + 0x3C, 0xFA, 0x64, 0xE3, 0x32, 0x6A, 0xD2, 0x56, 0xF0, 0xC0, 0x0F, 0x5F, 0x3A, 0xA9, 0x02, 0x70, + 0xEF, 0x4E, 0x5C, 0x3A, 0x68, 0xD7, 0xE5, 0x54, 0x72, 0xB7, 0xF2, 0xD5, 0xBC, 0xD5, 0xA0, 0x34, + 0xD7, 0xDB, 0x6E, 0xAF, 0x5A, 0x95, 0x03, 0xDE, 0x2F, 0x98, 0x73, 0xDB, 0x70, 0x01, 0xC4, 0xF2, + 0x96, 0x45, 0xB3, 0x41, 0x67, 0x5B, 0xFF, 0x7F, 0xE6, 0x00, 0x20, 0x51, 0x0C, 0xF2, 0xD0, 0x47, + 0x9C, 0x7A, 0xEA, 0x91, 0x07, 0x20, 0x4C, 0x05, 0xC8, 0xA5, 0x9E, 0x70, 0xA7, 0x31, 0x78, 0x92, + 0x24, 0x89, 0xB9, 0x70, 0x4C, 0x26, 0x41, 0x04, 0xA4, 0x40, 0x03, 0x19, 0x32, 0x72, 0xC8, 0x85, + 0x1D, 0xB9, 0x92, 0x20, 0x7F, 0xEE, 0x9D, 0x94, 0xE1, 0x49, 0x0C, 0xDD, 0x84, 0x16, 0x79, 0x11, + 0xF4, 0x11, 0x0B, 0x42, 0x62, 0x41, 0x70, 0xCB, 0x73, 0x1E, 0x0E, 0xE5, 0x20, 0x70, 0x7B, 0x10, + 0x40, 0x58, 0x5E, 0xC4, 0xE4, 0x23, 0x42, 0x02, 0x86, 0x34, 0xA2, 0x98, 0x24, 0x0A, 0x00, 0x19, + 0x63, 0x4E, 0xFD, 0x10, 0x43, 0x93, 0x32, 0x79, 0xF1, 0x90, 0x42, 0x88, 0x2E, 0x2C, 0xF0, 0x80, + 0x21, 0x0F, 0x30, 0x00, 0x5F, 0x30, 0x62, 0xF4, 0xB1, 0x61, 0x90, 0x47, 0x39, 0x18, 0xCB, 0x3F, + 0xEF, 0xF8, 0x60, 0xC0, 0x2F, 0x36, 0x3C, 0xB1, 0x22, 0x53, 0x99, 0x20, 0x90, 0x08, 0x9A, 0x5D, + 0x79, 0xD9, 0x80, 0x00, 0x29, 0xB4, 0xD6, 0x04, 0x59, 0x2C, 0xFC, 0x24, 0x13, 0x2A, 0x78, 0x76, + 0xF5, 0x95, 0x03, 0x0C, 0xA0, 0xA6, 0xA3, 0x17, 0x6E, 0x3D, 0xB2, 0xC0, 0x0F, 0x0A, 0x10, 0xB9, + 0xDA, 0x39, 0x08, 0x08, 0x90, 0x86, 0x00, 0x4E, 0x2E, 0x17, 0x86, 0x3B, 0xA5, 0x4D, 0xAA, 0x87, + 0x42, 0xAF, 0x0C, 0xE2, 0x00, 0xA6, 0x63, 0x8A, 0xF6, 0xA8, 0x0A, 0x91, 0x06, 0xF0, 0x4B, 0x9E, + 0xCE, 0x29, 0xF2, 0x17, 0x4B, 0x96, 0x16, 0x50, 0xA9, 0x9F, 0x9A, 0x02, 0x50, 0x00, 0x23, 0x81, + 0x9E, 0x1A, 0x41, 0x94, 0x47, 0x31, 0x10, 0xE6, 0x01, 0xD3, 0x98, 0xA5, 0x10, 0x2A, 0x2D, 0xF1, + 0x21, 0x46, 0x40, 0xB5, 0xDA, 0x8A, 0xD8, 0x02, 0x0D, 0x21, 0x9A, 0x80, 0x99, 0x98, 0xE0, 0x63, + 0xCE, 0x10, 0x01, 0xC8, 0x7A, 0xC2, 0x79, 0x11, 0x50, 0x65, 0x26, 0x2B, 0x9F, 0x64, 0xF9, 0xD1, + 0xE8, 0x93, 0x29, 0x32, 0x30, 0x84, 0x03, 0x0A, 0x28, 0x04, 0x2C, 0x46, 0x0B, 0x5C, 0x91, 0xAE, + 0x22, 0x64, 0x21, 0xB0, 0x13, 0x30, 0x99, 0xDC, 0xB4, 0xD3, 0xB3, 0xE9, 0x00, 0x50, 0x6A, 0xB2, + 0x00, 0xB4, 0xD1, 0x42, 0x50, 0x42, 0x00, 0xF6, 0x55, 0x51, 0xAA, 0x6A, 0x82, 0x09, 0x22, 0x08, + 0x38, 0xB0, 0x4D, 0xB7, 0x88, 0x2C, 0x60, 0x0D, 0x8B, 0xF8, 0xBE, 0x90, 0x89, 0x02, 0x0E, 0xE0, + 0x03, 0x81, 0xC0, 0x99, 0xDC, 0xAA, 0x2A, 0x44, 0xB3, 0xF8, 0xE9, 0x16, 0x04, 0x08, 0xD8, 0xC2, + 0x1C, 0x97, 0x0D, 0xCB, 0xE0, 0xC9, 0x28, 0x3A, 0x28, 0xF3, 0x5F, 0x6B, 0xBF, 0xD9, 0x72, 0xC4, + 0x62, 0x1D, 0x7F, 0x1B, 0x72, 0x0D, 0xCA, 0xBC, 0xD4, 0x86, 0x2D, 0x3E, 0xB9, 0xBC, 0x5C, 0x08, + 0x00, 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x20, 0x00, 0x6A, 0x00, + 0x25, 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0xE3, 0xA2, 0x14, 0xC6, 0x42, 0xAE, 0x6C, 0xEB, + 0xBE, 0x70, 0x2C, 0xCF, 0x2D, 0x94, 0x10, 0x4C, 0x71, 0x2C, 0x06, 0xF1, 0x24, 0x0A, 0xC7, 0x03, + 0x61, 0xA0, 0x19, 0x8F, 0xC8, 0x24, 0xCC, 0x10, 0x89, 0x48, 0x26, 0x93, 0x47, 0xA4, 0x10, 0xA8, + 0x56, 0x0B, 0x0F, 0xC2, 0x41, 0xC9, 0xED, 0x7A, 0x5B, 0x06, 0xC4, 0x44, 0x42, 0x9E, 0x18, 0x02, + 0x3A, 0x2B, 0xFA, 0xA1, 0xF8, 0xBA, 0xDF, 0xC9, 0xC6, 0xB8, 0xAC, 0x40, 0x30, 0xD4, 0x81, 0x01, + 0x81, 0xA0, 0x82, 0xFB, 0xFF, 0x2D, 0x0B, 0x0E, 0x73, 0x11, 0x6C, 0x78, 0x55, 0x0D, 0x08, 0x05, + 0x80, 0x8C, 0x8D, 0x05, 0x11, 0x08, 0x09, 0x09, 0x0E, 0x54, 0x87, 0x01, 0x0C, 0x04, 0x06, 0x10, + 0x8D, 0x9C, 0x6F, 0x0B, 0x38, 0x96, 0x78, 0x07, 0x05, 0x0A, 0x0C, 0x93, 0x0E, 0x93, 0x09, 0x0C, + 0x0A, 0x0D, 0x7D, 0x9D, 0xAF, 0x30, 0x75, 0x0E, 0x67, 0xA1, 0xB5, 0x79, 0xA3, 0x0C, 0x39, 0x9A, + 0xB0, 0xBC, 0x2B, 0x10, 0x0D, 0x37, 0x0E, 0xAC, 0x07, 0xB6, 0xB5, 0x03, 0x0D, 0xAB, 0x5B, 0x4A, + 0x07, 0x06, 0xCD, 0xCD, 0x3B, 0xBD, 0x32, 0x10, 0x3C, 0x0A, 0x37, 0x7B, 0x40, 0x0D, 0x0D, 0x07, + 0xDB, 0xDB, 0x03, 0xB5, 0x07, 0xA5, 0xCA, 0x30, 0x10, 0x06, 0xD5, 0x7B, 0x0E, 0x0E, 0x7B, 0x04, + 0x08, 0xEC, 0x08, 0x04, 0xC2, 0xBB, 0xD1, 0x31, 0x0B, 0xA3, 0xA4, 0xA6, 0x92, 0x92, 0x0C, 0x0E, + 0x0C, 0x0D, 0x10, 0x87, 0x03, 0xD5, 0x74, 0xB8, 0x82, 0x30, 0xEA, 0x5A, 0x1A, 0x5B, 0x03, 0x0E, + 0x00, 0x5B, 0x17, 0x29, 0x9E, 0xBC, 0x24, 0x0B, 0x0A, 0xEC, 0x23, 0x86, 0xE7, 0x98, 0xBE, 0x73, + 0x43, 0x66, 0x15, 0xB3, 0x55, 0xCE, 0x47, 0x82, 0x02, 0xAE, 0x1E, 0x1E, 0x39, 0xB0, 0x6A, 0xA3, + 0x25, 0x66, 0x26, 0x0F, 0xFF, 0x91, 0x44, 0xF0, 0x43, 0x9C, 0x48, 0x23, 0xC0, 0xBC, 0xA5, 0x0C, + 0x70, 0x80, 0x40, 0x83, 0x99, 0x96, 0x1A, 0x78, 0x74, 0xF9, 0x52, 0xC6, 0x82, 0x04, 0x32, 0x53, + 0x1A, 0x48, 0x80, 0x33, 0xD4, 0x80, 0x02, 0xEC, 0x42, 0xF6, 0x84, 0x21, 0x08, 0x67, 0x8E, 0xA2, + 0xB6, 0x12, 0x3C, 0x60, 0xB0, 0x74, 0xC6, 0x01, 0xA2, 0x1B, 0x75, 0xD2, 0x52, 0x33, 0xA0, 0x2B, + 0x54, 0x2B, 0x3E, 0x8A, 0x54, 0x5D, 0x42, 0xE4, 0x5B, 0x0E, 0x00, 0x56, 0xBA, 0x0E, 0x10, 0xC0, + 0x96, 0xAD, 0x57, 0xA8, 0x0D, 0x7E, 0x6C, 0x1A, 0xEB, 0xC2, 0xC0, 0x54, 0x4B, 0x0A, 0x08, 0xF8, + 0xCB, 0xB3, 0xB6, 0xAD, 0x5A, 0xB5, 0x5F, 0xC1, 0x46, 0x68, 0x40, 0xF7, 0x45, 0x1D, 0x8A, 0x47, + 0x23, 0xA1, 0xFD, 0xFB, 0x76, 0xA3, 0x42, 0x8A, 0x59, 0x1F, 0x10, 0x2E, 0xCC, 0x22, 0x22, 0x82, + 0x7D, 0x1F, 0xBD, 0x01, 0xFE, 0x0A, 0x20, 0xDB, 0x4C, 0x02, 0x6D, 0x96, 0xD2, 0x6B, 0x50, 0xE0, + 0x5E, 0x2E, 0x05, 0x29, 0x36, 0x05, 0x0E, 0x65, 0xE3, 0x66, 0x4A, 0x7D, 0x73, 0xA3, 0x2D, 0x60, + 0x90, 0xE5, 0x44, 0x0A, 0x66, 0xA4, 0xAB, 0x3D, 0x78, 0xB0, 0xC8, 0xCA, 0xDE, 0x94, 0x14, 0x7F, + 0x07, 0x28, 0x07, 0x79, 0x23, 0x52, 0xA5, 0xB0, 0xE8, 0x35, 0x03, 0x06, 0x04, 0x05, 0x30, 0x4A, + 0x2A, 0x68, 0x4E, 0xE2, 0x5D, 0x0B, 0x2D, 0x9A, 0x66, 0x0F, 0xEA, 0x35, 0x43, 0x53, 0x20, 0xC1, + 0x56, 0x93, 0x61, 0x78, 0xF6, 0xAC, 0xD9, 0xCF, 0x40, 0xE9, 0x3D, 0x20, 0x23, 0x10, 0x03, 0x80, + 0x54, 0x23, 0x00, 0x4C, 0x2A, 0x14, 0xE5, 0x25, 0xC1, 0xCC, 0x01, 0xBD, 0xE2, 0x26, 0x0F, 0x28, + 0xA2, 0xCC, 0x0C, 0x45, 0xEC, 0x30, 0x0D, 0x98, 0x97, 0xDD, 0x24, 0x04, 0x49, 0xC6, 0x0A, 0x02, + 0xC8, 0xB1, 0x50, 0xD4, 0xAA, 0x5A, 0xEE, 0x24, 0x48, 0x19, 0x00, 0xE4, 0xF4, 0xA0, 0xC0, 0x28, + 0x0A, 0xB0, 0xE2, 0x1B, 0x0D, 0x33, 0xA9, 0x25, 0x00, 0x52, 0x8B, 0x3C, 0xF8, 0x42, 0x01, 0x5A, + 0x1C, 0x62, 0x44, 0x86, 0x6B, 0x69, 0x46, 0x40, 0x87, 0x1E, 0x06, 0x02, 0x84, 0x88, 0x33, 0x14, + 0xF3, 0x57, 0x00, 0x6D, 0x09, 0x10, 0xC0, 0x09, 0x29, 0x2E, 0xE1, 0x80, 0x6B, 0x6A, 0xC4, 0x80, + 0x90, 0x66, 0x80, 0x69, 0xA6, 0xC0, 0x03, 0x0E, 0xD6, 0x28, 0x02, 0x04, 0x0C, 0x28, 0xC2, 0xE2, + 0x0A, 0x1C, 0xF9, 0xE0, 0xCE, 0x3E, 0x05, 0x94, 0xE6, 0x00, 0x02, 0x11, 0x68, 0x21, 0xA4, 0x0C, + 0x35, 0xB1, 0x11, 0x94, 0x49, 0x09, 0x35, 0xF0, 0x24, 0x0E, 0x48, 0x35, 0x61, 0x4A, 0x93, 0x29, + 0x4C, 0x69, 0xC4, 0x01, 0x42, 0x30, 0x70, 0x25, 0x1E, 0x20, 0x26, 0x44, 0x40, 0x94, 0x0C, 0x38, + 0xC4, 0x44, 0x13, 0x99, 0x1C, 0x10, 0x9B, 0x98, 0x34, 0x98, 0xC0, 0x4E, 0x9B, 0x56, 0x74, 0x54, + 0x08, 0x3B, 0x99, 0xB8, 0xF0, 0x48, 0x13, 0x4D, 0x88, 0x45, 0x27, 0x12, 0x0A, 0x99, 0x83, 0x8A, + 0x40, 0x73, 0xBE, 0x60, 0x57, 0x13, 0xA1, 0x0D, 0xFA, 0xD2, 0x6C, 0x93, 0x91, 0x10, 0x02, 0x00, + 0x21, 0xF9, 0x04, 0x09, 0x0A, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x17, 0x00, 0x6A, 0x00, 0x32, + 0x00, 0x00, 0x05, 0xFF, 0x20, 0x20, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0x8A, 0x85, 0x02, 0xAD, + 0x70, 0x2C, 0xCF, 0x74, 0x5D, 0x26, 0x0C, 0x63, 0xD8, 0x7C, 0xEF, 0xFF, 0xA2, 0x05, 0x21, 0x80, + 0x58, 0x2C, 0x70, 0x0B, 0xA0, 0x72, 0xC9, 0x64, 0x34, 0x0C, 0x89, 0x86, 0x42, 0xC8, 0xAC, 0x5A, + 0x6B, 0x54, 0x46, 0x81, 0x11, 0x70, 0x5E, 0xBF, 0x60, 0x94, 0xA2, 0xB0, 0x40, 0x10, 0x00, 0x86, + 0x73, 0x23, 0x71, 0x08, 0xBB, 0xAF, 0x90, 0x73, 0xE2, 0x11, 0x28, 0x97, 0x1B, 0xBA, 0xB7, 0x7E, + 0xA9, 0x68, 0x04, 0x0A, 0x01, 0x01, 0x04, 0x39, 0x01, 0x50, 0x7B, 0x87, 0x3E, 0x0B, 0x5C, 0x81, + 0x5D, 0x0F, 0x03, 0x01, 0x78, 0x69, 0x05, 0x88, 0x94, 0x33, 0x0C, 0x8F, 0x8C, 0x0B, 0x81, 0x5A, + 0x08, 0x06, 0x2D, 0x3F, 0x0A, 0x0A, 0x33, 0x0B, 0x63, 0x0D, 0x49, 0x95, 0x26, 0x2D, 0x8C, 0xAB, + 0x05, 0x04, 0x7E, 0x0D, 0x67, 0x3C, 0x10, 0x09, 0x0A, 0x0C, 0x26, 0x10, 0x0E, 0x83, 0x05, 0x07, + 0x0B, 0x69, 0x0F, 0xB4, 0x0E, 0x0F, 0x9D, 0xA8, 0x24, 0x06, 0x08, 0xAB, 0xC8, 0x81, 0xA1, 0x3C, + 0x07, 0x0E, 0x6B, 0x6D, 0x25, 0x06, 0x11, 0x11, 0x12, 0x13, 0x13, 0x0F, 0x11, 0x80, 0xAC, 0xC2, + 0xD0, 0xA8, 0x65, 0x01, 0x98, 0xC9, 0x10, 0x66, 0x0E, 0x93, 0x32, 0x07, 0x38, 0x02, 0x0C, 0xB4, + 0xA2, 0x25, 0x07, 0x08, 0x13, 0x12, 0xF2, 0x13, 0x06, 0x7F, 0x07, 0xDB, 0xED, 0x95, 0xDF, 0xE1, + 0xC9, 0x63, 0x71, 0xDD, 0x29, 0x8E, 0xB8, 0x12, 0xA0, 0x2E, 0x94, 0x03, 0x14, 0xB0, 0xE4, 0x55, + 0x53, 0x80, 0x40, 0x01, 0xB2, 0x01, 0xB9, 0x4E, 0x21, 0x3A, 0x30, 0x64, 0x00, 0xBF, 0x64, 0x0B, + 0x1E, 0x48, 0x3C, 0x41, 0x2A, 0x0A, 0xC1, 0x8F, 0x05, 0x8A, 0x04, 0x74, 0x10, 0x4F, 0x42, 0x84, + 0x07, 0x0E, 0x93, 0xFF, 0x35, 0x40, 0x60, 0xEE, 0x90, 0x14, 0x70, 0x17, 0x91, 0x29, 0x48, 0x80, + 0x62, 0xC1, 0x16, 0x05, 0x1F, 0x73, 0x12, 0x9C, 0xB9, 0xA2, 0x40, 0x04, 0x04, 0x09, 0x82, 0x6A, + 0x4B, 0xC6, 0x80, 0x80, 0x81, 0x17, 0x7A, 0x0A, 0xD4, 0xB3, 0x18, 0x33, 0x10, 0x84, 0x5F, 0x6C, + 0x48, 0xB4, 0x1A, 0xA8, 0x53, 0x67, 0x82, 0x1D, 0x2B, 0x84, 0x2C, 0x4A, 0xB6, 0xEA, 0xC0, 0x4C, + 0x1C, 0xA6, 0x20, 0x20, 0xB5, 0x32, 0x05, 0x66, 0xD3, 0x40, 0x07, 0xA0, 0xD8, 0x12, 0xD1, 0xE0, + 0x41, 0x83, 0xAA, 0x55, 0x61, 0x31, 0xC8, 0xA7, 0x82, 0xA1, 0x83, 0x7A, 0x5C, 0x19, 0x41, 0x48, + 0xDB, 0x22, 0x47, 0xD0, 0xA3, 0x4C, 0x52, 0x32, 0x3D, 0x0B, 0x0E, 0x01, 0x34, 0x03, 0x6E, 0xE1, + 0xC2, 0xC5, 0x43, 0x57, 0x05, 0x04, 0x28, 0x04, 0x1C, 0x38, 0xB9, 0x97, 0x17, 0xD9, 0x81, 0x02, + 0x7F, 0xC7, 0xF6, 0x48, 0x10, 0x68, 0x80, 0x00, 0x8B, 0x95, 0x73, 0x8D, 0x38, 0xB0, 0xEE, 0xAD, + 0xE2, 0x8F, 0x0A, 0x08, 0x00, 0x94, 0x01, 0xA1, 0x17, 0x66, 0x02, 0xB0, 0x71, 0x84, 0x52, 0x9A, + 0x97, 0xB4, 0xEA, 0x1F, 0x07, 0xC1, 0x11, 0x24, 0xDC, 0xC0, 0xC1, 0x18, 0x00, 0xA4, 0x10, 0x30, + 0x38, 0x8D, 0xDA, 0xF0, 0x92, 0x05, 0x69, 0x0F, 0xA4, 0x55, 0xE0, 0x40, 0x32, 0xDE, 0xAE, 0xE5, + 0x7A, 0xE0, 0x02, 0xD0, 0x79, 0x77, 0x65, 0x70, 0xB0, 0x09, 0x14, 0x20, 0xFE, 0x51, 0xFB, 0xC6, + 0x2F, 0x8F, 0x85, 0x42, 0x40, 0x86, 0xF9, 0x7B, 0x0C, 0x5C, 0x8C, 0x3C, 0x7F, 0x26, 0xDC, 0x85, + 0xC0, 0x83, 0x41, 0xA6, 0x4F, 0x6B, 0x41, 0x04, 0xA1, 0xD5, 0x73, 0xB4, 0xDA, 0x35, 0xAB, 0xB8, + 0x8C, 0x23, 0xBD, 0xF5, 0xEB, 0x30, 0x41, 0xD0, 0xD6, 0x69, 0x6B, 0x34, 0x80, 0x0A, 0x04, 0xEB, + 0xA8, 0x14, 0x85, 0xFF, 0x7E, 0x41, 0x60, 0xE6, 0x40, 0x02, 0x05, 0x48, 0xE1, 0x47, 0x75, 0xBB, + 0xB1, 0xC7, 0xC8, 0x4A, 0xC4, 0xCD, 0x47, 0x0C, 0x2C, 0x31, 0x85, 0x64, 0x46, 0x64, 0x09, 0x20, + 0xF0, 0xC0, 0x2F, 0xF7, 0x39, 0xA0, 0x89, 0x7F, 0xEB, 0x01, 0x18, 0x88, 0x5A, 0xF1, 0xE5, 0xC4, + 0x40, 0x74, 0xC4, 0x00, 0xD0, 0x8C, 0x85, 0x03, 0x18, 0xD0, 0x21, 0x02, 0xD4, 0xA1, 0x98, 0xA2, + 0x8A, 0x10, 0x28, 0xF0, 0x00, 0x5C, 0x08, 0x30, 0xA8, 0x8F, 0x33, 0x2A, 0x5A, 0x46, 0x40, 0x02, + 0x27, 0xEA, 0xF8, 0x99, 0x8A, 0x88, 0x39, 0xA3, 0x13, 0x66, 0x34, 0xC5, 0x48, 0xC2, 0x2C, 0x29, + 0x15, 0x79, 0x9D, 0x7A, 0x15, 0xAA, 0xB8, 0x80, 0x6F, 0x39, 0xA1, 0x64, 0x9E, 0x94, 0x00, 0xF4, + 0x67, 0x65, 0x5E, 0x4C, 0x65, 0x79, 0x9D, 0x4D, 0x0E, 0x20, 0x20, 0xE2, 0x16, 0xCD, 0x09, 0x09, + 0x26, 0x00, 0x84, 0x8C, 0xC9, 0xD5, 0x60, 0xA0, 0x9D, 0x89, 0xC0, 0x84, 0x88, 0xDD, 0xF6, 0x66, + 0x0A, 0xCC, 0xC9, 0x79, 0x25, 0x7B, 0xE8, 0x34, 0xB4, 0x4A, 0x30, 0x06, 0xEE, 0x29, 0xC6, 0x03, + 0xF7, 0xF9, 0x69, 0xE5, 0x63, 0x04, 0xC4, 0x84, 0x98, 0x48, 0x86, 0x9A, 0x40, 0xD1, 0x56, 0x8A, + 0x56, 0x66, 0x40, 0x03, 0x52, 0xB0, 0x94, 0xE8, 0xA0, 0x1A, 0x45, 0x7A, 0x42, 0x01, 0xBE, 0x51, + 0x56, 0x29, 0x57, 0x97, 0x1A, 0x20, 0x6A, 0x65, 0x2B, 0x61, 0xE5, 0xA9, 0x3B, 0x09, 0x10, 0x50, + 0xE5, 0xA8, 0xA3, 0x0E, 0xA0, 0xDD, 0xAA, 0x27, 0x20, 0xA8, 0x1A, 0xAC, 0xB8, 0x0E, 0x42, 0xEB, + 0x09, 0x14, 0xBD, 0x3A, 0xA6, 0x08, 0xB8, 0x16, 0xE5, 0xE6, 0xAA, 0xAD, 0x9C, 0xCA, 0x55, 0x0C, + 0x8A, 0x32, 0xF4, 0x25, 0xAD, 0x47, 0xF8, 0xBA, 0xCA, 0x0C, 0x7E, 0x0E, 0xD0, 0x56, 0x4B, 0xBB, + 0x4A, 0x75, 0x6B, 0x8F, 0x32, 0x34, 0x44, 0x2B, 0x00, 0x6C, 0xAB, 0x55, 0xAB, 0xD5, 0xB1, 0x32, + 0xC8, 0xC9, 0x14, 0x24, 0xC3, 0x54, 0x5B, 0x02, 0x2C, 0x9B, 0x86, 0xFB, 0x27, 0x26, 0x1F, 0x3D, + 0x52, 0x00, 0xB5, 0xE6, 0x8A, 0xD0, 0xE3, 0x25, 0xC8, 0x20, 0x4B, 0xE6, 0x23, 0x59, 0xAE, 0xF7, + 0x8E, 0xAA, 0xF1, 0x92, 0x30, 0xA9, 0xB1, 0x29, 0xA0, 0x9A, 0x80, 0x6F, 0x7D, 0x98, 0x9A, 0x56, + 0xA6, 0x0F, 0xC0, 0xDB, 0x2F, 0x09, 0x3E, 0x3A, 0x60, 0x6C, 0x00, 0x23, 0x5C, 0xD9, 0x9B, 0x9A, + 0x0E, 0x4C, 0x33, 0x8D, 0x30, 0x47, 0x16, 0x30, 0xEC, 0xC2, 0xC0, 0xF9, 0x68, 0xD4, 0x75, 0xA4, + 0x6D, 0xA2, 0xE6, 0x91, 0x06, 0x9C, 0xF2, 0x8E, 0xC5, 0x51, 0x2C, 0xCB, 0x71, 0x09, 0x8C, 0x0E, + 0x92, 0xA8, 0x57, 0x27, 0xA9, 0xF9, 0xCB, 0x97, 0x19, 0xC5, 0xCC, 0xD2, 0xCA, 0x33, 0x78, 0x35, + 0xF0, 0x8B, 0xB9, 0xE8, 0x52, 0xF2, 0x02, 0x1B, 0x93, 0xA2, 0x32, 0xCE, 0x30, 0xB4, 0x36, 0xB4, + 0x0D, 0x21, 0x00, 0x00, 0x3B}; diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Reuse_Session/Send_Reuse_Session.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Reuse_Session/Send_Reuse_Session.ino new file mode 100644 index 000000000..ed7d61396 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Reuse_Session/Send_Reuse_Session.ino @@ -0,0 +1,242 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example show how to login once for sending multiple messages. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +SMTPSession smtp; + +Session_Config config; + +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +#include "HeapStat.h" +HeapStat heapInfo; + +unsigned long sentMillis = 0; + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + MailClient.networkReconnect(true); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + smtp.debug(1); + + smtp.callback(smtpCallback); + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; +} + +void loop() +{ + if (millis() - sentMillis > 3 * 60 * 1000 || sentMillis == 0) + { + sentMillis = millis(); + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Send Email with session reusage"); + message.addRecipient(F("user"), RECIPIENT_EMAIL); + + message.html.content = F("

This is the HTML message.

"); + message.text.content = F("This is the text message"); + + Serial.println(); + Serial.println("Sending Email..."); + + if (!smtp.isLoggedIn()) + { + /* Set the TCP response read timeout in seconds */ + // smtp.setTCPTimeout(10); + + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + goto exit; + } + + if (!smtp.isLoggedIn()) + { + Serial.println("\nError, Not yet logged in."); + goto exit; + } + else + { + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + } + } + + if (!MailClient.sendMail(&smtp, &message, false)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + exit: + + heapInfo.collect(); + heapInfo.print(); + } +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + + Serial.println(status.info()); + + if (status.success()) + { + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + smtp.sendingResult.clear(); + } +} \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text _Silent_Mode/Send_Text_Silent_Mode.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text _Silent_Mode/Send_Text_Silent_Mode.ino new file mode 100644 index 000000000..2fa30a753 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text _Silent_Mode/Send_Text_Silent_Mode.ino @@ -0,0 +1,197 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example showes how to send text message without callback and debug. + +/** + * To use library in silent mode (no debug printing and callback), please define this macro in src/ESP_Mail_FS.h. + * #define SILENT_MODE + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define SMTP_HOST "" + +#define SMTP_PORT esp_mail_smtp_port_587 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +SMTPSession smtp; + +void printSmtpData(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + MailClient.networkReconnect(true); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + SMTP_Message message; + + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + String textMsg = "This is simple plain text message"; + message.text.content = textMsg; + + message.text.charSet = F("us-ascii"); + + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + message.addHeader(F("Message-ID: ")); + + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (!smtp.isLoggedIn()) + { + Serial.println("Not yet logged in."); + } + else + { + if (smtp.isAuthenticated()) + Serial.println("Successfully logged in."); + else + Serial.println("Connected with no Auth."); + } + + if (MailClient.sendMail(&smtp, &message)) + { + printSmtpData(smtp.status()); + } + else + { + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + } + + smtp.sendingResult.clear(); +} + +void loop() +{ +} + +void printSmtpData(SMTP_Status status) +{ + + if (status.success()) + { + + Serial.println("\n----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text/Send_Text.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text/Send_Text.ino new file mode 100644 index 000000000..ea9beee08 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text/Send_Text.ino @@ -0,0 +1,396 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +// This example showes how to send text message. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 // port 465 is not available for Outlook.com + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +// const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" +// "-----END CERTIFICATE-----\n"; + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /** If non-secure port is prefered (not allow SSL and TLS connection), use + * config.secure.mode = esp_mail_secure_mode_nonsecure; + * + * If SSL and TLS are always required, use + * config.secure.mode = esp_mail_secure_mode_ssl_tls; + * + * To disable SSL permanently (use less program space), define ESP_MAIL_DISABLE_SSL in ESP_Mail_FS.h + * or Custom_ESP_Mail_FS.h + */ + // config.secure.mode = esp_mail_secure_mode_nonsecure; + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* The full message sending logs can now save to file */ + /* Since v3.0.4, the sent logs stored in smtp.sendingResult will store only the latest message logs */ + // config.sentLogs.filename = "/path/to/log/file"; + // config.sentLogs.storage_type = esp_mail_file_storage_type_flash; + + /** In ESP32, timezone environment will not keep after wake up boot from sleep. + * The local time will equal to GMT time. + * + * To sync or set time with NTP server with the valid local time after wake up boot, + * set both gmt and day light offsets to 0 and assign the timezone environment string e.g. + + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 0; + config.time.day_light_offset = 0; + config.time.timezone_env_string = "JST-9"; // for Tokyo + + * The library will get (sync) the time from NTP server without GMT time offset adjustment + * and set the timezone environment variable later. + * + * This timezone environment string will be stored to flash or SD file named "/tze.txt" + * which set via config.time.timezone_file. + * + * See the timezone environment string list from + * https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv + * + */ + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + + /** If author and sender are not identical + message.sender.name = F("Sender"); + message.sender.email = "sender@mail.com"; + message.author.name = F("ESP Mail"); + message.author.email = AUTHOR_EMAIL; // should be the same email as config.login.email + */ + + message.subject = F("Test sending plain text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + String textMsg = "This is simple plain text message"; + message.text.content = textMsg; + + /** If the message to send is a large string, to reduce the memory used from internal copying while sending, + * you can assign string to message.text.blob by cast your string to uint8_t array like this + * + * String myBigString = "..... ......"; + * message.text.blob.data = (uint8_t *)myBigString.c_str(); + * message.text.blob.size = myBigString.length(); + * + * or assign string to message.text.nonCopyContent, like this + * + * message.text.nonCopyContent = myBigString.c_str(); + * + * Only base64 encoding is supported for content transfer encoding in this case. + */ + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + // If this is a reply message + // message.in_reply_to = ""; + // message.references = " "; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + // message.response.reply_to = "someone@somemail.com"; + // message.response.return_path = "someone@somemail.com"; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + // For Root CA certificate verification (ESP8266 and ESP32 only) + // config.certificate.cert_data = rootCACert; + // or + // config.certificate.cert_file = "/path/to/der/file"; + // config.certificate.cert_file_storage_type = esp_mail_file_storage_type_flash; // esp_mail_file_storage_type_sd + // config.certificate.verify = true; + + // The WiFiNINA firmware the Root CA certification can be added via the option in Firmware update tool in Arduino IDE + + /* Connect to server with the session config */ + + // Library will be trying to sync the time with NTP server if time is never sync or set. + // This is 10 seconds blocking process. + // If time reading was timed out, the error "NTP server time reading timed out" will show via debug and callback function. + // You can manually sync time by yourself with NTP library or calling configTime in ESP32 and ESP8266. + // Time can be set manually with provided timestamp to function smtp.setSystemTime. + + /* Set the TCP response read timeout in seconds */ + // smtp.setTCPTimeout(10); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + /** Or connect without log in and log in later + + if (!smtp.connect(&config, false)) + return; + + if (!smtp.loginWithPassword(AUTHOR_EMAIL, AUTHOR_PASSWORD)) + return; + */ + + if (!smtp.isLoggedIn()) + { + Serial.println("\nNot yet logged in."); + } + else + { + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + } + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text_Flowed/Send_Text_Flowed.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text_Flowed/Send_Text_Flowed.ino new file mode 100644 index 000000000..badb2b5a6 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Send_Text_Flowed/Send_Text_Flowed.ino @@ -0,0 +1,308 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt +*/ + +// This example shows how to send text message with text wrapping. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, the app password will be used for log in + * Check out https://github.com/mobizt/ESP-Mail-Client#gmail-smtp-and-imap-required-app-passwords-to-sign-in + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + +#if defined(ARDUINO_ARCH_SAMD) + while (!Serial) + ; +#endif + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /* Set the network reconnection option */ + MailClient.networkReconnect(true); + + // The WiFi credentials are required for Pico W + // due to it does not have reconnect feature. +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + /** Assign your host name or you public IPv4 or IPv6 only + * as this is the part of EHLO/HELO command to identify the client system + * to prevent connection rejection. + * If host name or public IP is not available, ignore this or + * use loopback address "127.0.0.1". + * + * Assign any text to this option may cause the connection rejection. + */ + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 3; + config.time.day_light_offset = 0; + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.subject = F("Test sending plain text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + /** The option to add soft line break to to the message for + * the long text message > 78 characters (rfc 3676) + * Some Servers may not compliant with this standard. + */ + message.text.flowed = true; + + /** if the option message.text.flowed is true, + * the following plain text message will be wrapped. + */ + message.text.content = F("The text below is the long quoted text which breaks into several lines.\r\n\r\n>> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n\r\nThis is the normal short text.\r\n\r\nAnother long text, abcdefg hijklmnop qrstuv wxyz abcdefg hijklmnop qrstuv wxyz abcdefg hijklmnop qrstuv wxyz."); + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (!smtp.isLoggedIn()) + { + Serial.println("\nNot yet logged in."); + } + else + { + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + } + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Set_Time/Set_Time.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Set_Time/Set_Time.ino new file mode 100644 index 000000000..fcf96414f --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Set_Time/Set_Time.ino @@ -0,0 +1,253 @@ + +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +// This example showes how to set the library and/or device time manually. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#include "RTC.h" +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +#define SMTP_HOST "" +#define SMTP_PORT esp_mail_smtp_port_587 + +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" +#define RECIPIENT_EMAIL "" + +SMTPSession smtp; + +void smtpCallback(SMTP_Status status); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) +WiFiMulti multi; +#endif + +void setup() +{ + + Serial.begin(115200); + + Serial.println(); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + multi.addAP(WIFI_SSID, WIFI_PASSWORD); + multi.run(); +#else + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); +#endif + + Serial.print("Connecting to Wi-Fi"); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + unsigned long ms = millis(); +#endif + + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(300); +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + if (millis() - ms > 10000) + break; +#endif + } + Serial.println(); + Serial.print("Connected with IP: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + Serial.print("Waiting for NTP server time reading"); + +#if defined(ESP8266) || defined(ESP32) && !defined(ARDUINO_NANO_RP2040_CONNECT) + + configTime(0, 0, "pool.ntp.org", "time.nist.gov"); + while (time(nullptr) < ESP_MAIL_CLIENT_VALID_TS) + { + delay(100); + } + +#elif defined(ARDUINO_RASPBERRY_PI_PICO_W) + + configTime(10000, 0, "pool.ntp.org", "time.nist.gov"); + while (time(nullptr) < ESP_MAIL_CLIENT_VALID_TS) + { + delay(100); + } + +#elif __has_include() || __has_include() + time_t ts = 0; + do + { + ts = WiFi.getTime(); + delay(100); + } while (ts < ESP_MAIL_CLIENT_VALID_TS); + + float gmtOffset = 3.0; // GMT offset in hour + + smtp.setSystemTime(ts, gmtOffset); + +#elif __has_include() + + // see https://docs.arduino.cc/tutorials/uno-r4-wifi/rtc + + RTC.begin(); + + // RTCTime startTime(30, Month::JUNE, 2023, 13, 37, 00, DayOfWeek::WEDNESDAY, SaveLight::SAVING_TIME_ACTIVE); + // RTC.setTime(startTime); + + RTCTime currentTime; + + // Get current time from RTC + RTC.getTime(currentTime); + + float gmtOffset = 3.0; // GMT offset in hour + smtp.setSystemTime(currentTime.getUnixTime(), gmtOffset); + +#endif + + // To disable library internal NTP time reading, please comment or remove the following macro defined in src/ESP_Mail_FS.h + // #define ENABLE_NTP_TIME + + MailClient.networkReconnect(true); + +#if defined(ARDUINO_RASPBERRY_PI_PICO_W) + MailClient.clearAP(); + MailClient.addAP(WIFI_SSID, WIFI_PASSWORD); +#endif + + smtp.debug(1); + + smtp.callback(smtpCallback); + + Session_Config config; + + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + + config.login.user_domain = F("127.0.0.1"); + + /** + * Once the system time (using smtp.setSystemTime) or device time was set before calling smtp.connect, the following config will + * not take effect when NTP time is enabled. + * + * config.time.ntp_server + * config.time.gmt_offset + * config.time.day_light_offset + * + * To reset the reference time and use config.time instead, call smtp.setSystemTime(0) whenever you want. + */ + + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); + message.sender.email = AUTHOR_EMAIL; + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); + + /* The time format of timestamp to inject into subject or content as using in strftime C++ function */ + message.timestamp.tag = "#esp_mail_current_time"; + + /* The tag that will be replaced with current timestamp */ + message.timestamp.format = "%B %d, %Y %H:%M:%S"; + + message.subject = F("Test sending plain text Email (#esp_mail_current_time)"); + + message.text.content = "This is simple plain text message\n\nSent #esp_mail_current_time"; + + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + if (!smtp.isLoggedIn()) + { + Serial.println("\nNot yet logged in."); + } + else + { + if (smtp.isAuthenticated()) + Serial.println("\nSuccessfully logged in."); + else + Serial.println("\nConnected with no Auth."); + } + + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); +} + +void loop() +{ +} + +void smtpCallback(SMTP_Status status) +{ + Serial.println(status.info()); + + if (status.success()) + { + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + + SMTP_Result result = smtp.sendingResult.getItem(i); + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/ESP-Mail-Client/examples/SMTP/Sleep/Sleep.ino b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Sleep/Sleep.ino new file mode 100644 index 000000000..2902423aa --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/examples/SMTP/Sleep/Sleep.ino @@ -0,0 +1,310 @@ +/** + * Created by K. Suwatchai (Mobizt) + * + * Email: suwatchai@outlook.com + * + * Github: https://github.com/mobizt/ESP-Mail-Client + * + * Copyright (c) 2023 mobizt + */ + +// This example showes how the device time was resume after device woke up from sleep. + +/** Note for library update from v2.x.x to v3.x.x. + * + * Struct data names changed + * + * "ESP_Mail_Session" changes to "Session_Config" + * "IMAP_Config" changes to "IMAP_Data" + * + * Changes in the examples + * + * ESP_Mail_Session session; + * to + * Session_Config config; + * + * IMAP_Config config; + * to + * IMAP_Data imap_data; + */ + +#include +#if defined(ESP32) +#include +#else + +// Other Client defined here +// To use custom Client, define ENABLE_CUSTOM_CLIENT in src/ESP_Mail_FS.h. +// See the example Custom_Client.ino for how to use. + +#endif + +#include + +#define WIFI_SSID "" +#define WIFI_PASSWORD "" + +/** For Gmail, to send Email via port 465 (SSL), less secure app option + * should be enabled in the account settings. https://myaccount.google.com/lesssecureapps?pli=1 + * + * Some Gmail user still not able to sign in using account password even above option was set up, + * for this case, use "App Password" to sign in instead. + * About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en + * + * For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to + * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc + * + * To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password + * and AUTHOR_EMAIL with your account email. + */ + +/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com */ +#define SMTP_HOST "" + +/** The smtp port e.g. + * 25 or esp_mail_smtp_port_25 + * 465 or esp_mail_smtp_port_465 + * 587 or esp_mail_smtp_port_587 + */ +#define SMTP_PORT esp_mail_smtp_port_587 // port 465 is not available for Outlook.com + +/* The log in credentials */ +#define AUTHOR_EMAIL "" +#define AUTHOR_PASSWORD "" + +/* Recipient email address */ +#define RECIPIENT_EMAIL "" + +/* Declare the global used SMTPSession object for SMTP transport */ +SMTPSession smtp; + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status); + +const char rootCACert[] PROGMEM = "-----BEGIN CERTIFICATE-----\n" + "-----END CERTIFICATE-----\n"; + +void sendEmail() +{ + /* Declare the Session_Config for user defined session credentials */ + Session_Config config; + + /* Set the session config */ + config.server.host_name = SMTP_HOST; + config.server.port = SMTP_PORT; + config.login.email = AUTHOR_EMAIL; + config.login.password = AUTHOR_PASSWORD; + config.login.user_domain = F("127.0.0.1"); + + /* + Set the NTP config time + For times east of the Prime Meridian use 0-12 + For times west of the Prime Meridian add 12 to the offset. + Ex. American/Denver GMT would be -6. 6 + 12 = 18 + See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets + */ + config.time.ntp_server = F("pool.ntp.org,time.nist.gov"); + config.time.gmt_offset = 0; + config.time.day_light_offset = 0; + config.time.timezone_env_string = "JST-9"; // for Tokyo + + // See the timezone environment string list from https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv + + /* Declare the message class */ + SMTP_Message message; + + /* Set the message headers */ + message.sender.name = F("ESP Mail"); // This witll be used with 'MAIL FROM' command and 'From' header field. + message.sender.email = AUTHOR_EMAIL; // This witll be used with 'From' header field. + message.subject = F("Test sending plain text Email"); + message.addRecipient(F("Someone"), RECIPIENT_EMAIL); // This will be used with RCPT TO command and 'To' header field. + + String textMsg = "This is simple plain text message"; + message.text.content = textMsg; + + /** If the message to send is a large string, to reduce the memory used from internal copying while sending, + * you can assign string to message.text.blob by cast your string to uint8_t array like this + * + * String myBigString = "..... ......"; + * message.text.blob.data = (uint8_t *)myBigString.c_str(); + * message.text.blob.size = myBigString.length(); + * + * or assign string to message.text.nonCopyContent, like this + * + * message.text.nonCopyContent = myBigString.c_str(); + * + * Only base64 encoding is supported for content transfer encoding in this case. + */ + + /** The Plain text message character set e.g. + * us-ascii + * utf-8 + * utf-7 + * The default value is utf-8 + */ + message.text.charSet = F("us-ascii"); + + /** The content transfer encoding e.g. + * enc_7bit or "7bit" (not encoded) + * enc_qp or "quoted-printable" (encoded) + * enc_base64 or "base64" (encoded) + * enc_binary or "binary" (not encoded) + * enc_8bit or "8bit" (not encoded) + * The default value is "7bit" + */ + message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; + + // If this is a reply message + // message.in_reply_to = ""; + // message.references = " "; + + /** The message priority + * esp_mail_smtp_priority_high or 1 + * esp_mail_smtp_priority_normal or 3 + * esp_mail_smtp_priority_low or 5 + * The default value is esp_mail_smtp_priority_low + */ + message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; + + // message.response.reply_to = "someone@somemail.com"; + // message.response.return_path = "someone@somemail.com"; + + /** The Delivery Status Notifications e.g. + * esp_mail_smtp_notify_never + * esp_mail_smtp_notify_success + * esp_mail_smtp_notify_failure + * esp_mail_smtp_notify_delay + * The default value is esp_mail_smtp_notify_never + */ + // message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; + + /* Set the custom message header */ + message.addHeader(F("Message-ID: ")); + + // For Root CA certificate verification (ESP8266 and ESP32 only) + // config.certificate.cert_data = rootCACert; + // or + // config.certificate.cert_file = "/path/to/der/file"; + // config.certificate.cert_file_storage_type = esp_mail_file_storage_type_flash; // esp_mail_file_storage_type_sd + // config.certificate.verify = true; + + // The WiFiNINA firmware the Root CA certification can be added via the option in Firmware update tool in Arduino IDE + + /* Connect to server with the session config */ + + // Library will be trying to sync the time with NTP server if time is never sync or set. + // This is 10 seconds blocking process. + // If time reading was timed out, the error "NTP server time reading timed out" will show via debug and callback function. + // You can manually sync time by yourself with NTP library or calling configTime in ESP32 and ESP8266. + // Time can be set manually with provided timestamp to function smtp.setSystemTime. + + /* Connect to the server */ + if (!smtp.connect(&config)) + { + MailClient.printf("Connection error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + return; + } + + /* Start sending Email and close the session */ + if (!MailClient.sendMail(&smtp, &message)) + MailClient.printf("Error, Status Code: %d, Error Code: %d, Reason: %s", smtp.statusCode(), smtp.errorCode(), smtp.errorReason().c_str()); + + // to clear sending result log + // smtp.sendingResult.clear(); + + MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap()); +} + +void setup() +{ + + Serial.begin(115200); + + Serial.println(); + + Serial.print("Connecting to AP"); + + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) + { + Serial.print("."); + delay(200); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + Serial.println(); + + /** Enable the debug via Serial port + * 0 for no debugging + * 1 for basic level debugging + * + * Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h + */ + smtp.debug(1); + + /* Set the callback function to get the sending results */ + smtp.callback(smtpCallback); + + sendEmail(); + + // Sleep for 60 seconds + + Serial.println("Going to sleep for 60 seconds..."); + +#if defined(ESP32) + + esp_sleep_enable_timer_wakeup(60 * 1000000); + + esp_deep_sleep_start(); + +#endif +} + +void loop() +{ +} + +/* Callback function to get the Email sending status */ +void smtpCallback(SMTP_Status status) +{ + /* Print the current status */ + Serial.println(status.info()); + + /* Print the sending result */ + if (status.success()) + { + // MailClient.printf used in the examples is for format printing via debug Serial port + // that works for all supported Arduino platform SDKs e.g. AVR, SAMD, ESP32 and ESP8266. + // In ESP8266 and ESP32, you can use Serial.printf directly. + + Serial.println("----------------"); + MailClient.printf("Message sent success: %d\n", status.completedCount()); + MailClient.printf("Message sent failed: %d\n", status.failedCount()); + Serial.println("----------------\n"); + struct tm dt; + + for (size_t i = 0; i < smtp.sendingResult.size(); i++) + { + /* Get the result item */ + SMTP_Result result = smtp.sendingResult.getItem(i); + + // In case, ESP32, ESP8266 and SAMD device, the timestamp get from result.timestamp should be valid if + // your device time was synched with NTP server. + // Other devices may show invalid timestamp as the device time was not set i.e. it will show Jan 1, 1970. + // You can call smtp.setSystemTime(xxx) to set device time manually. Where xxx is timestamp (seconds since Jan 1, 1970) + + MailClient.printf("Message No: %d\n", i + 1); + MailClient.printf("Status: %s\n", result.completed ? "success" : "failed"); + MailClient.printf("Date/Time: %s\n", MailClient.Time.getDateTimeString(result.timestamp, "%B %d, %Y %H:%M:%S").c_str()); + MailClient.printf("Recipient: %s\n", result.recipients.c_str()); + MailClient.printf("Subject: %s\n", result.subject.c_str()); + } + Serial.println("----------------\n"); + + // You need to clear sending result as the memory usage will grow up. + smtp.sendingResult.clear(); + } +} diff --git a/lib/libesp32/lib_mail/keywords.txt b/lib/libesp32/ESP-Mail-Client/keywords.txt similarity index 62% rename from lib/libesp32/lib_mail/keywords.txt rename to lib/libesp32/ESP-Mail-Client/keywords.txt index 8e669d92c..86c058045 100644 --- a/lib/libesp32/lib_mail/keywords.txt +++ b/lib/libesp32/ESP-Mail-Client/keywords.txt @@ -1,127 +1,194 @@ -###################################### -# Syntax Coloring Map ESP Mail Client -###################################### - -####################################### -# Classes and Structured Type (KEYWORD1) -####################################### - -MailClient KEYWORD1 -IMAPSession KEYWORD1 -SMTPSession KEYWORD1 -SMTP_Message KEYWORD1 -IMAP_Config KEYWORD1 -FoldersCollection KEYWORD1 -imapStatusCallback KEYWORD1 -IMAP_MSG_List KEYWORD1 -SelectedFolderInfo KEYWORD1 -ESP_Mail_Session KEYWORD1 -smtpStatusCallback KEYWORD1 -SMTP_Attachment KEYWORD1 -SMTP_Result KEYWORD1 -IMAP_MSG_Item KEYWORD1 -Content_Transfer_Encoding KEYWORD1 -MessageList KEYWORD1 - -############################################### -# Methods and Functions (KEYWORD2) -############################################### - -sendMail KEYWORD2 -readMail KEYWORD2 -setFlag KEYWORD2 -addFlag KEYWORD2 -removeFlag KEYWORD2 -sdBegin KEYWORD2 -sdMMCBegin KEYWORD2 -connect KEYWORD2 -closeSession KEYWORD2 -debug KEYWORD2 -getFolders KEYWORD2 -selectFolder KEYWORD2 -openFolder KEYWORD2 -closeFolder KEYWORD2 -callback KEYWORD2 -headerOnly KEYWORD2 -data KEYWORD2 -selectedFolder KEYWORD2 -errorReason KEYWORD2 -empty KEYWORD2 -resetAttachItem KEYWORD2 -clear KEYWORD2 -clearInlineimages KEYWORD2 -clearAttachments KEYWORD2 -clearRFC822Messages KEYWORD2 -clearRecipients KEYWORD2 -clearCc KEYWORD2 -clearBcc KEYWORD2 -clearHeader KEYWORD2 -addAttachment KEYWORD2 -addParallelAttachment KEYWORD2 -addInlineImage KEYWORD2 -addMessage KEYWORD2 -addRecipient KEYWORD2 -addCc KEYWORD2 -addBcc KEYWORD2 -addHeader KEYWORD2 -info KEYWORD2 -successs KEYWORD2 -completedCount KEYWORD2 -failedCount KEYWORD2 -getItem KEYWORD2 -size KEYWORD2 -flagCount KEYWORD2 -msgCount KEYWORD2 -nextUID KEYWORD2 -searchCount KEYWORD2 -availableMessages KEYWORD2 -flag KEYWORD2 -setClock KEYWORD2 -getUnixTime KEYWORD2 -getTimestamp KEYWORD2 -getYear KEYWORD2 -getMonth KEYWORD2 -getDay KEYWORD2 -getDayOfWeek KEYWORD2 -getDayOfWeekString KEYWORD2 -getHour KEYWORD2 -getMin KEYWORD2 -getSecond KEYWORD2 -getNumberOfDayThisYear KEYWORD2 -getTotalDays KEYWORD2 -dayofWeek KEYWORD2 -getCurrentSecond KEYWORD2 -getCurrentTimestamp KEYWORD2 -getTimeFromSec KEYWORD2 -getDateTimeString KEYWORD2 -copyMessages KEYWORD2 -deleteMessages KEYWORD2 -createFolder KEYWORD2 -deleteFolder KEYWORD2 - - -####################################### -# Struct (KEYWORD3) -####################################### - -esp_mail_email_info_t KEYWORD3 -esp_mail_plain_body_t KEYWORD3 -esp_mail_html_body_t KEYWORD3 -esp_mail_smtp_msg_response_t KEYWORD3 -esp_mail_smtp_enable_option_t KEYWORD3 -esp_mail_email_info_t KEYWORD3 -esp_mail_folder_info_item_t KEYWORD3 -esp_mail_sesson_sever_config_t KEYWORD3 -esp_mail_sesson_login_config_t KEYWORD3 -esp_mail_sesson_secure_config_t KEYWORD3 -esp_mail_sesson_cert_config_t KEYWORD3 -esp_mail_imap_fetch_config_t KEYWORD3 -esp_mail_imap_search_config_t KEYWORD3 -esp_mail_imap_limit_config_t KEYWORD3 -esp_mail_imap_enable_config_t KEYWORD3 -esp_mail_imap_download_config_t KEYWORD3 -esp_mail_imap_storage_config_t KEYWORD3 - -esp_mail_file_storage_type_none KEYWORD3 -esp_mail_file_storage_type_flash KEYWORD3 -esp_mail_file_storage_type_sd KEYWORD3 \ No newline at end of file +###################################### +# Syntax Coloring Map ESP Mail Client +###################################### + +####################################### +# Classes and Structured Type (KEYWORD1) +####################################### + +MailClient KEYWORD1 +IMAPSession KEYWORD1 +SMTPSession KEYWORD1 +SMTP_Message KEYWORD1 +IMAP_Config KEYWORD1 +IMAP_Data KEYWORD2 +FoldersCollection KEYWORD1 +imapStatusCallback KEYWORD1 +IMAP_MSG_List KEYWORD1 +SelectedFolderInfo KEYWORD1 +ESP_Mail_Session KEYWORD1 +Session_Config KEYWORD1 +smtpStatusCallback KEYWORD1 +imapResponseCallback KEYWORD1 +SMTP_Attachment KEYWORD1 +SMTP_Result KEYWORD1 +IMAP_MSG_Item KEYWORD1 +Content_Transfer_Encoding KEYWORD1 +MessageList KEYWORD1 + +############################################### +# Methods and Functions (KEYWORD2) +############################################### + +sendMail KEYWORD2 +appendMessage KEYWORD2 +readMail KEYWORD2 +setFlag KEYWORD2 +addFlag KEYWORD2 +removeFlag KEYWORD2 +networkReconnect KEYWORD2 +sdBegin KEYWORD2 +sdMMCBegin KEYWORD2 +getFreeHeap KEYWORD2 +connect KEYWORD2 +loginWithPassword KEYWORD2 +loginWithAccessToken KEYWORD2 +isAuthenticated KEYWORD2 +isLoggedIn KEYWORD2 +connected KEYWORD2 +keepAlive KEYWORD2 +isKeepAlive KEYWORD2 +customConnect KEYWORD2 +closeSession KEYWORD2 +debug KEYWORD2 +getFolders KEYWORD2 +selectFolder KEYWORD2 +openFolder KEYWORD2 +closeFolder KEYWORD2 +callback KEYWORD2 +headerOnly KEYWORD2 +data KEYWORD2 +selectedFolder KEYWORD2 +errorReason KEYWORD2 +statusCode KEYWORD2 +statusMessage KEYWORD2 +errorCode KEYWORD2 +empty KEYWORD2 +resetAttachItem KEYWORD2 +clear KEYWORD2 +clearInlineimages KEYWORD2 +clearAttachments KEYWORD2 +clearRFC822Messages KEYWORD2 +clearRecipients KEYWORD2 +clearCc KEYWORD2 +clearBcc KEYWORD2 +clearHeader KEYWORD2 +addAttachment KEYWORD2 +addParallelAttachment KEYWORD2 +addInlineImage KEYWORD2 +addMessage KEYWORD2 +addRecipient KEYWORD2 +addCc KEYWORD2 +addBcc KEYWORD2 +addHeader KEYWORD2 +info KEYWORD2 +successs KEYWORD2 +completedCount KEYWORD2 +failedCount KEYWORD2 +getItem KEYWORD2 +size KEYWORD2 +flagCount KEYWORD2 +msgCount KEYWORD2 +recentCount KEYWORD2 +nextUID KEYWORD2 +pollingStatus KEYWORD2 +searchCount KEYWORD2 +availableMessages KEYWORD2 +flag KEYWORD2 +setClock KEYWORD2 +getUnixTime KEYWORD2 +getTimestamp KEYWORD2 +getYear KEYWORD2 +getMonth KEYWORD2 +getDay KEYWORD2 +getDayOfWeek KEYWORD2 +getDayOfWeekString KEYWORD2 +getHour KEYWORD2 +getMin KEYWORD2 +getSecond KEYWORD2 +getNumberOfDayThisYear KEYWORD2 +getTotalDays KEYWORD2 +dayofWeek KEYWORD2 +getCurrentSecond KEYWORD2 +getCurrentTimestamp KEYWORD2 +getTimeFromSec KEYWORD2 +getDateTimeString KEYWORD2 +copyMessages KEYWORD2 +moveMessages KEYWORD2 +deleteMessages KEYWORD2 +getQuota KEYWORD2 +setQuota KEYWORD2 +getQuotaRoot KEYWORD2 +getACL KEYWORD2 +setACL KEYWORD2 +deleteACL KEYWORD2 +myRights KEYWORD2 +enable KEYWORD2 +getNamespace KEYWORD2 +createFolder KEYWORD2 +renameFolder KEYWORD2 +getSubscribesMailboxes KEYWORD2 +subscribe KEYWORD2 +unSubscribe KEYWORD2 +deleteFolder KEYWORD2 +listen KEYWORD2 +stopListen KEYWORD2 +folderChanged KEYWORD2 +sendCustomCommand KEYWORD2 +sendCustomData KEYWORD2 +toBase64 KEYWORD2 +getFlags KEYWORD2 +getUID KEYWORD2 +setTCPTimeout KEYWORD2 +setClient KEYWORD2 +setGSMClient KEYWORD2 +connectionRequestCallback KEYWORD2 +connectionUpgradeRequestCallback KEYWORD2 +networkConnectionRequestCallback KEYWORD2 +networkDisconnectionRequestCallback KEYWORD2 +networkStatusRequestCallback KEYWORD2 +setSystemTime KEYWORD2 +mimeDataStreamCallback KEYWORD2 +characterDecodingCallback KEYWORD2 +clearAP KEYWORD2 +addAP KEYWORD2 +isFirmwareUpdated KEYWORD2 +id KEYWORD2 +serverID KEYWORD2 +fileList KEYWORD2 +status KEYWORD2 + +####################################### +# Struct (KEYWORD3) +####################################### + +esp_mail_email_info_t KEYWORD3 +esp_mail_plain_body_t KEYWORD3 +esp_mail_html_body_t KEYWORD3 +esp_mail_smtp_msg_response_t KEYWORD3 +esp_mail_smtp_enable_option_t KEYWORD3 +esp_mail_email_info_t KEYWORD3 +esp_mail_folder_info_item_t KEYWORD3 +esp_mail_sesson_sever_config_t KEYWORD3 +esp_mail_sesson_login_config_t KEYWORD3 +esp_mail_sesson_secure_config_t KEYWORD3 +esp_mail_sesson_cert_config_t KEYWORD3 +esp_mail_imap_fetch_config_t KEYWORD3 +esp_mail_imap_search_config_t KEYWORD3 +esp_mail_imap_limit_config_t KEYWORD3 +esp_mail_imap_enable_config_t KEYWORD3 +esp_mail_imap_download_config_t KEYWORD3 +esp_mail_imap_storage_config_t KEYWORD3 +esp_mail_imap_polling_status_t KEYWORD3 +IMAP_Polling_Status KEYWORD3 +IMAP_Identification KEYWORD3 + +esp_mail_file_storage_type_none KEYWORD3 +esp_mail_file_storage_type_flash KEYWORD3 +esp_mail_file_storage_type_sd KEYWORD3 + +###################################### +# Constants (LITERAL1) +####################################### + +ESP_MAIL_PRINTF LITERAL1 \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/library.json b/lib/libesp32/ESP-Mail-Client/library.json new file mode 100644 index 000000000..6f1953984 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/library.json @@ -0,0 +1,16 @@ +{ + "name": "ESP Mail Client", + "version": "3.4.9", + "keywords": "communication, email, imap, smtp, esp32, esp8266, samd, arduino", + "description": "Arduino E-Mail Client Library to send, read and get incoming email notification for ESP32, ESP8266 and SAMD21 devices. The library also supported other Arduino Devices using Clients interfaces e.g. WiFiClient, EthernetClient, and GSMClient.", + "repository": { + "type": "git", + "url": "https://github.com/mobizt/ESP-Mail-Client.git" + }, + "authors": [{ + "name": "Mobizt", + "email": "suwatchai@outlook.com" + }], + "frameworks": "arduino", + "platforms": "espressif32, espressif8266, atmelsam, atmelavr, atmelmegaavr, ststm32, teensy, rp2040" +} diff --git a/lib/libesp32/ESP-Mail-Client/library.properties b/lib/libesp32/ESP-Mail-Client/library.properties new file mode 100644 index 000000000..80b2d2c7e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/library.properties @@ -0,0 +1,17 @@ +name=ESP Mail Client + +version=3.4.9 + +author=Mobizt + +maintainer=Mobizt + +sentence=Arduino E-Mail Client Library to send, read and get incoming email notification for ESP32, ESP8266 and SAMD21 devices. + +paragraph=The library also supported other Arduino devices using Clients interfaces e.g. WiFiClient, EthernetClient, and GSMClient. + +category=Communication + +url=https://github.com/mobizt/ESP-Mail-Client + +architectures=esp8266,esp32,sam,samd,stm32,STM32F1,STM32F4,teensy,avr,megaavr,mbed_nano,mbed_rp2040,rp2040 diff --git a/lib/libesp32/lib_mail/media/images/ArduinoIDE.png b/lib/libesp32/ESP-Mail-Client/media/images/ArduinoIDE.png similarity index 100% rename from lib/libesp32/lib_mail/media/images/ArduinoIDE.png rename to lib/libesp32/ESP-Mail-Client/media/images/ArduinoIDE.png diff --git a/lib/libesp32/ESP-Mail-Client/media/images/ESP32-PSRAM.png b/lib/libesp32/ESP-Mail-Client/media/images/ESP32-PSRAM.png new file mode 100644 index 000000000..4e5ece8f1 Binary files /dev/null and b/lib/libesp32/ESP-Mail-Client/media/images/ESP32-PSRAM.png differ diff --git a/lib/libesp32/ESP-Mail-Client/media/images/ESP8266_VM.png b/lib/libesp32/ESP-Mail-Client/media/images/ESP8266_VM.png new file mode 100644 index 000000000..abf0090ee Binary files /dev/null and b/lib/libesp32/ESP-Mail-Client/media/images/ESP8266_VM.png differ diff --git a/lib/libesp32/ESP-Mail-Client/media/images/SerialNINAPassthrough.png b/lib/libesp32/ESP-Mail-Client/media/images/SerialNINAPassthrough.png new file mode 100644 index 000000000..130e78fce Binary files /dev/null and b/lib/libesp32/ESP-Mail-Client/media/images/SerialNINAPassthrough.png differ diff --git a/lib/libesp32/lib_mail/media/images/esp-mail-client.png b/lib/libesp32/ESP-Mail-Client/media/images/esp-mail-client.png similarity index 100% rename from lib/libesp32/lib_mail/media/images/esp-mail-client.png rename to lib/libesp32/ESP-Mail-Client/media/images/esp-mail-client.png diff --git a/lib/libesp32/lib_mail/media/images/esp-mail-client.svg b/lib/libesp32/ESP-Mail-Client/media/images/esp-mail-client.svg similarity index 100% rename from lib/libesp32/lib_mail/media/images/esp-mail-client.svg rename to lib/libesp32/ESP-Mail-Client/media/images/esp-mail-client.svg diff --git a/lib/libesp32/ESP-Mail-Client/media/images/esptool.png b/lib/libesp32/ESP-Mail-Client/media/images/esptool.png new file mode 100644 index 000000000..17c9c143d Binary files /dev/null and b/lib/libesp32/ESP-Mail-Client/media/images/esptool.png differ diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client.cpp b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client.cpp new file mode 100644 index 000000000..4c58543a2 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client.cpp @@ -0,0 +1,1933 @@ +#ifndef ESP_MAIL_CLIENT_CPP +#define ESP_MAIL_CLIENT_CPP + +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +/** + * Mail Client Arduino Library for Arduino devices. + * + * Created August 28, 2023 + * + * This library allows Espressif's ESP32, ESP8266, SAMD and RP2040 Pico devices to send and read Email through the SMTP and IMAP servers. + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "ESP_Mail_Client.h" +#include "ESP_Mail_Client_Version.h" + +#include "ESP_Mail_IMAP.h" +#include "ESP_Mail_SMTP.h" + +void ESP_Mail_Client::networkReconnect(bool reconnect) +{ +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) && (defined(ESP32) || defined(ESP8266)) + WiFi.setAutoReconnect(reconnect); +#endif + networkAutoReconnect = reconnect; +} + +void ESP_Mail_Client::printf(const char *format, ...) +{ + int size = 2048; + char s[size]; + va_list va; + va_start(va, format); + vsnprintf(s, size, format, va); + va_end(va); + ESP_MAIL_DEFAULT_DEBUG_PORT.print(s); +} + +void ESP_Mail_Client::addAP(const String &ssid, const String &password) +{ + wifi.addAP(ssid, password); +} + +void ESP_Mail_Client::clearAP() +{ + wifi.clearAP(); +} + +#if defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD) + +bool ESP_Mail_Client::sdBegin(int8_t ss, int8_t sck, int8_t miso, int8_t mosi, uint32_t frequency) +{ + return mbfs->sdBegin(ss, sck, miso, mosi, frequency); +} + +#if defined(ESP8266) || defined(MB_ARDUINO_PICO) +bool ESP_Mail_Client::sdBegin(SDFSConfig *sdFSConfig) +{ + return mbfs->sdFatBegin(sdFSConfig); +} +#endif + +#if defined(ESP32) +bool ESP_Mail_Client::sdBegin(int8_t ss, SPIClass *spiConfig, uint32_t frequency) +{ + return mbfs->sdSPIBegin(ss, spiConfig, frequency); +} +#endif + +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) +bool ESP_Mail_Client::sdBegin(SdSpiConfig *sdFatSPIConfig, int8_t ss, int8_t sck, int8_t miso, int8_t mosi) +{ + return mbfs->sdFatBegin(sdFatSPIConfig, ss, sck, miso, mosi); +} + +bool ESP_Mail_Client::sdBegin(SdioConfig *sdFatSDIOConfig) +{ + return mbfs->sdFatBegin(sdFatSDIOConfig); +} +#endif + +#endif + +#if defined(ESP32) && defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD_MMC) + +bool ESP_Mail_Client::sdMMCBegin(const char *mountpoint, bool mode1bit, bool format_if_mount_failed) +{ + return mbfs->sdMMCBegin(mountpoint, mode1bit, format_if_mount_failed); +} + +#endif + +int ESP_Mail_Client::getFreeHeap() +{ +#if defined(MB_ARDUINO_ESP) + return ESP.getFreeHeap(); +#elif defined(MB_ARDUINO_PICO) + return rp2040.getFreeHeap(); +#else + return 0; +#endif +} + +// All following functions are for IMAP or SMTP only +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + +void ESP_Mail_Client::resumeNetwork(ESP_Mail_TCPClient *client) +{ + client->networkReconnect(); +} + +template +bool ESP_Mail_Client::sessionExisted(T sessionPtr) +{ + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + + Session_Config *config = sessionPtr->_session_cfg; + _vectorImpl *configPtrList = &(sessionPtr->_configPtrList); + + if (config) + { + int ptr = toAddr(*config); + for (size_t i = 0; i < configPtrList->size(); i++) + { + if ((*configPtrList)[i] == ptr) + return true; + } + + sessionPtr->closeSession(); + sessionPtr->_responseStatus.errorCode = MAIL_CLIENT_ERROR_SESSION_CONFIG_WAS_NOT_ASSIGNED; + sessionPtr->_responseStatus.text.clear(); + } + +#endif + return false; +} + +void ESP_Mail_Client::debugPrintNewLine() +{ +#if !defined(SILENT_MODE) + esp_mail_debug_print("", true); +#endif +} + +template +void ESP_Mail_Client::callBackSendNewLine(T sessionPtr, bool success) +{ +#if defined(SESSION_DEBUG_ENABLED) + sendCallback(sessionPtr, "", false, success); +#endif +} + +void ESP_Mail_Client::appendTagSpace(MB_String &buf, PGM_P tag) +{ + buf += (tag == NULL) ? esp_mail_imap_tag_str : tag; + appendSpace(buf); +} + +template +void ESP_Mail_Client::appendList(MB_String &buf, _vectorImpl &list) +{ + for (size_t i = 0; i < list.size(); i++) + { + if (i > 0) + buf += esp_mail_str_8; /* "," */ + buf += list[i]; + } +} + +void ESP_Mail_Client::appendSpace(MB_String &buf) +{ + buf += esp_mail_str_2 /* " " */; +} + +void ESP_Mail_Client::appendSpace(MB_String &buf, bool withTag, PGM_P value) +{ + if (withTag) + appendTagSpace(buf); + buf += value; + appendSpace(buf); +} + +void ESP_Mail_Client::appendSpace(MB_String &buf, bool withTag, int nunArgs, ...) +{ + if (withTag) + appendTagSpace(buf); + + va_list ap; + va_start(ap, nunArgs); + PGM_P p = va_arg(ap, PGM_P); + if (p) + buf += p; + for (int i = 2; i <= nunArgs; i++) + { + appendSpace(buf); + p = va_arg(ap, PGM_P); + if (p) + buf += p; + } + va_end(ap); + appendSpace(buf); +} + +void ESP_Mail_Client::prependSpace(MB_String &buf, PGM_P value) +{ + appendSpace(buf); + buf += value; +} + +void ESP_Mail_Client::appendDot(MB_String &buf) +{ + buf += esp_mail_str_27; /* "." */ +} + +void ESP_Mail_Client::prependDot(MB_String &buf, PGM_P value) +{ + buf += esp_mail_str_27; /* "." */ + buf += value; +} + +void ESP_Mail_Client::joinStringSpace(MB_String &buf, bool withTag, int nunArgs, ...) +{ + if (withTag) + appendTagSpace(buf); + + va_list ap; + va_start(ap, nunArgs); + PGM_P p = va_arg(ap, PGM_P); + if (p) + buf += p; + for (int i = 2; i <= nunArgs; i++) + { + appendSpace(buf); + p = va_arg(ap, PGM_P); + if (p) + buf += p; + } + va_end(ap); +} + +void ESP_Mail_Client::appendImap4KeyValue(MB_String &buf, PGM_P key, PGM_P value) +{ + buf += esp_mail_str_11; /* "\"" */ + buf += key; + buf += esp_mail_str_11; /* "\"" */ + appendSpace(buf); + buf += esp_mail_str_11; /* "\"" */ + buf += value; + buf += esp_mail_str_11; /* "\"" */ +} + +void ESP_Mail_Client::joinStringDot(MB_String &buf, int nunArgs, ...) +{ + va_list ap; + va_start(ap, nunArgs); + PGM_P p = va_arg(ap, PGM_P); + if (p) + buf += p; + for (int i = 2; i <= nunArgs; i++) + { + buf += esp_mail_str_27; /* "." */ + p = va_arg(ap, PGM_P); + if (p) + buf += p; + } + va_end(ap); +} + +template +void ESP_Mail_Client::sendCallback(T sessionPtr, PGM_P info, bool prependCRLF, bool success) +{ + +#if defined(SESSION_DEBUG_ENABLED) + + sessionPtr->_cbData._info.clear(); + + if (prependCRLF) + appendNewline(sessionPtr->_cbData._info); + if (strlen_P(info) > 0) + { + sessionPtr->_cbData._info += esp_mail_str_33; /* "#### " */ + sessionPtr->_cbData._info += info; + } + sessionPtr->_cbData._success = success; + if (sessionPtr->_statusCallback && !sessionPtr->_customCmdResCallback) + sessionPtr->_statusCallback(sessionPtr->_cbData); + +#endif +} + +template +void ESP_Mail_Client::printDebug(T sessionPtr, PGM_P cbMsg, PGM_P dbMsg, esp_mail_debug_tag_type type, bool prependCRLF, bool success) +{ +#if defined(SESSION_DEBUG_ENABLED) + + if (sessionPtr->_statusCallback != NULL && !isResponseCB(sessionPtr)) + sendCallback(sessionPtr, cbMsg, prependCRLF, success); + else if (sessionPtr->_debug) + debugPrintNewLine(); + + if (sessionPtr->_debug) + esp_mail_debug_print_tag(dbMsg, type, true); + +#endif +} + +void ESP_Mail_Client::printProgress(int progress, int &lastProgress) +{ +#if !defined(SILENT_MODE) + if (progress > 100) + progress = 100; + + if (lastProgress != progress && (progress == 0 || progress == 100 || lastProgress + ESP_MAIL_PROGRESS_REPORT_STEP <= progress)) + { + int len = 16; + int curTick = progress * len / 100; + int lastTick = lastProgress * len / 100; + + if (curTick > lastTick || progress == 0 || progress == 100) + { + MB_String s; + for (int i = 0; i < len; i++) + { + if (i == 0) + s = '['; + s += i < progress * len / 100 ? '#' : ' '; + if (i == len - 1) + s += ']'; + } + appendSpace(s); + s += progress; + appendSpace(s); + s += esp_mail_str_24; /* "%" */ + esp_mail_debug_print_tag(s.c_str(), esp_mail_debug_tag_type_client, true); + } + + lastProgress = progress; + } +#endif +} + +void ESP_Mail_Client::setTimezone(const char *TZ_Var, const char *TZ_file) +{ + + if (!TZ_Var) + return; + +#if defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO) + if (strlen(TZ_Var) > 0) + { + +#if defined(ESP32) + + mb_fs_mem_storage_type type = mb_fs_mem_storage_type_undefined; + +#if defined(MBFS_FLASH_FS) + type = mb_fs_mem_storage_type_flash; +#elif defined(MBFS_SD_FS) + type = mb_fs_mem_storage_type_sd; +#endif + + if (type != mb_fs_mem_storage_type_undefined) + { + MB_String filename = TZ_file; + if (mbfs->open(filename, type, mb_fs_open_mode_write) > -1) + { + mbfs->print(type, TZ_Var); + mbfs->close(type); + } + } + +#endif + + setenv("TZ", TZ_Var, 1); + tzset(); + timezoneEnvSet = true; + } +#endif +} + +void ESP_Mail_Client::preparePortFunction(Session_Config *session_config, bool isSMTP, bool &secure, bool &secureMode, bool &ssl) +{ + + if (session_config->ports_functions.list) + { + if (session_config->ports_functions.use_internal_list) + { + session_config->ports_functions.use_internal_list = false; + delete[] session_config->ports_functions.list; + session_config->ports_functions.list = nullptr; + } + } + + if (!session_config->ports_functions.list) + { + if (isSMTP) + { +#if defined(ENABLE_SMTP) + session_config->ports_functions.use_internal_list = true; + session_config->ports_functions.list = new port_function[3]; + session_config->ports_functions.size = 3; + + for (int i = 0; i < 3; i++) + session_config->ports_functions.list[i] = smtp_ports[i]; +#endif + } + else + { +#if defined(ENABLE_IMAP) + session_config->ports_functions.use_internal_list = true; + session_config->ports_functions.list = new port_function[2]; + session_config->ports_functions.size = 2; + + for (int i = 0; i < 2; i++) + session_config->ports_functions.list[i] = imap_ports[i]; +#endif + } + } + + getPortFunction(session_config->server.port, session_config->ports_functions, secure, secureMode, ssl, session_config->secure.startTLS); +} + +void ESP_Mail_Client::getPortFunction(uint16_t port, struct esp_mail_ports_functions &ports_functions, bool &secure, bool &secureMode, bool &ssl, bool &starttls) +{ + for (size_t i = 0; i < ports_functions.size; i++) + { + if (ports_functions.list[i].port == port) + { + if (ports_functions.list[i].protocol == esp_mail_protocol_plain_text) + { + secure = false; + secureMode = false; + } + else + { + if (ports_functions.list[i].protocol == esp_mail_protocol_tls) + starttls = true; + + secureMode = !starttls; + + if (ports_functions.list[i].protocol == esp_mail_protocol_ssl) + ssl = true; + } + return; + } + } +} + +void ESP_Mail_Client::getTimezone(const char *TZ_file, MB_String &out) +{ + +#if defined(ESP32) + + mb_fs_mem_storage_type type = mb_fs_mem_storage_type_undefined; + +#if defined(MBFS_FLASH_FS) + type = mb_fs_mem_storage_type_flash; +#elif defined(MBFS_SD_FS) + type = mb_fs_mem_storage_type_sd; +#endif + + if (type != mb_fs_mem_storage_type_undefined) + { + MB_String filename = TZ_file; + + if (mbfs->open(filename, type, mb_fs_open_mode_read) > 0) + { + out.clear(); + while (mbfs->available(type)) + { + out += (char)mbfs->read(type); + } + mbfs->close(type); + } + } +#endif +} + +void ESP_Mail_Client::setTime(const char *TZ_Var, const char *TZ_file, bool wait, bool debugProgress) +{ + + timeStatus = Time.timeReady(); + + if (!timeStatus) + { + +#if defined(ENABLE_IMAP) || defined(ENABLE_SMTP) + +#if defined(ENABLE_NTP_TIME) + + if (WiFI_CONNECTED) + { + Time.readNTPTime(wait ? 10000 : 0, debugProgress); + } + else + { +#if !defined(SILENT_MODE) + esp_mail_debug_print_tag(esp_mail_error_client_str_4 /* "NTP server time reading cannot begin when valid time is required because of no WiFi capability/activity detected." */, esp_mail_debug_tag_type_warning, true); + esp_mail_debug_print_tag(esp_mail_error_client_str_5 /* "Please set the library reference time manually using smtp.setSystemTime or imap.setSystemTime." */, esp_mail_debug_tag_type_warning, true); +#endif + } + + getSetTimezoneEnv(TZ_file, TZ_Var); + +#elif !defined(SILENT_MODE) + esp_mail_debug_print_tag(esp_mail_error_client_str_5 /* "Please set the library reference time manually using smtp.setSystemTime or imap.setSystemTime." */, esp_mail_debug_tag_type_warning, true); +#endif + +#endif + } + + timeStatus = Time.timeReady(); +} + +void ESP_Mail_Client::getSetTimezoneEnv(const char *TZ_file, const char *TZ_Var) +{ + // set and get TZ environment variable + + MB_String timezone; + + // only ESP32 only + getTimezone(TZ_file, timezone); + + if (timezone.length() == 0) + timezone = TZ_Var; + + // if timezone string assign + setTimezone(timezone.c_str(), TZ_file); +} + +bool ESP_Mail_Client::validEmail(const char *s) +{ + MB_String str(s); + size_t at = str.find('@'); + size_t dot = str.find('.', at); + return (at != MB_String::npos) && (dot != MB_String::npos); +} + +#if defined(ENABLE_SMTP) && defined(ENABLE_IMAP) + +bool ESP_Mail_Client::mAppendMessage(IMAPSession *imap, SMTP_Message *msg, bool lastAppend, MB_StringPtr flags, MB_StringPtr dateTime) +{ + this->imap = imap; + calDataLen = true; + dataLen = 0; + imap_ts = 0; + + if (!sessionExisted(imap)) + return false; + + MB_String _flags = flags; + _flags.trim(); + + MB_String _dt = dateTime; + _dt.trim(); + + bool rfc822MSG = false; + + sendContent(nullptr, msg, false, rfc822MSG); + + MB_String cmd; + + if (!imap->_feature_capability[esp_mail_imap_read_capability_multiappend]) + { + lastAppend = true; + imap->_prev_imap_cmd = esp_mail_imap_cmd_sasl_login; + } + + if (imap->_prev_imap_cmd != esp_mail_imap_cmd_append) + joinStringSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_append].text, imap->_currentFolder.c_str()); + + appendSpace(cmd); + + if (_flags.length() > 0) + { + appendString(cmd, _flags.c_str(), false, false, esp_mail_string_mark_type_round_bracket); + appendSpace(cmd); + } + + if (_dt.length() > 0) + { + appendString(cmd, _dt.c_str(), false, false, esp_mail_string_mark_type_double_quote); + appendSpace(cmd); + } + + appendString(cmd, MB_String((int)dataLen).c_str(), false, false, esp_mail_string_mark_type_curly_bracket); + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + { + imap->_prev_imap_cmd = esp_mail_imap_cmd_sasl_login; + return false; + } + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_append; + + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false)) + { + imap->_prev_imap_cmd = esp_mail_imap_cmd_sasl_login; + return false; + } + + calDataLen = false; + + rfc822MSG = false; + + if (!sendContent(nullptr, msg, false, rfc822MSG)) + { + imap->_prev_imap_cmd = esp_mail_imap_cmd_sasl_login; + return false; + } + + if (lastAppend) + { + if (imapSend(imap, esp_mail_str_18 /* "\r\n" */, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + { + imap->_prev_imap_cmd = esp_mail_imap_cmd_sasl_login; + return false; + } + + imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_append_last; + + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false)) + { + imap->_prev_imap_cmd = esp_mail_imap_cmd_sasl_login; + return false; + } + + imap->_prev_imap_cmd = esp_mail_imap_cmd_sasl_login; + } + + if (!lastAppend) + imap->_prev_imap_cmd = esp_mail_imap_cmd_append; + else + { +#if !defined(SILENT_MODE) + altSendCallback(nullptr, esp_mail_cb_str_45 /* "Message append successfully" */, esp_mail_dbg_str_73 /* "message append successfully" */, esp_mail_debug_tag_type_client, true, false); +#endif + } + return true; +} + +#endif + +char *ESP_Mail_Client::getRandomUID() +{ + char *tmp = allocMem(36); + sprintf(tmp, "%d", (int)random(2000, 4000)); + return tmp; +} + +void ESP_Mail_Client::splitToken(const char *str, _vectorImpl &tk, const char *delim) +{ + char *p = allocMem(strlen(str)); + strcpy(p, str); + char *pp = p; + char *end = p; + MB_String tmp; + while (pp != NULL) + { + // See RFC2047.h + ESP_MAIL_STRSEP(&end, delim); + if (strlen(pp) > 0) + { + tmp = pp; + tk.push_back(tmp); + } + pp = end; + } + // release memory + freeMem(&p); +} + +int ESP_Mail_Client::strpos(const char *haystack, const char *needle, int offset, bool caseSensitive) +{ + if (!haystack || !needle) + return -1; + + int hlen = strlen(haystack); + int nlen = strlen(needle); + + if (hlen == 0 || nlen == 0) + return -1; + + int hidx = offset, nidx = 0; + while ((*(haystack + hidx) != '\0') && (*(needle + nidx) != '\0') && hidx < hlen) + { + + bool nm = caseSensitive ? *(needle + nidx) != *(haystack + hidx) : tolower(*(needle + nidx)) != tolower(*(haystack + hidx)); + + if (nm) + { + hidx++; + nidx = 0; + } + else + { + nidx++; + hidx++; + if (nidx == nlen) + return hidx - nidx; + } + } + + return -1; +} + +char *ESP_Mail_Client::subStr(const char *buf, PGM_P beginToken, PGM_P endToken, int beginPos, int endPos, bool caseSensitive) +{ + char *tmp = nullptr; + if (beginToken) + { + int p1 = strposP(buf, beginToken, beginPos, caseSensitive); + if (p1 != -1) + { + while (buf[p1 + strlen_P(beginToken)] == ' ' || buf[p1 + strlen_P(beginToken)] == '\r' || buf[p1 + strlen_P(beginToken)] == '\n') + { + p1++; + if (strlen(buf) <= p1 + strlen_P(beginToken)) + { + p1--; + break; + } + } + + int p2 = -1; + if (endPos == 0) + p2 = strposP(buf, endToken, p1 + strlen_P(beginToken), caseSensitive); + + if (p2 == -1) + p2 = strlen(buf); + + int len = p2 - p1 - strlen_P(beginToken); + int ofs = endToken ? strlen_P(endToken) : 1; + tmp = allocMem(len + ofs); + memcpy(tmp, &buf[p1 + strlen_P(beginToken)], len); + } + } + else + { + int p1 = strposP(buf, endToken, beginPos); + if (p1 != -1) + { + tmp = allocMem(p1); + memcpy(tmp, &buf[2], p1 - 1); + } + } + + return tmp; +} + +bool ESP_Mail_Client::getHeader(const char *buf, PGM_P beginToken, MB_String &out, bool caseSensitive) +{ + if (strcmpP(buf, 0, beginToken, caseSensitive)) + { + char *tmp = subStr(buf, beginToken, NULL, 0, -1, caseSensitive); + if (tmp) + { + out = tmp; + // release memory + freeMem(&tmp); + return true; + } + } + + return false; +} + +void ESP_Mail_Client::appendHeaderField(MB_String &buf, const char *name, PGM_P value, bool comma, bool newLine, esp_mail_string_mark_type type) +{ + appendHeaderName(buf, name); + appendString(buf, value, comma, newLine, type); +} + +void ESP_Mail_Client::appendAddressHeaderField(MB_String &buf, esp_mail_address_info_t &source, esp_mail_rfc822_header_field_types type, bool header, bool comma, bool newLine) +{ + // Construct header field. + if (header) + appendHeaderName(buf, rfc822_headers[type].text); + + if (type != esp_mail_rfc822_header_field_cc && type != esp_mail_rfc822_header_field_bcc && + source.name.length() > 0) + { + appendString(buf, source.name.c_str(), false, false, esp_mail_string_mark_type_double_quote); + // Add white space after name for SMTP to fix iCloud Mail Service IMAP search compatibility issue #278 + // This is not restricted by rfc2822. + appendSpace(buf); + } + + appendString(buf, source.email.c_str(), comma, newLine, esp_mail_string_mark_type_angle_bracket); +} + +void ESP_Mail_Client::appendHeaderName(MB_String &buf, const char *name, bool clear, bool lowercase, bool space) +{ + if (clear) + buf.clear(); + + if (lowercase) + appendLowerCaseString(buf, name); + else + buf += name; + buf += esp_mail_str_34; /* ":" */ + if (space) + appendSpace(buf); +} + +void ESP_Mail_Client::appendLowerCaseString(MB_String &buf, PGM_P value, bool clear) +{ + if (clear) + buf.clear(); + char *tmp = strP2Lower(value); + buf += tmp; + freeMem(&tmp); +} + +void ESP_Mail_Client::appendHeaderProp(MB_String &buf, PGM_P prop, const char *value, bool &firstProp, bool lowerCase, bool isString, bool newLine) +{ + if (firstProp) + buf += esp_mail_str_35; /* ";" */ + appendSpace(buf); + if (lowerCase) + appendLowerCaseString(buf, prop); + else + buf += prop; + buf += esp_mail_str_7; /* "=" */ + if (isString) + buf += esp_mail_str_11; /* "\"" */ + buf += value; + if (isString) + buf += esp_mail_str_11; /* "\"" */ + buf += esp_mail_str_35; /* ";" */ + if (newLine) + appendNewline(buf); + + firstProp = false; +} + +void ESP_Mail_Client::appendString(MB_String &buf, PGM_P value, bool comma, bool newLine, esp_mail_string_mark_type type) +{ + if (comma) + buf += esp_mail_str_8; /* "," */ + + switch (type) + { + case esp_mail_string_mark_type_double_quote: + buf += esp_mail_str_11; /* "\"" */ + break; + case esp_mail_string_mark_type_angle_bracket: + buf += esp_mail_str_19; /* "<" */ + break; + case esp_mail_string_mark_type_round_bracket: + buf += esp_mail_str_38; /* "(" */ + break; + case esp_mail_string_mark_type_curly_bracket: + buf += esp_mail_str_36; /* "{" */ + break; + case esp_mail_string_mark_type_square_bracket: + buf += esp_mail_str_40; /* "[" */ + break; + default: + break; + } + + if (value) + buf += value; + + switch (type) + { + case esp_mail_string_mark_type_double_quote: + buf += esp_mail_str_11; /* "\"" */ + break; + case esp_mail_string_mark_type_angle_bracket: + buf += esp_mail_str_20; /* ">" */ + break; + case esp_mail_string_mark_type_round_bracket: + buf += esp_mail_str_39; /* ")" */ + break; + case esp_mail_string_mark_type_curly_bracket: + buf += esp_mail_str_37; /* "}" */ + break; + case esp_mail_string_mark_type_square_bracket: + buf += esp_mail_str_41; /* "]" */ + break; + default: + break; + } + + if (newLine) + appendNewline(buf); +} + +void ESP_Mail_Client::maskString(MB_String &buf, int len) +{ + for (int i = 0; i < len; i++) + buf += esp_mail_str_3; /* "*" */ +} + +void ESP_Mail_Client::appendDomain(MB_String &buf, const char *domain) +{ + buf += strlen(domain) > 0 ? domain : pgm2Str(esp_mail_str_1 /* "127.0.0.1" */); +} + +void ESP_Mail_Client::appendEmbedMessage(MB_String &buf, esp_mail_message_body_t &body, bool isHtml) +{ + appendHeaderName(buf, message_headers[esp_mail_message_header_field_content_disposition].text); + appendString(buf, body.embed.type == esp_mail_smtp_embed_message_type_inline ? esp_mail_content_disposition_type_t::inline_ : esp_mail_content_disposition_type_t::attachment, false, false); + + PGM_P pgm = isHtml ? esp_mail_str_14 /* "msg.html" */ : esp_mail_str_13; /* "msg.txt" */ + MB_String filename; + if (body.embed.filename.length() > 0) + filename = body.embed.filename; + else + filename = pgm; + + bool firstProp = true; + appendHeaderProp(buf, message_headers[esp_mail_message_header_field_filename].text, filename.c_str(), firstProp, true, true, true); + + if (body.embed.type == esp_mail_smtp_embed_message_type_inline) + { + appendHeaderName(buf, message_headers[esp_mail_message_header_field_content_location].text); + body.embed.filename.length() > 0 ? appendString(buf, body.embed.filename.c_str(), false, true) : appendString(buf, pgm, false, true); + appendHeaderField(buf, message_headers[esp_mail_message_header_field_content_id].text, body._int.cid.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); + } +} + +void ESP_Mail_Client::appendNewline(MB_String &buf) +{ + buf += esp_mail_str_18; /* "\r\n" */ +} + +void ESP_Mail_Client::getExtfromMIME(const char *mime, MB_String &ext) +{ + ext.clear(); + for (int i = 0; i < esp_mail_file_extension_maxType; i++) + { + if (strcmp_P(mime, mimeinfo[i].mimeType) == 0) + { + ext = mimeinfo[i].endsWith; + break; + } + } + + if (ext.length() == 0) + ext = esp_mail_str_42; /* ".dat" */ +} + +MB_String ESP_Mail_Client::mGetBase64(MB_StringPtr str) +{ + MB_String data = str; + return encodeBase64Str((uint8_t *)(data.c_str()), data.length()); +} + +int ESP_Mail_Client::readLine(ESP_Mail_TCPClient *client, char *buf, int bufLen, bool withLineBreak, int &count, bool &ovf, unsigned long timeoutSec, bool &isTimeout) +{ + int ret = -1; + char c = 0; + char _c = 0; + int idx = 0; + ovf = idx >= bufLen; + bool lineBreak = false; + isTimeout = false; + + unsigned long ms = millis(); + + // Instead of relying on data available, we looks for line break until timed out or disconnected or overflown occurred. + while (idx < bufLen && client->connected() && (!lineBreak || client->available() /* data may not available sometimes */)) + { + if (millis() - ms >= timeoutSec * 1000) + { + isTimeout = true; + break; + } + + yield_impl(); + + ret = client->read(); + if (ret > -1) + { + c = (char)ret; + buf[idx++] = c; + count++; + if (_c == '\r' && c == '\n') + { + lineBreak = true; + if (!withLineBreak) + { + buf[idx - 2] = 0; + idx -= 2; + } + return idx; + } + _c = c; + + if (idx >= bufLen - 1) + { + ovf = true; + return idx; + } + } + } + return idx; +} + +template +bool ESP_Mail_Client::readResponse(T sessionPtr, char *buf, int bufLen, int &readLen, bool withLineBreak, int &count, MB_String &ovfBuf) +{ + bool ovf = false, isTimeout = false; + unsigned long timeoutSec = TCP_CLIENT_DEFAULT_TCP_TIMEOUT_SEC; + + do + { + timeoutSec = sessionPtr->client.tcpTimeout(); + int len = readLine(&(sessionPtr->client), buf, bufLen, withLineBreak, count, ovf, timeoutSec, isTimeout); + readLen += len; + if (len > 0 && (ovf || ovfBuf.length() > 0)) + ovfBuf += buf; + + } while (ovf); + + if (isTimeout) + return false; + + if (ovfBuf.length() > 0) + { + +#if defined(SESSION_DEBUG_ENABLED) + sessionPtr->_responseStatus.errorCode = MAIL_CLIENT_ERROR_BUFFER_OVERFLOW; + sessionPtr->_responseStatus.text.clear(); + if (sessionPtr->_debug) + esp_mail_debug_print_tag(sessionPtr->errorReason().c_str(), esp_mail_debug_tag_type_warning, true); +#endif + } + + return true; +} + +template +bool ESP_Mail_Client::reconnect(T sessionPtr, unsigned long dataTime, bool downloadRequest) +{ + if (!sessionPtr) + return false; + + sessionPtr->client.setSession(sessionPtr->_session_cfg); + networkStatus = sessionPtr->client.networkReady(); + + if (dataTime > 0) + { + if (millis() - dataTime > (unsigned long)sessionPtr->client.tcpTimeout()) + { + closeTCPSession(sessionPtr); + + if (sessionPtr->_sessionType == esp_mail_session_type_imap) + { +#if defined(ENABLE_IMAP) + IMAPSession *ss = (IMAPSession *)sessionPtr; + if (ss->_headers.size() > 0) + { + if (downloadRequest) + { + errorStatusCB(ss, nullptr, IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT, true); + if (cPart(ss) && cHeader(ss)->part_headers.size() > 0) + cPart(ss)->download_error = ss->errorReason().c_str(); + } + else + { + errorStatusCB(ss, nullptr, MAIL_CLIENT_ERROR_READ_TIMEOUT, true); + if (cHeader(ss)) + cHeader(ss)->error_msg = ss->errorReason().c_str(); + } + } + else + { +#if !defined(SILENT_MODE) + if (sessionPtr->_debug) + esp_mail_debug_print_tag(esp_mail_error_network_str_9 /* "response read timed out" */, esp_mail_debug_tag_type_error, true); +#endif + } +#endif + } + else + { +#if defined(ENABLE_SMTP) + SMTPSession *ss = (SMTPSession *)sessionPtr; + errorStatusCB(ss, this->imap, MAIL_CLIENT_ERROR_READ_TIMEOUT, false); +#endif + } + return false; + } + } + + if (!networkStatus) + { + closeTCPSession(sessionPtr); + + if (sessionPtr->_sessionType == esp_mail_session_type_imap) + { +#if defined(ENABLE_IMAP) + IMAPSession *ss = (IMAPSession *)sessionPtr; + if (ss->_mbif._idleTimeMs > 0 || ss->_imap_cmd == esp_mail_imap_cmd_idle || ss->_imap_cmd == esp_mail_imap_cmd_done) + { + // defer the polling error report + if (millis() - ss->_last_polling_error_ms > 10000 && !sessionPtr->connected()) + { + ss->_last_polling_error_ms = millis(); + errorStatusCB(ss, nullptr, MAIL_CLIENT_ERROR_CONNECTION_CLOSED, true); + } + } + else if (millis() - ss->_last_network_error_ms > 1000) + { + ss->_last_network_error_ms = millis(); + errorStatusCB(ss, nullptr, MAIL_CLIENT_ERROR_CONNECTION_CLOSED, true); + } + + if (ss->_headers.size() > 0) + { + if (cPart(ss) && downloadRequest) + cPart(ss)->download_error = ss->errorReason().c_str(); + else if (cHeader(ss)) + cHeader(ss)->error_msg = ss->errorReason().c_str(); + } + +#endif + } + else + { +#if defined(ENABLE_SMTP) + SMTPSession *ss = (SMTPSession *)sessionPtr; + errorStatusCB(ss, nullptr, MAIL_CLIENT_ERROR_CONNECTION_CLOSED, false); +#endif + } + + if (millis() - _lastReconnectMillis > _reconnectTimeout && !sessionPtr->connected()) + { + if (sessionPtr->_session_cfg->network_connection_handler) + { + // dummy + sessionPtr->client.disconnect(); + sessionPtr->_session_cfg->network_connection_handler(); + } + else + { + if (MailClient.networkAutoReconnect) + MailClient.resumeNetwork(&(sessionPtr->client)); + } + + _lastReconnectMillis = millis(); + } + + networkStatus = sessionPtr->client.networkReady(); + } + + return networkStatus; +} + +template +void ESP_Mail_Client::sendCB(T sessionPtr, PGM_P info, bool prependCRLF, bool success) +{ + if (sessionPtr) + { + sessionPtr->_cbData._info.clear(); + + if (prependCRLF) + appendNewline(sessionPtr->_cbData._info); + if (strlen_P(info) > 0) + { + sessionPtr->_cbData._info += esp_mail_str_33; /* "#### " */ + sessionPtr->_cbData._info += info; + } + sessionPtr->_cbData._success = success; + if (sessionPtr->_statusCallback) + sessionPtr->_statusCallback(sessionPtr->_cbData); + } +} + +template +void ESP_Mail_Client::sendErrorCB(T sessionPtr, PGM_P info, bool prependCRLF, bool success) +{ +#if !defined(SILENT_MODE) + MB_String e = esp_mail_str_12; /* "Error, " */ + e += info; + sendCB(sessionPtr, e.c_str(), prependCRLF, success); +#endif +} + +template +void ESP_Mail_Client::errorStatusCB(T1 sessionPtr, T2 sessionPtr2, int error, bool clearLastStatus) +{ + + if (sessionPtr) + { + sessionPtr->_responseStatus.errorCode = error; + + if (clearLastStatus) + sessionPtr->_responseStatus.text.clear(); + +#if !defined(SILENT_MODE) + if (sessionPtr->_statusCallback && !sessionPtr->_customCmdResCallback) + sendErrorCB(sessionPtr, sessionPtr->errorReason().c_str(), false, false); + + if (sessionPtr->_debug && !sessionPtr->_customCmdResCallback) + esp_mail_debug_print_tag(sessionPtr->errorReason().c_str(), esp_mail_debug_tag_type_error, true); +#endif + } + else if (sessionPtr2 && !calDataLen) + errorStatusCB(sessionPtr2, nullptr, error, clearLastStatus); +} + +template +bool ESP_Mail_Client::isResponseCB(T sessionPtr) +{ +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + return sessionPtr->_customCmdResCallback != NULL; +#endif + return false; +} + +template +void ESP_Mail_Client::printLibInfo(T sessionPtr) +{ +#if defined(SESSION_DEBUG_ENABLED) + + if (sessionPtr->_statusCallback != NULL && !isResponseCB(sessionPtr)) + sendCallback(sessionPtr, + sessionPtr->_sessionType == esp_mail_session_type_smtp ? esp_mail_cb_str_1 /* "Connecting to SMTP server..." */ + : esp_mail_cb_str_15 /* "Connecting to IMAP server..." */, + false, false); + + if (sessionPtr->_debug && !isResponseCB(sessionPtr)) + { + MB_String dbMsg = esp_mail_version_str; /* "ESP Mail Client v" */ + dbMsg += ESP_MAIL_VERSION; + esp_mail_debug_print_tag(dbMsg.c_str(), esp_mail_debug_tag_type_client, true); + +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() == 0 && !isResponseCB(sessionPtr)) + esp_mail_debug_print_tag(esp_mail_error_mem_str_4 /* "PSRAM was enabled but not detected." */, esp_mail_debug_tag_type_warning, true); +#endif + } + +#endif +} + +template +bool ESP_Mail_Client::beginConnection(Session_Config *session_config, T sessionPtr, bool secureMode) +{ + + sessionPtr->client.setWiFi(&wifi); + sessionPtr->client.setSession(session_config); + + if (!reconnect(sessionPtr)) + return false; + +#if defined(SESSION_DEBUG_ENABLED) + if (sessionPtr->_debug && !isResponseCB(sessionPtr)) + { + esp_mail_debug_print_tag(sessionPtr->_sessionType == esp_mail_session_type_smtp + ? esp_mail_dbg_str_2 /* "connecting to SMTP server" */ + : esp_mail_dbg_str_18 /* "connecting to IMAP server" */, + esp_mail_debug_tag_type_client, true); + + MB_String dbMsg = esp_mail_dbg_str_19; /* "Host > " */ + dbMsg += session_config->server.host_name; + esp_mail_debug_print_tag(dbMsg.c_str(), esp_mail_debug_tag_type_client, true); + + dbMsg = esp_mail_dbg_str_20; /* "Port > " */ + dbMsg += session_config->server.port; + esp_mail_debug_print_tag(dbMsg.c_str(), esp_mail_debug_tag_type_client, true); + } +#endif + + sessionPtr->client.begin(session_config->server.host_name.c_str(), session_config->server.port); + + sessionPtr->client.ethDNSWorkAround(); + + if (!sessionPtr->client.connect(secureMode, session_config->certificate.verify)) + { + if (sessionPtr->_sessionType == esp_mail_session_type_smtp) + { +#if defined(ENABLE_SMTP) + return handleSMTPError((SMTPSession *)sessionPtr, SMTP_STATUS_SERVER_CONNECT_FAILED, false); +#endif + } + else + { +#if defined(ENABLE_IMAP) + return handleIMAPError((IMAPSession *)sessionPtr, IMAP_STATUS_SERVER_CONNECT_FAILED, false); +#endif + } + } + + return true; +} + +template +bool ESP_Mail_Client::prepareTime(Session_Config *session_config, T sessionPtr) +{ + bool timeShouldBeValid = false; + + if (sessionPtr->_sessionType == esp_mail_session_type_smtp) + timeShouldBeValid = true; +#if !defined(ESP_MAIL_DISABLE_SSL) + else + timeShouldBeValid = session_config->certificate.cert_file.length() > 0 || session_config->cert_ptr != 0; +#endif + +#if defined(ENABLE_NTP_TIME) && defined(ESP_MAIL_WIFI_IS_AVAILABLE) + bool ntpEnabled = true; +#else + bool ntpEnabled = false; +#endif + +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) + + if (session_config->time.ntp_server.length() > 0 || timeShouldBeValid) + { + + Time.begin(session_config->time.gmt_offset, session_config->time.day_light_offset, session_config->time.ntp_server.c_str()); + + if (!Time.timeReady()) + { + if (sessionPtr->client.type() == esp_mail_client_type_external_gsm_client) + { + int year = 0; + int month = 0; + int day = 0; + int hour = 0; + int min = 0; + int sec = 0; + float timezone = 0; + if (sessionPtr->client.gprsGetTime(year, month, day, hour, min, sec, timezone)) + Time.setTimestamp(Time.getTimestamp(year, month, day, hour, min, sec), timezone); + } + else if (session_config->time.ntp_server.length()) + { +#if defined(ENABLE_NTP_TIME) +#if !defined(SILENT_MODE) + if (sessionPtr->_debug && !isResponseCB(sessionPtr)) + esp_mail_debug_print_tag(esp_mail_dbg_str_21 /* "Reading time from NTP server" */, esp_mail_debug_tag_type_client, false); +#endif + + setTime(session_config->time.timezone_env_string.c_str(), session_config->time.timezone_file.c_str(), true, sessionPtr->_debug && !isResponseCB(sessionPtr)); +#endif + } + } + } + +#endif + +#if defined(ESP32) + if (Time.timeReady() && !timezoneEnvSet) + getSetTimezoneEnv(session_config->time.timezone_file.c_str(), session_config->time.timezone_env_string.c_str()); +#endif + + if (Time.timeReady()) + return true; + else if (WiFI_CONNECTED && timeShouldBeValid) + { + errorStatusCB(sessionPtr, nullptr, ntpEnabled && session_config->time.ntp_server.length() ? MAIL_CLIENT_ERROR_NTP_TIME_SYNC_TIMED_OUT : MAIL_CLIENT_ERROR_TIME_WAS_NOT_SET, false); + return false; + } + + return true; +} + +template +bool ESP_Mail_Client::sessionReady(T sessionPtr) +{ + // If network connection failure or tcp session closed, close session to clear resources. + if (!reconnect(sessionPtr) || !connected(sessionPtr)) + { + closeTCPSession(sessionPtr); + +#if defined(ENABLE_IMAP) + if (sessionPtr->_sessionType == esp_mail_session_type_imap && !connected(sessionPtr)) + errorStatusCB(sessionPtr, nullptr, MAIL_CLIENT_ERROR_CONNECTION_CLOSED, false); +#endif + + return false; + } + + return true; +} + +void ESP_Mail_Client::setCert(Session_Config *session_config, const char *ca) +{ + int ptr = reinterpret_cast(ca); + if (ptr != session_config->cert_ptr) + { + session_config->cert_updated = true; + session_config->cert_ptr = ptr; + } +} + +void ESP_Mail_Client::setSecure(ESP_Mail_TCPClient &client, Session_Config *session_config) +{ + + client.setMBFS(mbfs); + + client.setSession(session_config); + +#if !defined(ESP_MAIL_DISABLE_SSL) + + if (client.getCertType() == esp_mail_cert_type_undefined || session_config->cert_updated) + { + if (session_config->certificate.cert_file.length() > 0 || session_config->certificate.cert_data != NULL || session_config->cert_ptr > 0) + { + client.setClockReady(timeStatus); + } + + if (session_config->certificate.cert_file.length() == 0) + { + if (session_config->cert_ptr > 0) + client.setCACert(reinterpret_cast(session_config->cert_ptr)); + else if (session_config->certificate.cert_data != NULL) + client.setCACert(session_config->certificate.cert_data); + else + client.setCACert(NULL); + } + else + { + if (!client.setCertFile(session_config->certificate.cert_file.c_str(), mbfs_type session_config->certificate.cert_file_storage_type)) + client.setCACert(NULL); + } + session_config->cert_updated = false; + } +#endif +} + +void ESP_Mail_Client::appendMultipartContentType(MB_String &buf, esp_mail_multipart_types type, const char *boundary) +{ + bool firstProp = true; + appendHeaderField(buf, message_headers[esp_mail_message_header_field_content_type].text, multipart_types[type].text, false, false); + appendHeaderProp(buf, esp_mail_str_90 /* "boundary" */, boundary, firstProp, false, true, true); + appendNewline(buf); +} + +String ESP_Mail_Client::errorReason(bool isSMTP, int errorCode, const char *msg) +{ + MB_String ret; + +#if defined(ENABLE_ERROR_STRING) && !defined(SILENT_MODE) + + // If there is server meanningful response (msg) is available, return it instead + if (strlen(msg) > 0) + return msg; + + // The error code enums were defined in ESP_Mail_Error.h and MB_FS.h. + switch (errorCode) + { + + case TCP_CLIENT_ERROR_CONNECTION_REFUSED: + ret = esp_mail_error_network_str_7; /* "connection refused" */ + break; + case TCP_CLIENT_ERROR_SEND_DATA_FAILED: + ret = esp_mail_error_network_str_8; /* "data sending failed" */ + break; + case TCP_CLIENT_ERROR_NOT_INITIALIZED: + ret = esp_mail_error_client_str_1; /* "client and/or necessary callback functions are not yet assigned" */ + break; + case TCP_CLIENT_ERROR_NOT_CONNECTED: + ret = esp_mail_error_network_str_4; /* "not connected" */ + break; + + case MAIL_CLIENT_ERROR_CONNECTION_CLOSED: + ret = esp_mail_error_network_str_6; /* "connection closed" */ + break; + case MAIL_CLIENT_ERROR_READ_TIMEOUT: + ret = esp_mail_error_network_str_3; /* "response read timed out" */ + break; + case MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP: + ret = esp_mail_error_ssl_str_1; /* "fail to set up the SSL/TLS structure" */ + break; + case MAIL_CLIENT_ERROR_OUT_OF_MEMORY: + ret = esp_mail_error_mem_str_8; /* "out of memory" */ + break; + case MAIL_CLIENT_ERROR_NTP_TIME_SYNC_TIMED_OUT: + ret = esp_mail_error_network_str_2; /* "NTP server time reading timed out" */ + break; + case MAIL_CLIENT_ERROR_SESSION_CONFIG_WAS_NOT_ASSIGNED: + ret = esp_mail_error_session_str_1; /* "the Session_Config object was not assigned" */ + break; + case MAIL_CLIENT_ERROR_TIME_WAS_NOT_SET: + ret = esp_mail_error_time_str_1; /* "library or device time was not set" */ + break; + case MAIL_CLIENT_ERROR_NOT_YET_LOGIN: + ret = esp_mail_error_auth_str_3; /* "not yet log in" */ + break; + case MAIL_CLIENT_ERROR_BUFFER_OVERFLOW: + ret = esp_mail_error_mem_str_9; /* "buffer overflow" */ + break; + +#if defined(ENABLE_SMTP) + case SMTP_STATUS_SERVER_CONNECT_FAILED: + ret = esp_mail_error_network_str_1; /* "unable to connect to server" */ + break; + case SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED: + ret = esp_mail_error_smtp_str_1; /* "SMTP server greeting failed" */ + break; + case SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED: + ret = esp_mail_error_smtp_str_1; /* "SMTP server greeting failed" */ + break; + case SMTP_STATUS_AUTHEN_NOT_SUPPORT: + ret = esp_mail_error_auth_str_1; /* "the provided SASL authentication mechanism is not support" */ + break; + case SMTP_STATUS_AUTHEN_FAILED: + ret = esp_mail_error_smtp_str_2; /* "authentication failed" */ + break; + case SMTP_STATUS_USER_LOGIN_FAILED: + ret = esp_mail_error_smtp_str_2; /* "authentication failed" */ + break; + case SMTP_STATUS_PASSWORD_LOGIN_FAILED: + ret = esp_mail_error_smtp_str_3; /* "login password is not valid" */ + break; + case SMTP_STATUS_SEND_HEADER_SENDER_FAILED: + ret = esp_mail_error_smtp_str_4; /* "send header failed" */ + break; + case SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED: + ret = esp_mail_error_smtp_str_9; /* "set recipient failed" */ + break; + case SMTP_STATUS_SEND_BODY_FAILED: + ret = esp_mail_error_smtp_str_5; /* "send body failed" */ + break; + case SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED: + ret = esp_mail_error_auth_str_2; /* "OAuth2.0 log in was disabled for this server" */ + break; + case SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED: + ret = esp_mail_error_smtp_str_8; /* "some of the recipient Email address is not valid" */ + break; + case SMTP_STATUS_NO_VALID_SENDER_EXISTED: + ret = esp_mail_error_smtp_str_7; /* "sender Email address is not valid" */ + break; + case SMTP_STATUS_NO_SUPPORTED_AUTH: + ret = esp_mail_error_auth_str_1; /* "the provided SASL authentication mechanism is not support" */ + break; + case SMTP_STATUS_SEND_CUSTOM_COMMAND_FAILED: + ret = esp_mail_error_smtp_str_10; /* "send custom command failed" */ + break; + case SMTP_STATUS_XOAUTH2_AUTH_FAILED: + ret = esp_mail_error_smtp_str_11; /* "XOAuth2 authenticate failed" */ + break; + case SMTP_STATUS_UNDEFINED: + ret = esp_mail_error_smtp_str_12; /* "undefined error" */ + break; +#endif + +#if defined(ENABLE_IMAP) + case IMAP_STATUS_SERVER_CONNECT_FAILED: + ret = esp_mail_error_network_str_1; /* "unable to connect to server" */ + break; + case IMAP_STATUS_IMAP_RESPONSE_FAILED: + ret = esp_mail_error_imap_str_18; /* "server replied NO or BAD response" */ + break; + case IMAP_STATUS_AUTHENTICATE_FAILED: + ret = esp_mail_error_imap_str_19; /* "authenticate failed" */ + break; + case IMAP_STATUS_BAD_COMMAND: + ret = esp_mail_error_imap_str_17; /* "could not parse command" */ + break; + case IMAP_STATUS_STORE_FAILED: + ret = esp_mail_error_imap_str_20; /* "flags or keywords store failed" */ + break; + case IMAP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED: + ret = esp_mail_error_imap_str_21; /* "server is not support OAuth2 login" */ + break; + case IMAP_STATUS_NO_MESSAGE: + ret = esp_mail_error_imap_str_5; /* "some of the requested messages no longer exist" */ + break; + case IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT: + ret = esp_mail_error_network_str_5; /* "connection timeout" */ + break; + case IMAP_STATUS_CLOSE_MAILBOX_FAILED: + ret = esp_mail_error_imap_str_3; /* "fail to close the mailbox" */ + break; + case IMAP_STATUS_OPEN_MAILBOX_FAILED: + ret = esp_mail_error_imap_str_4; /* "fail to open the mailbox" */ + break; + case IMAP_STATUS_LIST_MAILBOXS_FAILED: + ret = esp_mail_error_imap_str_1; /* "fail to list the mailboxes" */ + break; + case IMAP_STATUS_CHECK_CAPABILITIES_FAILED: + ret = esp_mail_error_imap_str_2; /* "fail to check the capabilities" */ + break; + case IMAP_STATUS_NO_SUPPORTED_AUTH: + ret = esp_mail_error_auth_str_1; /* "the provided SASL authentication mechanism is not support" */ + break; + case IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED: + ret = esp_mail_error_imap_str_5; /* "no mailbox opened" */ + break; + case IMAP_STATUS_FIRMWARE_UPDATE_INIT_FAILED: + ret = esp_mail_error_imap_str_6; /* "firmware update initialization failed" */ + break; + case IMAP_STATUS_FIRMWARE_UPDATE_WRITE_FAILED: + ret = esp_mail_error_imap_str_7; /* "firmware update write failed" */ + break; + case IMAP_STATUS_FIRMWARE_UPDATE_END_FAILED: + ret = esp_mail_error_imap_str_8; /* "firmware update finalize failed" */ + break; + case IMAP_STATUS_CHANGEDSINC_MODSEQ_TEST_FAILED: + ret = esp_mail_error_imap_str_14; /* "no message changed since (assigned) modsec" */ + break; + case IMAP_STATUS_MODSEQ_WAS_NOT_SUPPORTED: + ret = esp_mail_error_imap_str_15; /* "CONDSTORE was not supported or modsec was not supported for selected mailbox" */ + break; + +#endif + +#if defined(MBFS_FLASH_FS) || defined(MBFS_SD_FS) + + case MB_FS_ERROR_FILE_IO_ERROR: + ret = esp_mail_error_mem_str_7; /* "file I/O error" */ + break; + case MB_FS_ERROR_FILE_NOT_FOUND: + ret = esp_mail_error_mem_str_6; /* "file not found." */ + break; + case MB_FS_ERROR_FLASH_STORAGE_IS_NOT_READY: + ret = esp_mail_error_mem_str_1; /* "flash Storage is not ready." */ + break; + case MB_FS_ERROR_SD_STORAGE_IS_NOT_READY: + ret = esp_mail_error_mem_str_2; /* "SD Storage is not ready." */ + break; + case MB_FS_ERROR_FILE_STILL_OPENED: + ret = esp_mail_error_mem_str_5; /* "file is still opened." */ + break; + +#endif + default: + break; + } + +#endif + + return ret.c_str(); +} + +template +void ESP_Mail_Client::closeTCPSession(T sessionPtr) +{ + if (!sessionPtr) + return; + + sessionPtr->client.stop(); + + _lastReconnectMillis = millis(); + + memset(sessionPtr->_auth_capability, 0, esp_mail_auth_capability_maxType); + memset(sessionPtr->_feature_capability, 0, + sessionPtr->_sessionType == esp_mail_session_type_smtp +#if defined(ENABLE_SMTP) + ? (int)esp_mail_smtp_send_capability_maxType +#else + ? 0 +#endif + : (int)esp_mail_imap_read_capability_maxType); + + sessionPtr->_authenticated = false; + sessionPtr->_loginStatus = false; +} + +template +bool ESP_Mail_Client::connected(T sessionPtr) +{ + return sessionPtr->client.connected(); +} + +size_t ESP_Mail_Client::getReservedLen(size_t len) +{ + return mbfs->getReservedLen(len); +} + +template +T ESP_Mail_Client::allocMem(size_t size, bool clear) +{ + return reinterpret_cast(mbfs->newP(size, clear)); +} + +void ESP_Mail_Client::freeMem(void *ptr) +{ + mbfs->delP(ptr); +} + +bool ESP_Mail_Client::strcmpP(const char *buf, int ofs, PGM_P beginToken, bool caseSensitive) +{ + if (ofs < 0) + { + int p = strposP(buf, beginToken, 0, caseSensitive); + if (p == -1) + return false; + ofs = p; + } + + char *tmp2 = allocMem(strlen_P(beginToken) + 1); + memcpy(tmp2, &buf[ofs], strlen_P(beginToken)); + tmp2[strlen_P(beginToken)] = 0; + MB_String s = beginToken; + bool ret = (strcasecmp(s.c_str(), tmp2) == 0); + // release memory + freeMem(&tmp2); + return ret; +} + +int ESP_Mail_Client::strposP(const char *buf, PGM_P beginToken, int ofs, bool caseSensitive) +{ + MB_String s = beginToken; + return strpos(buf, s.c_str(), ofs, caseSensitive); +} + +char *ESP_Mail_Client::strP(PGM_P pgm) +{ + size_t len = strlen_P(pgm) + 1; + char *buf = allocMem(len); + strcpy_P(buf, pgm); + buf[len - 1] = 0; + return buf; +} + +char *ESP_Mail_Client::strP2Lower(PGM_P pgm) +{ + size_t len = strlen_P(pgm) + 1; + char *buf = allocMem(len); + strcpy_P(buf, pgm); + + for (char *p = buf; *p; p++) + { + *p = tolower(*p); + } + + buf[len - 1] = 0; + return buf; +} + +void ESP_Mail_Client::strReplaceP(MB_String &buf, PGM_P name, PGM_P value) +{ + char *n = strP(name); + char *v = strP(value); + + buf.replaceAll(n, v); + + freeMem(&n); + freeMem(&v); +} + +bool ESP_Mail_Client::isOAuthError(char *buf, int bufLen, int &chunkIdx, int ofs) +{ + bool ret = false; + if (chunkIdx == 0) + { + size_t olen; + unsigned char *decoded = decodeBase64((const unsigned char *)(buf + ofs), bufLen - ofs, &olen); + if (decoded) + { + ret = strposP((char *)decoded, esp_mail_str_44 /* "{\"status\":" */, 0) > -1; + freeMem(&decoded); + } + chunkIdx++; + } + return ret; +} + +MB_String ESP_Mail_Client::getXOAUTH2String(const MB_String &email, const MB_String &accessToken) +{ + MB_String raw = esp_mail_str_45; /* "user=" */ + raw += email; + raw += esp_mail_str_46; /* "\1auth=Bearer " */ + raw += accessToken; + raw += esp_mail_str_43; /* "\1\1" */ + return encodeBase64Str((const unsigned char *)raw.c_str(), raw.length()); +} + +unsigned char *ESP_Mail_Client::decodeBase64(const unsigned char *src, size_t len, size_t *out_len) +{ + unsigned char *out, *pos, block[4], tmp; + size_t i, count, olen; + int pad = 0; + size_t extra_pad; + + unsigned char *dtable = allocMem(256); + + memset(dtable, 0x80, 256); + + for (i = 0; i < sizeof(b64_index_table) - 1; i++) + dtable[b64_index_table[i]] = (unsigned char)i; + dtable['='] = 0; + + count = 0; + for (i = 0; i < len; i++) + { + if (dtable[src[i]] != 0x80) + count++; + } + + if (count == 0) + goto exit; + + extra_pad = (4 - count % 4) % 4; + + olen = (count + extra_pad) / 4 * 3; + + pos = out = allocMem(olen); + + if (out == NULL) + goto exit; + + count = 0; + + for (i = 0; i < len + extra_pad; i++) + { + unsigned char val; + + if (i >= len) + val = '='; + else + val = src[i]; + tmp = dtable[val]; + if (tmp == 0x80) + continue; + + if (val == '=') + pad++; + block[count] = tmp; + count++; + if (count == 4) + { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if (pad) + { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else + { + // release memory + free(out); + goto exit; + } + break; + } + } + } + + *out_len = pos - out; + // release memory + freeMem(&dtable); + return out; +exit: + // release memory + freeMem(&dtable); + return nullptr; +} + +MB_String ESP_Mail_Client::encodeBase64Str(const unsigned char *src, size_t len) +{ + return encodeBase64Str((uint8_t *)src, len); +} + +MB_String ESP_Mail_Client::encodeBase64Str(uint8_t *src, size_t len) +{ + MB_String outStr; + unsigned char *out, *pos; + const unsigned char *end, *in; + size_t olen = 4 * ((len + 2) / 3); + if (olen < len) + return outStr; + + outStr.resize(olen); + out = (unsigned char *)&outStr[0]; + + end = src + len; + in = src; + pos = out; + + while (end - in >= 3) + { + *pos++ = b64_index_table[in[0] >> 2]; + *pos++ = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = b64_index_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = b64_index_table[in[2] & 0x3f]; + in += 3; + } + + if (end - in) + { + *pos++ = b64_index_table[in[0] >> 2]; + if (end - in == 1) + { + *pos++ = b64_index_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } + else + { + *pos++ = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = b64_index_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + } + + return outStr; +} + +#endif + +ESP_Mail_Client MailClient = ESP_Mail_Client(); + +#endif /* ESP_MAIL_CLIENT_CPP */ diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client.h new file mode 100644 index 000000000..69099a497 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client.h @@ -0,0 +1,2862 @@ +#ifndef ESP_MAIL_CLIENT_H +#define ESP_MAIL_CLIENT_H + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +/** + * Mail Client Arduino Library for Arduino devices. + * + * Created August 28, 2023 + * + * This library allows Espressif's ESP32, ESP8266, SAMD and RP2040 Pico devices to send and read Email through the SMTP and IMAP servers. + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "extras/RFC2047.h" +#include +#include + +#include +#include +#include + +#if __has_include() +#include +#endif + +#if __has_include() +#include +#endif + +#include "ESP_Mail_FS.h" +#include "ESP_Mail_Const.h" +#include "extras/MB_Time.h" + +#if defined(MB_ARDUINO_ESP) || defined(MB_ARDUINO_PICO) +#define ESP_MAIL_PRINTF ESP_MAIL_DEFAULT_DEBUG_PORT.printf +#else +#define ESP_MAIL_PRINTF MailClient.printf +#endif + +#if defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO) + +#define UPLOAD_CHUNKS_NUM 12 + +#if defined(ESP32) + +#define ESP_MAIL_MIN_MEM 70000 + +#elif defined(ESP8266) + +#define SD_CS_PIN 15 +#define ESP_MAIL_MIN_MEM 8000 + +#elif defined(MB_ARDUINO_PICO) + +#define ESP_MAIL_MIN_MEM 70000 +#define SD_CS_PIN PIN_SPI1_SS + +#endif + +#else + +#undef min +#undef max +#define ESP_MAIL_MIN_MEM 3000 +#define UPLOAD_CHUNKS_NUM 5 + +#ifdef __arm__ +// should use uinstd.h to define sbrk but Due causes a conflict +extern "C" char *sbrk(int incr); +#else // __ARM__ +extern char *__brkval; +#endif // __arm__ + +#endif + +#include "ESP_Mail_TCPClient.h" + +using namespace mb_string; + +class IMAPSession; +class SMTPSession; +class SMTP_Status; +class DownloadProgress; +class MessageData; + +#if defined(ENABLE_IMAP) + +class MessageList +{ +public: + friend class IMAPSession; + MessageList(){}; + ~MessageList() { clear(); }; + void add(int uid) + { + if (uid > 0) + _list.push_back(uid); + } + + void clear() { _list.clear(); } + +private: + _vectorImpl _list; +}; + +/* The class that provides the info of selected or opened mailbox folder */ +class SelectedFolderInfo +{ +public: + friend class ESP_Mail_Client; + friend class IMAPSession; + SelectedFolderInfo(){}; + ~SelectedFolderInfo() { clear(); }; + + /* Get the flags count for this mailbox */ + size_t flagCount(bool permanent = false) { return permanent ? _permanent_flags.size() : _flags.size(); }; + + /* Get the numbers of messages in this mailbox */ + size_t msgCount() { return _msgCount; }; + + /* Get the numbers of messages in this mailbox that recent flag was set */ + size_t recentCount() { return _recentCount; }; + + /* Get the order of message in number of message in this mailbox that reoved */ + /** + * The IMAP_Polling_Status has the properties e.g. type, messageNum, and argument. + * + * The type property is the type of status e.g.imap_polling_status_type_undefined, imap_polling_status_type_new_message, + * imap_polling_status_type_remove_message, and imap_polling_status_type_fetch_message. + * + * The messageNum property is message number or order from the total number of message that added, fetched or deleted. + * + * The argument property is the argument of commands e.g. FETCH + */ + IMAP_Polling_Status pollingStatus() { return _polling_status; }; + + /* Get the The unique identifier (UID) validity value */ + size_t uidValidity() { return _uidValidity; }; + + /* Get the predict next message UID */ + size_t nextUID() { return _nextUID; }; + + /* Get the index of first unseen message */ + size_t unseenIndex() { return _unseenMsgIndex; }; + + /* Get the highest modification sequence */ + uint64_t highestModSeq() { return strtoull(_highestModSeq.c_str(), NULL, 10); }; + + /* Check for the modification sequence supports */ + bool modSeqSupported() { return _highestModSeq.length() > 0 && !_nomodsec; }; + + /* Get the numbers of messages from search result based on the search criteria + */ + size_t searchCount() { return _searchCount; }; + + /* Get the numbers of messages to be stored in the ressult */ + size_t availableMessages() { return _availableItems; }; + + /* Get the flag argument at the specified index */ + String flag(size_t index, bool permanent = false) + { + size_t size = permanent ? _permanent_flags.size() : _flags.size(); + if (index < size) + return permanent ? _permanent_flags[index].c_str() : _flags[index].c_str(); + return ""; + } + +private: + void addFlag(const char *flag, bool permanent) + { + MB_String s = flag; + if (permanent) + _permanent_flags.push_back(s); + else + _flags.push_back(s); + }; + void clear() + { + for (size_t i = 0; i < _flags.size(); i++) + _flags[i].clear(); + _flags.clear(); + + for (size_t i = 0; i < _permanent_flags.size(); i++) + _permanent_flags[i].clear(); + _permanent_flags.clear(); + + _msgCount = 0; + _polling_status.argument.clear(); + _polling_status.messageNum = 0; + _polling_status.type = imap_polling_status_type_undefined; + _idleTimeMs = 0; + _searchCount = 0; + } + + size_t _msgCount = 0; + size_t _recentCount = 0; + size_t _uidValidity = 0; + size_t _nextUID = 0; + size_t _unseenMsgIndex = 0; + MB_String _highestModSeq; + size_t _searchCount = 0; + size_t _availableItems = 0; + unsigned long _idleTimeMs = 0; + bool _folderChanged = false; + bool _floderChangedState = false; + bool _nomodsec = false; + IMAP_Polling_Status _polling_status; + _vectorImpl _flags; + _vectorImpl _permanent_flags; +}; + +/* The class that provides the list of FolderInfo e.g. name, attributes and + * delimiter */ +class FoldersCollection +{ +public: + friend class ESP_Mail_Client; + friend class IMAPSession; + FoldersCollection(){}; + ~FoldersCollection() { clear(); }; + size_t size() { return _folders.size(); }; + + struct esp_mail_folder_info_item_t info(size_t index) + { + struct esp_mail_folder_info_item_t fd; + if (index < _folders.size()) + { + fd.name = _folders[index].name.c_str(); + fd.attributes = _folders[index].attributes.c_str(); + fd.delimiter = _folders[index].delimiter.c_str(); + } + return fd; + } + + esp_mail_folder_info_t operator[](size_t index) + { + if (index < _folders.size()) + return _folders[index]; + + return esp_mail_folder_info_t(); + } + +private: + void add(struct esp_mail_folder_info_t fd) { _folders.push_back(fd); }; + void clear() + { + for (size_t i = 0; i < _folders.size(); i++) + { + _folders[i].name.clear(); + _folders[i].attributes.clear(); + _folders[i].delimiter.clear(); + } + _folders.clear(); + } + _vectorImpl _folders; +}; + +/* The class that provides the list of IMAP_Quota_Root_Info e.g. resource name, used and limit */ +class IMAP_Quota_Roots_List +{ + friend class IMAPSession; + +public: + IMAP_Quota_Roots_List(){}; + ~IMAP_Quota_Roots_List() { clear(); }; + + size_t size() { return _quota_roots.size(); }; + + IMAP_Quota_Root_Info operator[](size_t index) + { + if (index < _quota_roots.size()) + return _quota_roots[index]; + + return IMAP_Quota_Root_Info(); + } + +private: + _vectorImpl _quota_roots; + + void add(IMAP_Quota_Root_Info v) + { + _quota_roots.push_back(v); + } + void clear() + { + _quota_roots.clear(); + } +}; + +/* The class that provides the list of IMAP_Namespaces */ +class IMAP_Namespaces +{ + friend class IMAPSession; + +public: + IMAP_Namespaces(){}; + ~IMAP_Namespaces() { clear(); }; + + size_t size() { return _ns_list.size(); }; + + IMAP_Namespace_Info operator[](size_t index) + { + if (index < _ns_list.size()) + return _ns_list[index]; + + return IMAP_Namespace_Info(); + } + +private: + _vectorImpl _ns_list; + + void add(IMAP_Namespace_Info v) + { + _ns_list.push_back(v); + } + void clear() + { + _ns_list.clear(); + } +}; + +/* The class that provides the list of IMAP_Namespaces */ +class IMAP_Rights_List +{ + friend class IMAPSession; + +public: + IMAP_Rights_List(){}; + ~IMAP_Rights_List() { clear(); }; + + size_t size() { return _rights_list.size(); }; + + IMAP_Rights_Info operator[](size_t index) + { + if (index < _rights_list.size()) + return _rights_list[index]; + + return IMAP_Rights_Info(); + } + +private: + _vectorImpl _rights_list; + + void add(IMAP_Rights_Info v) + { + _rights_list.push_back(v); + } + void clear() + { + _rights_list.clear(); + } +}; + +typedef struct esp_mail_imap_nanespace_list_t +{ + IMAP_Namespaces personal_namespaces; + IMAP_Namespaces other_users_namespaces; + IMAP_Namespaces shared_namespaces; +} IMAP_Namespaces_List; + +/* The class that provides the status of message feching and searching */ +class IMAP_Status +{ +public: + IMAP_Status(); + ~IMAP_Status(); + const char *info(); + bool success(); + void empty(); + friend class IMAPSession; + + MB_String _info; + bool _success = false; +}; + +typedef void (*imapStatusCallback)(IMAP_Status); +typedef void (*imapResponseCallback)(IMAP_Response); +typedef void (*MIMEDataStreamCallback)(MIME_Data_Stream_Info); +typedef void (*imapCharacterDecodingCallback)(IMAP_Decoding_Info *); + +#else + +enum esp_mail_imap_read_capability_types +{ + esp_mail_imap_read_capability_maxType +}; + +// Dummy class used in template functions (errorStatusCB). +class IMAPSession +{ +public: + struct IMAP_Status + { + public: + const char *info() { return ""; }; + bool success() { return false; }; + void empty(); + MB_String _info; + bool _success = false; + }; + + typedef void (*imapStatusCallback)(IMAP_Status); + MB_String errorReason() { return ""; } + bool _debug; + imapStatusCallback _statusCallback = nullptr; + void *_customCmdResCallback = nullptr; + esp_mail_session_type _sessionType = esp_mail_session_type_imap; + + struct esp_mail_imap_response_status_t + { + int errorCode = 0; + MB_String tag; + MB_String text; + MB_String status; + bool completed = false; + }; + + esp_mail_imap_response_status_t _responseStatus; + IMAP_Status _cbData; +}; +#endif + +#if defined(ENABLE_SMTP) + +/* The SMTP message class */ +class SMTP_Message +{ +public: + SMTP_Message() + { + text.content_type = "text/plain"; + html.content_type = "text/html"; + }; + + ~SMTP_Message() { clear(); }; + + void resetAttachItem(SMTP_Attachment &att) + { + att.blob.size = 0; + att.blob.data = nullptr; + att.file.path.clear(); + att.file.storage_type = esp_mail_file_storage_type_none; + att.descr.name.clear(); + att.descr.filename.clear(); + att.descr.transfer_encoding.clear(); + att.descr.content_encoding.clear(); + att.descr.mime.clear(); + att.descr.content_id.clear(); + att._int.att_type = esp_mail_att_type_none; + att._int.index = 0; + att._int.msg_uid = 0; + att._int.flash_blob = false; + att._int.xencoding = esp_mail_msg_xencoding_none; + att._int.parallel = false; + att._int.cid.clear(); + } + + void clear() + { + sender.name.clear(); + sender.email.clear(); + subject.clear(); + text.charSet.clear(); + text.content.clear(); + text.content_type.clear(); + text.embed.enable = false; + html.charSet.clear(); + html.content.clear(); + html.content_type.clear(); + html.embed.enable = false; + response.reply_to.clear(); + response.notify = esp_mail_smtp_notify::esp_mail_smtp_notify_never; + priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + for (size_t i = 0; i < _rcp.size(); i++) + { + _rcp[i].name.clear(); + _rcp[i].email.clear(); + } + + for (size_t i = 0; i < _cc.size(); i++) + _cc[i].email.clear(); + + for (size_t i = 0; i < _bcc.size(); i++) + _bcc[i].email.clear(); + + for (size_t i = 0; i < _hdr.size(); i++) + _hdr[i].clear(); + + for (size_t i = 0; i < _att.size(); i++) + { + _att[i].descr.filename.clear(); + _att[i].blob.data = nullptr; + _att[i].descr.mime.clear(); + _att[i].descr.name.clear(); + _att[i].blob.size = 0; + _att[i].descr.transfer_encoding.clear(); + _att[i].file.path.clear(); + _att[i].file.storage_type = esp_mail_file_storage_type_none; + } + + for (size_t i = 0; i < _parallel.size(); i++) + { + _parallel[i].descr.filename.clear(); + _parallel[i].blob.data = nullptr; + _parallel[i].descr.mime.clear(); + _parallel[i].descr.name.clear(); + _parallel[i].blob.size = 0; + _parallel[i].descr.transfer_encoding.clear(); + _parallel[i].file.path.clear(); + _parallel[i].file.storage_type = esp_mail_file_storage_type_none; + } + + _rcp.clear(); + _cc.clear(); + _bcc.clear(); + _hdr.clear(); + _att.clear(); + _parallel.clear(); + } + + /** Clear all the inline images + */ + void clearInlineimages() + { + for (int i = (int)_att.size() - 1; i >= 0; i--) + { + if (_att[i]._int.att_type == esp_mail_att_type_inline) + _att.erase(_att.begin() + i); + } + }; + + /* Clear all the attachments */ + void clearAttachments() + { + for (int i = (int)_att.size() - 1; i >= 0; i--) + { + if (_att[i]._int.att_type == esp_mail_att_type_attachment) + _att.erase(_att.begin() + i); + } + + for (int i = (int)_parallel.size() - 1; i >= 0; i--) + _parallel.erase(_parallel.begin() + i); + }; + + /** Clear all rfc822 message attachment + */ + void clearRFC822Messages() + { + for (int i = (int)_rfc822.size() - 1; i >= 0; i--) + { + _rfc822[i].clear(); + _rfc822.erase(_rfc822.begin() + i); + } + }; + + /** Clear the primary recipient mailboxes + */ + void clearRecipients() { _rcp.clear(); }; + + /** Clear the Carbon-copy recipient mailboxes + */ + void clearCc() { _cc.clear(); }; + + /** Clear the Blind-carbon-copy recipient mailboxes + */ + void clearBcc() { _bcc.clear(); }; + + /** Clear the custom message headers + */ + void clearHeader() { _hdr.clear(); }; + + /** Add attachment to the message + * + * @param att The SMTP_Attachment data item + */ + void addAttachment(SMTP_Attachment &att) + { + att._int.att_type = esp_mail_att_type_attachment; + att._int.parallel = false; + att._int.flash_blob = true; + _att.push_back(att); + }; + + /** Add parallel attachment to the message + * + * @param att The SMTP_Attachment data item + */ + void addParallelAttachment(SMTP_Attachment &att) + { + att._int.att_type = esp_mail_att_type_attachment; + att._int.parallel = true; + att._int.flash_blob = true; + _parallel.push_back(att); + }; + + /** Add inline image to the message + * + * @param att The SMTP_Attachment data item + */ + void addInlineImage(SMTP_Attachment &att) + { + att._int.flash_blob = true; + att._int.parallel = false; + att._int.att_type = esp_mail_att_type_inline; + att._int.cid = random(2000, 4000); + _att.push_back(att); + }; + + /** Add rfc822 message to the message + * + * @param msg The RFC822_Message class object + */ + void addMessage(SMTP_Message &msg) { _rfc822.push_back(msg); } + + /** Add the primary recipient mailbox to the message + * + * @param name The name of primary recipient + * @param email The Email address of primary recipient + */ + template + void addRecipient(T1 name, T2 email) + { + struct esp_mail_address_info_t rcp; + rcp.name = toStringPtr(name); + rcp.email = toStringPtr(email); + _rcp.push_back(rcp); + }; + + /** Add Carbon-copy recipient mailbox + * + * @param email The Email address of the secondary recipient + */ + template + void addCc(T email) + { + struct esp_mail_address_info_t cc; + cc.email = toStringPtr(email); + _cc.push_back(cc); + }; + + /** Add Blind-carbon-copy recipient mailbox + * + * @param email The Email address of the tertiary recipient + */ + template + void addBcc(T email) + { + struct esp_mail_address_info_t bcc; + bcc.email = toStringPtr(email); + _bcc.push_back(bcc); + }; + + /** Add the custom header to the message + * + * @param hdr The header name and value + */ + template + void addHeader(T hdr) + { + _hdr.push_back(MB_String().setPtr(toStringPtr(hdr))); + }; + + /* The message author config */ + struct esp_mail_address_info_t author; + + /* The message sender (agent or teansmitter) config */ + struct esp_mail_address_info_t sender; + + /* The topic of message */ + MB_String subject; + + /* The message type */ + byte type = esp_mail_msg_type_none; + + /* The PLAIN text message */ + esp_mail_plain_body_t text; + + /* The HTML text message */ + esp_mail_html_body_t html; + + /* The response config */ + struct esp_mail_smtp_msg_response_t response; + + /* The priority of the message */ + esp_mail_smtp_priority priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; + + /* The enable options */ + struct esp_mail_smtp_enable_option_t enable; + + /* The message from config */ + struct esp_mail_address_info_t from; + + /* The message identifier */ + MB_String messageID; + + /* The keywords or phrases, separated by commas */ + MB_String keywords; + + /* The comments about message */ + MB_String comments; + + /* The date of message */ + MB_String date; + + /* The field that contains the parent's message ID of the message to which this one is a reply */ + MB_String in_reply_to; + + /* The field that contains the parent's references (if any) and followed by the parent's message ID (if any) of the message to which this one is a reply */ + MB_String references; + + /* The timestamp value to replace in text */ + esp_mail_timestamp_value_t timestamp; + +private: + friend class ESP_Mail_Client; + _vectorImpl _rcp; + _vectorImpl _cc; + _vectorImpl _bcc; + _vectorImpl _hdr; + _vectorImpl _att; + _vectorImpl _parallel; + _vectorImpl _rfc822; +}; + +class SMTP_Status +{ +public: + friend class SMTPSession; + friend class ESP_Mail_Client; + + SMTP_Status(); + ~SMTP_Status(); + const char *info(); + bool success(); + void empty(); + size_t completedCount(); + size_t failedCount(); + +private: + MB_String _info; + bool _success = false; + size_t _sentSuccess = 0; + size_t _sentFailed = 0; +}; + +typedef void (*smtpStatusCallback)(SMTP_Status); +typedef void (*smtpResponseCallback)(SMTP_Response); + +#endif + +class ESP_Mail_Client +{ + +public: + ESP_Mail_Client() + { + mbfs = new MB_FS(); + }; + + ~ESP_Mail_Client() + { + if (mbfs) + delete mbfs; + mbfs = nullptr; + + wifi.clearAP(); + }; + +#if defined(ENABLE_SMTP) + /** Sending Email through the SMTP server + * + * @param smtp The pointer to SMTP session object which holds the data and the + * TCP client. + * @param msg The pointer to SMTP_Message class which contains the header, + * body, and attachments. + * @param closeSession The option to Close the SMTP session after sent. + * @return The boolean value indicates the success of operation. + */ + bool sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true); +#endif + +#if defined(ENABLE_SMTP) && defined(ENABLE_IMAP) + /** Append message to the mailbox + * + * @param imap The pointer to IMAP session object which holds the data and the + * TCP client. + * @param msg The pointer to SMTP_Message class which contains the header, + * body, and attachments. + * @param lastAppend The last message to append (optional). In case of MULTIAPPEND extension + * is supported, set this to false will append messages in single APPEND command. + * @param flags The flags to set to this message (optional). + * @param dateTime The date/time to set to this message (optional). + * @return The boolean value indicates the success of operation. + */ + template + bool appendMessage(IMAPSession *imap, SMTP_Message *msg, bool lastAppend = true, T1 flags = "", T2 dateTime = "") { return mAppendMessage(imap, msg, lastAppend, toStringPtr(flags), toStringPtr(dateTime)); } +#endif + +#if defined(ENABLE_IMAP) + /** Reading Email through IMAP server. + * + * @param imap The pointer to IMAP session object which holds the data and + the TCP client. + + * @param closeSession The option to close the IMAP session after fetching or + searching the Email. + * @return The boolean value indicates the success of operation. + */ + bool readMail(IMAPSession *imap, bool closeSession = true); + + /** Set the argument to the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the + * TCP client. + * @param msgUID The UID of the message. + * @param flags The flag list to set. + * @param closeSession The option to close the IMAP session after set flag. + * @param silent The option to ignore the response. + * @param modsequence The int32_t option for UNCHANGESINCE conditional test. + * @return The boolean value indicates the success of operation. + * + * The modsequence value can be used only if IMAP server supports Conditional STORE extension + * and the selected mailbox supports modsequences. + */ + template + bool setFlag(IMAPSession *imap, int msgUID, T flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(msgUID), toStringPtr(flags), esp_mail_imap_store_flag_type_set, closeSession, silent, true, modsequence); } + + /** Set the argument to the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the + * TCP client. + * @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number. + * @param UID The option for sequenceSet whether it is UID or message sequence number. + * @param flags The flag list to set. + * @param closeSession The option to close the IMAP session after set flag. + * @param silent The option to ignore the response. + * @param modsequence The int32_t option for UNCHANGESINCE conditional test. + * @return The boolean value indicates the success of operation. + * + * The modsequence value can be used only if IMAP server supports Conditional STORE extension + * and the selected mailbox supports modsequences. + */ + template + bool setFlag(IMAPSession *imap, T1 sequenceSet, bool UID, T2 flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(sequenceSet), toStringPtr(flags), esp_mail_imap_store_flag_type_set, closeSession, silent, UID, modsequence); } + + /** Add the argument to the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the + * TCP client. + * @param msgUID The UID of the message. + * @param flags The flag list to add. + * @param closeSession The option to close the IMAP session after add flag. + * @param silent The option to ignore the response. + * @param modsequence The int32_t option for UNCHANGESINCE conditional test. + * @return The boolean value indicates the success of operation. + * + * The modsequence value can be used only if IMAP server supports Conditional STORE extension + * and the selected mailbox supports modsequences. + */ + template + bool addFlag(IMAPSession *imap, int msgUID, T flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(msgUID), toStringPtr(flags), esp_mail_imap_store_flag_type_add, closeSession, silent, true, modsequence); } + + /** Add the argument to the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the + * TCP client. + * @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number. + * @param UID The option for sequenceSet whether it is UID or message sequence number. + * @param flags The flag list to add. + * @param closeSession The option to close the IMAP session after set flag. + * @param silent The option to ignore the response. + * @param modsequence The int32_t option for UNCHANGESINCE conditional test. + * @return The boolean value indicates the success of operation. + * + * The modsequence value can be used only if IMAP server supports Conditional STORE extension + * and the selected mailbox supports modsequences. + */ + template + bool addFlag(IMAPSession *imap, T1 sequenceSet, bool UID, T2 flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(sequenceSet), toStringPtr(flags), esp_mail_imap_store_flag_type_add, closeSession, silent, UID, modsequence); } + + /** Remove the argument from the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the + * TCP client. + * @param msgUID The UID of the message that flags to be removed. + * @param flags The flag list to remove. + * @param closeSession The option to close the IMAP session after remove flag. + * @param silent The option to ignore the response. + * @param modsequence The int32_t option for UNCHANGESINCE conditional test. + * @return The boolean value indicates the success of operation. + * + * The modsequence value can be used only if IMAP server supports Conditional STORE extension + * and the selected mailbox supports modsequences. + */ + template + bool removeFlag(IMAPSession *imap, int msgUID, T flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(msgUID), toStringPtr(flags), esp_mail_imap_store_flag_type_remove, closeSession, silent, true, modsequence); } + + /** Remove the argument from the Flags for the specified message. + * + * @param imap The pointer to IMAP session object which holds the data and the + * TCP client. + * @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number. + * @param UID The option for sequenceSet whether it is UID or message sequence number. + * @param flags The flag list to remove. + * @param closeSession The option to close the IMAP session after set flag. + * @param silent The option to ignore the response. + * @param modsequence The int32_t option for UNCHANGESINCE conditional test. + * @return The boolean value indicates the success of operation. + * + * The modsequence value can be used only if IMAP server supports Conditional STORE extension + * and the selected mailbox supports modsequences. + */ + template + bool removeFlag(IMAPSession *imap, T1 sequenceSet, bool UID, T2 flags, bool closeSession, bool silent = false, int32_t modsequence = -1) { return mSetFlag(imap, toStringPtr(sequenceSet), toStringPtr(flags), esp_mail_imap_store_flag_type_remove, closeSession, silent, UID, modsequence); } + +#endif + + /** Reconnect WiFi or network if lost connection. + * + * @param reconnect The boolean to set/unset WiFi AP reconnection. + */ + void networkReconnect(bool reconnect); + + /* Obsoleted */ + void setUDPClient(void *client, float gmtOffset) {} + + /** Clear all WiFi access points assigned. + * + */ + void clearAP(); + + /** Add WiFi access point for non-ESP device to resume WiFi connection. + * + * @param ssid The WiFi SSID. + * @param password The WiFi password. + */ + void addAP(const String &ssid, const String &password); + + /** + * Formatted printing on debug port. + * + */ + void printf(const char *format, ...); + +#if defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD) + + /** Initiate SD card with SPI port configuration. + * + * @param ss SPI Chip/Slave Select pin. + * @param sck SPI Clock pin. + * @param miso SPI MISO pin. + * @param mosi SPI MOSI pin. + * @param frequency The SPI frequency + * @return Boolean type status indicates the success of the operation. + */ + bool sdBegin(int8_t ss = -1, int8_t sck = -1, int8_t miso = -1, int8_t mosi = -1, uint32_t frequency = 4000000); + +#if defined(ESP8266) || defined(MB_ARDUINO_PICO) + + /** Initiate SD card with SD FS configurations (ESP8266 only). + * + * @param ss SPI Chip/Slave Select pin. + * @param sdFSConfig The pointer to SDFSConfig object (ESP8266 only). + * @return Boolean type status indicates the success of the operation. + */ + bool sdBegin(SDFSConfig *sdFSConfig); + +#endif + +#if defined(ESP32) + /** Initiate SD card with chip select and SPI configuration (ESP32 only). + * + * @param ss SPI Chip/Slave Select pin. + * @param spiConfig The pointer to SPIClass object for SPI configuartion. + * @param frequency The SPI frequency. + * @return Boolean type status indicates the success of the operation. + */ + bool sdBegin(int8_t ss, SPIClass *spiConfig = nullptr, uint32_t frequency = 4000000); +#endif + +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + /** Initiate SD card with SdFat SPI and pins configurations (with SdFat included only). + * + * @param sdFatSPIConfig The pointer to SdSpiConfig object for SdFat SPI configuration. + * @param ss SPI Chip/Slave Select pin. + * @param sck SPI Clock pin. + * @param miso SPI MISO pin. + * @param mosi SPI MOSI pin. + * @return Boolean type status indicates the success of the operation. + */ + bool sdBegin(SdSpiConfig *sdFatSPIConfig, int8_t ss = -1, int8_t sck = -1, int8_t miso = -1, int8_t mosi = -1); + + /** Initiate SD card with SdFat SDIO configuration (with SdFat included only). + * + * @param sdFatSDIOConfig The pointer to SdioConfig object for SdFat SDIO configuration. + * @return Boolean type status indicates the success of the operation. + */ + bool sdBegin(SdioConfig *sdFatSDIOConfig); + +#endif + +#endif + +#if defined(ESP32) && defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD_MMC) + /** Initialize the SD_MMC card (ESP32 only). + * + * @param mountpoint The mounting point. + * @param mode1bit Allow 1 bit data line (SPI mode). + * @param format_if_mount_failed Format SD_MMC card if mount failed. + * @return The boolean value indicates the success of operation. + */ + bool sdMMCBegin(const char *mountpoint = "/sdcard", bool mode1bit = false, bool format_if_mount_failed = false); +#endif + + /** Get free Heap memory. + * + * @return Free memory amount in byte. + */ + int getFreeHeap(); + + /** Get base64 encode string. + * + * @return String of base64 encoded string. + */ + template + String toBase64(T str) { return mGetBase64(toStringPtr(str)).c_str(); } + + MB_Time Time; + +#if defined(ENABLE_IMAP) + + // Get encoding type from character set string + esp_mail_char_decoding_scheme getEncodingFromCharset(const char *enc); + + // Decode Latin1 to UTF-8 + int decodeLatin1_UTF8(unsigned char *out, int *outlen, const unsigned char *in, int *inlen); + + // Decode TIS620 to UTF-8 + void decodeTIS620_UTF8(char *out, const char *in, size_t len); + + // handle rfc2047 Q (quoted printable) and B (base64) decodings + RFC2047_Decoder RFC2047Decoder; + +#endif + +private: + friend class SMTPSession; + friend class IMAPSession; + + MB_FS *mbfs = nullptr; + bool timeStatus = false; + time_t ts = 0; + bool networkAutoReconnect = true; + volatile bool networkStatus = false; + esp_mail_wifi_credentials_t wifi; + bool timezoneEnvSet = false; + + IMAPSession *imap = nullptr; + bool calDataLen = false; + uint32_t dataLen = 0; + uint32_t imap_ts = 0; + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + + unsigned long _lastReconnectMillis = 0; + uint16_t _reconnectTimeout = ESP_MAIL_NETWORK_RECONNECT_TIMEOUT; + + // Resume network connection + void resumeNetwork(ESP_Mail_TCPClient *client); + + // Get the CRLF ending string w/wo CRLF included. Return the size of string read and the current octet read. + int readLine(ESP_Mail_TCPClient *client, char *buf, int bufLen, bool withLineBreak, int &count, bool &ovf, unsigned long timeoutSec, bool &isTimeout); + + // readLine with overflow handling. + template + bool readResponse(T sessionPtr, char *buf, int bufLen, int &readLen, bool withLineBreak, int &count, MB_String &ovfBuf); + + // Network reconnection and return the connection status + template + bool reconnect(T sessionPtr, unsigned long dataTime = 0, bool downloadRequest = false); + + // Send callback + template + void sendCB(T sessionPtr, PGM_P info = "", bool prependCRLF = false, bool success = false); + + // PGM string replacement + void strReplaceP(MB_String &buf, PGM_P key, PGM_P value); + + // Check for OAuth log in error response + bool isOAuthError(char *buf, int bufLen, int &chunkIdx, int ofs); + + // Get SASL XOAUTH2 string + MB_String getXOAUTH2String(const MB_String &email, const MB_String &accessToken); + + // Send error callback + template + void sendErrorCB(T sessionPtr, PGM_P info, bool prependCRLF = false, bool success = false); + + // Send the error status callback + template + void errorStatusCB(T1 sessionPtr, T2 sessionPtr2, int error, bool clearLastStatus); + + // Check response callback was assigned? + template + bool isResponseCB(T sessionPtr); + + // Print library info + template + void printLibInfo(T sessionPtr); + + // Begin server connection + template + bool beginConnection(Session_Config *session_config, T sessionPtr, bool secureMode); + + // Prepare system time + template + bool prepareTime(Session_Config *session_config, T sessionPtr); + + // Check for session. Close session If not ready. + template + bool sessionReady(T sessionPtr); + + // Set cert data + void setCert(Session_Config *session_cfg, const char *ca); + // Set secure data + void setSecure(ESP_Mail_TCPClient &client, Session_Config *session_config); + + void appendMultipartContentType(MB_String &buf, esp_mail_multipart_types type, const char *boundary); + + String errorReason(bool isSMTP, int errorCode, const char *msg); + + // Close TCP session and clear auth_capability, read/send_capability, connected and authenticate statuses + template + void closeTCPSession(T sessionPtr); + + // Get and set timezone + void getSetTimezoneEnv(const char *TZ_file, const char *TZ_Var); + + // Get TCP connected status + template + bool connected(T sessionPtr); + + // Get the memory allocation block size of multiple of 4 + size_t getReservedLen(size_t len); + + // Check Email for valid format + bool validEmail(const char *s); + + // Get random UID for SMTP content ID and IMAP attachment default file name + char *getRandomUID(); + + // Spit the string into token strings + void splitToken(const char *str, _vectorImpl &tk, const char *delim); + + // Decode base64 encoded string + unsigned char *decodeBase64(const unsigned char *src, size_t len, size_t *out_len); + + // Decode base64 encoded string + MB_String encodeBase64Str(const unsigned char *src, size_t len); + + // Decode base64 encoded string + MB_String encodeBase64Str(uint8_t *src, size_t len); + + // Decode base64 encoded string + MB_String mGetBase64(MB_StringPtr str); + + // Sub string + char *subStr(const char *buf, PGM_P beginToken, PGM_P endToken, int beginPos, int endPos = 0, bool caseSensitive = true); + + // Find string + int strpos(const char *haystack, const char *needle, int offset, bool caseSensitive = true); + + // Memory allocation + template + T allocMem(size_t size, bool clear = true); + + // Memory deallocation + void freeMem(void *ptr); + + // PGM string compare + bool strcmpP(const char *buf, int ofs, PGM_P beginToken, bool caseSensitive = true); + + // Find PGM string + int strposP(const char *buf, PGM_P beginToken, int ofs, bool caseSensitive = true); + + // Memory allocation for PGM string + char *strP(PGM_P pgm); + + // Memory allocation for PGM lower case string + char *strP2Lower(PGM_P pgm); + + // Set or sync device system time with NTP server + // Do not modify or remove + void setTime(const char *TZ_Var, const char *TZ_file, bool wait, bool debugProgress); + + // Set the device time zone via TZ environment variable + void setTimezone(const char *TZ_Var, const char *TZ_file); + + // Get TZ environment variable from file + // Do not modify or remove + void getTimezone(const char *TZ_file, MB_String &out); + + // Check the session existent + template + bool sessionExisted(T sessionPtr); + + // Send SMTP/IMAP callback + template + void sendCallback(T sessionPtr, PGM_P info, bool prependCRLF, bool success); + + // Send IMAP/SMTP response callback and print debug message + template + void printDebug(T sessionPtr, PGM_P cbMsg, PGM_P dbMsg, esp_mail_debug_tag_type type, bool prependCRLF, bool success); + + // Get header content from response based on the field name + bool getHeader(const char *buf, PGM_P beginToken, MB_String &out, bool caseSensitive); + + // Append header field to buffer + void appendHeaderField(MB_String &buf, const char *name, PGM_P value, bool comma, bool newLine, esp_mail_string_mark_type type = esp_mail_string_mark_type_none); + + // Append SMTP address header field + void appendAddressHeaderField(MB_String &buf, esp_mail_address_info_t &source, esp_mail_rfc822_header_field_types type, bool header, bool comma, bool newLine); + + // Append header field name to buffer + void appendHeaderName(MB_String &buf, const char *name, bool clear = false, bool lowercase = false, bool space = true); + + // Append lowercase string to buffer + void appendLowerCaseString(MB_String &buf, PGM_P value, bool clear = false); + + // Append header field property to buffer + void appendHeaderProp(MB_String &buf, PGM_P prop, const char *value, bool &firstProp, bool lowerCase, bool isString, bool newLine); + + // Append quote string to buffer + void appendString(MB_String &buf, PGM_P value, bool comma, bool newLine, esp_mail_string_mark_type type = esp_mail_string_mark_type_none); + + // Append list to buffer + template + void appendList(MB_String &buf, _vectorImpl &list); + + // Append space to buffer + void appendSpace(MB_String &buf); + + // Append space to buffer after value + void appendSpace(MB_String &buf, bool withTag, PGM_P value); + + // Append space to buffer after values + void appendSpace(MB_String &buf, bool withTag, int nunArgs, ...); + + // Append space to buffer before value + void prependSpace(MB_String &buf, PGM_P value); + + // Append dot to buffer + void appendDot(MB_String &buf); + + // Append IMAP string key value list + void appendImap4KeyValue(MB_String &buf, PGM_P key, PGM_P value); + + // Append dot to buffer before value + void prependDot(MB_String &buf, PGM_P value); + + // Join 2 strings to buffer with space + void joinStringSpace(MB_String &buf, bool withTag, int nunArgs, ...); + + // Join 2 strings to buffer with dot + void joinStringDot(MB_String &buf, int nunArgs, ...); + + // Append mask(*) string to buffer + void maskString(MB_String &buf, int len); + + // Append domain to buffer + void appendDomain(MB_String &buf, const char *domain); + + // Append embedded message header to buffer + void appendEmbedMessage(MB_String &buf, esp_mail_message_body_t &body, bool isHtml); + + // Append crlf to buffer + void appendNewline(MB_String &buf); + + // Append tag to the buffer + void appendTagSpace(MB_String &buf, PGM_P tag = NULL); + + // Print newline + void debugPrintNewLine(); + + // Send newline to callback + template + void callBackSendNewLine(T sessionPtr, bool success); + + // Print progress bar + void printProgress(int progress, int &lastProgress); + + // Get file extension with dot from MIME string + void getExtfromMIME(const char *mime, MB_String &ext); + + // Prepare ports + void preparePortFunction(Session_Config *session_config, bool isSMTP, bool &secure, bool &secureMode, bool &ssl); + + // Get operation config based on port and its protocol + void getPortFunction(uint16_t port, struct esp_mail_ports_functions &ports_functions, bool &secure, bool &secureMode, bool &ssl, bool &starttls); + +#endif + +#if defined(ENABLE_SMTP) + + // Encode Quoted Printable string + void encodeQP(const char *buf, char *out); + + // Add the soft line break to the long text line rfc 3676 + void formatFlowedText(MB_String &content); + + // Insert soft break + void softBreak(MB_String &content, const char *quoteMarks); + + // Get content type (MIME) from file extension + void getMIME(const char *ext, MB_String &mime); + + // Get content type (MIME) from file name + void mimeFromFile(const char *name, MB_String &mime); + + // Get MIME boundary string + MB_String getMIMEBoundary(size_t len); + + // Send Email function + bool mSendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true); + + // SMTP send data + size_t smtpSend(SMTPSession *smtp, PGM_P data, bool newline = false); + + // SMTP send data + size_t smtpSend(SMTPSession *smtp, int data, bool newline = false); + + // SMTP send data + size_t smtpSend(SMTPSession *smtp, uint8_t *data, size_t size); + + // Handle the error by sending callback and close session + bool handleSMTPError(SMTPSession *smtp, int err, bool ret = false); + + // Send parallel attachment RFC1521 + bool sendParallelAttachments(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary); + + // Send attachment + bool sendAttachments(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, bool parallel = false); + + // Send message content + bool sendContent(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG); + + // Send imap or smtp callback + void altSendCallback(SMTPSession *smtp, PGM_P cbMsg, PGM_P dbMsg, esp_mail_debug_tag_type type, bool prependCRLF, bool success); + + // Send message data + bool sendMSGData(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG); + + // Send RFC 822 message + bool sendRFC822Msg(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, bool closeSession, bool rfc822MSG); + + // Get RFC 822 message envelope + void getRFC822MsgEnvelope(SMTPSession *smtp, SMTP_Message *msg, MB_String &buf); + + // Append boundary string to buffer + void appendBoundaryString(MB_String &buf, const char *value, bool endMark, bool newLine); + + // Send BDAT command RFC 3030 + bool sendBDAT(SMTPSession *smtp, SMTP_Message *msg, int len, bool last); + + // Get transfer encoding + void getXEncoding(esp_mail_msg_xencoding &xencoding, const char *enc); + + // Set the unencoded xencoding enum for html, text and attachment from its xencoding string + void checkUnencodedData(SMTPSession *smtp, SMTP_Message *msg); + + // Check imap or smtp has callback set + bool altIsCB(SMTPSession *smtp); + + // Check imap or smtp has debug set + bool altIsDebug(SMTPSession *smtp); + + // Send BLOB attachment + bool sendBlobAttachment(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att); + + // Send file content + bool sendFile(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att); + + // Send imap or smtp storage error callback + void altSendStorageErrorCB(SMTPSession *smtp, int err); + + // Open file to send an attachment + bool openFileRead(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, MB_String &buf, const MB_String &boundary, bool inlined); + + // Open text file or html file for to send message + bool openFileRead2(SMTPSession *smtp, SMTP_Message *msg, const char *path, esp_mail_file_storage_type storageType); + + // Send inline attachments + bool sendInline(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, byte type); + + // Send storage error callback + void sendStorageNotReadyError(SMTPSession *smtp, esp_mail_file_storage_type storageType); + + // Append message + bool mAppendMessage(IMAPSession *imap, SMTP_Message *msg, bool lastAppend, MB_StringPtr flags, MB_StringPtr dateTime); + + // Get numbers of attachment based on type + size_t numAtt(SMTPSession *smtp, esp_mail_attach_type type, SMTP_Message *msg); + + // Check for valid recipient Email + bool checkEmail(SMTPSession *smtp, SMTP_Message *msg); + + // Send text parts MIME message + bool sendPartText(SMTPSession *smtp, SMTP_Message *msg, byte type, const char *boundary); + + // Alternative string data sending to send imap APPEND data or smtp data + bool altSendData(MB_String &s, bool newLine, SMTPSession *smtp, SMTP_Message *msg, bool addSendResult, bool getResponse, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode); + + // Alternative bytes data sending to send imap APPEND data or smtp data + bool altSendData(uint8_t *data, size_t size, SMTPSession *smtp, SMTP_Message *msg, bool addSendResult, bool getResponse, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode); + + // Send MIME message + bool sendMSG(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary); + + // Get an attachment part header string + void getAttachHeader(MB_String &header, const MB_String &boundary, SMTP_Attachment *attach, size_t size, bool isInline); + + // Get RFC 8222 part header string + void getRFC822PartHeader(SMTPSession *smtp, MB_String &header, const MB_String &boundary); + + // Send BLOB type text part or html part MIME message + bool sendBlobBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type); + + // Send file type text part or html part MIME message + bool sendFileBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type); + + // Base64 and QP encodings for text and html messages and replace embeded attachment file name with content ID + void encodingText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, MB_String &content); + + // Blob or Stream available + int chunkAvailable(SMTPSession *smtp, esp_mail_smtp_send_base64_data_info_t &data_info); + + // Read chunk data of blob or file + int getChunk(SMTPSession *smtp, esp_mail_smtp_send_base64_data_info_t &data_info, unsigned char *rawChunk, bool base64); + + // Terminate chunk reading + void closeChunk(esp_mail_smtp_send_base64_data_info_t &data_info); + + // Get base64 encoded buffer or raw buffer + void getBuffer(bool base64, uint8_t *out, uint8_t *in, int &encodedCount, int &bufIndex, bool &dataReady, int &size, size_t chunkSize); + + // Send blob or file as base64 encoded chunk + bool sendBase64(SMTPSession *smtp, SMTP_Message *msg, esp_mail_smtp_send_base64_data_info_t &data_info, bool base64, bool report); + + // Save sending logs to file + void saveSendingLogs(SMTPSession *smtp, SMTP_Message *msg, bool result); + + // Get imap or smtp report progress var pointer + uint32_t altProgressPtr(SMTPSession *smtp); + + // Get SMTP response status (statusCode and text) + void getResponseStatus(const char *buf, esp_mail_smtp_status_code statusCode, int beginPos, struct esp_mail_smtp_response_status_t &status); + + // Parse SMTP authentication capability + void parseAuthCapability(SMTPSession *smtp, char *buf); + + // Add the sending result + bool addSendingResult(SMTPSession *smtp, SMTP_Message *msg, bool result, bool showResult); + + // Handle SMTP server authentication + bool smtpAuth(SMTPSession *smtp, bool &ssl); + + // Handle SMTP response + bool handleSMTPResponse(SMTPSession *smtp, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode); + + // Print the upload status to the debug port + void uploadReport(const char *filename, uint32_t pgAddr, int progress); + + // Get MB_FS object pointer + MB_FS *getMBFS(); + + // Set device system time + int setTimestamp(time_t ts); +#endif + +#if defined(ENABLE_IMAP) + + // Check if child part (part number string) is a member of the parent part (part number string) + // part number string format: .. + bool multipartMember(const MB_String &parent, const MB_String &child); + + // Decode string + int decodeChar(const char *s); + + // Decode Quoted Printable string + void decodeQP_UTF8(const char *buf, char *out); + + // Actually not decode because 7bit string is enencode string unless prepare valid 7bit string and do qp decoding + char *decode7Bit_UTF8(char *buf); + + // Actually not decode because 8bit string is enencode string unless prepare valid 8bit string + char *decode8Bit_UTF8(char *buf); + + // Decode string base on encoding + void decodeString(IMAPSession *imap, MB_String &string, const char *enc = ""); + + /** + * Encode a code point using UTF-8 + * + * @author Ondřej Hruška + * https://gist.github.com/MightyPork/52eda3e5677b4b03524e40c9f0ab1da5 + * + * @license MIT + * + * @param out - output buffer (min 5 characters), will be 0-terminated + * @param utf - code point 0-0x10FFFF + * @return number of bytes on success, 0 on failure (also produces U+FFFD, which uses 3 bytes) + */ + int encodeUnicode_UTF8(char *out, uint32_t utf); + + // Append headers fetch command + void appendHeadersFetchCommand(IMAPSession *imap, MB_String &cmd, int index, bool debug); + + // Append rfc822 headers fetch command + void appendRFC822HeadersFetchCommand(MB_String &cmd); + + // Get multipart MIME fetch command + bool getMultipartFechCmd(IMAPSession *imap, int msgIdx, MB_String &partText); + + // Fetch multipart MIME body header + bool fetchMultipartBodyHeader(IMAPSession *imap, int msgIdx); + + // Print body part fetching debug + void printBodyPartFechingDubug(IMAPSession *imap, const char *partNum, bool multiLevel); + + // Handle IMAP server authentication + bool imapAuth(IMAPSession *imap, bool &ssl); + + // Send IMAP command + bool sendFetchCommand(IMAPSession *imap, int msgIndex, esp_mail_imap_command cmdCase); + + // Send data + size_t imapSend(IMAPSession *imap, PGM_P data, bool newline = false); + + // Send data + size_t imapSend(IMAPSession *imap, int data, bool newline = false); + + // Send data + size_t imapSend(IMAPSession *imap, uint8_t *data, size_t size); + + // Log out + bool imapLogout(IMAPSession *imap); + + // Send storage error callback + void sendStorageNotReadyError(IMAPSession *imap, esp_mail_file_storage_type storageType); + + // Parse search response + int parseSearchResponse(IMAPSession *imap, esp_mail_imap_response_data &res, PGM_P tag, const char *key); + + // Parse header state + bool parseHeaderField(IMAPSession *imap, const char *buf, PGM_P beginToken, bool caseSensitive, struct esp_mail_message_header_t &header, int &headerState, int state); + + // Parse header response + void parseHeaderResponse(IMAPSession *imap, esp_mail_imap_response_data &res, bool caseSensitive = true); + + // Set the header based on state parsed + void collectHeaderField(IMAPSession *imap, char *buf, struct esp_mail_message_header_t &header, int state); + + // Get decoded header + bool getDecodedHeader(IMAPSession *imap, const char *buf, PGM_P beginToken, MB_String &out, bool caseSensitive); + + // Check attachment for firmware file + void checkFirmwareFile(IMAPSession *imap, const char *filename, struct esp_mail_message_part_info_t &part, bool defaultSize = false); + + // Parse part header response + void parsePartHeaderResponse(IMAPSession *imap, esp_mail_imap_response_data &res, bool caseSensitive = true); + + // Count char in string + int countChar(const char *buf, char find); + + // Store the value to string via its the pointer + bool storeStringPtr(IMAPSession *imap, uint32_t addr, MB_String &value, const char *buf); + + // Get part header properties + bool getPartHeaderProperties(IMAPSession *imap, const char *buf, PGM_P p, PGM_P e, bool num, MB_String &value, MB_String &old_value, esp_mail_char_decoding_scheme &scheme, bool caseSensitive); + + // Url decode for UTF-8 encoded header text + char *urlDecode(const char *str); + + // Reset the pointer to multiline response keeping string + void resetStringPtr(struct esp_mail_message_part_info_t &part); + + // Get current part + struct esp_mail_message_part_info_t *cPart(IMAPSession *imap); + + // Get current header + struct esp_mail_message_header_t *cHeader(IMAPSession *imap); + +#if !defined(MB_USE_STD_VECTOR) + // Decending sort + void numDecSort(_vectorImpl &arr); +#endif + + // Handle IMAP response + bool handleIMAPResponse(IMAPSession *imap, int errCode, bool closeSession); + + // Print the file download status via debug port + void downloadReport(IMAPSession *imap, int progress); + + // Print the message fetch status via debug port + void fetchReport(IMAPSession *imap, int progress, bool html); + + // Print the message search status via debug port + void searchReport(IMAPSession *imap, int progress); + + // Get current message num item + struct esp_mail_imap_msg_num_t cMSG(IMAPSession *imap); + + // Get current message Index + int cIdx(IMAPSession *imap); + + // Get IMAP response status e.g. OK, NO and Bad status enum value + esp_mail_imap_response_status imapResponseStatus(IMAPSession *imap, char *response, PGM_P tag); + + // Add header item to string buffer + void addHeaderItem(MB_String &str, esp_mail_message_header_t *header, bool json); + + // Get RFC822 header string pointer by index + int getRFC822HeaderPtr(int index, esp_mail_imap_rfc822_msg_header_item_t *header); + + // Add RFC822 headers to string buffer + void addRFC822Headers(MB_String &s, esp_mail_imap_rfc822_msg_header_item_t *header, bool json); + + // Add RFC822 header item to string buffer + void addRFC822HeaderItem(MB_String &s, esp_mail_imap_rfc822_msg_header_item_t *header, int index, bool json); + + // Add header string by name and value to string buffer + void addHeader(MB_String &s, const char *name, const char *s_value, int num_value, bool trim, bool isJson); + + // Save header string buffer to file + void saveHeader(IMAPSession *imap, bool json); + + // Send MIME stream to callback + void sendStreamCB(IMAPSession *imap, void *buf, size_t len, int chunkIndex, bool hrdBrk); + + // Prepare file path for saving + void prepareFilePath(IMAPSession *imap, MB_String &filePath, bool header); + + // Decode text and store it to buffer or file + void decodeText(IMAPSession *imap, esp_mail_imap_response_data &res); + + // Handle atachment parsing and download + bool parseAttachmentResponse(IMAPSession *imap, char *buf, esp_mail_imap_response_data &res); + + // Get List + char *getList(char *buf, bool &isList); + + // Parse mailbox folder open response + void parseFoldersResponse(IMAPSession *imap, char *buf, bool list); + + // Prepare alias (short name) file list for unsupported long file name filesystem + void prepareFileList(IMAPSession *imap, MB_String &filePath); + + // Parse capability response + bool parseCapabilityResponse(IMAPSession *imap, const char *buf, int &chunkIdx); + + // Parse Idle response + bool parseIdleResponse(IMAPSession *imap); + + // Append Fetch UID/Flags string to buffer + void appendFetchString(MB_String &buf, bool uid); + + // Parse command response + void parseCmdResponse(IMAPSession *imap, char *buf, PGM_P find); + + // Get flags + bool getFlags(IMAPSession *imap, char *buf, esp_mail_imap_response_types type); + + // Parse examine response + void parseExamineResponse(IMAPSession *imap, char *buf); + + // Handle the error by sending callback and close session + bool handleIMAPError(IMAPSession *imap, int err, bool ret); + + // Set Flag + bool mSetFlag(IMAPSession *imap, MB_StringPtr sequenceSet, MB_StringPtr flags, esp_mail_imap_store_flag_type type, bool closeSession, bool silent = false, bool UID = true, int32_t modsequence = -1); + +#endif +}; + +#if defined(ENABLE_IMAP) + +class IMAPSession +{ +public: + IMAPSession(Client *client); + IMAPSession(); + ~IMAPSession(); + + /** Set the tcp timeout. + * + * @param timeoutSec The tcp timeout in seconds. + */ + void setTCPTimeout(unsigned long timeoutSec); + + /** Assign custom Client from Arduino Clients. + * + * @param client The pointer to Arduino Client derived class e.g. WiFiClient, EthernetClient or GSMClient. + */ + void setClient(Client *client); + + /** Assign TinyGsm Clients. + * + * @param client The pointer to TinyGsmClient. + * @param modem The pointer to TinyGsm modem object. Modem should be initialized and/or set mode before transfering data. + * @param pin The SIM pin. + * @param apn The GPRS APN (Access Point Name). + * @param user The GPRS user. + * @param password The GPRS password. + */ + void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password); + + /** Assign the callback function to handle the network connection for custom Client. + * + * @param networkConnectionCB The function that handles the network connection. + */ + void networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB); + + /** Assign the callback function to handle the network connection status acknowledgement. + * + * @param networkStatusCB The function that handle the network connection status acknowledgement. + */ + void networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB); + + /** Set the network status acknowledgement. + * + * @param status The network status. + */ + void setNetworkStatus(bool status); + + /** Set the BearSSL IO buffer size. + * + * @param rx The BearSSL receive buffer size in bytes. + * @param tx The BearSSL trasmit buffer size in bytes. + */ + void setSSLBufferSize(int rx = -1, int tx = -1); + + /** Begin the IMAP server connection. + * + * @param session_config The pointer to Session_Config structured data that keeps + * the server and log in details. + * @param imap_data The pointer to IMAP_Data structured data that keeps the + * operation options. + * @param login The bool option for login after server connection. + * @return The boolean value which indicates the success of operation. + */ + bool connect(Session_Config *session_config, IMAP_Data *imap_data, bool login = true); + + /** Log in to IMAP server using Email and password. + * + * @param email The IMAP server account email. + * @param password The IMAP server account password. + * @return The boolean value which indicates the success of operation. + */ + template + bool loginWithPassword(T1 email, T2 password) { return mLogin(toStringPtr(email), toStringPtr(password), false); }; + + /** Log in to IMAP server using Email and access token. + * + * @param email The IMAP server account email. + * @param token The Access token to log in. + * @return The boolean value which indicates the success of operation. + */ + template + bool loginWithAccessToken(T1 email, T2 token) { return mLogin(toStringPtr(email), toStringPtr(token), true); }; + + /** Send the client identification to the server + * + * @param identification The pointer to IMAP_Identification structured data that keeps + * the key properties e.g., name, version, os, os_version, vendor, support_url, address, + * date, command, arguments, and environment. + */ + bool id(IMAP_Identification *identification); + + /** Return the server ID returns from ID command. + * @return The server ID string. + */ + String serverID(); + + /** Return the SASL authentication status. + * @return The boolean value indicates SASL authentication status. + */ + bool isAuthenticated(); + + /** Return the log status. + * @return The boolean value log in status. + */ + bool isLoggedIn(); + + /** Return firmware update result when attachment filename matches. + * @return The boolean value indicates the firmware update status. + */ + bool isFirmwareUpdateSuccess(); + + /** Begin the IMAP server connection without authentication. + * + * @param session_config The pointer to Session_Config structured data that keeps + * the server and log in details. + * @param callback The callback function that accepts IMAP_Response as parameter. + * @param tag The tag that pass to the callback function. + * @return The boolean value indicates the success of operation. + */ + template + bool customConnect(Session_Config *session_config, imapResponseCallback callback, T tag = "") { return mCustomConnect(session_config, callback, toStringPtr(tag)); }; + + /** Close the IMAP session. + * + * @return The boolean value which indicates the success of operation. + */ + bool closeSession(); + + /** Get TCP connection status. + * + * @return The boolean value indicates the connection status. + */ + bool connected(); + + /** Set to enable the debug. + * + * @param level The level to enable the debug message + * level = 0, no debugging + * level = 1, basic level debugging + */ + void debug(int level); + + /** Get the list of all the mailbox folders since the TCP session was opened + * and user was authenticated. + * + * @param folders The FoldersCollection class that contains the collection of + * the + * FolderInfo structured data. + * @return The boolean value which indicates the success of operation. + */ + bool getFolders(FoldersCollection &folders); + + /** Select or open the mailbox folder to search or fetch the message inside. + * + * @param folderName The known mailbox folder name. The default name is INBOX. + * @param readOnly The option to open the mailbox for read only. Set this + * option to false when you wish + * to modify the Flags using the setFlag, addFlag and removeFlag functions. + * @return The boolean value which indicates the success of operation. + * + * @note: the function will exit immediately and return true if the time since previous success folder selection (open) + * with the same readOnly mode, is less than 5 seconds. + */ + template + bool selectFolder(T folderName, bool readOnly = true) { return mSelectFolder(toStringPtr(folderName), readOnly); } + + /** Open the mailbox folder to read or search the mesages. + * + * @param folderName The name of known mailbox folder to be opened. + * @param readOnly The option to open the mailbox for reading only. Set this + * option to false when you wish + * to modify the flags using the setFlag, addFlag and removeFlag functions. + * @return The boolean value which indicates the success of operation. + * + * @note: the function will exit immediately and return true if the time since previous success folder selection (open) + * with the same readOnly mode, is less than 5 seconds. + */ + template + bool openFolder(T folderName, bool readOnly = true) { return mOpenFolder(toStringPtr(folderName), readOnly); } + + /** Close the mailbox folder that was opened. + * + * @param expunge The option to allow emty the deleted flag set messages in case folder was open with editable mode. + * @return The boolean value which indicates the success of operation. + */ + bool closeFolder(bool expunge = false) { return mCloseFolder(expunge); } + + /** Create folder. + * + * @param folderName The name of folder to create. + * @return The boolean value which indicates the success of operation. + */ + template + bool createFolder(T folderName) { return mCreateFolder(toStringPtr(folderName)); } + + /** Rename folder. + * + * @param currentFolderName The name of folder to rename. + * @param newFolderName The new name of folder to rename. + * @return The boolean value which indicates the success of operation. + */ + template + bool renameFolder(T1 currentFolderName, T2 newFolderName) { return mRenameFolder(toStringPtr(currentFolderName), toStringPtr(newFolderName)); } + + /** Delete folder. + * + * @param folderName The name of folder to delete. + * @return The boolean value which indicates the success of operation. + */ + template + bool deleteFolder(T folderName) { return mDeleteFolder(toStringPtr(folderName)); } + + /** Get subscribes mailboxes. + * + * @param reference The reference name. + * @param mailbox The mailbox name with possible wildcards. + * @param folders The return FoldersCollection that contains the folder info e.g., name, attribute and delimiter. + * @return The boolean value which indicates the success of operation. + */ + template + bool getSubscribesMailboxes(T1 reference, T2 mailbox, FoldersCollection &folders) { return mGetSubscribesMailboxes(toStringPtr(reference), toStringPtr(mailbox), folders); } + + /** Subscribe mailbox. + * + * @param folderName The name of folder to subscribe. + * @return The boolean value which indicates the success of operation. + */ + template + bool subscribe(T folderName) { return mSubscribe(toStringPtr(folderName)); } + + /** Unsubscribe mailbox. + * + * @param folderName The name of folder to unsubscribe. + * @return The boolean value which indicates the success of operation. + */ + template + bool unSubscribe(T folderName) { return mUnSubscribe(toStringPtr(folderName)); } + + /** Get UID number in selected or opened mailbox. + * + * @param msgNum The message number or order in the total message numbers. + * @return UID number in selected or opened mailbox. + * + * @note Returns 0 when fail to get UID. + */ + int getUID(int msgNum); + + /** Get message flags in selected or opened mailbox. + * + * @param msgNum The message number or order in the total message numbers. + * @return Message flags in selected or opened mailbox. + * + * @note Returns empty string when fail to get flags. + */ + const char *getFlags(int msgNum); + + /** Send the custom IMAP command and get the result via callback. + * + * @param cmd The command string. + * @param callback The callback function that accepts IMAP_Response as parameter. + * @param tag The tag string to pass to the callback function. + * @return The boolean value which indicates the success of operation. + * + * @note imap.connect and imap.selectFolder or imap.openFolder are needed to call once prior to call this function. + */ + template + bool sendCustomCommand(T1 cmd, imapResponseCallback callback, T2 tag = "") { return mSendCustomCommand(toStringPtr(cmd), callback, toStringPtr(tag)); } + + /** Send the custom IMAP command data string. + * + * @param data The string data. + * @param last The flag represents the last data to send (optional). + * @return The boolean value which indicates the success of operation. + * + * @note Should be used after calling sendCustomCommand("APPEND xxxxxx"); + */ + template + bool sendCustomData(T data, bool lastData = false) { return mSendData(toStringPtr(data), lastData, esp_mail_imap_cmd_custom); } + + /** Send the custom IMAP command data. + * + * @param data The byte data. + * @param size The data size. + * @param lastData The flag represents the last data to send (optional). + * @return The boolean value which indicates the success of operation. + * + * @note Should be used after calling ssendCustomCommand("APPEND xxxxxx"); + */ + bool sendCustomData(uint8_t *data, size_t size, bool lastData = false) { return mSendData(data, size, lastData, esp_mail_imap_cmd_custom); } + + /** Copy the messages to the defined mailbox folder. + * + * @param toCopy The pointer to the MessageList class that contains the + * list of messages to copy. + * @param dest The destination folder that the messages to copy to. + * @return The boolean value which indicates the success of operation. + */ + template + bool copyMessages(MessageList *toCopy, T dest) { return mCopyMessages(toCopy, toStringPtr(dest)); } + + /** Copy the messages to the defined mailbox folder. + * + * @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number. + * @param UID The option for sequenceSet whether it is UID or message sequence number. + * @param dest The destination folder that the messages to copy to. + * @return The boolean value indicates the success of operation. + */ + template + bool copyMessages(T1 sequenceSet, bool UID, T2 dest) { return mCopyMessagesSet(toStringPtr(sequenceSet), UID, toStringPtr(dest)); } + + /** Move the messages to the defined mailbox folder. + * + * @param toMove The pointer to the MessageList class that contains the + * list of messages to move. + * @param dest The destination folder that the messages to move to. + * @return The boolean value which indicates the success of operation. + */ + template + bool moveMessages(MessageList *toCopy, T dest) { return mMoveMessages(toCopy, toStringPtr(dest)); } + + /** Move the messages to the defined mailbox folder. + * + * @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number. + * @param UID The option for sequenceSet whether it is UID or message sequence number. + * @param dest The destination folder that the messages to move to. + * @return The boolean value indicates the success of operation. + */ + template + bool moveMessages(T1 sequenceSet, bool UID, T2 dest) { return mMoveMessagesSet(toStringPtr(sequenceSet), UID, toStringPtr(dest)); } + + /** Delete the messages in the opened mailbox folder. + * + * @param toDelete The pointer to the MessageList class that contains the + * list of messages to delete. + * @param expunge The boolean option to expunge all messages. + * @param modsequence The int32_t option for UNCHANGESINCE conditional test. + * @return The boolean value which indicates the success of operation. + * + * The modsequence value can be used only if IMAP server supports Conditional STORE extension + * and the selected mailbox supports modsequences. + */ + bool deleteMessages(MessageList *toDelete, bool expunge = false, int32_t modsequence = -1) { return mDeleteMessages(toDelete, expunge, modsequence); } + + /** Delete the messages in the opened mailbox folder. + * + * @param sequenceSet The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number. + * @param UID The option for sequenceSet whether it is UID or message sequence number. + * @param expunge The boolean option to expunge all messages. + * @param modsequence The int32_t option for UNCHANGESINCE conditional test. + * @return The boolean value which indicates the success of operation. + * + * The modsequence value can be used only if IMAP server supports Conditional STORE extension + * and the selected mailbox supports modsequences. + */ + template + bool deleteMessages(T sequenceSet, bool UID, bool expunge = false, int32_t modsequence = -1) { return mDeleteMessagesSet(toStringPtr(sequenceSet), UID, expunge, modsequence); } + + /** Get the quota root's resource usage and limits. + * + * @param quotaRoot The quota root to get. + * @param info The pointer to IMAP_Quota_Root_Info that contains quota root's resource name, usage and limit. + * @return The boolean value which indicates the success of operation. + */ + template + bool getQuota(T quotaRoot, IMAP_Quota_Root_Info *info) { return mGetSetQuota(toStringPtr(quotaRoot), info, true); } + + /** Set the quota root's resource usage and limits. + * + * @param quotaRoot The quota root to set. + * @param data The pointer to IMAP_Quota_Root_Info that contains quota root's resource name, usage and limit. + * @return The boolean value which indicates the success of operation. + */ + template + bool setQuota(T quotaRoot, IMAP_Quota_Root_Info *data) { return mGetSetQuota(toStringPtr(quotaRoot), data, false); } + + /** Get the list of quota roots for the named mailbox. + * + * @param mailbox The mailbox name. + * @param quotaRootsList The pointer to IMAP_Quota_Roots_List that contains the list of IMAP_Quota_Root_Info. + * @return The boolean value which indicates the success of operation. + */ + template + bool getQuotaRoot(T mailbox, IMAP_Quota_Roots_List *quotaRootsList) { return mGetQuotaRoots(toStringPtr(mailbox), quotaRootsList); } + + /** Get the ACLs for a mailbox. + * + * @param mailbox The mailbox name. + * @param aclList The pointer to the returning IMAP_Rights_List object. + * @return The boolean value which indicates the success of operation. + */ + template + bool getACL(T mailbox, IMAP_Rights_List *aclList) { return mManageACL(toStringPtr(mailbox), aclList, nullptr, toStringPtr(""), esp_mail_imap_cmd_get_acl); }; + + /** Get the ACLs for a mailbox. + * + * @param mailbox The mailbox name. + * @param acl The pointer to the acl IMAP_Rights_Info to set. + * @return The boolean value which indicates the success of operation. + */ + template + bool setACL(T mailbox, IMAP_Rights_Info *acl) { return mManageACL(toStringPtr(mailbox), nullptr, acl, toStringPtr(""), esp_mail_imap_cmd_set_acl); }; + + /** Delete the ACLs set for identifier on mailbox. + * + * @param mailbox The mailbox name. + * @param identifier The identifier (user) to remove the rights. + * @return The boolean value which indicates the success of operation. + */ + template + bool deleteACL(T1 mailbox, T2 identifier) { return mManageACL(toStringPtr(mailbox), nullptr, nullptr, toStringPtr(identifier), esp_mail_imap_cmd_delete_acl); }; + + /** Show my ACLs for a mailbox. + * + * @param mailbox The mailbox name. + * @param acl The pointer to the returning IMAP_Rights_Info object. + * @return The boolean value which indicates the success of operation. + */ + template + bool myRights(T mailbox, IMAP_Rights_Info *acl) { return mManageACL(toStringPtr(mailbox), nullptr, acl, toStringPtr(""), esp_mail_imap_cmd_my_rights); }; + + /** Returns IMAP namespaces. + * + * @param mailbox The mailbox name. + * @param ns The pointer to the returning IMAP_Namespaces_List object. + * @return The boolean value which indicates the success of operation. + */ + bool getNamespace(IMAP_Namespaces_List *ns) { return mNamespace(ns); }; + + /** Enable IMAP capability. + * + * @param capability The mailbox name. + * @return The boolean value which indicates the success of operation. + */ + template + bool enable(T capability) { return mEnable(toStringPtr(capability)); }; + + /** Listen for the selected or open mailbox for updates. + * @return The boolean value which indicates the success of operation. + */ + bool listen() { return mListen(false); }; + + /** Stop listen for the mailbox for updates. + * @return The boolean value which indicates the success of operation. + */ + bool stopListen() { return mStopListen(false); }; + + /** Check for the selected or open mailbox updates. + * @return The boolean value which indicates the changes status of mailbox. + */ + bool folderChanged(); + + /** Send NOOP command to IMAP server. + * @return The boolean value which indicates the success of operation. + */ + bool noop(); + + /** Assign the callback function that returns the operating status when + * fetching or reading the Email. + * + * @param imapCallback The function that accepts the imapStatusCallback as + * parameter. + */ + void callback(imapStatusCallback imapCallback); + + /** Assign the callback function to decode the string based on the character set. + * + * @param callback The function that accepts the pointer to IMAP_Decoding_Info as parameter. + */ + void characterDecodingCallback(imapCharacterDecodingCallback callback); + + /** Assign the callback function that returns the MIME data stream from + * fetching or reading the Email. + * + * @param mimeDataStreamCallback The function that accepts the MIME_Stream_Info as + * parameter. + */ + void mimeDataStreamCallback(MIMEDataStreamCallback mimeDataStreamCallback); + + /** Determine if no message body contained in the search result and only the + * message header is available. + */ + bool headerOnly(); + + /** Get the message list from search or fetch the Emails + * + * @return The IMAP_MSG_List structured data which contains text and html + * contents, + * attachments, inline images, embedded rfc822 messages details for each + * message. + */ + IMAP_MSG_List data(); + + /** Get the details of the selected or opned mailbox folder + * + * @return The SelectedFolderInfo class which contains the info about flags, + * total messages, next UID, + * search count and the available messages count. + */ + SelectedFolderInfo selectedFolder(); + + /** Get the error details when readingg the Emails + * + * @return The string of error details. + */ + String errorReason(); + + /** Get the operating status error code. + * + * @return The int value of operating status error code. + * + * The negative value indicated error. + * See src/ESP_Mail_Error.h and extras/MB_FS.h + */ + int errorCode(); + + /** Clear all the cache data stored in the IMAP session object. + */ + void empty(); + + /** Get the status of message fetching and searching. + * + * @return The IMAP_Status object contains the fetching and searching statuses. + */ + IMAP_Status status(); + + /** Get the JSON string of file name list of files that stored in SD card. + * + * @return The JSON string of filenames. + * @note This will available only when standard SD library was used and file storage is SD. + */ + String fileList(); + + /** Set the current timestamp. + * + * @param ts The current timestamp. + * @param gmtOffset The GMT offset. + */ + void setSystemTime(time_t ts, float gmtOffset = 0); + + /** Setup TCP KeepAlive for internal TCP client. + * + * @param tcpKeepIdleSeconds lwIP TCP Keepalive idle in seconds. + * @param tcpKeepIntervalSeconds lwIP TCP Keepalive interval in seconds. + * @param tcpKeepCount lwIP TCP Keepalive count. + * + * For the TCP (KeepAlive) options, see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/lwip.html#tcp-options. + * + * If value of one of these parameters is zero, the TCP KeepAlive will be disabled. + * + * You can check the server connecting status, by exexuting .connected() which will return true when connection to the server is still alive. + */ + void keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount); + + /** Get TCP KeepAlive status. + * + * @return Boolean status of TCP KeepAlive. + */ + bool isKeepAlive(); + + friend class ESP_Mail_Client; + friend class foldderList; + +private: + // Log in to IMAP server + bool mLogin(MB_StringPtr email, MB_StringPtr password, bool isToken); + + // Clear message data + void clearMessageData(); + + // Check for valid UID or set wildcard * as UID + void checkUID(); + + // Check for valid saving file path or prepend / + void checkPath(); + + // Get message item by index + void getMessages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg); + + // Get RFC822 message item by index + void getRFC822Messages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg); + + // Close mailbox + bool closeMailbox(bool expunge = false); + + // Open mailbox + bool openMailbox(MB_StringPtr folder, esp_mail_imap_auth_mode mode, bool waitResponse, bool unselect); + + // Get folders list + bool getMailboxes(FoldersCollection &folders); + + // Get subscribes mailboxes + bool mGetSubscribesMailboxes(MB_StringPtr reference, MB_StringPtr mailbox, FoldersCollection &folders); + + // Subscribe the mailbox + bool mSubscribe(MB_StringPtr folder); + + // Unsubscribe the mailbox + bool mUnSubscribe(MB_StringPtr folder); + + // Get UID + int mGetUID(int msgNum); + + // Fetch by sequence set + bool mFetchSequenceSet(); + + // Return string from TAG prepended command + MB_String prependTag(PGM_P cmd, PGM_P tag = NULL); + + // Check capabilities + bool checkCapabilities(); + + // Listen mailbox changes + bool mListen(bool recon); + + // Stop listen mailbox + bool mStopListen(bool recon); + + // Send custom command + bool mSendCustomCommand(MB_StringPtr cmd, imapResponseCallback callback, MB_StringPtr tag); + + // Send data after sending APPEND command + bool mSendData(MB_StringPtr data, bool lastData, esp_mail_imap_command cmd); + + // Send data after sending APPEND command + bool mSendData(uint8_t *data, size_t size, bool lastData, esp_mail_imap_command cmd); + + // Delete folder + bool mDeleteFolder(MB_StringPtr folderName); + + // Create folder + bool mCreateFolder(MB_StringPtr folderName); + + // Rename folder + bool mRenameFolder(MB_StringPtr currentFolderName, MB_StringPtr newFolderName); + + // Copy message + bool copyMsg(MessageList *toCopy, const char *sequenceSet, bool UID, MB_StringPtr dest); + + // Copy message + bool mCopyMessages(MessageList *toCopy, MB_StringPtr dest); + + // Copy message using sequence set + bool mCopyMessagesSet(MB_StringPtr sequenceSet, bool UID, MB_StringPtr dest); + + // Move message + bool moveMsg(MessageList *toMove, const char *sequenceSet, bool UID, MB_StringPtr dest); + + // Move message + bool mMoveMessages(MessageList *toMove, MB_StringPtr dest); + + // Move message using sequence set + bool mMoveMessagesSet(MB_StringPtr sequenceSet, bool UID, MB_StringPtr dest); + + // Check for conditional STORE extention support + bool isCondStoreSupported(); + + // Check for mailbox mod-sequence support + bool isModseqSupported(); + + // add UNCHANGEDSINCE STORE modifier and CHANGEDSINCE FETCH modifier to command + void addModifier(MB_String &cmd, esp_mail_imap_command_types type, int32_t modsequence); + + // Delete message + bool deleteMsg(MessageList *toDelete, const char *sequenceSet, bool UID, bool expunge, int32_t modsequence = -1); + + // Delete messages + bool mDeleteMessages(MessageList *toDelete, bool expunge = false, int32_t modsequence = -1); + + // Delete messages + bool mDeleteMessagesSet(MB_StringPtr sequenceSet, bool UID, bool expunge = false, int32_t modsequence = -1); + + // Get or set the quota root's resource usage and limits. + bool mGetSetQuota(MB_StringPtr quotaRoot, IMAP_Quota_Root_Info *data, bool getMode); + + // Parse the IMAP_Quota_Root_info + void mParseQuota(const char *quota, IMAP_Quota_Root_Info *data); + + // Get the list of quota roots for the named mailbox. + bool mGetQuotaRoots(MB_StringPtr mailbox, IMAP_Quota_Roots_List *quotaRootsList); + + // Get or set ACL. + bool mManageACL(MB_StringPtr mailbox, IMAP_Rights_List *acl_list, IMAP_Rights_Info *acl, MB_StringPtr identifier, esp_mail_imap_command type); + + // Parse ACL + void parseACL(MB_String &acl_str, IMAP_Rights_List *right_list); + + // parse Rights + void parseRights(MB_String &righs_str, IMAP_Rights_Info *info); + + // Get Rights from IMAP_Rights_Info + void getRights(MB_String &righs_str, IMAP_Rights_Info *info); + + // Get namespace + bool mNamespace(IMAP_Namespaces_List *ns); + + // Enable the IMAP capability + bool mEnable(MB_StringPtr capability); + + // Parse namespaces + void parseNamespaces(MB_String &ns_str, IMAP_Namespaces *ns); + + // Close folder + bool mCloseFolder(bool expunge = false); + + // Open folder + bool mOpenFolder(MB_StringPtr folderName, bool readOnly); + + // Select folder + bool mSelectFolder(MB_StringPtr folderName, bool readOnly); + + // Custom TCP connection + bool mCustomConnect(Session_Config *session_config, imapResponseCallback callback, MB_StringPtr tag); + + // Append ID list to buffer + void appendIdList(MB_String &list, IMAP_Identification *identification); + + // Handle connection + bool handleConnection(Session_Config *session_config, IMAP_Data *imap_data, bool &ssl); + + // Start TCP connection + bool connect(bool &ssl); + + // Print features not supported debug error message + void printDebugNotSupported(); + + bool _sessionSSL = false; + bool _sessionLogin = false; + bool _loginStatus = false; + unsigned long _last_polling_error_ms = 0; + unsigned long _last_host_check_ms = 0; + unsigned long _last_server_connect_ms = 0; + unsigned long _last_network_error_ms = 0; + unsigned long tcpTimeout = TCP_CLIENT_DEFAULT_TCP_TIMEOUT_SEC; + struct esp_mail_imap_response_status_t _responseStatus; + int _cMsgIdx = 0; + int _cPartIdx = 0; + int _totalRead = 0; + _vectorImpl _headers; + + esp_mail_imap_command _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_sasl_login; + esp_mail_imap_command _prev_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_sasl_login; + esp_mail_imap_command _imap_custom_cmd = esp_mail_imap_cmd_custom; + esp_mail_imap_command _prev_imap_custom_cmd = esp_mail_imap_cmd_custom; + bool _idle = false; + MB_String _cmd; + _vectorImpl _multipart_levels; + int _rfc822_part_count = 0; + bool _unseen = false; + bool _readOnlyMode = true; + bool _msgDownload = false; + bool _attDownload = false; + bool _storageReady = false; + bool _storageChecked = false; + + bool _auth_capability[esp_mail_auth_capability_maxType]; + bool _feature_capability[esp_mail_imap_read_capability_maxType]; + Session_Config *_session_cfg; + _vectorImpl _configPtrList; + MB_String _currentFolder; + bool _mailboxOpened = false; + unsigned long _lastSameFolderOpenMillis = 0; + MB_String _nextUID; + MB_String _unseenMsgIndex; + MB_String _flags_tmp; + MB_String _quota_tmp; + MB_String _quota_root_tmp; + MB_String _acl_tmp; + MB_String _ns_tmp; + MB_String _server_id_tmp; + MB_String _sdFileList; + + struct esp_mail_imap_data_config_t *_imap_data = nullptr; + + int _userHeaderOnly = -1; + bool _headerOnly = true; + bool _uidSearch = false; + bool _headerSaved = false; + bool _debug = false; + int _debugLevel = 0; + bool _secure = false; + bool _authenticated = false; + bool _isFirmwareUpdated = false; + imapStatusCallback _statusCallback = NULL; + imapResponseCallback _customCmdResCallback = NULL; + MIMEDataStreamCallback _mimeDataStreamCallback = NULL; + imapCharacterDecodingCallback _charDecCallback = NULL; + + _vectorImpl _imap_msg_num; + esp_mail_session_type _sessionType = esp_mail_session_type_imap; + + FoldersCollection _folders; + SelectedFolderInfo _mbif; + int _uid_tmp = 0; + int _lastProgress = -1; + + ESP_Mail_TCPClient client; + + IMAP_Status _cbData; +}; + +#endif + +#if defined(ENABLE_SMTP) + +class SendingResult +{ +private: + _vectorImpl _result; + + void add(SMTP_Result *r) + { + _result.push_back(*r); + } + +public: + friend class SMTPSession; + friend class ESP_Mail_Client; + SendingResult(){}; + ~SendingResult() { clear(); }; + + void clear() + { + for (size_t i = 0; i < _result.size(); i++) + { + _result[i].recipients.clear(); + _result[i].subject.clear(); + _result[i].timestamp = 0; + _result[i].completed = false; + } + _result.clear(); + } + + SMTP_Result getItem(size_t index) + { + SMTP_Result r; + if (index < _result.size()) + return _result[index]; + return r; + } + size_t size() { return _result.size(); }; +}; + +class SMTPSession +{ +public: + SMTPSession(Client *client); + SMTPSession(); + ~SMTPSession(); + + /** Set the tcp timeout. + * + * @param timeoutSec The tcp timeout in seconds. + */ + void setTCPTimeout(unsigned long timeoutSec); + + /** Assign custom Client from Arduino Clients. + * + * @param client The pointer to Arduino Client derived class e.g. WiFiClient, EthernetClient or GSMClient. + */ + void setClient(Client *client); + + /** Assign TinyGsm Clients. + * + * @param client The pointer to TinyGsmClient. + * @param modem The pointer to TinyGsm modem object. Modem should be initialized and/or set mode before transfering data. + * @param pin The SIM pin. + * @param apn The GPRS APN (Access Point Name). + * @param user The GPRS user. + * @param password The GPRS password. + */ + void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password); + + /** Assign the callback function to handle the network connection for custom Client. + * + * @param networkConnectionCB The function that handles the network connection. + */ + void networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB); + + /** Assign the callback function to handle the network connection status acknowledgement. + * + * @param networkStatusCB The function that handle the network connection status acknowledgement. + */ + void networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB); + + /** Set the network status acknowledgement. + * + * @param status The network status. + */ + void setNetworkStatus(bool status); + + /** Set the BearSSL IO buffer size. + * + * @param rx The BearSSL receive buffer size in bytes. + * @param tx The BearSSL trasmit buffer size in bytes. + */ + void setSSLBufferSize(int rx = -1, int tx = -1); + + /** Begin the SMTP server connection. + * + * @param session_config The pointer to Session_Config structured data that keeps + * the server and log in details. + * @param login The bool option for login after server connection. + * @return The boolean value indicates the success of operation. + */ + bool connect(Session_Config *session_config, bool login = true); + + /** Log in to SMTP server using Email and password. + * + * @param email The SMTP server account email. + * @param password The SMTP server account password. + * @return The boolean value which indicates the success of operation. + */ + template + bool loginWithPassword(T1 email, T2 password) { return mLogin(toStringPtr(email), toStringPtr(password), false); }; + + /** Log in to SMTP server using Email and access token. + * + * @param email The SMTP server account email. + * @param token The Access token to log in. + * @return The boolean value which indicates the success of operation. + */ + template + bool loginWithAccessToken(T1 email, T2 token) { return mLogin(toStringPtr(email), toStringPtr(token), true); }; + + /** Return the SASL authentication status. + * @return The boolean value indicates SASL authentication status. + */ + bool isAuthenticated(); + + /** Return the log status. + * @return The boolean value indicates log in status. + */ + bool isLoggedIn(); + + /** Begin the SMTP server connection without authentication. + * + * @param session_config The pointer to Session_Config structured data that keeps + * the server and log in details. + * @param callback The callback function that accepts the SMTP_Response as parameter. + * @param commandID The command identifier number that will pass to the callback. + * @return The int value of status code. + * + * @note If commandID was not set or set to -1, the command identifier will be auto increased started from zero. + */ + int customConnect(Session_Config *session_config, smtpResponseCallback callback, int commandID = -1); + + /** Close the SMTP session. + * + */ + bool closeSession(); + + /** Get TCP connection status. + * + * @return The boolean value indicates the connection status. + */ + bool connected(); + + /** Send the custom SMTP command and get the result via callback. + * + * @param cmd The command string. + * @param callback The function that accepts the SMTP_Response as parameter. + * @param commandID The command identifier number that will pass to the callback. + * @return The integer value of response code. + * + * @note smtp.connect or smtp.customConnect is needed to call once prior to call this function. + * + * If commandID was not set or set to -1, the command identifier will be auto increased started from zero. + */ + template + int sendCustomCommand(T cmd, smtpResponseCallback callback, int commandID = -1) { return mSendCustomCommand(toStringPtr(cmd), callback, commandID); } + + /** Send the custom SMTP command data string. + * + * @param data The string data. + * @return The boolean value which indicates the success of operation. + * + * @note Should be used after calling sendCustomCommand("DATA"); + */ + template + bool sendCustomData(T data) { return mSendData(toStringPtr(data)); } + + /** Send the custom SMTP command data. + * + * @param data The byte data. + * @param size The data size. + * @return The boolean value which indicates the success of operation. + * + * @note Should be used after calling sendCustomCommand("DATA"); + */ + bool sendCustomData(uint8_t *data, size_t size) { return mSendData(data, size); } + + /** Set to enable the debug. + * + * @param level The level to enable the debug message + * level = 0, no debugging + * level = 1, basic level debugging + */ + void debug(int level); + + /** Get the error details when sending the Email + * + * @return The string of error details. + */ + String errorReason(); + + /** Get the SMTP server response status code. + * + * @return The int value of SMTP server response status code. + * + * See RFC 5321 standard's documentation. + */ + int statusCode(); + + /** Get the SMTP server response status message. + * + * @return The int value of SMTP server response status message. + * + */ + String statusMessage(); + + /** Get the operating status error code. + * + * @return The int value of operating status error code. + * + * The negative value indicated error. + * See src/ESP_Mail_Error.h and extras/MB_FS.h + */ + int errorCode(); + + /** Set the Email sending status callback function. + * + * @param smtpCallback The callback function that accept the + * smtpStatusCallback param. + */ + void callback(smtpStatusCallback smtpCallback); + + /** Get the status of message fetching and searching. + * + * @return The SMTP_Status object contains the sending status. + */ + SMTP_Status status(); + + /** Set the current timestamp. + * + * @param ts The current timestamp. + * @param gmtOffset The GMT offset. + */ + void setSystemTime(time_t ts, float gmtOffset = 0); + + /** Setup TCP KeepAlive for internal TCP client. + * + * @param tcpKeepIdleSeconds lwIP TCP Keepalive idle in seconds. + * @param tcpKeepIntervalSeconds lwIP TCP Keepalive interval in seconds. + * @param tcpKeepCount lwIP TCP Keepalive count. + * + * For the TCP (KeepAlive) options, see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/lwip.html#tcp-options. + * + * If value of one of these parameters is zero, the TCP KeepAlive will be disabled. + * + * You can check the server connecting status, by exexuting .connected() which will return true when connection to the server is still alive. + */ + void keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount); + + /** Get TCP KeepAlive status. + * + * @return Boolean status of TCP KeepAlive. + */ + bool isKeepAlive(); + + SendingResult sendingResult; + + friend class ESP_Mail_Client; + +private: + bool _sessionSSL = false; + bool _sessionLogin = false; + struct esp_mail_smtp_response_status_t _responseStatus; + int _sentSuccessCount = 0; + int _sentFailedCount = 0; + bool _chunkedEnable = false; + int _chunkCount = 0; + uint32_t ts = 0; + unsigned long tcpTimeout = TCP_CLIENT_DEFAULT_TCP_TIMEOUT_SEC; + + esp_mail_smtp_command _smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_greeting; + + bool _auth_capability[esp_mail_auth_capability_maxType]; + bool _feature_capability[esp_mail_smtp_send_capability_maxType]; + + Session_Config *_session_cfg = NULL; + _vectorImpl _configPtrList; + + bool _debug = false; + int _debugLevel = 0; + bool _secure = false; + bool _authenticated = false; + bool _loginStatus = false; + bool _waitForAuthenticate = false; + bool _canForward = false; + smtpStatusCallback _statusCallback = NULL; + smtpResponseCallback _customCmdResCallback = NULL; + int _commandID = -1; + bool _sdStorageReady = false; + bool _flashStorageReady = false; + bool _sdStorageChecked = false; + bool _flashStorageChecked = false; + + esp_mail_session_type _sessionType = esp_mail_session_type_smtp; + SMTP_Status _cbData; + struct esp_mail_smtp_msg_type_t _msgType; + int _lastProgress = -1; + + ESP_Mail_TCPClient client; + + // Start TCP connection + bool connect(bool &ssl); + + // Log in to SMTP server + bool mLogin(MB_StringPtr email, MB_StringPtr password, bool isToken); + + // Handle TCP connection + bool handleConnection(Session_Config *session_config, bool &ssl); + + // Send custom command + int mSendCustomCommand(MB_StringPtr cmd, smtpResponseCallback callback, int commandID = -1); + + // Send data after sending DATA command + bool mSendData(MB_StringPtr data); + + // Send data after sending DATA command + bool mSendData(uint8_t *data, size_t size); +}; + +#endif + +#if defined(ENABLE_SMTP) && defined(ENABLE_IMAP) + +class ESP_Mail_Message : public SMTP_Message +{ +public: + ESP_Mail_Message(){}; + ~ESP_Mail_Message(){}; +}; + +#endif + +extern ESP_Mail_Client MailClient; + +#endif /* ESP_MAIL_CLIENT_H */ diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client_Version.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client_Version.h new file mode 100644 index 000000000..21cd038f6 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Client_Version.h @@ -0,0 +1,12 @@ + +#pragma once + +#ifndef ESP_MAIL_VERSION + +#define ESP_MAIL_VERSION "3.4.9" +#define ESP_MAIL_VERSION_NUM 30409 + +/* The inconsistent file version checking to prevent mixed versions compilation. */ +#define VALID_VERSION_CHECK(ver) (ver == ESP_MAIL_VERSION_NUM) + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Const.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Const.h new file mode 100644 index 000000000..195ab0b11 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Const.h @@ -0,0 +1,3492 @@ +// Created August 20, 2023 + +#pragma once + +#ifndef ESP_MAIL_CONST_H +#define ESP_MAIL_CONST_H + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +#include +#include "ESP_Mail_FS.h" +#include "ESP_Mail_Error.h" +#include "extras/MB_FS.h" +#include "extras/RFC2047.h" +#include +#include + +#if defined(ESP_MAIL_DEBUG_PORT) +#define ESP_MAIL_DEFAULT_DEBUG_PORT ESP_MAIL_DEBUG_PORT +#else +#define ESP_MAIL_DEFAULT_DEBUG_PORT Serial +#endif + +#include +#include + +#define _vectorImpl std::vector +#define MB_VECTOR std::vector + +#if !defined(FPSTR) +#define FPSTR +#endif + +#include "extras/Networks_Provider.h" +#include "extras/ESP8266_Supports.h" + +#if defined(ESP8266) +#if __has_include() +#include +#endif +#endif + +#if defined(ENABLE_IMAP) && (defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO)) +#if defined(ESP32) +#include +#elif defined(ESP8266) || defined(MB_ARDUINO_PICO) +#include +#endif +#define ESP_MAIL_OTA_UPDATE_ENABLED +#endif + +#if !defined(SILENT_MODE) && (defined(ENABLE_SMTP) || defined(ENABLE_IMAP)) +#define SESSION_DEBUG_ENABLED +#endif + +#define TCP_CLIENT_DEFAULT_TCP_TIMEOUT_SEC 30 + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + +#define MAX_EMAIL_SEARCH_LIMIT 1000 +#define BASE64_CHUNKED_LEN 76 +#define FLOWED_TEXT_LEN 78 +#define QP_ENC_MSG_LEN 76 +#define ESP_MAIL_NETWORK_RECONNECT_TIMEOUT 10000 +#define ESP_MAIL_PROGRESS_REPORT_STEP 5 +#define ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED 0 +#define ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE 256 +#define ESP_MAIL_CLIENT_RESPONSE_BUFFER_SIZE 1024 // should be 1 k or more to prevent buffer overflow +#define ESP_MAIL_CLIENT_VALID_TS 1577836800 + +#endif + +typedef enum +{ + esp_mail_cert_type_undefined = -1, + esp_mail_cert_type_none = 0, + esp_mail_cert_type_data, + esp_mail_cert_type_file, + esp_mail_cert_type_bundle + +} esp_mail_cert_type; + +typedef enum +{ + esp_mail_client_type_undefined, + esp_mail_client_type_internal_basic_client, + esp_mail_client_type_external_basic_client, + esp_mail_client_type_external_gsm_client + +} esp_mail_client_type; + +/* The filesystem types enum */ +enum esp_mail_file_storage_type +{ + esp_mail_file_storage_type_none, + esp_mail_file_storage_type_flash, + esp_mail_file_storage_type_sd +}; + +/* The session types enum */ +enum esp_mail_session_type +{ + esp_mail_session_type_smtp, + esp_mail_session_type_imap +}; + +/* The secure connection mode preference */ +typedef enum +{ + // No preferences + esp_mail_secure_mode_undefined = 0, + // Always use SSL and TLS via STARTTLS rfc2595 section 3 and rfc3207 + esp_mail_secure_mode_ssl_tls, + // Plain text mode only (non SSL/TLS) + // To disable SSL/TLS permanently, define ESP_MAIL_DISABLE_SSL in ESP_Mail_FS.h + esp_mail_secure_mode_nonsecure + +} esp_mail_secure_mode; + +using namespace mb_string; + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + +typedef void (*NetworkConnectionHandler)(void); + +/* The file types enum */ +enum esp_mail_file_extension +{ + /** The arrangement is related to mimeinfo struct. + * Do not modify or remove. + */ + esp_mail_file_extension_html, + esp_mail_file_extension_htm, + esp_mail_file_extension_css, + esp_mail_file_extension_txt, + esp_mail_file_extension_js, + esp_mail_file_extension_json, + esp_mail_file_extension_png, + esp_mail_file_extension_gif, + esp_mail_file_extension_jpg, + esp_mail_file_extension_ico, + esp_mail_file_extension_svg, + esp_mail_file_extension_ttf, + esp_mail_file_extension_otf, + esp_mail_file_extension_woff, + esp_mail_file_extension_woff2, + esp_mail_file_extension_eot, + esp_mail_file_extension_sfnt, + esp_mail_file_extension_xml, + esp_mail_file_extension_pdf, + esp_mail_file_extension_zip, + esp_mail_file_extension_gz, + esp_mail_file_extension_appcache, + esp_mail_file_extension_dat, + esp_mail_file_extension_binary, + esp_mail_file_extension_maxType +}; + +struct esp_mail_mime_prop_t +{ + char endsWith[10]; + char mimeType[30]; +}; + +const struct esp_mail_mime_prop_t mimeinfo[esp_mail_file_extension_maxType] PROGMEM = { + /** The arrangement is related to esp_mail_file_extension enum. + * Do not modify or remove. + */ + {".html", "text/html"}, + {".htm", "text/html"}, + {".css", "text/css"}, + {".txt", "text/plain"}, + {".js", "application/javascript"}, + {".json", "application/json"}, + {".png", "image/png"}, + {".gif", "image/gif"}, + {".jpg", "image/jpeg"}, + {".ico", "image/x-icon"}, + {".svg", "image/svg+xml"}, + {".ttf", "application/x-font-ttf"}, + {".otf", "application/x-font-opentype"}, + {".woff", "application/font-woff"}, + {".woff2", "application/font-woff2"}, + {".eot", "application/vnd.ms-fontobject"}, + {".sfnt", "application/font-sfnt"}, + {".xml", "text/xml"}, + {".pdf", "application/pdf"}, + {".zip", "application/zip"}, + {".gz", "application/x-gzip"}, + {".appcache", "text/cache-manifest"}, + {".dat", "application/dat"}, + {"", "application/octet-stream"}}; + +#if defined(ENABLE_SMTP) + +/* The SMTP commands types enum */ +enum esp_mail_smtp_command_types +{ + /** The SMTP commands per stansards. + * The arrangement is related to smtp_commands struct. + * Do not modify or remove. + */ + esp_mail_smtp_command_auth, + esp_mail_smtp_command_login, + esp_mail_smtp_command_helo, + esp_mail_smtp_command_ehlo, + esp_mail_smtp_command_quit, + esp_mail_smtp_command_mail, + esp_mail_smtp_command_rcpt, + esp_mail_smtp_command_data, + esp_mail_smtp_command_bdat, + esp_mail_smtp_command_last, + esp_mail_smtp_command_plain, + esp_mail_smtp_command_from, + esp_mail_smtp_command_to, + esp_mail_smtp_command_notify, + esp_mail_smtp_command_success, + esp_mail_smtp_command_failure, + esp_mail_smtp_command_delay, + esp_mail_smtp_command_body, + esp_mail_smtp_command_terminate, + esp_mail_smtp_command_starttls, + esp_mail_smtp_command_maxType +}; + +/* The SMTP server capability types enum (except for SASL) */ +enum esp_mail_smtp_send_capability_types +{ + /** The server capability keywords per standard. + * The arrangement is related to smtp_send_capabilities struct. + * Do not modify or remove. + */ + esp_mail_smtp_send_capability_binary_mime, + esp_mail_smtp_send_capability_8bit_mime, + esp_mail_smtp_send_capability_chunking, + esp_mail_smtp_send_capability_utf8, + esp_mail_smtp_send_capability_pipelining, + esp_mail_smtp_send_capability_dsn, + esp_mail_smtp_send_capability_esmtp, + esp_mail_smtp_send_capability_maxType +}; + +#endif + +#if defined(ENABLE_IMAP) + +/* The IMAP server response types enum */ +enum esp_mail_imap_response_types +{ + /** The IMAP response. + * The arrangement is related to imap_responses struct. + * Do not modify or remove. + */ + esp_mail_imap_response_ok, + esp_mail_imap_response_no, + esp_mail_imap_response_bad, + esp_mail_imap_response_list, + esp_mail_imap_response_flags, + esp_mail_imap_response_search, + esp_mail_imap_response_fetch, + esp_mail_imap_response_nil, + esp_mail_imap_response_uid, + esp_mail_imap_response_capability_untagged, + esp_mail_imap_response_capability, + esp_mail_imap_response_lsub, + esp_mail_imap_response_quota, + esp_mail_imap_response_quotaroot, + esp_mail_imap_response_acl, + esp_mail_imap_response_myrights, + esp_mail_imap_response_namespace, + esp_mail_imap_response_untagged, + esp_mail_imap_response_exists, + esp_mail_imap_response_expunge, + esp_mail_imap_response_recent, + esp_mail_imap_response_uidnext, + esp_mail_imap_response_unseen, + esp_mail_imap_response_id, + esp_mail_imap_response_highest_modsec, + esp_mail_imap_response_nomodsec, + esp_mail_imap_response_permanent_flags, + esp_mail_imap_response_uidvalidity, + esp_mail_imap_response_maxType +}; + +/* The IMAP commands types enum */ +enum esp_mail_imap_command_types +{ + /** The IMAP commands per standards. + * The arrangement is related to imap_commands struct. + * Do not modify or remove. + */ + esp_mail_imap_command_starttls, + esp_mail_imap_command_append, + esp_mail_imap_command_capability, + esp_mail_imap_command_authenticate, + esp_mail_imap_command_plain, + esp_mail_imap_command_uid, + esp_mail_imap_command_fetch, + esp_mail_imap_command_flags, + esp_mail_imap_command_login, + esp_mail_imap_command_list, + esp_mail_imap_command_examine, + esp_mail_imap_command_search, + esp_mail_imap_command_logout, + esp_mail_imap_command_body, + esp_mail_imap_command_mime, + esp_mail_imap_command_close, + esp_mail_imap_command_exists, + esp_mail_imap_command_peek, + esp_mail_imap_command_text, + esp_mail_imap_command_fields, + esp_mail_imap_command_header, + esp_mail_imap_command_new, + esp_mail_imap_command_all, + esp_mail_imap_command_select, + esp_mail_imap_command_expunge, + esp_mail_imap_command_create, + esp_mail_imap_command_delete, + esp_mail_imap_command_idle, + esp_mail_imap_command_done, + esp_mail_imap_command_recent, + esp_mail_imap_command_unseen, + esp_mail_imap_command_rename, + esp_mail_imap_command_lsub, + esp_mail_imap_command_subscribe, + esp_mail_imap_command_unsubscribe, + esp_mail_imap_command_silent, + esp_mail_imap_command_move, + esp_mail_imap_command_getquota, + esp_mail_imap_command_setquota, + esp_mail_imap_command_root, + esp_mail_imap_command_get_acl, + esp_mail_imap_command_set_acl, + esp_mail_imap_command_delete_acl, + esp_mail_imap_command_myrights, + esp_mail_imap_command_namespace, + esp_mail_imap_command_enable, + esp_mail_imap_command_xoauth2, + esp_mail_imap_command_store, + esp_mail_imap_command_plus_flags, + esp_mail_imap_command_minus_flags, + esp_mail_imap_command_copy, + esp_mail_imap_command_id, + esp_mail_imap_command_unselect, + esp_mail_imap_command_condstore, + esp_mail_imap_command_noop, + esp_mail_imap_command_unchangedsince, + esp_mail_imap_command_changedsince, + esp_mail_imap_command_modsec, + esp_mail_imap_command_maxType +}; + +/* The IMAP server capability types enum (except for SASL) */ +enum esp_mail_imap_read_capability_types +{ + /** The server capability keywords per standard. + * The arrangement is related imap_read_capabilities struct. + * Do not modify or remove. + */ + + esp_mail_imap_read_capability_imap4, + esp_mail_imap_read_capability_imap4rev1, + // rfc2177 + esp_mail_imap_read_capability_idle, + esp_mail_imap_read_capability_literal_plus, + esp_mail_imap_read_capability_literal_minus, + esp_mail_imap_read_capability_multiappend, + esp_mail_imap_read_capability_uidplus, + // rfc4314 + esp_mail_imap_read_capability_acl, + esp_mail_imap_read_capability_binary, + esp_mail_imap_read_capability_logindisable, + // rfc6851 + esp_mail_imap_read_capability_move, + // rfc2087 + esp_mail_imap_read_capability_quota, + // rfc2342 + esp_mail_imap_read_capability_namespace, + // rfc5161 + esp_mail_imap_read_capability_enable, + // rfc2971 + esp_mail_imap_read_capability_id, + esp_mail_imap_read_capability_unselect, + esp_mail_imap_read_capability_children, + // rfc7162 (rfc4551 obsoleted) + esp_mail_imap_read_capability_condstore, + esp_mail_imap_read_capability_auto_caps, + esp_mail_imap_read_capability_maxType +}; + +/* The Identification keys enum used for IMAP ID command */ +enum esp_mail_imap_identification_keys +{ + /** The identification keys per standard. + * The arrangement is related imap_identification_keys struct. + * Do not modify or remove. + */ + + esp_mail_imap_identification_key_name, + esp_mail_imap_identification_key_version, + esp_mail_imap_identification_key_os, + esp_mail_imap_identification_key_os_version, + esp_mail_imap_identification_key_vendor, + esp_mail_imap_identification_key_support_url, + esp_mail_imap_identification_key_address, + esp_mail_imap_identification_key_date, + esp_mail_imap_identification_key_command, + esp_mail_imap_identification_key_arguments, + esp_mail_imap_identification_key_environment, + esp_mail_imap_identification_key_maxType +}; + +#endif + +/* The character encoding types enum used for decoding */ +enum esp_mail_char_decoding_types +{ + /** Supported charactor encodings. + * The arrangement is related to char_decodings struct. + * Do not modify or remove. + */ + esp_mail_char_decoding_utf8, + esp_mail_char_decoding_iso_8859_1, + esp_mail_char_decoding_iso_8859_11, + esp_mail_char_decoding_tis_620, + esp_mail_char_decoding_windows_874, + esp_mail_char_decoding_maxType +}; + +/* The MIME multipart message types */ +enum esp_mail_multipart_types +{ + /** MultiPart MIME. + * The arrangement is related to multipart_types struct. + * Do not modify or remove. + */ + esp_mail_multipart_type_mixed, + esp_mail_multipart_type_related, + esp_mail_multipart_type_parallel, + esp_mail_multipart_type_alternative, + esp_mail_multipart_maxType +}; + +/* The rfc822 message header fileds types enum */ +enum esp_mail_rfc822_header_field_types +{ + /** The rfc822 message header fields. + * The arrangement is related to rfc822_headers struct. + * Do not modify or remove. + */ + esp_mail_rfc822_header_field_from, + esp_mail_rfc822_header_field_sender, + esp_mail_rfc822_header_field_to, + esp_mail_rfc822_header_field_cc, + esp_mail_rfc822_header_field_subject, + esp_mail_rfc822_header_field_date, + esp_mail_rfc822_header_field_msg_id, + esp_mail_rfc822_header_field_return_path, + esp_mail_rfc822_header_field_reply_to, + esp_mail_rfc822_header_field_in_reply_to, + esp_mail_rfc822_header_field_references, + esp_mail_rfc822_header_field_comments, + esp_mail_rfc822_header_field_keywords, + esp_mail_rfc822_header_field_bcc, + esp_mail_rfc822_header_field_flags, + esp_mail_rfc822_header_field_maxType +}; + +/* The message header fileds types enum and its subproperties enum */ +enum esp_mail_message_header_field_types +{ + /** Additional fields and props. + * Some are used for the library information data field name. + * The arrangement is related to message_headers struct. + * Do not modify or remove. + */ + esp_mail_message_header_field_number, + esp_mail_message_header_field_uid, + esp_mail_message_header_field_accept_language, + esp_mail_message_header_field_content_language, + esp_mail_message_header_field_filename, + esp_mail_message_header_field_name, + esp_mail_message_header_field_size, + esp_mail_message_header_field_mime, + esp_mail_message_header_field_type, + esp_mail_message_header_field_description, + esp_mail_message_header_field_creation_date, + esp_mail_message_header_field_x_priority, + esp_mail_message_header_field_x_msmail_priority, + esp_mail_message_header_field_importance, + esp_mail_message_header_field_content_type, + esp_mail_message_header_field_content_transfer_encoding, + esp_mail_message_header_field_content_disposition, + esp_mail_message_header_field_content_location, + esp_mail_message_header_field_content_id, + esp_mail_message_header_field_content_description, + esp_mail_message_header_field_mime_version, + esp_mail_message_header_field_charset, + esp_mail_message_header_field_format, + esp_mail_message_header_field_delsp, + esp_mail_message_header_field_modification_date, + esp_mail_message_header_field_maxType +}; + +/* The auth capability types enum which shared usage between SMTP and IMAP */ +enum esp_mail_auth_capability_types +{ + /** The server capability keywords per standard. + * The arrangement is related to smtp_auth_capabilities and imap_auth_capabilities structs. + * Do not modify or remove. + */ + + esp_mail_auth_capability_plain, + esp_mail_auth_capability_xoauth2, + esp_mail_auth_capability_cram_md5, + esp_mail_auth_capability_digest_md5, + esp_mail_auth_capability_login, + esp_mail_auth_capability_starttls, + // imap rfc4959 + esp_mail_auth_capability_sasl_ir, + + esp_mail_auth_capability_maxType, +}; + +/* The smessage types enum */ +enum esp_mail_message_type +{ + esp_mail_msg_type_none = 0, + esp_mail_msg_type_plain = 1, + esp_mail_msg_type_html = 2, + esp_mail_msg_type_enriched = 1 +}; + +/* The string mark types enum used in joinStringx functions */ +enum esp_mail_string_mark_type +{ + esp_mail_string_mark_type_none, + esp_mail_string_mark_type_double_quote, + esp_mail_string_mark_type_angle_bracket, + esp_mail_string_mark_type_round_bracket, + esp_mail_string_mark_type_curly_bracket, + esp_mail_string_mark_type_square_bracket +}; + +/* The debug TAG types enum */ +enum esp_mail_debug_tag_type +{ + esp_mail_debug_tag_type_client, + esp_mail_debug_tag_type_server, + esp_mail_debug_tag_type_error, + esp_mail_debug_tag_type_info, + esp_mail_debug_tag_type_warning +}; + +/* The embed attachment types enum */ +enum esp_mail_smtp_embed_message_type +{ + esp_mail_smtp_embed_message_type_attachment = 0, + esp_mail_smtp_embed_message_type_inline +}; + +/* The attachment types enum */ +enum esp_mail_attach_type +{ + esp_mail_att_type_none, + esp_mail_att_type_attachment, + esp_mail_att_type_inline +}; + +/* The debug levels for printing the debug information via Serial port */ +enum esp_mail_debug_level +{ + esp_mail_debug_level_none = 0, + esp_mail_debug_level_basic, + esp_mail_debug_level_maintainer = 0xfff, + esp_mail_debug_level_developer = esp_mail_debug_level_maintainer + 1 +}; + +/* The content transfer encoding enum */ +enum esp_mail_msg_xencoding +{ + esp_mail_msg_xencoding_none, + /* rfc2045 section 2.7 */ + esp_mail_msg_xencoding_7bit, + esp_mail_msg_xencoding_qp, + esp_mail_msg_xencoding_base64, + /* rfc2045 section 2.8 */ + esp_mail_msg_xencoding_8bit, + /* rfc2045 section 2.9 */ + esp_mail_msg_xencoding_binary +}; + +/* The port protocols enum */ +enum esp_mail_protocol +{ + esp_mail_protocol_plain_text, + esp_mail_protocol_ssl, + esp_mail_protocol_tls +}; + +/* The internal use strct */ +struct esp_mail_internal_use_t +{ + esp_mail_msg_xencoding xencoding = esp_mail_msg_xencoding_none; + MB_String cid; +}; + +/* The struct contains port number and its protocol */ +struct port_function +{ + uint16_t port; + esp_mail_protocol protocol; +}; + +/* The struct that contains the list of port_function and its size */ +struct esp_mail_ports_functions +{ + friend class IMAPSession; + friend class SMTPSession; + friend class esp_mail_session_config_t; + + uint16_t size = 0; + port_function *list = nullptr; + bool use_internal_list = false; +}; + +/* The content transfer encoding type struct */ +struct esp_mail_transfer_encoding_t +{ + /* The default 7-bit transfer encoding for US-ACII characters*/ + static constexpr const char *enc_7bit = "7bit"; + + /* The quoted printable transfer encoding for non-US-ASCII characters*/ + static constexpr const char *enc_qp = "quoted-printable"; + + /* The base64 encoded transfer encoding */ + static constexpr const char *enc_base64 = "base64"; + + /* The 8-bit transfer encoding for extended-US-ASCII characters*/ + static constexpr const char *enc_8bit = "8bit"; + + /* The binary transfer encoding for extended-US-ASCII characters with no line + * length limit*/ + static constexpr const char *enc_binary = "binary"; +}; + +/* The content disposition types strucr (rfc 2183) */ +struct esp_mail_content_disposition_type_t +{ + /** if it is intended to be displayed automatically + * upon display of the message. + */ + static constexpr const char *inline_ = "inline"; + + /** to indicate that they are separate from the main body + * of the mail message, and that their display should not + * be automatic, but contingent upon some further action of the user. + */ + static constexpr const char *attachment = "attachment"; +}; + +/* The file (SD/flash) message content struct used for providing SMTP message content from file */ +struct esp_mail_file_message_content_t +{ + /* The file path include its name */ + MB_String name; + + /** The type of file storages e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + esp_mail_file_storage_type type = esp_mail_file_storage_type_flash; +}; + +/* The blob or flash string message content struct used for providing SMTP message content from blob or flash string */ +struct esp_mail_blob_message_content_t +{ + /* The array of content in flash memory */ + const uint8_t *data = nullptr; + + /* The array size in bytes */ + size_t size = 0; +}; + +/* The option to embed this message content as a file */ +struct esp_mail_smtp_embed_message_body_t +{ + /* Enable to send this message body as file */ + bool enable = false; + + /* The name of embedded file */ + MB_String filename; + + /** The embedded type + * esp_mail_smtp_embed_message_type_attachment or 0 + * esp_mail_smtp_embed_message_type_inline or 1 + */ + esp_mail_smtp_embed_message_type type = esp_mail_smtp_embed_message_type_attachment; +}; + +/** This is the base struct for SMTP message. + * This is for input and later used as esp_mail_plain_body_t + * and esp_mail_html_body_t. + * Its members are similar to esp_mail_imap_plain_body_t + * and esp_mail_imap_html_body_t unless it contains + * MB_String object to hold the string. + */ +struct esp_mail_message_body_t +{ + /* The option to embed this message content as a file */ + struct esp_mail_smtp_embed_message_body_t embed; + + /* The PLAIN/HTML content of the message */ + MB_String content; + + const char *nonCopyContent = ""; + + /* The blob that contins PLAIN/HTML content of the message */ + struct esp_mail_blob_message_content_t blob; + + /* The file that contins PLAIN/HTML content of the message */ + struct esp_mail_file_message_content_t file; + + /* The charset of the PLAIN/HTML content of the message */ + MB_String charSet = "UTF-8"; + + /* The content type of message */ + MB_String content_type = mimeinfo[esp_mail_file_extension_txt].mimeType; + + /* The option to encode the content for data transfer */ + MB_String transfer_encoding = "7bit"; + + /* The option to send the PLAIN text with wrapping */ + bool flowed = false; + + /* The internal usage data */ + struct esp_mail_internal_use_t _int; +}; + +/** The PLAIN text body details of the fetching message. + * This is for output and its members are similar to + * esp_mail_message_body_t unless there is no string object + * to hold string data unless the pointer to the const strings + * in IMAPSession object. + */ +struct esp_mail_imap_plain_body_t +{ + /* The option to embed this message content as a file */ + struct esp_mail_smtp_embed_message_body_t embed; + + /* The PLAIN text content of the message */ + const char *content = ""; + + /* The blob that contins PLAIN text content of the message */ + struct esp_mail_blob_message_content_t blob; + + /* The file that contins PLAIN text content of the message */ + struct esp_mail_file_message_content_t file; + + /* The charset of the PLAIN text content of the message */ + const char *charSet = "UTF-8"; + + /* The content type of message */ + const char *content_type = mimeinfo[esp_mail_file_extension_txt].mimeType; + + /* The option to encode the content for data transfer */ + const char *transfer_encoding = "7bit"; + + /* The option to send the PLAIN text with wrapping */ + bool flowed = false; + + /* The internal usage data */ + struct esp_mail_internal_use_t _int; +}; + +/** The HTML body details of the fetching message. + * This is for output and its members are similar to + * esp_mail_message_body_t unless there is no string object + * to hold string data unless the pointer to the const strings + * in IMAPSession object. + */ +struct esp_mail_imap_html_body_t +{ + /* The option to embedded the content as a file */ + struct esp_mail_smtp_embed_message_body_t embed; + + /* The HTML content of the message */ + const char *content = ""; + + /* The blob that contins HTML content of the message */ + struct esp_mail_blob_message_content_t blob; + + /* The file that contins HTML content of the message */ + struct esp_mail_file_message_content_t file; + + /* The charset of the HTML content of the message */ + const char *charSet = "UTF-8"; + + /* The content type of message */ + const char *content_type = mimeinfo[esp_mail_file_extension_html].mimeType; + + /* The option to encode the content for data transfer */ + const char *transfer_encoding = "7bit"; + + /* The internal usage data */ + struct esp_mail_internal_use_t _int; +}; + +/* The PLAIN text body details of the message */ +typedef struct esp_mail_message_body_t esp_mail_plain_body_t; + +/* The HTML text body details of the message */ +typedef struct esp_mail_message_body_t esp_mail_html_body_t; + +/* The attachment info struct used for output */ +struct esp_mail_attachment_info_t +{ + const char *filename = ""; + const char *name = ""; + const char *creationDate = ""; + const char *mime = ""; + const char *description = ""; + esp_mail_attach_type type = esp_mail_att_type_none; + size_t size; +}; + +#if defined(ENABLE_SMTP) + +struct esp_mail_smtp_command_t +{ + char text[9]; +}; + +struct esp_mail_timestamp_value_t +{ + /* The time format of timestamp to inject into subject or content as using in strftime C++ function */ + MB_String format; + /* The tag that will be replaced with current timestamp */ + MB_String tag; +}; + +/** The SMTP commands per stansards. + * The arrangement is related to esp_mail_smtp_command_types enum. + * Do not modify or remove. + */ +const struct esp_mail_smtp_command_t smtp_commands[esp_mail_smtp_command_maxType] PROGMEM = { + "AUTH", + "LOGIN", + "HELO", + "EHLO", + "QUIT", + "MAIL", + "RCPT", + "DATA", + "BDAT", + "LAST", + "PLAIN", + "FROM:", + "TO:", + "NOTIFY", + "SUCCESS", + "FAILURE", + "DELAY", + "BODY", + "\r\n.\r\n", + "STARTTLS"}; + +struct esp_mail_smtp_commands_tokens +{ +public: + esp_mail_smtp_commands_tokens(bool pre) + { + preToken = pre; + } + MB_String operator[](size_t index) + { + MB_String s = preToken ? " " : smtp_commands[index].text; + s += !preToken ? " " : smtp_commands[index].text; + return s; + } + +private: + bool preToken = false; +}; + +// The smtp commands with leading space. +static esp_mail_smtp_commands_tokens smtp_cmd_pre_tokens(true); + +// The smtp commands with trailing space. +static esp_mail_smtp_commands_tokens smtp_cmd_post_tokens(false); + +#endif + +#if defined(ENABLE_IMAP) + +struct esp_mail_imap_command_t +{ + char text[15]; +}; + +/** The IMAP commands per standards. + * The arrangement is related to esp_mail_imap_command_types enum. + * Do not modify or remove. + */ +const struct esp_mail_imap_command_t imap_commands[esp_mail_imap_command_maxType] PROGMEM = { + "STARTTLS", + "APPEND", + "CAPABILITY", + "AUTHENTICATE", + "PLAIN", + "UID", + "FETCH", + "FLAGS", + "LOGIN", + "LIST", + "EXAMINE", + "SEARCH", + "LOGOUT", + "BODY", + "MIME", + "CLOSE", + "EXISTS", + "PEEK", + "TEXT", + "FIELDS", + "HEADER", + "NEW", + "ALL", + "SELECT", + "EXPUNGE", + "CREATE", + "DELETE", + "IDLE", + "DONE", + "RECENT", + "UNSEEN", + "RENAME", + "LSUB", + "SUBSCRIBE", + "UNSUBSCRIBE", + "SILENT", + "MOVE", + "GETQUOTA", + "SETQUOTA", + "ROOT", + "GETACL", + "SETACL", + "DELETEACL", + "MYRIGHTS", + "NAMESPACE", + "ENABLE", + "XOAUTH2", + "STORE", + "+FLAGS", + "-FLAGS", + "COPY", + "ID", + "UNSELECT", + "CONDSTORE", + "NOOP", + "UNCHANGEDSINCE", + "CHANGEDSINCE", + "MODSEC"}; + +struct esp_mail_imap_commands_tokens +{ +public: + esp_mail_imap_commands_tokens(bool pre) + { + preToken = pre; + } + MB_String operator[](size_t index) + { + MB_String s = preToken ? " " : imap_commands[index].text; + s += !preToken ? " " : imap_commands[index].text; + return s; + } + +private: + bool preToken = false; +}; + +// The imap commands with leading space. +static esp_mail_imap_commands_tokens imap_cmd_pre_tokens(true); + +// The imap commands with trailing space. +static esp_mail_imap_commands_tokens imap_cmd_post_tokens(false); + +struct esp_mail_imap_response_t +{ + char text[18]; +}; + +/** The IMAP response. + * The arrangement is related to esp_mail_imap_response_types enum. + * Do not modify or remove. + */ +const struct esp_mail_imap_response_t imap_responses[esp_mail_imap_response_maxType] PROGMEM = { + // Tagged + "OK ", + "NO ", + "BAD ", + // Untagged + "* LIST ", + "* FLAGS ", + "* SEARCH ", + " FETCH ", + " NIL ", + " UID ", + "* CAPABILITY ", + "CAPABILITY ", + "* LSUB ", + "* QUOTA ", + "* QUOTAROOT ", + "* ACL ", + "* MYRIGHTS ", + "* NAMESPACE ", + "* ", + " EXISTS", + " EXPUNGE", + " RECENT", + " [UIDNEXT ", + " [UNSEEN ", + "* ID ", + " [HIGHESTMODSEQ ", + " [NOMODSEQ]", + " [PERMANENTFLAGS ", + " [UIDVALIDITY "}; + +#endif + +struct esp_mail_char_decoding_t +{ + char text[12]; +}; + +/** Supported charactor encodings. + * The arrangement is related to esp_mail_char_decoding_types enum. + * Do not modify or remove. + */ +const struct esp_mail_char_decoding_t char_decodings[esp_mail_char_decoding_maxType] PROGMEM = { + "utf-8", + "iso-8859-1", + "iso-8859-11", + "tis-620", + "windows-874"}; + +struct esp_mail_multipart_t +{ + char text[22]; +}; + +/** MultiPart MIME. + * The arrangement is related to esp_mail_multipart_types enum. + * Do not modify or remove. + */ +const struct esp_mail_multipart_t multipart_types[esp_mail_multipart_maxType] PROGMEM = { + "multipart/mixed", + "multipart/related", + "multipart/parallel", + "multipart/alternative"}; + +struct esp_mail_rfc822_header_field_t +{ + char text[20]; + bool isNum; + bool trim; +}; + +/** The rfc822 message header fields. + * The arrangement is related to esp_mail_rfc822_header_field_types enum. + * Do not modify or remove. + */ +const struct esp_mail_rfc822_header_field_t rfc822_headers[esp_mail_rfc822_header_field_maxType] PROGMEM = { + {"From", false, true}, + {"Sender", false, true}, + {"To", false, true}, + {"Cc", false, true}, + {"Subject", false, false}, + {"Date", false, false}, + {"Message-ID", false, false}, + {"Return-Path", false, true}, + {"Reply-To", false, true}, + {"In-Reply-To", false, true}, + {"References", false, true}, + {"Comments", false, false}, + {"Keywords", false, false}, + {"Bcc", false, true}, + {"Flags", false, false}}; + +struct esp_mail_message_header_field_t +{ + char text[26]; +}; + +/** Additional fields and props. + * The arrangement is related to esp_mail_message_header_field_types enum. + * Do not modify or remove. + */ +const struct esp_mail_message_header_field_t message_headers[esp_mail_message_header_field_maxType] PROGMEM = { + "Number", + "UID", + "Accept-Language", + "Content-Language", + "Filename", + "Name", + "Size", + "MIME", + "Type", + "Description", + "Creation-Date", + "X-Priority", + "X-MSMail-Priority", + "Importance", + "Content-Type", + "Content-transfer-encoding", + "Content-Disposition", + "Content-Location", + "Content-ID", + "Content-Description", + "Mime-Version", + "Charset", + "format", + "delsp", + "Modification-Date"}; + +struct esp_mail_auth_capability_t +{ + char text[20]; +}; + +#if defined(ENABLE_SMTP) + +/** The server capability keywords per standard. + * The arrangement is related to esp_mail_auth_capability_types enum. + * Do not modify or remove. + */ +const struct esp_mail_auth_capability_t smtp_auth_capabilities[esp_mail_auth_capability_maxType] PROGMEM = { + "PLAIN", + "XOAUTH2", + "CRAM-MD5", + "DIGEST-MD5", + "LOGIN", + "STARTTLS", + "DUMMY_AUTH" /* SASL-IR */}; + +struct esp_mail_smtp_auth_tokens +{ +public: + esp_mail_smtp_auth_tokens(bool pre) + { + preToken = pre; + } + MB_String operator[](size_t index) + { + MB_String s = preToken ? " " : smtp_auth_capabilities[index].text; + s += !preToken ? " " : smtp_auth_capabilities[index].text; + return s; + } + +private: + bool preToken = false; +}; + +// The smtp auth capability with leading space. +static esp_mail_smtp_auth_tokens smtp_auth_cap_pre_tokens(true); +// The smtp auth capability with trailing space. +static esp_mail_smtp_auth_tokens smtp_auth_cap_post_tokens(false); + +struct esp_mail_smtp_send_capability_t +{ + char text[15]; +}; + +/** The server capability keywords per standard. + * The arrangement is related esp_mail_smtp_send_capability_types enum. + * Do not modify or remove. + */ +const struct esp_mail_smtp_send_capability_t smtp_send_capabilities[esp_mail_smtp_send_capability_maxType] PROGMEM = { + "BINARYMIME", + "8BITMIME", + "CHUNKING", + "SMTPUTF8", + "PIPELINING", + "DSN", + "" /* ESMTP */}; + +struct esp_mail_smtp_send_tokens +{ +public: + esp_mail_smtp_send_tokens(bool pre) + { + preToken = pre; + } + MB_String operator[](size_t index) + { + MB_String s = preToken ? " " : smtp_send_capabilities[index].text; + s += !preToken ? " " : smtp_send_capabilities[index].text; + return s; + } + +private: + bool preToken = false; +}; + +static esp_mail_smtp_send_tokens smtp_send_cap_pre_tokens(true); + +#endif + +#if defined(ENABLE_IMAP) + +/** The server capability keywords per standard. + * The arrangement is related esp_mail_auth_capability_types enum. + * Do not modify or remove. + */ +const struct esp_mail_auth_capability_t imap_auth_capabilities[esp_mail_auth_capability_maxType] PROGMEM = { + "AUTH=PLAIN", + "AUTH=XOAUTH2", + "CRAM-MD5", + "DIGEST-MD5", + "DUMMY_AUTH", /* Log in */ + "STARTTLS", + "SASL-IR"}; + +struct esp_mail_imap_auth_tokens +{ +public: + esp_mail_imap_auth_tokens(bool pre) + { + preToken = pre; + } + MB_String operator[](size_t index) + { + MB_String s = preToken ? " " : imap_auth_capabilities[index].text; + s += !preToken ? " " : imap_auth_capabilities[index].text; + return s; + } + +private: + bool preToken = false; +}; + +// The imap auth capability with leading space. +static esp_mail_imap_auth_tokens imap_auth_cap_pre_tokens(true); + +struct esp_mail_imap_read_capability_t +{ + char text[15]; +}; + +/** The server capability keywords per standard. + * The arrangement is related esp_mail_imap_read_capability_types enum. + * Do not modify or remove. + */ +const struct esp_mail_imap_read_capability_t imap_read_capabilities[esp_mail_imap_read_capability_maxType] PROGMEM = { + "IMAP4", + "IMAP4rev1", + "IDLE", + "LITERAL+", + "LITERAL-", + "MULTIAPPEND", + "UIDPLUS", + "ACL", + "BINARY", + "LOGINDISABLED", + "MOVE", + "QUOTA", + "NAMESPACE", + "ENABLE", + "ID", + "UNSELECT", + "CHILDREN", + "CONDSTORE" + "" /* Auto cap */}; + +struct esp_mail_imap_read_tokens +{ +public: + esp_mail_imap_read_tokens(bool pre) + { + preToken = pre; + } + MB_String operator[](size_t index) + { + MB_String s = preToken ? " " : imap_read_capabilities[index].text; + s += !preToken ? " " : imap_read_capabilities[index].text; + return s; + } + +private: + bool preToken = false; +}; + +// The imap auth capability with leading space. +static esp_mail_imap_read_tokens imap_read_cap_pre_tokens(true); + +// The imap auth capability with trailing space. +static esp_mail_imap_read_tokens imap_read_cap_post_tokens(false); + +struct esp_mail_imap_identification_key_t +{ + char text[15]; +}; + +/** The identification keys per standard. + * The arrangement is related esp_mail_imap_identification_key_types enum. + * Do not modify or remove. + */ +const struct esp_mail_imap_identification_key_t imap_identification_keys[esp_mail_imap_identification_key_maxType] PROGMEM = { + "name", + "version", + "os", + "os-version", + "vendor", + "support-url", + "address", + "date", + "command", + "arguments", + "environment"}; + +/* The IMAP ID data struct */ +typedef struct esp_mail_imap_identity_t +{ + MB_String name; + MB_String version; + MB_String os; + MB_String os_version; + MB_String vendor; + MB_String support_url; + MB_String address; + MB_String date; + MB_String command; + MB_String arguments; + MB_String environment; + +} IMAP_Identification; + +#endif + +#endif + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) +/* The email address info [SMTP_Message]*/ +struct esp_mail_address_info_t +{ + /* The name of Email author/sender */ + MB_String name; + + /* The Email address */ + MB_String email; +}; +#endif + +#if defined(ENABLE_SMTP) + +/* The SMTP message notification types enum */ +enum esp_mail_smtp_notify +{ + esp_mail_smtp_notify_never = 0, + esp_mail_smtp_notify_success = 1, + esp_mail_smtp_notify_failure = 2, + esp_mail_smtp_notify_delay = 4 +}; + +/* The SMTP status codes enum */ +enum esp_mail_smtp_status_code +{ + esp_mail_smtp_status_code_0, // default + + /* Positive Completion */ + esp_mail_smtp_status_code_211 = 221, // System status, or system help reply + esp_mail_smtp_status_code_214 = 214, // Help message(A response to the HELP command) + esp_mail_smtp_status_code_220 = 220, // Service ready + esp_mail_smtp_status_code_221 = 221, // Service closing transmission channel [RFC 2034] + esp_mail_smtp_status_code_235 = 235, // 2.7.0 Authentication succeeded[RFC 4954] + esp_mail_smtp_status_code_250 = 250, // Requested mail action okay, completed + esp_mail_smtp_status_code_251 = 251, // User not local; will forward + esp_mail_smtp_status_code_252 = 252, // Cannot verify the user, but it will + // try to deliver the message anyway + + /* Positive Intermediate */ + esp_mail_smtp_status_code_334 = 334, //(Server challenge - the text part + // contains the Base64 - encoded + // challenge)[RFC 4954] + esp_mail_smtp_status_code_354 = 354, // Start mail input + + /* Transient Negative Completion */ + /* "Transient Negative" means the error condition is temporary, and the action + may be requested again.*/ + esp_mail_smtp_status_code_421 = 421, // Service is unavailable because the server is shutting down. + esp_mail_smtp_status_code_432 = 432, // 4.7.12 A password transition is needed [RFC 4954] + esp_mail_smtp_status_code_450 = 450, // Requested mail action not taken: mailbox unavailable (e.g., + // mailbox busy or temporarily blocked for policy reasons) + esp_mail_smtp_status_code_451 = 451, // Requested action aborted : local error in processing + // e.g.IMAP server unavailable[RFC 4468] + esp_mail_smtp_status_code_452 = 452, // Requested action not taken : insufficient system storage + esp_mail_smtp_status_code_454 = 454, // 4.7.0 Temporary authentication failure[RFC 4954] + esp_mail_smtp_status_code_455 = 455, // Server unable to accommodate parameters + + /* Permanent Negative Completion */ + esp_mail_smtp_status_code_500 = 500, // Syntax error, command unrecognized + // (This may include errors such as + // command line too long) + // e.g. Authentication Exchange line is too long [RFC 4954] + esp_mail_smtp_status_code_501 = 501, // Syntax error in parameters or arguments + // e.g. 5.5.2 Cannot Base64-decode Client responses [RFC 4954] + // 5.7.0 Client initiated Authentication Exchange (only when the SASL + // mechanism specified that client does not begin the authentication exchange) + // [RFC 4954] + esp_mail_smtp_status_code_502 = 502, // Command not implemented + esp_mail_smtp_status_code_503 = 503, // Bad sequence of commands + esp_mail_smtp_status_code_504 = 504, // Command parameter is not implemented + // e.g. 5.5.4 Unrecognized authentication type [RFC 4954] + esp_mail_smtp_status_code_521 = 521, // Server does not accept mail [RFC 7504] + esp_mail_smtp_status_code_523 = 523, // Encryption Needed [RFC 5248] + esp_mail_smtp_status_code_530 = 530, // 5.7.0 Authentication required [RFC 4954] + esp_mail_smtp_status_code_534 = 534, // 5.7.9 Authentication mechanism is too weak [RFC 4954] + esp_mail_smtp_status_code_535 = 535, // 5.7.8 Authentication credentials invalid [RFC 4954] + esp_mail_smtp_status_code_538 = 538, // 5.7.11 Encryption required for + // requested authentication mechanism[RFC + // 4954] + esp_mail_smtp_status_code_550 = 550, // Requested action not taken: mailbox unavailable (e.g., mailbox not + // found, no access, or command rejected for policy reasons) + esp_mail_smtp_status_code_551 = 551, // User not local; please try + esp_mail_smtp_status_code_552 = 552, // Requested mail action aborted: exceeded storage allocation + esp_mail_smtp_status_code_553 = 553, // Requested action not taken: mailbox name not allowed + esp_mail_smtp_status_code_554 = 554, // Transaction has failed (Or, in the + // case of a connection-opening response, + // "No SMTP service here") + // e.g. 5.3.4 Message too big for system [RFC 4468] + esp_mail_smtp_status_code_556 = 556, // Domain does not accept mail[RFC 7504] +}; + +/* The SMTP ports enum */ +enum esp_mail_smtp_port +{ + esp_mail_smtp_port_25 = 25, // PLAIN/TLS with STARTTLS + esp_mail_smtp_port_465 = 465, // SSL + esp_mail_smtp_port_587 = 587, // TLS with STARTTLS +}; + +const struct port_function smtp_ports[3] = { + {esp_mail_smtp_port_25, esp_mail_protocol_plain_text}, + {esp_mail_smtp_port_465, esp_mail_protocol_ssl}, + {esp_mail_smtp_port_587, esp_mail_protocol_tls}}; + +/* The SMTP message response [SMTP_Message] */ +struct esp_mail_smtp_msg_response_t +{ + /* The author Email address to reply */ + MB_String reply_to; + + /* The sender Email address to return the message */ + MB_String return_path; + + /** The Delivery Status Notifications e.g. esp_mail_smtp_notify_never, + * esp_mail_smtp_notify_success, + * esp_mail_smtp_notify_failure, and + * esp_mail_smtp_notify_delay + */ + int notify = esp_mail_smtp_notify::esp_mail_smtp_notify_never; +}; + +/* The SMTP enable option [SMTP_Message] */ +struct esp_mail_smtp_enable_option_t +{ + /* Enable chunk data sending for large message */ + bool chunking = false; +}; + +/* The SMTP blob data attachment data [Session_Config] */ +struct esp_mail_attach_blob_t +{ + /* BLOB data (flash or ram) */ + const uint8_t *data = nullptr; + + /* BLOB data size in byte */ + size_t size = 0; +}; + +/* The SMTP file attachment data [Session_Config] */ +struct esp_mail_attach_file_t +{ + MB_String path; + /** The file storage type e.g. esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + esp_mail_file_storage_type storage_type = esp_mail_file_storage_type_none; +}; + +/* The SMTP attachment decription [Session_Config] */ +struct esp_mail_attach_descr_t +{ + /* The name of attachment */ + MB_String name; + + /* The attachment file name */ + MB_String filename; + + /* The MIME type of attachment */ + MB_String mime; + + /* The transfer encoding of attachment e.g. base64 */ + MB_String transfer_encoding = "base64"; + + /* The content encoding of attachment e.g. base64 */ + MB_String content_encoding; + + /* The content id of attachment file */ + MB_String content_id; + + /* The description of attachment file */ + MB_String description; +}; + +/* Used internally in esp_mail_attachment_t */ +struct esp_mail_attach_internal_t +{ + esp_mail_attach_type att_type = esp_mail_att_type_attachment; + int index = 0; + int msg_uid = 0; + bool flash_blob = false; + esp_mail_msg_xencoding xencoding = esp_mail_msg_xencoding_none; + bool parallel = false; + MB_String cid; +}; + +/* The struct used as SMTP_Attachment for SMTP and ESP_Mail_Attachment for IMAP */ +struct esp_mail_attachment_t +{ + /* The attachment description */ + struct esp_mail_attach_descr_t descr; + + /* The BLOB data config */ + struct esp_mail_attach_blob_t blob; + + /* The file data config */ + struct esp_mail_attach_file_t file; + + /* reserved for internal usage */ + struct esp_mail_attach_internal_t _int; +}; + +/* The struct used as SMTP_Result */ +struct esp_mail_smtp_send_status_t +{ + /* The status of the message */ + bool completed = false; + + /* The primary recipient mailbox of the message */ + MB_String recipients; + + /* The topic of the message */ + MB_String subject; + + /* The timestamp of the message */ + uint32_t timestamp = 0; +}; + +/* Used internally for SMTPSession */ +struct esp_mail_smtp_msg_type_t +{ + bool rfc822 = false; + int rfc822Idx = 0; +}; + +/* Used internally for holding base64 data sources */ +struct esp_mail_smtp_send_base64_data_info_t +{ + esp_mail_file_storage_type storageType = esp_mail_file_storage_type_none; + const char *filename = ""; + const uint8_t *rawPtr = nullptr; + bool flashMem = false; + size_t size = 0; + size_t dataIndex = 0; +}; + +/* SMTP commands types enum */ +enum esp_mail_smtp_command +{ + esp_mail_smtp_cmd_undefined, + esp_mail_smtp_cmd_initial_state, + esp_mail_smtp_cmd_greeting, + esp_mail_smtp_cmd_start_tls, + esp_mail_smtp_cmd_login_user, + esp_mail_smtp_cmd_auth_plain, + esp_mail_smtp_cmd_auth_login, + esp_mail_smtp_cmd_auth_xoauth2, + esp_mail_smtp_cmd_login_psw, + esp_mail_smtp_cmd_send_header_sender, + esp_mail_smtp_cmd_send_header_recipient, + esp_mail_smtp_cmd_send_body, + esp_mail_smtp_cmd_chunk_termination, + esp_mail_smtp_cmd_logout, + esp_mail_smtp_cmd_custom +}; + +/* SMTP message priority level enum */ +enum esp_mail_smtp_priority +{ + esp_mail_smtp_priority_high = 1, + esp_mail_smtp_priority_normal = 3, + esp_mail_smtp_priority_low = 5, +}; + +/* SMTP response data */ +typedef struct esp_mail_smtp_response_status_t +{ + /* The SMTP server response status code */ + int statusCode = 0; + + /* error code */ + int errorCode = 0; + int id = -1; + MB_String text; +} SMTP_Response; + +#endif + +#if defined(ENABLE_IMAP) + +enum esp_mail_imap_msg_num_type +{ + esp_mail_imap_msg_num_type_undefined, + esp_mail_imap_msg_num_type_uid, + esp_mail_imap_msg_num_type_number +}; + +enum esp_mail_imap_store_flag_type +{ + esp_mail_imap_store_flag_type_set, + esp_mail_imap_store_flag_type_add, + esp_mail_imap_store_flag_type_remove +}; + +enum esp_mail_char_decoding_scheme +{ + esp_mail_char_decoding_scheme_default = -1, + esp_mail_char_decoding_scheme_utf_8, + esp_mail_char_decoding_scheme_iso8859_1, + esp_mail_char_decoding_scheme_iso8859_11, + esp_mail_char_decoding_scheme_tis_620, + esp_mail_char_decoding_scheme_windows_874 +}; + +enum esp_mail_imap_rights_type_t +{ + /* a - administer (perform SETACL/DELETEACL/GETACL/LISTRIGHTS) */ + esp_mail_imap_rights_administer = 'a' - 'a', + /* c - RFC2086 (obsoleted) create (CREATE new sub-mailboxes in any implementation-defined hierarchy) */ + esp_mail_imap_rights_create_c = 'c' - 'a', + /* d - RFC2086 (obsoleted) delete (STORE DELETED flag, perform EXPUNGE) */ + esp_mail_imap_rights_delete_d = 'd' - 'a', + /* e - perform EXPUNGE and expunge as a part of CLOSE */ + esp_mail_imap_rights_expunge = 'e' - 'a', + /* i - insert (perform APPEND, COPY into mailbox) */ + esp_mail_imap_rights_insert = 'i' - 'a', + /* k - RFC4314 create mailboxes (CREATE new sub-mailboxes in any implementation-defined hierarchy, parent mailbox for the new mailbox name in RENAME)*/ + esp_mail_imap_rights_create = 'k' - 'a', + /* l - lookup (mailbox is visible to LIST/LSUB commands, SUBSCRIBE mailbox) */ + esp_mail_imap_rights_lookup = 'l' - 'a', + /* p - post (send mail to submission address for mailbox, not enforced by IMAP4 itself) */ + esp_mail_imap_rights_post = 'p' - 'a', + /* r - read (SELECT the mailbox, perform STATUS) */ + esp_mail_imap_rights_read = 'r' - 'a', + /* s - keep seen/unseen information across sessions (set or clear \SEEN flag via STORE, also set \SEEN during APPEND/COPY/ FETCH BODY[...]) */ + esp_mail_imap_rights_seen = 's' - 'a', + /* t - RFC4314 delete messages (set or clear \DELETED flag via STORE, set \DELETED flag during APPEND/COPY) */ + esp_mail_imap_rights_delete_message = 't' - 'a', + /* w - write (set or clear flags other than \SEEN and \DELETED via STORE, also set them during APPEND/COPY) */ + esp_mail_imap_rights_write = 'w' - 'a', + /* x - RFC4314 delete mailbox (DELETE mailbox, old mailbox name in RENAME) */ + esp_mail_imap_rights_delete_mailbox = 'x' - 'a', + + esp_mail_imap_rights_maxType = esp_mail_imap_rights_delete_mailbox + 1 +}; + +enum esp_mail_imap_port +{ + esp_mail_imap_port_143 = 143, // PLAIN/TLS with STARTTLS + esp_mail_imap_port_993 = 993, // SSL +}; + +const struct port_function imap_ports[2] = { + {esp_mail_imap_port_143, esp_mail_protocol_plain_text}, + {esp_mail_imap_port_993, esp_mail_protocol_ssl}}; + +enum esp_mail_imap_auth_mode +{ + esp_mail_imap_mode_examine, + esp_mail_imap_mode_select +}; + +enum esp_mail_imap_response_status +{ + esp_mail_imap_resp_unknown, + esp_mail_imap_resp_ok, + esp_mail_imap_resp_no, + esp_mail_imap_resp_bad +}; + +enum esp_mail_imap_polling_status_type +{ + imap_polling_status_type_undefined, + imap_polling_status_type_new_message, + imap_polling_status_type_remove_message, + imap_polling_status_type_fetch_message +}; + +enum esp_mail_imap_header_state +{ + esp_mail_imap_state_content_type = esp_mail_rfc822_header_field_maxType, + esp_mail_imap_state_content_transfer_encoding, + esp_mail_imap_state_accept_language, + esp_mail_imap_state_content_language, + esp_mail_imap_state_char_set, + esp_mail_imap_state_boundary +}; + +enum esp_mail_imap_command +{ + esp_mail_imap_cmd_capability, + esp_mail_imap_cmd_starttls, + esp_mail_imap_cmd_sasl_login, + esp_mail_imap_cmd_sasl_auth_plain, + esp_mail_imap_cmd_sasl_auth_oauth, + esp_mail_imap_cmd_list, + esp_mail_imap_cmd_lsub, + esp_mail_imap_cmd_subscribe, + esp_mail_imap_cmd_unsubscribe, + esp_mail_imap_cmd_select, + esp_mail_imap_cmd_examine, + esp_mail_imap_cmd_close, + esp_mail_imap_cmd_status, + esp_mail_imap_cmd_search, + esp_mail_imap_cmd_fetch_body_header, + esp_mail_imap_cmd_fetch_body_mime, + esp_mail_imap_cmd_fetch_body_text, + esp_mail_imap_cmd_fetch_body_attachment, + esp_mail_imap_cmd_fetch_body_inline, + esp_mail_imap_cmd_fetch_sequence_set, + esp_mail_imap_cmd_logout, + esp_mail_imap_cmd_store, + esp_mail_imap_cmd_move, + esp_mail_imap_cmd_get_quota, + esp_mail_imap_cmd_set_quota, + esp_mail_imap_cmd_get_quota_root, + esp_mail_imap_cmd_get_acl, + esp_mail_imap_cmd_set_acl, + esp_mail_imap_cmd_delete_acl, + esp_mail_imap_cmd_my_rights, + esp_mail_imap_cmd_namespace, + esp_mail_imap_cmd_expunge, + esp_mail_imap_cmd_create, + esp_mail_imap_cmd_rename, + esp_mail_imap_cmd_delete, + esp_mail_imap_cmd_idle, + esp_mail_imap_cmd_done, + esp_mail_imap_cmd_get_uid, + esp_mail_imap_cmd_get_flags, + esp_mail_imap_cmd_append, + esp_mail_imap_cmd_append_last, + esp_mail_imap_cmd_enable, + esp_mail_imap_cmd_id, + esp_mail_imap_cmd_unselect, + esp_mail_imap_cmd_noop, + esp_mail_imap_cmd_copy, + esp_mail_imap_cmd_custom +}; + +enum esp_mail_imap_mime_fetch_type +{ + esp_mail_imap_mime_fetch_type_part, + esp_mail_imap_mime_fetch_type_sub_part1, + esp_mail_imap_mime_fetch_type_sub_part2 +}; + +enum esp_mail_imap_header_type +{ + esp_mail_imap_header_from, + esp_mail_imap_header_to, + esp_mail_imap_header_cc, + esp_mail_imap_header_subject, + esp_mail_imap_header_date, + esp_mail_imap_header_msg_id, + esp_mail_imap_header_cont_lang, + esp_mail_imap_header_accept_lang +}; + +enum esp_mail_imap_multipart_sub_type +{ + esp_mail_imap_multipart_sub_type_none = 0, + esp_mail_imap_multipart_sub_type_mixed, + esp_mail_imap_multipart_sub_type_alternative, + esp_mail_imap_multipart_sub_type_parallel, + esp_mail_imap_multipart_sub_type_digest, + esp_mail_imap_multipart_sub_type_related, + esp_mail_imap_multipart_sub_type_report, +}; + +enum esp_mail_imap_message_sub_type +{ + esp_mail_imap_message_sub_type_none = 0, + esp_mail_imap_message_sub_type_rfc822, + esp_mail_imap_message_sub_type_delivery_status, + esp_mail_imap_message_sub_type_partial, + esp_mail_imap_message_sub_type_external_body, +}; + +typedef struct esp_mail_imap_response_status_t +{ + // No IMAP server response status code (statusCode), server returns OK, NO and BAD response instead + + /* error code */ + int errorCode = 0; + MB_String tag; + MB_String text; + MB_String status; + bool completed = false; + +public: + void clear(bool clearTag = true) + { + if (clearTag) + tag.clear(); + status.clear(); + text.clear(); + completed = false; + } +} IMAP_Response; + +struct esp_mail_imap_msg_num_t +{ + esp_mail_imap_msg_num_type type = esp_mail_imap_msg_num_type_undefined; + uint32_t value = 0; +}; + +__attribute__((used)) struct +{ + bool operator()(struct esp_mail_imap_msg_num_t a, struct esp_mail_imap_msg_num_t b) const { return a.value > b.value; } +} compareMore; + +struct esp_mail_imap_rfc822_msg_header_item_t +{ + MB_String header_items[esp_mail_rfc822_header_field_maxType]; +}; + +/* IMAP quota root info */ +typedef struct esp_mail_imap_quota_root_info_t +{ + /* The quota root */ + MB_String quota_root; + + /* The resource name e.g. STORAGE and MESSAGE */ + MB_String name; + + /* The resource usage in kilo octets */ + size_t usage = 0; + + /* The resource limit in kilo octets */ + size_t limit = 0; + +} IMAP_Quota_Root_Info; + +/* IMAP namespace info */ +typedef struct esp_mail_imap_namespace_info_t +{ + /* The leading prefix */ + MB_String prefix; + + /* The hierarchy delimiter */ + MB_String delimiter; + +} IMAP_Namespace_Info; + +typedef struct esp_mail_imap_rights_info_t +{ + MB_String identifier; + bool rights[esp_mail_imap_rights_maxType]; + +} IMAP_Rights_Info; + +/* descrete media types (rfc 2046) */ +struct esp_mail_imap_descrete_media_type_t +{ + /** textual information with subtypes + * "plain" + * "enriched" (rfc 1896 revised from richtext in rfc 1341) + * + * unrecognized subtypes and charset should be interpreted as + * application/octet-stream + * + * parameters: + * "charset" (rfc 2045) default is us-ascii + * for character set includes 8-bit characters + * and such characters are used in the body, Content-Transfer-Encoding + * header field and a corresponding encoding on the data are required + * + * ISO-8859-X where "X" is to be replaced, as + * necessary, for the parts of ISO-8859 [ISO-8859]. + */ + static constexpr const char *text = "text"; + + /** image data with subtypes (rfc 2048) + * "jpeg" + * "gif" + * + * unrecognized subtypes should be interpreted as application/octet-stream + */ + static constexpr const char *image = "image"; + + /** audio data with initial subtype + * "baic" -- for single channel audio encoded using 8bit ISDN mu-law [PCM] + * at a sample rate of 8000 Hz. + * + * Unrecognized subtypes of "audio" should at a miniumum be treated as + * "application/octet-stream" + */ + static constexpr const char *audio = "audio"; + + /** video data with initial subtype + * "mpeg" + * + * Unrecognized subtypes of "video" should at a minumum be treated as + * "application/octet-stream" + */ + static constexpr const char *video = "video"; + + /** some other kind of data, typically either + * uninterpreted binary data or information to be + * processed by an application with subtypes + * + * "octet-stream" -- uninterpreted binary data + * "PostScript" -- for the transport of PostScript material + * + * Other expected uses include spreadsheets, data for mail-based + * scheduling systems, and languages for "active" (computational) + * messaging, and word processing formats that are not directly readable. + * + * The octet-stream subtype parameters: + * TYPE, PADDING, NAME + */ + static constexpr const char *application = "application"; +}; + +/** composite media types (rfc 2046) + * + * As stated in the definition of the Content-Transfer-Encoding field + * [RFC 2045], no encoding other than "7bit", "8bit", or "binary" is + * permitted for entities of type "multipart". The "multipart" boundary + * delimiters and header fields are always represented as 7bit US-ASCII + * in any case (though the header fields may encode non-US-ASCII header + * text as per RFC 2047) and data within the body parts can be encoded + * on a part-by-part basis, with Content-Transfer-Encoding fields for + * each appropriate body part. + */ +struct esp_mail_imap_composite_media_type_t +{ + /** data consisting of multiple entities of independent data types + * The Content-Type field for multipart entities requires one parameter, + * "boundary". + * The boundary delimiter line is then defined as a line + * consisting entirely of two hyphen characters ("-", decimal value 45) + * followed by the boundary parameter value from the Content-Type header + * field, optional linear whitespace, and a terminating CRLF. + * + * NOTE: The CRLF preceding the boundary delimiter line is conceptually + * attached to the boundary so that it is possible to have a part that + * does not end with a CRLF (line break). Body parts that must be + * considered to end with line breaks, therefore, must have two CRLFs + * preceding the boundary delimiter line, the first of which is part of + * the preceding body part, and the second of which is part of the + * encapsulation boundary. + * + * Boundary delimiters must not appear within the encapsulated material, + * and must be no longer than 70 characters, not counting the two + * leading hyphens. + * + * The boundary delimiter line following the last body part is a + * distinguished delimiter that indicates that no further body parts + * will follow. Such a delimiter line is identical to the previous + * delimiter lines, with the addition of two more hyphens after the + * boundary parameter value. + * + * See rfc2049 Appendix A for a Complex Multipart Example + */ + static constexpr const char *multipart = "multipart"; + + /* an encapsulated message */ + static constexpr const char *message = "message"; +}; + +typedef struct esp_mail_imap_mime_data_stream_info_t +{ + /* message UID */ + uint32_t uid = 0; + + /* content type */ + const char *type = ""; + + /* disposition */ + const char *disposition = ""; + + /* content character set */ + const char *charSet = ""; + + /* text content flowed format parameter */ + bool flowed = false; + + /* text content format DelSp parameter */ + bool delsp = false; + + /* content transfer encoding */ + const char *transfer_encoding = ""; + + /* content ID */ + const char *cid = ""; + + /* content description */ + const char *description = ""; + + /* content file name */ + const char *filename = ""; + + /* content name */ + const char *name = ""; + + /* creation date */ + const char *date = ""; + + /* content size */ + size_t size = 0; + + /* octet size */ + size_t octet_size = 0; + + /* current octet count */ + int octet_count = 0; + + /* data size */ + size_t data_size = 0; + + /* data buffer */ + void *data = NULL; + + bool isFirstData = false; + + bool isLastData = false; + +} MIME_Data_Stream_Info; + +typedef struct esp_mail_imap_decoding_info +{ + enum message_part_type + { + message_part_type_header, + message_part_type_text + }; + + /* The character set of the string to decode */ + const char *charset = ""; + + /* The string to decode */ + const char *data = ""; + + /* The decoded string to be processed */ + MB_String decodedString; + + /** The type of data that currently processed + * 0 or IMAP_Decoding_Info::message_part_type_header + * 1 or IMAP_Decoding_Info::message_part_type_text + */ + message_part_type type = message_part_type_header; + +} IMAP_Decoding_Info; + +struct esp_mail_imap_media_text_sub_type_t +{ + static constexpr const char *plain = "plain"; + static constexpr const char *enriched = "enriched"; + static constexpr const char *html = "html"; +}; + +/* multipart sub types */ +struct esp_mail_imap_multipart_sub_type_t +{ + /* a generic mixed set of parts */ + static constexpr const char *mixed = "mixed"; + + /* the same data in multiple formats */ + static constexpr const char *alternative = "alternative"; + + /* parts intended to be viewed simultaneously */ + static constexpr const char *parallel = "parallel"; + + /* multipart entities in which each part has a default type of + * "message/rfc822" */ + static constexpr const char *digest = "digest"; + + /* for compound objects consisting of several inter-related body parts (rfc + * 2387) */ + static constexpr const char *related = "related"; + + /* rfc 3462 */ + static constexpr const char *report = "report"; +}; + +/* message body sub types */ +struct esp_mail_imap_message_sub_type_t +{ + /* body contains an encapsulated message, with the syntax of an RFC 822 + * message. */ + static constexpr const char *rfc822 = "rfc822"; + + /* to allow large objects to be delivered as several separate pieces of mail + */ + static constexpr const char *Partial = "Partial"; + + /* the actual body data are not included, but merely referenced */ + static constexpr const char *External_Body = "External-Body"; + + static constexpr const char *delivery_status = "delivery-status"; +}; + +/* IMAP polling status */ +typedef struct esp_mail_imap_polling_status_t +{ + /** The type of status e.g. imap_polling_status_type_undefined, imap_polling_status_type_new_message, + * imap_polling_status_type_fetch_message and imap_polling_status_type_remove_message. + */ + esp_mail_imap_polling_status_type type = imap_polling_status_type_undefined; + + /** Message number or order from the total number of message that added, fetched or deleted. + */ + size_t messageNum = 0; + + /** Argument of commands e.g. FETCH + */ + MB_String argument; +} IMAP_Polling_Status; + +struct esp_mail_message_part_info_t +{ + enum content_header_field + { + content_header_field_none, + content_header_field_type, + content_header_field_description, + content_header_field_id, + content_header_field_disposition, + content_header_field_transfer_enc, + content_header_field_ext + + }; + + int octetLen = 0; + int octetCount = 0; + int attach_data_size = 0; + int textLen = 0; + bool sizeProp = false; + int nestedLevel = 0; + + // pointer to the MB_String for storing multi-line header field content. + uint32_t stringPtr = 0; + esp_mail_char_decoding_scheme stringEnc = esp_mail_char_decoding_scheme_default; + + content_header_field cur_content_hdr = content_header_field_none; + + MB_String partNumStr; + MB_String partNumFetchStr; + MB_String text; + MB_String filename; + MB_String CID; + MB_String type; + MB_String save_path; + MB_String name; + MB_String content_disposition; + MB_String content_description; + MB_String content_type; + MB_String descr; + MB_String content_transfer_encoding; + MB_String creation_date; + MB_String modification_date; + MB_String charset; + MB_String download_error; + esp_mail_attach_type attach_type = esp_mail_att_type_none; + esp_mail_message_type msg_type = esp_mail_msg_type_none; + bool file_open_write = false; + bool multipart = false; + bool is_firmware_file = false; + bool save_to_file = true; + size_t firmware_downloaded_byte = 0; + esp_mail_imap_multipart_sub_type multipart_sub_type = esp_mail_imap_multipart_sub_type_none; + esp_mail_imap_message_sub_type message_sub_type = esp_mail_imap_message_sub_type_none; + bool rfc822_part = false; + int rfc822_msg_Idx = 0; + struct esp_mail_imap_rfc822_msg_header_item_t rfc822_header; + bool error = false; + bool plain_flowed = false; + bool plain_delsp = false; + esp_mail_msg_xencoding xencoding = esp_mail_msg_xencoding_none; +}; + +struct esp_mail_message_header_t +{ + int header_data_len = 0; + + struct esp_mail_imap_rfc822_msg_header_item_t header_fields; + + MB_String content_type; + MB_String content_transfer_encoding; + uint32_t message_uid = 0; + uint32_t message_no = 0; + MB_String boundary; + MB_String accept_language; + MB_String content_language; + MB_String char_set; + bool multipart = false; + bool rfc822_part = false; + bool hasAttachment = false; + int rfc822Idx = 0; + MB_String partNumStr; + + esp_mail_imap_multipart_sub_type multipart_sub_type = esp_mail_imap_multipart_sub_type_none; + esp_mail_imap_message_sub_type message_sub_type = esp_mail_imap_message_sub_type_none; + MB_String msgID; + MB_String flags; + MB_String error_msg; + bool error = false; + _vectorImpl part_headers; + int attachment_count = 0; + int sd_alias_file_count = 0; + int total_download_size = 0; + int downloaded_size = 0; + int total_attach_data_size = 0; + int downloaded_bytes = 0; + int message_data_count = 0; +}; + +/* Internal use */ +struct esp_mail_folder_info_t +{ + MB_String name; + MB_String attributes; + MB_String delimiter; +}; + +struct esp_mail_folder_info_item_t +{ + /* The name of folder */ + const char *name = ""; + + /* The attributes of folder */ + const char *attributes = ""; + + /* The delimeter of folder */ + const char *delimiter = ""; +}; + +struct esp_mail_imap_download_config_t +{ + /* To download the PLAIN text content of the message */ + bool text = false; + + /* To download the HTML content of the message */ + bool html = false; + + /* To download the attachments of the message */ + bool attachment = false; + + /* To download the inline image of the message */ + bool inlineImg = false; + + /* To download the rfc822 mesages in the message */ + bool rfc822 = false; + + /* To download the message header */ + bool header = false; +}; + +struct esp_mail_imap_enable_config_t +{ + /* To store the PLAIN text of the message in the IMAPSession */ + bool text = false; + + /* To store the HTML of the message in the IMAPSession */ + bool html = false; + + /* To store the rfc822 messages in the IMAPSession */ + bool rfc822 = false; + + /* To enable the download status via the serial port */ + bool download_status = false; + + /* To sort the message UID of the search result in descending order */ + bool recent_sort = false; + + /* To allow case sesitive in header parsing */ + bool header_case_sensitive = false; +}; + +struct esp_mail_imap_limit_config_t +{ + /* The maximum messages from the search result */ + size_t search = 10; + + /* The maximum messages from the sequence set fetching result */ + size_t fetch = 30; + + /** The maximum size of the memory buffer to store the message content. + * This is only limit for data to be stored in the IMAPSession. + */ + size_t msg_size = 1024; + + /* The maximum size of each attachment to download */ + size_t attachment_size = 1024 * 1024 * 5; + + /* The IMAP idle timeout in ms (1 min to 29 min). Default is 8 min */ + size_t imap_idle_timeout = 8 * 60 * 1000; + + /** The IMAP idle host check interval in ms (30 sec to imap_idle_timeout) + * for internet availability checking to ensure the connection is active. + * Default is 1 min. + */ + size_t imap_idle_host_check_interval = 60 * 1000; +}; + +struct esp_mail_imap_storage_config_t +{ + /* The path to save the downloaded file */ + MB_String saved_path; + + /** The type of file storages e.g. + * esp_mail_file_storage_type_none, + * esp_mail_file_storage_type_flash, and + * esp_mail_file_storage_type_sd + */ + esp_mail_file_storage_type type = esp_mail_file_storage_type_flash; +}; + +struct esp_mail_imap_search_config_t +{ + /* The search criteria */ + MB_String criteria; + + /* The option to search the unseen message */ + bool unseen_msg = false; +}; + +struct esp_mail_imap_sequence_set_t +{ + /* The sequence set string i.g., unique identifier (UID) or message sequence number or ranges of UID or sequence number */ + MB_String string; + + /* The option for sequenceSet whether it is UID or message sequence number */ + bool UID = false; + + /* The option for header only fetching */ + bool headerOnly = false; +}; + +struct esp_mail_imap_fetch_config_t +{ + /* The UID of message to fetch */ + MB_String uid; + + /* The message sequence number to fetch */ + MB_String number; + + /* The sequence set options */ + esp_mail_imap_sequence_set_t sequence_set; + + /* Set the message flag as seen */ + bool set_seen = false; + + /* The int32_t option for CHANGESINCE conditional test. */ + int32_t modsequence = 0; + + /* The config to fetch only the header */ + bool headerOnly = false; +}; + +struct esp_mail_imap_firmware_config_t +{ + /* Update firmware using message attachments if one of its filename matches. */ + MB_String attach_filename; + + /* Save firmware file */ + bool save_to_file = false; +}; + +struct esp_mail_imap_data_config_t +{ + /* The config for fetching */ + struct esp_mail_imap_fetch_config_t fetch; + + /* The config for search */ + struct esp_mail_imap_search_config_t search; + + /* The config about the limits */ + struct esp_mail_imap_limit_config_t limit; + + /* The config to enable the features */ + struct esp_mail_imap_enable_config_t enable; + + /* The config about downloads */ + struct esp_mail_imap_download_config_t download; + + /* The config about the storage and path to save the downloaded file */ + struct esp_mail_imap_storage_config_t storage; + + /* The config about firmware updates and downloads for ESP32, ESP8266 and Raspberry Pi Pico */ + struct esp_mail_imap_firmware_config_t firmware_update; + + IMAP_Identification identification; +}; + +/* Mail and MIME Header Fields */ +struct esp_mail_imap_msg_item_t +{ + friend class IMAPSession; + +public: + esp_mail_imap_msg_item_t() + { + text.content_type = mimeinfo[esp_mail_file_extension_txt].mimeType; + html.content_type = mimeinfo[esp_mail_file_extension_html].mimeType; + }; + + /* The message number */ + int msgNo = 0; + + /* The message UID */ + int UID = 0; + + /* The message identifier (RFC 4021) */ + const char *ID = ""; + + /* The language(s) for auto-responses (RFC 4021) */ + const char *acceptLang = ""; + + /* The language of message content (RFC 4021) */ + const char *contentLang = ""; + + /* The mailbox of message author (RFC 4021) */ + const char *from = ""; + + /* The charset of the mailbox of message author */ + // deprecated + const char *fromCharset = ""; + + /* The primary recipient mailbox (RFC 4021) */ + const char *to = ""; + + /* The charset of the primary recipient mailbox */ + // deprecated + const char *toCharset = ""; + + /* The Carbon-copy recipient mailboxes (RFC 4021) */ + const char *cc = ""; + + /* The charset of the Carbon-copy recipient mailbox header */ + // deprecated + const char *ccCharset = ""; + + /* The Blind-carbon-copy recipient mailboxes (RFC 4021) */ + const char *bcc = ""; + + /* The charset of the Blind-carbon-copy recipient mailbox header */ + // deprecated + const char *bccCharset = ""; + + /* The message date and time (RFC 4021) */ + const char *date = ""; + + /* The topic of message (RFC 4021) */ + const char *subject = ""; + + /* The topic of message charset */ + // deprecated + const char *subjectCharset = ""; + + /* The message flags */ + const char *flags = ""; + + /* The PLAIN text content of the message */ + esp_mail_imap_plain_body_t text; + + /* The HTML content of the message */ + esp_mail_imap_html_body_t html; + + /* rfc822 related */ + + /* The sender Email */ + const char *sender; + + /* The charset of the sender Email */ + // deprecated + const char *senderCharset = ""; + + /* The keywords or phrases, separated by commas */ + const char *keywords = ""; + + /* The comments about message */ + const char *comments = ""; + + /* The field that contains the parent's message ID of the message to which this one is a reply */ + const char *in_reply_to = ""; + + /* The field that contains the parent's references (if any) and followed by the parent's message ID (if any) of the message to which this one is a reply */ + const char *references = ""; + + /* The return recipient of the message */ + const char *return_path = ""; + + /* The Email address to reply */ + const char *reply_to; + + /* The error description from fetching the message */ + const char *fetchError = ""; + + /* The info about the attachments in the message */ + _vectorImpl attachments; + + /* The info about the rfc822 messages included in the message */ + _vectorImpl rfc822; + + /* The status for message that contains attachment */ + bool hasAttachment = false; + +private: + void setRFC822Headers(struct esp_mail_imap_rfc822_msg_header_item_t *rfc822_header) + { + from = rfc822_header->header_items[esp_mail_rfc822_header_field_from].c_str(); + sender = rfc822_header->header_items[esp_mail_rfc822_header_field_sender].c_str(); + to = rfc822_header->header_items[esp_mail_rfc822_header_field_to].c_str(); + cc = rfc822_header->header_items[esp_mail_rfc822_header_field_cc].c_str(); + subject = rfc822_header->header_items[esp_mail_rfc822_header_field_subject].c_str(); + date = rfc822_header->header_items[esp_mail_rfc822_header_field_date].c_str(); + ID = rfc822_header->header_items[esp_mail_rfc822_header_field_msg_id].c_str(); + return_path = rfc822_header->header_items[esp_mail_rfc822_header_field_return_path].c_str(); + reply_to = rfc822_header->header_items[esp_mail_rfc822_header_field_reply_to].c_str(); + in_reply_to = rfc822_header->header_items[esp_mail_rfc822_header_field_in_reply_to].c_str(); + references = rfc822_header->header_items[esp_mail_rfc822_header_field_references].c_str(); + comments = rfc822_header->header_items[esp_mail_rfc822_header_field_comments].c_str(); + keywords = rfc822_header->header_items[esp_mail_rfc822_header_field_keywords].c_str(); + bcc = rfc822_header->header_items[esp_mail_rfc822_header_field_bcc].c_str(); + flags = rfc822_header->header_items[esp_mail_rfc822_header_field_flags].c_str(); + text.charSet = ""; + text.content_type = ""; + text.transfer_encoding = ""; + html.charSet = ""; + html.content_type = ""; + html.transfer_encoding = ""; + } +}; + +struct esp_mail_imap_msg_list_t +{ + /* The info of a message */ + _vectorImpl msgItems; +}; + +struct esp_mail_imap_multipart_level_t +{ + uint8_t level = 0; + bool fetch_rfc822_header = false; + bool append_body_text = false; +}; + +struct esp_mail_imap_response_data +{ +public: + esp_mail_imap_response_status imapResp = esp_mail_imap_resp_unknown; + char *response = nullptr; + int readLen = 0; + long dataTime = millis(); + int chunkBufSize = 512; + int chunkIdx = 0; + bool isUntaggedResponse = false; + bool untaggedRespCompleted = false; + bool completedResponse = false; + bool endSearch = false; + struct esp_mail_message_header_t header; + struct esp_mail_message_part_info_t part; + MB_String filePath; + bool downloadRequest = false; + int octetCount = 0; + int octetLength = 0; + bool tmo = false; + int headerState = 0; + int searchCount = 0; + char *lastBuf = nullptr; + char *buf = nullptr; + + esp_mail_imap_response_data(int bufLen) { chunkBufSize = bufLen; }; + ~esp_mail_imap_response_data() { clear(); } + void clear() + { + if (response) + free(response); + if (lastBuf) + free(lastBuf); + if (buf) + free(buf); + + response = nullptr; + lastBuf = nullptr; + buf = nullptr; + } +}; + +#endif + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + +struct esp_mail_link_internal_t +{ + MB_String cid; +}; + +struct esp_mail_sesson_cert_config_t +{ + /* The certificate data (base64 data) */ + const char *cert_data = NULL; + + /* The certificate file (DER format) */ + MB_String cert_file; + + /* The storage type */ + esp_mail_file_storage_type cert_file_storage_type; + + /* The cerificate verification option */ + bool verify = false; +}; + +struct esp_mail_smtp_logs_config_t +{ + + /* The log file path */ + MB_String filename; + + /* The storage type */ + esp_mail_file_storage_type storage_type; +}; + +struct esp_mail_sesson_sever_config_t +{ + /* The hostName of the server */ + MB_String host_name; + /* The port on the server to connect to */ + uint16_t port = 0; +}; + +/* The log in credentials */ +struct esp_mail_sesson_login_config_t +{ + /* The user Email address to log in */ + MB_String email; + + /* The user password to log in */ + MB_String password; + + /* The OAuth2.0 access token to log in */ + MB_String accessToken; + + /* The host name or public IP of client system */ + MB_String user_domain; +}; + +/* The device time config */ +struct esp_mail_sesson_time_config_t +{ + /* set the NTP servers (use comma to separate the servers) to let the library to set the time from NTP server */ + MB_String ntp_server; + + /* the GMT offset or time zone */ + float gmt_offset = 0; + + /* the day light saving offset */ + float day_light_offset = 0; + + /** TZ environment variable for local time setting + * See https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv + */ + MB_String timezone_env_string; + + /* the file path to store TZ environment variable */ + MB_String timezone_file = "/tze.txt"; +}; + +struct esp_mail_sesson_secure_config_t +{ + /** The option (obsoleted) to send the SMTP and IMAP commands to start the TLS connection rfc2595 section 3 and rfc3207 */ + bool startTLS = false; + + /* The secure connection mode preference */ + esp_mail_secure_mode mode = esp_mail_secure_mode_undefined; +}; + +struct esp_mail_spi_ethernet_module_t +{ +#if defined(ESP8266) && defined(ESP8266_CORE_SDK_V3_X_X) +#ifdef INC_ENC28J60_LWIP + ENC28J60lwIP *enc28j60 = nullptr; +#endif +#ifdef INC_W5100_LWIP + Wiznet5100lwIP *w5100 = nullptr; +#endif +#ifdef INC_W5500_LWIP + Wiznet5500lwIP *w5500 = nullptr; +#endif +#elif defined(MB_ARDUINO_PICO) + +#endif +}; + +struct esp_mail_session_config_t +{ + friend class IMAPSession; + friend class SMTPSession; + friend class ESP_Mail_Client; + + /* The server config */ + struct esp_mail_sesson_sever_config_t server; + + /* The log in config */ + struct esp_mail_sesson_login_config_t login; + + /* The device time config */ + struct esp_mail_sesson_time_config_t time; + + /* The secure config */ + struct esp_mail_sesson_secure_config_t secure; + + /* The certificate config */ + struct esp_mail_sesson_cert_config_t certificate; + + /* SPI Ethernet Module config for ESP8266 */ + struct esp_mail_spi_ethernet_module_t spi_ethernet_module; + + /* The callback function for WiFi connection */ + NetworkConnectionHandler network_connection_handler = NULL; + + /* specific ports and its protocols */ + struct esp_mail_ports_functions ports_functions; + + /* The mail sending logs config */ + struct esp_mail_smtp_logs_config_t sentLogs; + +public: + esp_mail_session_config_t(){}; + + ~esp_mail_session_config_t() + { + clear(); + aremovePtr(); + } + + void addPtr(_vectorImpl *listPtr, int ptr) + { + if (listPtr) + { + this->listPtr = listPtr; + bool existed = false; + + for (size_t i = 0; i < this->listPtr->size(); i++) + { + if ((*this->listPtr)[i] == ptr) + existed = true; + } + + if (!existed) + this->listPtr->push_back(ptr); + } + } + + void aremovePtr() + { + if (listPtr) + { + int ptr = toAddr(*this); + for (size_t i = 0; i < listPtr->size(); i++) + { + if ((*listPtr)[i] == ptr) + { + listPtr->erase(listPtr->begin() + i, listPtr->begin() + i + 1); + break; + } + } + } + } + + void clear() + { + server.host_name.clear(); + server.port = 0; + + secure.startTLS = false; + secure.mode = esp_mail_secure_mode_undefined; + + login.email.clear(); + login.password.clear(); + login.user_domain.clear(); + login.accessToken.clear(); + + time.day_light_offset = 0; + time.gmt_offset = 0; + time.ntp_server.clear(); + time.timezone_env_string.clear(); + + certificate.cert_data = ""; + certificate.cert_file = ""; + certificate.cert_file_storage_type = esp_mail_file_storage_type_none; + certificate.verify = false; + + clearPorts(); + } + +private: + int cert_ptr = 0; + bool cert_updated = false; + _vectorImpl *listPtr = nullptr; + + // Internal flags use to keep user sercure.startTLS and secure.mode. + bool int_start_tls = false; + esp_mail_secure_mode int_mode = esp_mail_secure_mode_undefined; + + void clearPorts() + { + if (ports_functions.list) + { + if (ports_functions.use_internal_list) + { + ports_functions.size = 0; + ports_functions.use_internal_list = false; + delete[] ports_functions.list; + ports_functions.list = nullptr; + } + } + } +}; + +/** The content transfer encoding + * enc_7bit or "7bit" + * enc_qp or "quoted-printable" + * enc_base64 or "base64" + * enc_binary or "binary" + * enc_8bit or "8bit" + */ +typedef struct esp_mail_transfer_encoding_t Content_Transfer_Encoding; + +/* The session configuations */ +typedef struct esp_mail_session_config_t ESP_Mail_Session; // obsoleted +typedef struct esp_mail_session_config_t Session_Config; + +#endif + +#if defined(ENABLE_SMTP) +/* The result from sending the Email */ +typedef struct esp_mail_smtp_send_status_t SMTP_Result; + +/* The attachment details for sending the Email */ +typedef struct esp_mail_attachment_t SMTP_Attachment; +#endif + +#if defined(ENABLE_SMTP) && defined(ENABLE_IMAP) + +typedef struct esp_mail_attachment_t ESP_Mail_Attachment; + +#endif + +#if defined(ENABLE_IMAP) +/* The info of the selected or open mailbox folder e.g. name, attributes and + * delimiter */ +typedef struct esp_mail_folder_info_item_t FolderInfo; +/* The attachment item details for a message which returned from fetching the + * Email */ +typedef struct esp_mail_attachment_info_t IMAP_Attach_Item; + +/** The IMAP operation configuations */ +typedef struct esp_mail_imap_data_config_t IMAP_Config; // obsoleted + +typedef struct esp_mail_imap_data_config_t IMAP_Data; + +/* The message item data of the IMAP_MSG_List which contains header, body and + * attachments info for eacch message*/ +typedef struct esp_mail_imap_msg_item_t IMAP_MSG_Item; + +/* The list that contains the message items from searching or fetching the Email + */ +typedef struct esp_mail_imap_msg_list_t IMAP_MSG_List; + +#endif + +struct esp_mail_wifi_credential_t +{ + MB_String ssid; + MB_String password; +}; + +struct esp_mail_wifi_credentials_t +{ + friend class ESP_Mail_Client; + friend class ESP_Mail_TCPClient; + +public: + esp_mail_wifi_credentials_t(){}; + ~esp_mail_wifi_credentials_t() + { + clearAP(); + clearMulti(); + }; + void addAP(const String &ssid, const String &password) + { + esp_mail_wifi_credential_t cred; + cred.ssid = ssid; + cred.password = password; + credentials.push_back(cred); + } + void clearAP() + { + credentials.clear(); + } + +private: + _vectorImpl credentials; +#if defined(ESP_MAIL_HAS_WIFIMULTI) + WiFiMulti *multi = nullptr; +#endif + + void reconnect() + { + if (credentials.size()) + { + disconnect(); + connect(); + } + } + + void connect() + { +#if defined(ESP_MAIL_HAS_WIFIMULTI) + + clearMulti(); + multi = new WiFiMulti(); + for (size_t i = 0; i < credentials.size(); i++) + multi->addAP(credentials[i].ssid.c_str(), credentials[i].password.c_str()); + + if (credentials.size() > 0) + multi->run(); + +#elif defined(ESP_MAIL_WIFI_IS_AVAILABLE) + WiFi.begin((CONST_STRING_CAST)credentials[0].ssid.c_str(), credentials[0].password.c_str()); +#endif + } + + void disconnect() + { +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) + WiFi.disconnect(); +#endif + } + + void clearMulti() + { +#if defined(ESP_MAIL_HAS_WIFIMULTI) + if (multi) + delete multi; + multi = nullptr; +#endif + } +}; + +static const char esp_mail_imap_tag_str[] PROGMEM = "xmail"; + +#if !defined(SILENT_MODE) +static const char esp_mail_version_str[] PROGMEM = "ESP Mail Client v"; + +///////////////////////// +// SMTP debug string + +static const char esp_mail_dbg_str_1[] PROGMEM = "send command, STARTTLS"; +static const char esp_mail_dbg_str_2[] PROGMEM = "connecting to SMTP server"; + +#if defined(ENABLE_SMTP) +static const char esp_mail_dbg_str_3[] PROGMEM = "send Email"; +static const char esp_mail_dbg_str_4[] PROGMEM = "SMTP server connected"; +static const char esp_mail_dbg_str_5[] PROGMEM = "send SMTP command, EHLO"; +static const char esp_mail_dbg_str_6[] PROGMEM = "send SMTP command, AUTH LOGIN"; +static const char esp_mail_dbg_str_7[] PROGMEM = "send SMTP command, AUTH PLAIN"; +static const char esp_mail_dbg_str_8[] PROGMEM = "send message header"; +static const char esp_mail_dbg_str_9[] PROGMEM = "send message body"; +static const char esp_mail_dbg_str_10[] PROGMEM = "send attachments"; +static const char esp_mail_dbg_str_11[] PROGMEM = "terminate the SMTP session"; +static const char esp_mail_dbg_str_12[] PROGMEM = "message sent successfully"; +static const char esp_mail_dbg_str_13[] PROGMEM = "send next Email"; +static const char esp_mail_dbg_str_14[] PROGMEM = "send inline data"; +static const char esp_mail_dbg_str_15[] PROGMEM = "send smtp command, AUTH XOAUTH2"; +static const char esp_mail_dbg_str_16[] PROGMEM = "finishing the message sending"; +static const char esp_mail_dbg_str_17[] PROGMEM = "No ESMTP supported, send SMTP command, HELO"; +#endif + +///////////////////////// +// IMAP debug string +static const char esp_mail_dbg_str_18[] PROGMEM = "connecting to IMAP server"; +static const char esp_mail_dbg_str_19[] PROGMEM = "Host > "; +static const char esp_mail_dbg_str_20[] PROGMEM = "Port > "; +static const char esp_mail_dbg_str_21[] PROGMEM = "Reading time from NTP server"; +static const char esp_mail_dbg_str_22[] PROGMEM = "perform SSL/TLS handshake"; + +#if defined(ENABLE_IMAP) +static const char esp_mail_dbg_str_23[] PROGMEM = "get my ACL"; +static const char esp_mail_dbg_str_24[] PROGMEM = "checking the capability"; +static const char esp_mail_dbg_str_25[] PROGMEM = "fetching message "; +static const char esp_mail_dbg_str_26[] PROGMEM = "fetch message header"; +static const char esp_mail_dbg_str_27[] PROGMEM = "fetch body part header, "; +static const char esp_mail_dbg_str_28[] PROGMEM = "fetch body sub part header, "; +static const char esp_mail_dbg_str_29[] PROGMEM = "finished reading Email"; +static const char esp_mail_dbg_str_30[] PROGMEM = "UID is "; +static const char esp_mail_dbg_str_31[] PROGMEM = "log out completed"; +static const char esp_mail_dbg_str_32[] PROGMEM = "closing the "; +static const char esp_mail_dbg_str_33[] PROGMEM = "IMAP server connected"; +static const char esp_mail_dbg_str_34[] PROGMEM = "send IMAP command, LOGIN"; +static const char esp_mail_dbg_str_35[] PROGMEM = "send IMAP command, LIST"; +static const char esp_mail_dbg_str_36[] PROGMEM = "searching messages"; +static const char esp_mail_dbg_str_37[] PROGMEM = "send IMAP command, FETCH"; +static const char esp_mail_dbg_str_38[] PROGMEM = "send IMAP command, LOGOUT"; +static const char esp_mail_dbg_str_39[] PROGMEM = "message fetching completed"; +static const char esp_mail_dbg_str_40[] PROGMEM = "opening the mailbox folder"; +static const char esp_mail_dbg_str_41[] PROGMEM = "setting FLAG"; +static const char esp_mail_dbg_str_42[] PROGMEM = "adding FLAG"; +static const char esp_mail_dbg_str_43[] PROGMEM = "removing FLAG"; +static const char esp_mail_dbg_str_44[] PROGMEM = "send IMAP command, AUTHENTICATE PLAIN"; +static const char esp_mail_dbg_str_45[] PROGMEM = "send IMAP command, AUTH XOAUTH2"; +static const char esp_mail_dbg_str_46[] PROGMEM = "reading plain TEXT message"; +static const char esp_mail_dbg_str_47[] PROGMEM = "reading HTML message"; +static const char esp_mail_dbg_str_48[] PROGMEM = "copying message(s) to "; +static const char esp_mail_dbg_str_49[] PROGMEM = "creating folder"; +static const char esp_mail_dbg_str_50[] PROGMEM = "deleting folder"; +static const char esp_mail_dbg_str_51[] PROGMEM = "listening to "; +static const char esp_mail_dbg_str_52[] PROGMEM = " folder changes"; +static const char esp_mail_dbg_str_53[] PROGMEM = "polling established"; +static const char esp_mail_dbg_str_54[] PROGMEM = "Mailbox listening stopped"; +static const char esp_mail_dbg_str_55[] PROGMEM = "renaming folder"; +static const char esp_mail_dbg_str_56[] PROGMEM = "send IMAP command, LSUB"; +static const char esp_mail_dbg_str_57[] PROGMEM = "send IMAP command, SUBSCRIBE"; +static const char esp_mail_dbg_str_58[] PROGMEM = "send IMAP command, UNSUBSCRIBE"; +static const char esp_mail_dbg_str_59[] PROGMEM = "moving message(s) to "; +static const char esp_mail_dbg_str_60[] PROGMEM = "send IMAP command, GETQUOTA"; +static const char esp_mail_dbg_str_61[] PROGMEM = "send IMAP command, SETQUOTA"; +static const char esp_mail_dbg_str_62[] PROGMEM = "send IMAP command, GETQUOTAROOT"; +static const char esp_mail_dbg_str_63[] PROGMEM = "send IMAP command, GETACL"; +static const char esp_mail_dbg_str_64[] PROGMEM = "send IMAP command, SETACL"; +static const char esp_mail_dbg_str_65[] PROGMEM = "send IMAP command, DELETEACL"; +static const char esp_mail_dbg_str_66[] PROGMEM = "send IMAP command, MYRIGHTS"; +static const char esp_mail_dbg_str_67[] PROGMEM = "send IMAP command, NAMESPACE"; +static const char esp_mail_dbg_str_68[] PROGMEM = "selecting the "; +static const char esp_mail_dbg_str_69[] PROGMEM = "appending message"; +static const char esp_mail_dbg_str_70[] PROGMEM = "download attachment %d of %d"; +static const char esp_mail_dbg_str_71[] PROGMEM = "download HTML message"; +static const char esp_mail_dbg_str_72[] PROGMEM = "deleting the ACL"; +static const char esp_mail_dbg_str_73[] PROGMEM = "message append successfully"; +static const char esp_mail_dbg_str_74[] PROGMEM = "download plain TEXT message"; +static const char esp_mail_dbg_str_75[] PROGMEM = "deleting message(s)"; +static const char esp_mail_dbg_str_76[] PROGMEM = "check the capability"; +static const char esp_mail_dbg_str_77[] PROGMEM = "get the ACL"; +static const char esp_mail_dbg_str_78[] PROGMEM = "set the ACL"; +static const char esp_mail_dbg_str_79[] PROGMEM = "get UID"; +static const char esp_mail_dbg_str_80[] PROGMEM = "get Flags"; +static const char esp_mail_dbg_str_81[] PROGMEM = "delete folder"; +static const char esp_mail_dbg_str_82[] PROGMEM = "send IMAP command, ID"; +static const char esp_mail_dbg_str_83[] PROGMEM = "send IMAP command, NOOP"; +#endif + +///////////////////////// +// SMTP callback string + +static const char esp_mail_cb_str_1[] PROGMEM = "Connecting to SMTP server..."; +static const char esp_mail_cb_str_2[] PROGMEM = "Sending STARTTLS command..."; + +#if defined(ENABLE_SMTP) +static const char esp_mail_cb_str_3[] PROGMEM = "Sending greeting response..."; +static const char esp_mail_cb_str_4[] PROGMEM = "Sending message header..."; +static const char esp_mail_cb_str_5[] PROGMEM = "Sending message body..."; +static const char esp_mail_cb_str_6[] PROGMEM = "Sending attachments..."; +static const char esp_mail_cb_str_7[] PROGMEM = "Closing the session..."; +static const char esp_mail_cb_str_8[] PROGMEM = "Sending inline data..."; +static const char esp_mail_cb_str_9[] PROGMEM = "Sending Email..."; +static const char esp_mail_cb_str_10[] PROGMEM = "Sending next Email..."; +static const char esp_mail_cb_str_11[] PROGMEM = "Finishing the message sending..."; +static const char esp_mail_cb_str_12[] PROGMEM = "SMTP server connected, wait for greeting..."; +static const char esp_mail_cb_str_13[] PROGMEM = "Message sent successfully"; +#endif + +///////////////////////// +// IMAP callback string + +static const char esp_mail_cb_str_14[] PROGMEM = "Logging in..."; // shared with SMTP +static const char esp_mail_cb_str_15[] PROGMEM = "Connecting to IMAP server..."; + +#if defined(ENABLE_IMAP) + +static const char esp_mail_cb_str_16[] PROGMEM = "Reading the list of mailboxes..."; +static const char esp_mail_cb_str_17[] PROGMEM = "Checking the capability..."; +static const char esp_mail_cb_str_18[] PROGMEM = "Searching messages..."; +static const char esp_mail_cb_str_19[] PROGMEM = "Downloading attachments..."; +static const char esp_mail_cb_str_20[] PROGMEM = "Logging out..."; +static const char esp_mail_cb_str_21[] PROGMEM = "Saving message header to file..."; +static const char esp_mail_cb_str_22[] PROGMEM = "Get FLAG..."; +static const char esp_mail_cb_str_23[] PROGMEM = "Removing FLAG..."; +static const char esp_mail_cb_str_24[] PROGMEM = "Adding FLAG..."; +static const char esp_mail_cb_str_25[] PROGMEM = "Get UID..."; +static const char esp_mail_cb_str_26[] PROGMEM = "Setting FLAG..."; +static const char esp_mail_cb_str_27[] PROGMEM = "Closing the mailbox folder..."; +static const char esp_mail_cb_str_28[] PROGMEM = "Reading messages..."; +static const char esp_mail_cb_str_29[] PROGMEM = "Listening to mailbox changes..."; +static const char esp_mail_cb_str_30[] PROGMEM = "Listing the subscribed mailboxes..."; +static const char esp_mail_cb_str_31[] PROGMEM = "Subscribe mailbox..."; +static const char esp_mail_cb_str_32[] PROGMEM = "Unsubscribe mailbox..."; +static const char esp_mail_cb_str_33[] PROGMEM = "Get quota root resource usage and limit..."; +static const char esp_mail_cb_str_34[] PROGMEM = "Set quota root resource usage and limit..."; +static const char esp_mail_cb_str_35[] PROGMEM = "Get the list of quota roots..."; +static const char esp_mail_cb_str_36[] PROGMEM = "Get the ACL..."; +static const char esp_mail_cb_str_37[] PROGMEM = "Setting the ACL..."; +static const char esp_mail_cb_str_38[] PROGMEM = "Deleting the ACL..."; +static const char esp_mail_cb_str_39[] PROGMEM = "Get my ACL..."; +static const char esp_mail_cb_str_40[] PROGMEM = "Get namespace..."; +static const char esp_mail_cb_str_41[] PROGMEM = "Enable capability..."; +static const char esp_mail_cb_str_42[] PROGMEM = "Updating firmware..."; +static const char esp_mail_cb_str_43[] PROGMEM = "Downloading messages..."; +static const char esp_mail_cb_str_44[] PROGMEM = "Appending message..."; +static const char esp_mail_cb_str_45[] PROGMEM = "Message append successfully"; +static const char esp_mail_cb_str_46[] PROGMEM = "Finished reading Email"; +static const char esp_mail_cb_str_47[] PROGMEM = "Log out completed"; +static const char esp_mail_cb_str_48[] PROGMEM = "IMAP server connected"; +static const char esp_mail_cb_str_49[] PROGMEM = "Polling established"; +static const char esp_mail_cb_str_50[] PROGMEM = "Mailbox listening stopped"; +static const char esp_mail_cb_str_51[] PROGMEM = "Open the mailbox folder..."; +static const char esp_mail_cb_str_52[] PROGMEM = "Checking the capability..."; +static const char esp_mail_cb_str_53[] PROGMEM = "Renaming folder..."; +static const char esp_mail_cb_str_54[] PROGMEM = "UID is "; +static const char esp_mail_cb_str_55[] PROGMEM = "Get Flags..."; +static const char esp_mail_cb_str_56[] PROGMEM = "Deleting folder..."; +static const char esp_mail_cb_str_57[] PROGMEM = "Deleting message(s)..."; +static const char esp_mail_cb_str_58[] PROGMEM = "Copying message(s)..."; +static const char esp_mail_cb_str_59[] PROGMEM = "Creating folder..."; +static const char esp_mail_cb_str_60[] PROGMEM = "Moving message(s)..."; +static const char esp_mail_cb_str_61[] PROGMEM = "Send client identification..."; +static const char esp_mail_cb_str_62[] PROGMEM = "Send noop..."; +#endif + +#endif + +///////////////////////// +// Mem error string + +#if defined(ENABLE_ERROR_STRING) || !defined(SILENT_MODE) +#if defined(MBFS_FLASH_FS) || defined(MBFS_SD_FS) +static const char esp_mail_error_mem_str_1[] PROGMEM = "flash Storage is not ready."; +static const char esp_mail_error_mem_str_2[] PROGMEM = "SD Storage is not ready."; +static const char esp_mail_error_mem_str_3[] PROGMEM = "file does not exist or can't access"; +#endif +static const char esp_mail_error_mem_str_4[] PROGMEM = "PSRAM was enabled but not detected."; +#endif + +#if defined(ENABLE_ERROR_STRING) + +#if defined(MBFS_FLASH_FS) || defined(MBFS_SD_FS) +static const char esp_mail_error_mem_str_5[] PROGMEM = "file is still opened."; +static const char esp_mail_error_mem_str_6[] PROGMEM = "file not found."; +static const char esp_mail_error_mem_str_7[] PROGMEM = "file I/O error"; +#endif + +static const char esp_mail_error_mem_str_8[] PROGMEM = "out of memory"; +static const char esp_mail_error_mem_str_9[] PROGMEM = "buffer overflow"; + +#endif + +#if defined(MB_ARDUINO_PICO) +#if defined(ENABLE_ERROR_STRING) || !defined(SILENT_MODE) +static const char esp_mail_error_mem_str_10[] PROGMEM = "please make sure that the size of flash filesystem is not 0 in Pico."; +#endif +#endif + +///////////////////////// +// Client error string + +#if !defined(SILENT_MODE) +static const char esp_mail_error_client_str_1[] PROGMEM = "client and/or necessary callback functions are not yet assigned"; +static const char esp_mail_error_client_str_2[] PROGMEM = "network connection callback is required"; +static const char esp_mail_error_client_str_3[] PROGMEM = "network connection status callback is required"; +static const char esp_mail_error_client_str_4[] PROGMEM = "NTP server time reading cannot begin when valid time is required because of no WiFi capability/activity detected."; +static const char esp_mail_error_client_str_5[] PROGMEM = "Please set the library reference time manually using smtp.setSystemTime or imap.setSystemTime."; +#endif + +///////////////////////// +// Network error string + +#if !defined(SILENT_MODE) +static const char esp_mail_error_network_str_1[] PROGMEM = "unable to connect to server"; +#if defined(ENABLE_ERROR_STRING) +static const char esp_mail_error_network_str_2[] PROGMEM = "NTP server time reading timed out"; +static const char esp_mail_error_network_str_3[] PROGMEM = "response read timed out"; +static const char esp_mail_error_network_str_4[] PROGMEM = "not connected"; +static const char esp_mail_error_network_str_5[] PROGMEM = "connection timeout"; +static const char esp_mail_error_network_str_6[] PROGMEM = "connection closed"; +static const char esp_mail_error_network_str_7[] PROGMEM = "connection refused"; +static const char esp_mail_error_network_str_8[] PROGMEM = "data sending failed"; +#endif +#endif + +#if defined(ENABLE_ERROR_STRING) || !defined(SILENT_MODE) +static const char esp_mail_error_network_str_9[] PROGMEM = "response read timed out"; +#endif + +///////////////////////// +// SSL error string + +#if defined(ENABLE_ERROR_STRING) +static const char esp_mail_error_ssl_str_1[] PROGMEM = "fail to set up the SSL/TLS structure"; +#endif +#if defined(ENABLE_ERROR_STRING) || !defined(SILENT_MODE) +static const char esp_mail_error_ssl_str_2[] PROGMEM = "the alert SSL record received"; +static const char esp_mail_error_ssl_str_3[] PROGMEM = "make sure the SSL/TLS handshake was done before sending the data"; +#endif + +///////////////////////// +// Auth error string + +#if defined(ENABLE_ERROR_STRING) +static const char esp_mail_error_auth_str_1[] PROGMEM = "the provided SASL authentication mechanism is not support"; +static const char esp_mail_error_auth_str_2[] PROGMEM = "OAuth2.0 log in was disabled for this server"; +static const char esp_mail_error_auth_str_3[] PROGMEM = "not yet log in"; +#endif + +///////////////////////// +// Session error string + +#if defined(ENABLE_ERROR_STRING) +static const char esp_mail_error_session_str_1[] PROGMEM = "the Session_Config object was not assigned"; +#endif + +///////////////////////// +// Time error string +#if defined(ENABLE_ERROR_STRING) +static const char esp_mail_error_time_str_1[] PROGMEM = "library or device time was not set, see examples/SMTP/Set_Time.ino for manually time setting"; +#endif + +///////////////////////// +// SMTP error string +#if defined(ENABLE_SMTP) +#if defined(ENABLE_ERROR_STRING) +static const char esp_mail_error_smtp_str_1[] PROGMEM = "SMTP server greeting failed"; +static const char esp_mail_error_smtp_str_2[] PROGMEM = "authentication failed"; +static const char esp_mail_error_smtp_str_3[] PROGMEM = "login password is not valid"; +static const char esp_mail_error_smtp_str_4[] PROGMEM = "send header failed"; +static const char esp_mail_error_smtp_str_5[] PROGMEM = "send body failed"; +static const char esp_mail_error_smtp_str_7[] PROGMEM = "sender Email address is not valid"; +static const char esp_mail_error_smtp_str_8[] PROGMEM = "some of the recipient Email address is not valid"; +static const char esp_mail_error_smtp_str_9[] PROGMEM = "set recipient failed"; +static const char esp_mail_error_smtp_str_10[] PROGMEM = "send custom command failed"; +static const char esp_mail_error_smtp_str_11[] PROGMEM = "XOAuth2 authenticate failed"; +static const char esp_mail_error_smtp_str_12[] PROGMEM = "undefined error"; +#endif +#endif + +///////////////////////// +// IMAP error string +#if defined(ENABLE_IMAP) +#if defined(ENABLE_ERROR_STRING) +static const char esp_mail_error_imap_str_1[] PROGMEM = "fail to list the mailboxes"; +static const char esp_mail_error_imap_str_2[] PROGMEM = "fail to check the capabilities"; + +static const char esp_mail_error_imap_str_3[] PROGMEM = "fail to close the mailbox"; + +static const char esp_mail_error_imap_str_4[] PROGMEM = "fail to open the mailbox"; +static const char esp_mail_error_imap_str_5[] PROGMEM = "some of the requested messages no longer exist"; +static const char esp_mail_error_imap_str_6[] PROGMEM = "firmware update initialization failed"; +static const char esp_mail_error_imap_str_7[] PROGMEM = "firmware update write failed"; +static const char esp_mail_error_imap_str_8[] PROGMEM = "firmware update finalize failed"; + +#endif +#if defined(ENABLE_ERROR_STRING) || !defined(SILENT_MODE) +static const char esp_mail_error_imap_str_9[] PROGMEM = "no messages found for the specified search criteria"; +static const char esp_mail_error_imap_str_10[] PROGMEM = "no search criteria provided, then fetching the latest message"; +static const char esp_mail_error_imap_str_11[] PROGMEM = "no mailbox opened"; +static const char esp_mail_error_imap_str_12[] PROGMEM = "no content"; +static const char esp_mail_error_imap_str_13[] PROGMEM = "this feature was not supported"; +static const char esp_mail_error_imap_str_14[] PROGMEM = "no message changed since (assigned) modsec"; +static const char esp_mail_error_imap_str_15[] PROGMEM = "CONDSTORE was not supported or modsec was not supported for selected mailbox"; +static const char esp_mail_error_imap_str_17[] PROGMEM = "could not parse command"; +static const char esp_mail_error_imap_str_18[] PROGMEM = "server disconnected or returned error"; +static const char esp_mail_error_imap_str_19[] PROGMEM = "authenticate failed"; +static const char esp_mail_error_imap_str_20[] PROGMEM = "flags or keywords store failed"; +static const char esp_mail_error_imap_str_21[] PROGMEM = "server is not support OAuth2 login"; +#endif +#endif + +///////////////////////// +// General use string +static const char esp_mail_str_1[] PROGMEM = "127.0.0.1"; +static const char esp_mail_str_2[] PROGMEM = " "; +static const char esp_mail_str_3[] PROGMEM = "*"; +static const char esp_mail_str_4[] PROGMEM = "High"; +static const char esp_mail_str_5[] PROGMEM = "Normal"; +static const char esp_mail_str_6[] PROGMEM = "Low"; +static const char esp_mail_str_7[] PROGMEM = "="; +static const char esp_mail_str_8[] PROGMEM = ","; +static const char esp_mail_str_9[] PROGMEM = "--"; +static const char esp_mail_str_10[] PROGMEM = "/"; +static const char esp_mail_str_11[] PROGMEM = "\""; +static const char esp_mail_str_12[] PROGMEM = "Error, "; +static const char esp_mail_str_13[] PROGMEM = "msg.txt"; +static const char esp_mail_str_14[] PROGMEM = "msg.html"; +static const char esp_mail_str_15[] PROGMEM = "flash content message"; +static const char esp_mail_str_16[] PROGMEM = "file content message"; +static const char esp_mail_str_17[] PROGMEM = "cid:"; +static const char esp_mail_str_18[] PROGMEM = "\r\n"; +static const char esp_mail_str_19[] PROGMEM = "<"; +static const char esp_mail_str_20[] PROGMEM = ">"; +static const char esp_mail_str_21[] PROGMEM = "(\"name\" \"ESP Mail Client\" \"version\" \"%s\")"; +static const char esp_mail_str_22[] PROGMEM = "message/rfc822"; +static const char esp_mail_str_23[] PROGMEM = "upload"; +static const char esp_mail_str_24[] PROGMEM = "%"; +static const char esp_mail_str_25[] PROGMEM = "status code: "; +static const char esp_mail_str_26[] PROGMEM = ", text: "; +static const char esp_mail_str_27[] PROGMEM = "."; +static const char esp_mail_str_28[] PROGMEM = "> C: "; +static const char esp_mail_str_29[] PROGMEM = "< S: "; +static const char esp_mail_str_30[] PROGMEM = "! E: "; +static const char esp_mail_str_31[] PROGMEM = "! I: "; +static const char esp_mail_str_32[] PROGMEM = "! W: "; +static const char esp_mail_str_33[] PROGMEM = "#### "; +static const char esp_mail_str_34[] PROGMEM = ":"; +static const char esp_mail_str_35[] PROGMEM = ";"; +static const char esp_mail_str_36[] PROGMEM = "{"; +static const char esp_mail_str_37[] PROGMEM = "}"; +static const char esp_mail_str_38[] PROGMEM = "("; +static const char esp_mail_str_39[] PROGMEM = ")"; +static const char esp_mail_str_40[] PROGMEM = "["; +static const char esp_mail_str_41[] PROGMEM = "]"; +static const char esp_mail_str_42[] PROGMEM = "\r\n"; +static const char esp_mail_str_43[] PROGMEM = "\1\1"; +static const char esp_mail_str_44[] PROGMEM = "{\"status\":"; +static const char esp_mail_str_45[] PROGMEM = "user="; +static const char esp_mail_str_46[] PROGMEM = "\1auth=Bearer "; +static const char esp_mail_str_47[] PROGMEM = "0123456789ABCDEF"; +static const char esp_mail_str_48[] PROGMEM = "<0.0>"; +static const char esp_mail_str_49[] PROGMEM = "<0."; +static const char esp_mail_str_50[] PROGMEM = "Search limit: %d\nFound %d messages\nShow %d messages"; +static const char esp_mail_str_51[] PROGMEM = "1.0"; +static const char esp_mail_str_52[] PROGMEM = "Fetch message %d, UID: %d"; +static const char esp_mail_str_53[] PROGMEM = "Fetch message %d, Number: %d"; +static const char esp_mail_str_54[] PROGMEM = "Attachments (%d)"; +static const char esp_mail_str_55[] PROGMEM = "Free Heap: "; +static const char esp_mail_str_56[] PROGMEM = "content-"; +static const char esp_mail_str_58[] PROGMEM = "format=\"flowed\""; +static const char esp_mail_str_59[] PROGMEM = "format=flowed"; +static const char esp_mail_str_60[] PROGMEM = "delsp=\"yes\""; +static const char esp_mail_str_61[] PROGMEM = "delsp=yes"; +static const char esp_mail_str_62[] PROGMEM = "name"; +static const char esp_mail_str_63[] PROGMEM = "+ "; +static const char esp_mail_str_64[] PROGMEM = "boundary=\""; +static const char esp_mail_str_65[] PROGMEM = "/header.json"; +static const char esp_mail_str_66[] PROGMEM = "/header.txt"; +static const char esp_mail_str_67[] PROGMEM = "{\"Filename\":\""; +static const char esp_mail_str_68[] PROGMEM = "Index: "; +static const char esp_mail_str_69[] PROGMEM = ",\"RFC822\":"; +static const char esp_mail_str_70[] PROGMEM = "\r\n\r\nRFC822:\r\n"; +static const char esp_mail_str_71[] PROGMEM = ",\"Attachments\":{\"Count\":"; +static const char esp_mail_str_72[] PROGMEM = ",\"Files\":["; +static const char esp_mail_str_73[] PROGMEM = "\r\n\r\nAttachments ("; +static const char esp_mail_str_74[] PROGMEM = ")\r\n"; +static const char esp_mail_str_75[] PROGMEM = "]}"; +static const char esp_mail_str_76[] PROGMEM = "{\"Messages\":["; +static const char esp_mail_str_77[] PROGMEM = ",\""; +static const char esp_mail_str_78[] PROGMEM = "{\""; +static const char esp_mail_str_79[] PROGMEM = "\":\""; +static const char esp_mail_str_80[] PROGMEM = "{\"Renamed\":\""; +static const char esp_mail_str_81[] PROGMEM = "\",\"Original\":\""; +static const char esp_mail_str_82[] PROGMEM = "\"}]"; +static const char esp_mail_str_83[] PROGMEM = "_"; +static const char esp_mail_str_84[] PROGMEM = "message"; +static const char esp_mail_str_85[] PROGMEM = "rfc822"; +static const char esp_mail_str_86[] PROGMEM = "/msg"; +static const char esp_mail_str_87[] PROGMEM = "/rfc822_msg"; +static const char esp_mail_str_88[] PROGMEM = "polling established on "; +static const char esp_mail_str_89[] PROGMEM = " folder..."; +static const char esp_mail_str_90[] PROGMEM = "boundary"; +static const char esp_mail_str_91[] PROGMEM = "\\Deleted"; +static const char esp_mail_str_92[] PROGMEM = "Subject: %s"; +static const char esp_mail_str_93[] PROGMEM = "Message sent success: %d"; +static const char esp_mail_str_94[] PROGMEM = "Message sent failed: %d"; +static const char esp_mail_str_95[] PROGMEM = "Status: %s"; +static const char esp_mail_str_96[] PROGMEM = "Date/Time: %s"; +static const char esp_mail_str_97[] PROGMEM = "Recipient: %s"; +static const char esp_mail_str_98[] PROGMEM = "success"; +static const char esp_mail_str_99[] PROGMEM = "failed"; + +#if defined(ENABLE_SMTP) +static const char boundary_table[] PROGMEM = "=_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +#endif + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + +static const unsigned char b64_index_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void __attribute__((used)) +appendDebugTag(MB_String &buf, esp_mail_debug_tag_type type, bool clear, PGM_P text = NULL) +{ + if (clear) + buf.clear(); + + switch (type) + { + case esp_mail_debug_tag_type_client: + buf += esp_mail_str_28; /* "> C: "*/ + break; + case esp_mail_debug_tag_type_server: + buf += esp_mail_str_29; /* "< S: " */ + break; + case esp_mail_debug_tag_type_error: + buf += esp_mail_str_30; /* "! E: "*/ + break; + case esp_mail_debug_tag_type_info: + buf += esp_mail_str_31; /* "! I: "*/ + break; + case esp_mail_debug_tag_type_warning: + buf += esp_mail_str_32; /* "! W: "*/ + break; + default: + break; + } + + if (text != NULL) + buf += text; +} + +static void __attribute__((used)) +yield_impl() +{ +#if defined(ARDUINO_ESP8266_MAJOR) && defined(ARDUINO_ESP8266_MINOR) && defined(ARDUINO_ESP8266_REVISION) && ((ARDUINO_ESP8266_MAJOR == 3 && ARDUINO_ESP8266_MINOR >= 1) || ARDUINO_ESP8266_MAJOR > 3) + esp_yield(); +#else + delay(0); +#endif +} + +// Print debug message w/wo new line to debug port +static void __attribute__((used)) +esp_mail_debug_print(PGM_P msg = "", bool newLine = true) +{ + yield_impl(); + if (newLine) + ESP_MAIL_DEFAULT_DEBUG_PORT.println(msg); + else + ESP_MAIL_DEFAULT_DEBUG_PORT.print(msg); +} + +static void __attribute__((used)) +esp_mail_debug_print_tag(PGM_P msg, esp_mail_debug_tag_type type, bool newLine = true, bool showTag = true) +{ + yield_impl(); + + MB_String s; + if (showTag) + appendDebugTag(s, type, false, msg); + else + s = msg; + + if (newLine) + ESP_MAIL_DEFAULT_DEBUG_PORT.println(s.c_str()); + else + ESP_MAIL_DEFAULT_DEBUG_PORT.print(s.c_str()); +} + +#endif + +typedef void (*ConnectionUpgradeRequestCallback)(void); +typedef void (*NetworkConnectionRequestCallback)(void); +typedef void (*NetworkDisconnectionRequestCallback)(void); +typedef void (*NetworkStatusRequestCallback)(void); +// Optional +typedef void (*ConnectionRequestCallback)(const char *, int); +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Error.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Error.h new file mode 100644 index 000000000..172e7f8d4 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_Error.h @@ -0,0 +1,86 @@ +/** + * Created August 6, 2023 + */ +#pragma once + +#ifndef ESP_MAIL_ERROR_H +#define ESP_MAIL_ERROR_H + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +#define TCP_CLIENT_ERROR_CONNECTION_REFUSED -1 +#define TCP_CLIENT_ERROR_SEND_DATA_FAILED -2 +#define TCP_CLIENT_ERROR_NOT_INITIALIZED -3 +#define TCP_CLIENT_ERROR_NOT_CONNECTED -4 + +#if defined(ENABLE_SMTP) + +#define SMTP_STATUS_SERVER_CONNECT_FAILED -100 +#define SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED -101 +#define SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED -102 +#define SMTP_STATUS_AUTHEN_NOT_SUPPORT -103 +#define SMTP_STATUS_AUTHEN_FAILED -104 +#define SMTP_STATUS_USER_LOGIN_FAILED -105 +#define SMTP_STATUS_PASSWORD_LOGIN_FAILED -106 +#define SMTP_STATUS_SEND_HEADER_SENDER_FAILED -107 +#define SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED -108 +#define SMTP_STATUS_SEND_BODY_FAILED -109 +#define SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED -110 +#define SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED -111 +#define SMTP_STATUS_NO_VALID_SENDER_EXISTED -112 +#define SMTP_STATUS_NO_SUPPORTED_AUTH -113 +#define SMTP_STATUS_SEND_CUSTOM_COMMAND_FAILED -114 +#define SMTP_STATUS_XOAUTH2_AUTH_FAILED -115 +#define SMTP_STATUS_UNDEFINED -116 +#endif + +#if defined(ENABLE_IMAP) + +#define IMAP_STATUS_SERVER_CONNECT_FAILED -200 +#define IMAP_STATUS_IMAP_RESPONSE_FAILED -201 +#define IMAP_STATUS_AUTHENTICATE_FAILED -202 +#define IMAP_STATUS_BAD_COMMAND -203 +#define IMAP_STATUS_STORE_FAILED -204 +#define IMAP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED -205 +#define IMAP_STATUS_NO_MESSAGE -206 +#define IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT -207 +#define IMAP_STATUS_CLOSE_MAILBOX_FAILED -208 +#define IMAP_STATUS_OPEN_MAILBOX_FAILED -209 +#define IMAP_STATUS_LIST_MAILBOXS_FAILED -210 +#define IMAP_STATUS_CHECK_CAPABILITIES_FAILED -211 +#define IMAP_STATUS_NO_SUPPORTED_AUTH -212 +#define IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED -213 +#define IMAP_STATUS_FIRMWARE_UPDATE_INIT_FAILED -214 +#define IMAP_STATUS_FIRMWARE_UPDATE_WRITE_FAILED -215 +#define IMAP_STATUS_FIRMWARE_UPDATE_END_FAILED -216 +#define IMAP_STATUS_CHANGEDSINC_MODSEQ_TEST_FAILED -217 +#define IMAP_STATUS_MODSEQ_WAS_NOT_SUPPORTED -218 +#endif + +/** + * MB_FS.h + #define MB_FS_ERROR_FILE_IO_ERROR -300 + #define MB_FS_ERROR_FILE_NOT_FOUND -301 + #define MB_FS_ERROR_FLASH_STORAGE_IS_NOT_READY -302 + #define MB_FS_ERROR_SD_STORAGE_IS_NOT_READY -303 + #define MB_FS_ERROR_FILE_STILL_OPENED -304 +*/ + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + +#define MAIL_CLIENT_ERROR_CONNECTION_CLOSED -400 +#define MAIL_CLIENT_ERROR_READ_TIMEOUT -401 +#define MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP -402 +#define MAIL_CLIENT_ERROR_OUT_OF_MEMORY -403 +#define MAIL_CLIENT_ERROR_NTP_TIME_SYNC_TIMED_OUT -404 +#define MAIL_CLIENT_ERROR_SESSION_CONFIG_WAS_NOT_ASSIGNED -405 +#define MAIL_CLIENT_ERROR_TIME_WAS_NOT_SET -406 +#define MAIL_CLIENT_ERROR_NOT_YET_LOGIN -407 +#define MAIL_CLIENT_ERROR_BUFFER_OVERFLOW -408 + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_FS.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_FS.h new file mode 100644 index 000000000..b9c9755d5 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_FS.h @@ -0,0 +1,170 @@ + + +#pragma once + +#ifndef ESP_MAIL_CONFIG_H +#define ESP_MAIL_CONFIG_H + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +#include +#include "extras/MB_MCU.h" + +/** 📌 Predefined Build Options + * ⛔ Use following build flag to disable all predefined options. + * -D DISABLE_ALL_OPTIONS + */ + +/**📍 For enabling the device or library time setup from NTP server + * ⛔ Use following build flag to disable. + * -D DISABLE_NTP_TIME + */ +#define ENABLE_NTP_TIME + +/**📍 For enabling the error string from error reason + * ⛔ Use following build flag to disable. + * -D DISABLE_ERROR_STRING + */ +#define ENABLE_ERROR_STRING + +/**📍 For IMAP class compilation + * ⛔ Use following build flag to disable. + * -D DISABLE_IMAP + */ +#define ENABLE_IMAP + +/**📍 For SMTP class compilation + * ⛔ Use following build flag to disable. + * -D DISABLE_SMTP + */ +#define ENABLE_SMTP + +/**📍 For enabling PSRAM support + * ⛔ Use following build flag to disable. + * -D DISABLE_PSRAM + */ +#define ESP_MAIL_USE_PSRAM + +/**📌 For enabling flash filesystem support + * + * 📍 For SPIFFS + * #define ESP_MAIL_DEFAULT_FLASH_FS SPIFFS + * + * + * 📍 For LittleFS Filesystem + * #include + * #define ESP_MAIL_DEFAULT_FLASH_FS LittleFS + * + * + * 📍 For SPIFFS Filesystem + * #if defined(ESP32) + * #include + * #endif + * #define ESP_MAIL_DEFAULT_FLASH_FS SPIFFS + * + * + * 📍 For FAT Filesystem + * #include + * #define ESP_MAIL_DEFAULT_FLASH_FS FFat //For ESP32 FAT + * + * 🚫 Use following build flags to disable. + * -D DISABLE_FLASH or -DDISABLE_FLASH in PlatformIO + */ + +#if defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO) + +#if defined(ESP8266) || defined(MB_ARDUINO_PICO) + +#include +#define ESP_MAIL_DEFAULT_FLASH_FS LittleFS + +#elif defined(ESP_ARDUINO_VERSION) /* ESP32 core >= v2.0.x */ /* ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(2, 0, 0) */ + +#include +#define ESP_MAIL_DEFAULT_FLASH_FS LittleFS + +#else + +#include +#define ESP_MAIL_DEFAULT_FLASH_FS SPIFFS + +#endif + +#endif + +// For ESP32, format SPIFFS or FFat if mounting failed +#define ESP_MAIL_FORMAT_FLASH_IF_MOUNT_FAILED 1 + +/**📌 For enabling SD filesystem support + * + * 📍 For SD + * #include + * #define ESP_MAIL_DEFAULT_SD_FS SD + * #define ESP_MAIL_CARD_TYPE_SD 1 + * + * 📍 For SD MMC (ESP32) + * #include + * #define ESP_MAIL_DEFAULT_SD_FS SD_MMC //For ESP32 SDMMC + * #define ESP_MAIL_CARD_TYPE_SD_MMC 1 + * + * 📍 For SdFat on ESP32 and other devices except for ESP8266 + * #include //https://github.com/greiman/SdFat + * static SdFat sd_fat_fs; //should declare as static here + * #define ESP_MAIL_DEFAULT_SD_FS sd_fat_fs + * #define ESP_MAIL_CARD_TYPE_SD 1 + * #define ESP_MAIL_SD_FS_FILE SdFile + * + * + * ⛔ Use following build flags to disable. + * -D DISABLE_SD or -DDISABLE_SD in PlatformIO + */ +#if defined(ESP32) || defined(ESP8266) +#include +#define ESP_MAIL_DEFAULT_SD_FS SD +#define ESP_MAIL_CARD_TYPE_SD 1 +#elif defined(MB_ARDUINO_PICO) +// Use SDFS (ESP8266SdFat) instead of SD +#include +#define ESP_MAIL_DEFAULT_SD_FS SDFS +#define ESP_MAIL_CARD_TYPE_SD 1 +#endif + +/** 🔖 Optional Build Options + * + * 🏷️ For silent operation (no debug printing and callback) + * #define SILENT_MODE + * + * 🏷️ For ENC28J60 Ethernet module support in ESP8266 + * #define ENABLE_ESP8266_ENC28J60_ETH + * + * 🏷️ For W5500 Ethernet module support in ESP8266 + * #define ENABLE_ESP8266_W5500_ETH + * + * 🏷️ For W5100 Ethernet module support in ESP8266 + * #define ENABLE_ESP8266_W5100_ETH + * + * 🏷️ For disabling on-board WiFI functionality in case external Client usage + * #define ESP_MAIL_DISABLE_ONBOARD_WIFI + * + * 🏷️ For disabling native (sdk) Ethernet functionality in case external Client usage + * #define ESP_MAIL_DISABLE_NATIVE_ETHERNET + * + * 🏷️ For disabling SSL connection (also disabling TLS using STARTTLS) in MAP and SMTP application + * #define ESP_MAIL_DISABLE_SSL + * + * 🏷️ For debug port assignment if SILENT_MODE option was not set + * #define ESP_MAIL_DEBUG_PORT Serial + */ + +#define ENABLE_ESP8266_ENC28J60_ETH + +#if __has_include("Custom_ESP_Mail_FS.h") +#include "Custom_ESP_Mail_FS.h" +#endif + +#include "extras/Build_Options.h" + +#endif diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_IMAP.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_IMAP.h new file mode 100644 index 000000000..ddfdbed08 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_IMAP.h @@ -0,0 +1,6783 @@ + +#ifndef ESP_MAIL_IMAP_H +#define ESP_MAIL_IMAP_H + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +/** + * Mail Client Arduino Library for Espressif's ESP32 and ESP8266, Raspberry Pi RP2040 Pico, and SAMD21 with u-blox NINA-W102 WiFi/Bluetooth module + * + * Created August 28, 2023 + * + * This library allows Espressif's ESP32, ESP8266, SAMD and RP2040 Pico devices to send and read Email through the SMTP and IMAP servers. + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "ESP_Mail_Client_Version.h" +#include "ESP_Mail_Client.h" + +#if defined(ENABLE_IMAP) + +#if defined(MB_ARDUINO_PICO) +extern uint8_t _FS_start; +extern uint8_t _FS_end; +#endif + +int ESP_Mail_Client::decodeChar(const char *s) +{ + return 16 * hexval(*(s + 1)) + hexval(*(s + 2)); +} + +void ESP_Mail_Client::decodeQP_UTF8(const char *buf, char *out) +{ + char *tmp = strP(esp_mail_str_47 /* "0123456789ABCDEF" */); + int idx = 0; + while (*buf) + { + if (*buf != '=') + out[idx++] = *buf++; + else if (*(buf + 1) == '\r' && *(buf + 2) == '\n') + buf += 3; + else if (*(buf + 1) == '\n') + buf += 2; + else if (!strchr(tmp, *(buf + 1))) + out[idx++] = *buf++; + else if (!strchr(tmp, *(buf + 2))) + out[idx++] = *buf++; + else + { + out[idx++] = decodeChar(buf); + buf += 3; + } + } + + // release memory + freeMem(&tmp); +} + +char *ESP_Mail_Client::decode7Bit_UTF8(char *buf) +{ + MB_String s; + + // only non NULL and 7-bit ASCII are allowed + + // rfc2045 section 2.7 + + size_t len = buf ? strlen(buf) : 0; + + for (size_t i = 0; i < len; i++) + { + if (buf[i] > 0 && buf[i] < 128 && i < 998) + s.append(1, buf[i]); + } + + // some special chars can't send in 7bit unless encoded as queoted printable string + char *decoded = allocMem(s.length() + 10); + decodeQP_UTF8(s.c_str(), decoded); + s.clear(); + return decoded; +} + +char *ESP_Mail_Client::decode8Bit_UTF8(char *buf) +{ + MB_String s; + + // only non NULL and less than 998 octet length are allowed + + // rfc2045 section 2.8 + + size_t len = buf ? strlen(buf) : 0; + + for (size_t i = 0; i < len; i++) + { + if (buf[i] > 0 && i < 998) + s.append(1, buf[i]); + } + + char *decoded = allocMem(s.length() + 1); + strcpy(decoded, s.c_str()); + s.clear(); + return decoded; +} + +void ESP_Mail_Client::decodeString(IMAPSession *imap, MB_String &str, const char *enc) +{ + + size_t p1 = 0, p2 = 0; + MB_String headerEnc; + + if (strlen(enc) == 0) + { + while (str[p1] == ' ' && p1 < str.length() - 1) + p1++; + + if (str[p1] == '=' && str[p1 + 1] == '?') + { + p2 = str.find('?', p1 + 2); + if (p2 != MB_String::npos) + headerEnc = str.substr(p1 + 2, p2 - p1 - 2); + } + } + else + headerEnc = enc; + + int bufSize = str.length() + 10; + char *buf = allocMem(bufSize); + + // Content Q and B decodings + RFC2047Decoder.decode(mbfs, buf, str.c_str(), bufSize); + + // Char set decoding + esp_mail_char_decoding_scheme scheme = getEncodingFromCharset(headerEnc.c_str()); + if (imap->_charDecCallback) + { + IMAP_Decoding_Info decoding; + decoding.charset = headerEnc.c_str(); + decoding.data = buf; + decoding.type = IMAP_Decoding_Info::message_part_type_header; + + imap->_charDecCallback(&decoding); + + if (decoding.decodedString.length() > 0) + { + char *buf2 = allocMem(decoding.decodedString.length() + 1); + strcpy(buf2, decoding.decodedString.c_str()); + // release memory and point to new buffer + freeMem(&buf); + buf = buf2; + } + } + else if (scheme == esp_mail_char_decoding_scheme_iso8859_1) + { + int len = strlen(buf); + int olen = (len + 1) * 2; + unsigned char *out = allocMem(olen); + decodeLatin1_UTF8(out, &olen, (unsigned char *)buf, &len); + // release memory and point to new buffer + freeMem(&buf); + buf = (char *)out; + } + else if (scheme == esp_mail_char_decoding_scheme_tis_620 || scheme == esp_mail_char_decoding_scheme_iso8859_11 || scheme == esp_mail_char_decoding_scheme_windows_874) + { + size_t len2 = strlen(buf); + char *tmp = allocMem((len2 + 1) * 3); + decodeTIS620_UTF8(tmp, buf, len2); + // release memory and point to new buffer + freeMem(&buf); + buf = tmp; + } + + str = buf; + // release memory + freeMem(&buf); +} + +esp_mail_char_decoding_scheme ESP_Mail_Client::getEncodingFromCharset(const char *enc) +{ + esp_mail_char_decoding_scheme scheme = esp_mail_char_decoding_scheme_default; + + for (int i = esp_mail_char_decoding_utf8; i < esp_mail_char_decoding_maxType; i++) + { + if (strpos(enc, char_decodings[i].text, 0, false) > -1) + scheme = (esp_mail_char_decoding_scheme)i; + } + + return scheme; +} + +int ESP_Mail_Client::encodeUnicode_UTF8(char *out, uint32_t utf) +{ + if (utf <= 0x7F) + { + // Plain ASCII + out[0] = (char)utf; + out[1] = 0; + return 1; + } + else if (utf <= 0x07FF) + { + // 2-byte unicode + out[0] = (char)(((utf >> 6) & 0x1F) | 0xC0); + out[1] = (char)(((utf >> 0) & 0x3F) | 0x80); + out[2] = 0; + return 2; + } + else if (utf <= 0xFFFF) + { + // 3-byte unicode + out[0] = (char)(((utf >> 12) & 0x0F) | 0xE0); + out[1] = (char)(((utf >> 6) & 0x3F) | 0x80); + out[2] = (char)(((utf >> 0) & 0x3F) | 0x80); + out[3] = 0; + return 3; + } + else if (utf <= 0x10FFFF) + { + // 4-byte unicode + out[0] = (char)(((utf >> 18) & 0x07) | 0xF0); + out[1] = (char)(((utf >> 12) & 0x3F) | 0x80); + out[2] = (char)(((utf >> 6) & 0x3F) | 0x80); + out[3] = (char)(((utf >> 0) & 0x3F) | 0x80); + out[4] = 0; + return 4; + } + else + { + // error - use replacement character + out[0] = (char)0xEF; + out[1] = (char)0xBF; + out[2] = (char)0xBD; + out[3] = 0; + return 0; + } +} + +void ESP_Mail_Client::decodeTIS620_UTF8(char *out, const char *in, size_t len) +{ + // output is the 3-byte value UTF-8 + int j = 0; + for (size_t i = 0; i < len; i++) + { + if (in[i] < 0x80) + out[j++] = in[i]; + else if ((in[i] >= 0xa0 && in[i] < 0xdb) || (in[i] > 0xde && in[i] < 0xfc)) + { + int unicode = 0x0e00 + in[i] - 0xa0; + char o[5]; + memset(o, 0, 5); + int r = encodeUnicode_UTF8(o, unicode); + for (int x = 0; x < r; x++) + out[j++] = o[x]; + } + } +} + +int ESP_Mail_Client::decodeLatin1_UTF8(unsigned char *out, int *outlen, const unsigned char *in, int *inlen) +{ + unsigned char *outstart = out; + const unsigned char *base = in; + const unsigned char *processed = in; + unsigned char *outend = out + *outlen; + const unsigned char *inend; + unsigned int c; + int bits; + + inend = in + (*inlen); + while ((in < inend) && (out - outstart + 5 < *outlen)) + { + c = *in++; + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) + { + *out++ = c; + bits = -6; + } + else + { + *out++ = ((c >> 6) & 0x1F) | 0xC0; + bits = 0; + } + + for (; bits >= 0; bits -= 6) + { + if (out >= outend) + break; + *out++ = ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char *)in; + } + *outlen = out - outstart; + *inlen = processed - base; + return (0); +} + +bool ESP_Mail_Client::sendFetchCommand(IMAPSession *imap, int msgIndex, esp_mail_imap_command cmdCase) +{ + + MB_String cmd, cmd2, cmd3; + appendHeadersFetchCommand(imap, cmd, msgIndex, false); + + if (cmdCase == esp_mail_imap_cmd_fetch_body_mime) + { + joinStringDot(cmd2, 2, imap_commands[esp_mail_imap_command_header].text, imap_commands[esp_mail_imap_command_fields].text); + appendSpace(cmd2); + joinStringSpace(cmd3, false, 2, message_headers[esp_mail_message_header_field_content_type].text, message_headers[esp_mail_message_header_field_content_transfer_encoding].text); + appendString(cmd2, cmd3.c_str(), false, false, esp_mail_string_mark_type_round_bracket); + } + else if (cmdCase == esp_mail_imap_cmd_fetch_body_text) + cmd2 = cPart(imap)->partNumFetchStr.length() > 0 ? cPart(imap)->partNumFetchStr.c_str() : imap_commands[esp_mail_imap_command_text].text; + else if (cmdCase == esp_mail_imap_cmd_fetch_body_attachment) + cmd2 = cPart(imap)->partNumFetchStr; + + if (cmd2.length() > 0) + appendString(cmd, cmd2.c_str(), false, false, esp_mail_string_mark_type_square_bracket); + + bool allowPartialFetch = (cmdCase == esp_mail_imap_cmd_fetch_body_attachment && cPart(imap)->is_firmware_file) ? false : true; + + if (imap->_mimeDataStreamCallback) + allowPartialFetch = false; + + if (allowPartialFetch) + { + // Apply partial fetch in case download was disabled. + if (!imap->_storageReady && imap->_attDownload && cmdCase == esp_mail_imap_cmd_fetch_body_attachment) + cmd += esp_mail_str_48; /* "<0.0>" */ // This case should not happen because the memory storage was previousely checked. + else if ((!imap->_msgDownload && cmdCase == esp_mail_imap_cmd_fetch_body_text) || (imap->_msgDownload && !imap->_storageReady)) + { + cmd += esp_mail_str_49; /* "<0." */ + cmd += imap->_imap_data->limit.msg_size; + cmd += esp_mail_str_20; /* ">" */ + } + } + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + return true; +} + +bool ESP_Mail_Client::readMail(IMAPSession *imap, bool closeSession) +{ + if (!imap || !sessionExisted(imap)) + return false; + + imap->checkUID(); + imap->checkPath(); + imap->_cbData._success = false; + + if (!imap->connected()) + imap->_mailboxOpened = false; + + imap->_isFirmwareUpdated = false; + + MB_String buf, command, _uid; + + size_t readCount = 0; + imap->_multipart_levels.clear(); + + if (!reconnect(imap)) + return false; + + imap->_msgDownload = imap->_imap_data->download.text || imap->_imap_data->download.html; + imap->_attDownload = imap->_imap_data->download.attachment || imap->_imap_data->download.inlineImg; + + if (!imap->_storageChecked) + { + imap->_storageChecked = true; + imap->_storageReady = imap->_imap_data->download.header || (!imap->_imap_data->fetch.headerOnly && (imap->_msgDownload || imap->_attDownload)) ? mbfs->checkStorageReady(mbfs_type imap->_imap_data->storage.type) : true; + } + + bool readyToDownload = (imap->_msgDownload || imap->_attDownload) && imap->_storageReady; + + if (!imap->_storageReady) + sendStorageNotReadyError(imap, imap->_imap_data->storage.type); + +#if defined(MB_ARDUINO_ESP) || defined(MB_ARDUINO_PICO) + + int cmem = MailClient.getFreeHeap(); + + if (cmem < ESP_MAIL_MIN_MEM) + { +#if !defined(SILENT_MODE) + if (imap->_debug && imap->_statusCallback && !imap->_customCmdResCallback) + { + esp_mail_debug_print(); + errorStatusCB(imap, nullptr, MAIL_CLIENT_ERROR_OUT_OF_MEMORY, true); + } +#endif + + goto out; + } +#endif + + if (!imap->connected() && !imap->_loginStatus) + { +#if !defined(SILENT_MODE) + if (imap->_debug && imap->_statusCallback && !imap->_customCmdResCallback) + { + esp_mail_debug_print(); + errorStatusCB(imap, nullptr, MAIL_CLIENT_ERROR_NOT_YET_LOGIN, true); + } +#endif + return false; + } + + // new session + if (!imap->connected()) + { + // authenticate new + + bool ssl = false; + + if (!imap->connect(ssl)) + { + closeTCPSession(imap); + return false; + } + + if (!imapAuth(imap, ssl)) + { + closeTCPSession(imap); + return false; + } + } + else + { + // If time config changed, we will update time + MailClient.prepareTime(imap->_session_cfg, imap); + + // reuse session + for (size_t i = 0; i < imap->_headers.size(); i++) + imap->_headers[i].part_headers.clear(); + imap->_headers.clear(); + + if (imap->_imap_data->fetch.sequence_set.string.length() > 0 || imap->_imap_data->fetch.uid.length() > 0 || imap->_imap_data->fetch.number.length() > 0) + imap->_headerOnly = false; + else + imap->_headerOnly = true; + } + + imap->_rfc822_part_count = 0; + imap->_mbif._availableItems = 0; + imap->_imap_msg_num.clear(); + imap->_uidSearch = false; + imap->_mbif._searchCount = 0; + + if (imap->_currentFolder.length() == 0) + return handleIMAPError(imap, IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED, false); + + if (!imap->_mailboxOpened || (imap->_imap_data->fetch.set_seen && !imap->_headerOnly && imap->_readOnlyMode)) + { + if (!imap->openFolder(imap->_currentFolder.c_str(), imap->_readOnlyMode && !imap->_imap_data->fetch.set_seen)) + return handleIMAPError(imap, IMAP_STATUS_OPEN_MAILBOX_FAILED, false); + } + + if (imap->_headerOnly) + { + if (imap->_imap_data->search.criteria.length() > 0) + { + command = esp_mail_imap_tag_str; + +#if !defined(SILENT_MODE) + printDebug(imap, + esp_mail_cb_str_18 /* "Searching messages..." */, + esp_mail_dbg_str_36 /* "searching messages" */, + esp_mail_debug_tag_type_client, + true, + false); + +#endif + + if (strposP(imap->_imap_data->search.criteria.c_str(), imap_cmd_post_tokens[esp_mail_imap_command_uid].c_str(), 0) != -1) + { + imap->_uidSearch = true; + command += imap_cmd_pre_tokens[esp_mail_imap_command_uid]; + } + + command += imap_cmd_pre_tokens[esp_mail_imap_command_search]; + + imap->_imap_data->search.criteria.trim(); + + MB_String tag; + appendTagSpace(tag); + + // Remove internal used reserved tag + if (strpos(imap->_imap_data->search.criteria.c_str(), tag.c_str(), 0, true) == 0) + imap->_imap_data->search.criteria.erase(0, tag.length()); + + for (size_t i = 0; i < imap->_imap_data->search.criteria.length(); i++) + { + if (imap->_imap_data->search.criteria[i] != ' ' && imap->_imap_data->search.criteria[i] != '\r' && imap->_imap_data->search.criteria[i] != '\n') + buf.append(1, imap->_imap_data->search.criteria[i]); + + if (imap->_imap_data->search.criteria[i] == ' ') + { + + if ((imap->_uidSearch && strcmp(buf.c_str(), imap_commands[esp_mail_imap_command_uid].text) == 0) || (imap->_unseen && buf.find(imap_commands[esp_mail_imap_command_all].text) != MB_String::npos)) + buf.clear(); + + if (strcmp(buf.c_str(), imap_commands[esp_mail_imap_command_search].text) != 0 && buf.length() > 0) + prependSpace(command, buf.c_str()); + + buf.clear(); + } + } + + if (imap->_unseen && strpos(imap->_imap_data->search.criteria.c_str(), imap_cmd_pre_tokens[esp_mail_imap_command_new].c_str(), 0) == -1) + command += imap_cmd_pre_tokens[esp_mail_imap_command_new]; + + if (buf.length() > 0) + prependSpace(command, buf.c_str()); + + if (!imap->isModseqSupported() && strpos(imap->_imap_data->search.criteria.c_str(), imap_cmd_pre_tokens[esp_mail_imap_command_modsec].c_str(), 0, false) != -1) + { + imap->_responseStatus.errorCode = IMAP_STATUS_MODSEQ_WAS_NOT_SUPPORTED; +#if !defined(SILENT_MODE) + + if (imap->_statusCallback) + sendErrorCB(imap, imap->errorReason().c_str(), false, false); + + if (imap->_debug) + esp_mail_debug_print_tag(imap->errorReason().c_str(), esp_mail_debug_tag_type_error, true); + +#endif + return false; + } + + if (imapSend(imap, command.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + command.clear(); + + imap->_imap_cmd = esp_mail_imap_cmd_search; + + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, closeSession)) + return false; + +#if !defined(SILENT_MODE) + if (imap->_statusCallback) + { + callBackSendNewLine(imap, false); + if (imap->_imap_msg_num.size() > 0) + { + int bufLen = 100; + char *buf = allocMem(bufLen); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_50 /* "Search limit: %d\nFound %d messages\nShow %d messages\n" */), (int)imap->_imap_data->limit.search, imap->_mbif._searchCount, (int)imap->_imap_msg_num.size()); + sendCallback(imap, buf, false, false); + // release memory + freeMem(&buf); + } + else + sendCallback(imap, esp_mail_error_imap_str_9 /* "no messages found for the specified search criteria" */, false, false); + } +#endif + } + else + { +#if !defined(SILENT_MODE) + if (imap->_statusCallback) + sendCallback(imap, esp_mail_error_imap_str_10 /* "no search criteria provided, then fetching the latest message" */, false, false); +#endif + imap->_mbif._availableItems++; + + esp_mail_imap_msg_num_t msg_num; + msg_num.type = esp_mail_imap_msg_num_type_number; + msg_num.value = (uint32_t)imap->_mbif._msgCount; + + imap->_imap_msg_num.push_back(msg_num); + imap->_headerOnly = false; + imap->_imap_data->fetch.number = imap->_mbif._msgCount; + } + } + else + { + + if (imap->_imap_data->fetch.sequence_set.string.length() > 0) + { + imap->_headerOnly = imap->_imap_data->fetch.sequence_set.headerOnly; + imap->mFetchSequenceSet(); + + imap->_mbif._availableItems = imap->_imap_msg_num.size(); + } + else + { + if (imap->_imap_data->fetch.uid.length() > 0) + { + imap->_mbif._availableItems++; + + esp_mail_imap_msg_num_t msg_num; + msg_num.type = esp_mail_imap_msg_num_type_uid; + msg_num.value = (uint32_t)atoi(imap->_imap_data->fetch.uid.c_str()); + + imap->_imap_msg_num.push_back(msg_num); + } + + if (imap->_imap_data->fetch.number.length() > 0) + { + imap->_mbif._availableItems++; + + esp_mail_imap_msg_num_t msg_num; + msg_num.type = esp_mail_imap_msg_num_type_number; + msg_num.value = (uint32_t)atoi(imap->_imap_data->fetch.number.c_str()); + + imap->_imap_msg_num.push_back(msg_num); + } + } + } + + if (imap->_imap_data->fetch.headerOnly) + imap->_headerOnly = true; + + for (size_t i = 0; i < imap->_imap_msg_num.size(); i++) + { + imap->_cMsgIdx = i; + imap->_totalRead++; + +#if defined(MB_ARDUINO_ESP) || defined(MB_ARDUINO_PICO) + if (MailClient.getFreeHeap() - (imap->_imap_data->limit.msg_size * (i + 1)) < ESP_MAIL_MIN_MEM) + { + errorStatusCB(imap, nullptr, MAIL_CLIENT_ERROR_OUT_OF_MEMORY, true); + goto out; + } +#endif + +#if !defined(SILENT_MODE) + if (imap->_statusCallback) + { + readCount++; + int bufLen = 100; + PGM_P p = imap->_uidSearch || imap->_imap_msg_num[i].type == esp_mail_imap_msg_num_type_uid ? esp_mail_str_52 /* "Fetch message %d, UID: %d" */ : esp_mail_str_53 /* "Fetch message %d, Number: %d" */; + char *buf = allocMem(bufLen); + snprintf(buf, bufLen, pgm2Str(p), imap->_totalRead, (int)imap->_imap_msg_num[i].value); + sendCallback(imap, buf, true, false); + // release memory + freeMem(&buf); + } + + if (imap->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_37 /* "send IMAP command, FETCH" */, esp_mail_debug_tag_type_client, true); +#endif + MB_String cmd; + appendHeadersFetchCommand(imap, cmd, i, true); + + // We fetch only known RFC822 headers because + // using Fetch RFC822.HEADER reurns all included unused headers + // which required more memory and network bandwidth. + MB_String cmd2; + appendRFC822HeadersFetchCommand(cmd2); + + appendString(cmd, cmd2.c_str(), false, false, esp_mail_string_mark_type_square_bracket); + + imap->addModifier(cmd, esp_mail_imap_command_changedsince, imap->_imap_data->fetch.modsequence); + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + { + if (i < imap->_imap_msg_num.size() - 1) + continue; + return false; + } + + imap->_imap_cmd = esp_mail_imap_cmd_fetch_body_header; + + int err = imap->_headerOnly ? IMAP_STATUS_IMAP_RESPONSE_FAILED : IMAP_STATUS_BAD_COMMAND; + + if (!handleIMAPResponse(imap, err, closeSession)) + { + if (i < imap->_imap_msg_num.size() - 1) + continue; + return false; + } + + if (!cHeader(imap)) + continue; + + if (imap->_imap_msg_num[i].type == esp_mail_imap_msg_num_type_number) + cHeader(imap)->message_uid = imap->mGetUID(cHeader(imap)->message_no); + + cHeader(imap)->flags = imap->getFlags(cHeader(imap)->message_no); + + if (!imap->_headerOnly) + { + imap->_cPartIdx = 0; + + // Reset attachment state if it was set by "multipart/mixed" content type header + cHeader(imap)->hasAttachment = false; + +#if !defined(SILENT_MODE) + if (imap->_debug) + debugPrintNewLine(); +#endif + + // multipart + if (cHeader(imap)->multipart) + { + struct esp_mail_imap_multipart_level_t mlevel; + mlevel.level = 1; + mlevel.fetch_rfc822_header = false; + mlevel.append_body_text = false; + imap->_multipart_levels.push_back(mlevel); + + if (!fetchMultipartBodyHeader(imap, i)) + return false; + } + else + { + // single part + if (imap->_debug) + printBodyPartFechingDubug(imap, "1", false); + + cHeader(imap)->partNumStr.clear(); + if (!sendFetchCommand(imap, i, esp_mail_imap_cmd_fetch_body_mime)) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_fetch_body_mime; + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, closeSession)) + return false; + } + + if (readyToDownload && imap->_imap_data->storage.saved_path.length() == 0) + imap->_imap_data->storage.saved_path = esp_mail_str_10; /* "/" */ + + if (cHeader(imap)->part_headers.size() > 0) + { + + cHeader(imap)->sd_alias_file_count = 0; + + imap->_sdFileList.clear(); + if (!mbfs->longNameSupported()) + imap->_sdFileList = esp_mail_str_40; /* "[" */ + +#if !defined(SILENT_MODE) + + if (cHeader(imap)->attachment_count > 0 && imap->_statusCallback) + { + int bufLen = 100; + char *buf = allocMem(bufLen); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_54 /* "Attachments (%d)" */), cHeader(imap)->attachment_count); + callBackSendNewLine(imap, false); + sendCallback(imap, buf, false, false); + // release memory + freeMem(&buf); + + int count = 0; + + for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) + { + imap->_cPartIdx = j; + if (!cPart(imap)->rfc822_part && cPart(imap)->attach_type != esp_mail_att_type_none) + { + count++; + MB_String str = count; + appendDot(str); + prependSpace(str, cPart(imap)->filename.c_str()); + sendCallback(imap, str.c_str(), false, false); + } + } + } + +#endif + + MB_String s1, s2; + int _idx1 = 0; + for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) + { + imap->_cPartIdx = j; + if (cPart(imap)->rfc822_part) + { + s1 = cPart(imap)->partNumStr; + _idx1 = cPart(imap)->rfc822_msg_Idx; + } + else if (s1.length() > 0) + { + if (multipartMember(s1, cPart(imap)->partNumStr)) + { + cPart(imap)->message_sub_type = esp_mail_imap_message_sub_type_rfc822; + cPart(imap)->rfc822_msg_Idx = _idx1; + } + } + + if (cPart(imap)->multipart_sub_type == esp_mail_imap_multipart_sub_type_parallel) + s2 = cPart(imap)->partNumStr; + else if (s2.length() > 0) + { + if (multipartMember(s2, cPart(imap)->partNumStr)) + { + cPart(imap)->attach_type = esp_mail_att_type_attachment; + if (cPart(imap)->filename.length() == 0) + { + if (cPart(imap)->name.length() > 0) + cPart(imap)->filename = cPart(imap)->name; + else + { + char *uid = getRandomUID(); + cPart(imap)->filename = uid; + cPart(imap)->filename += mimeinfo[esp_mail_file_extension_dat].endsWith; + freeMem(&uid); + } + } + } + } + + checkFirmwareFile(imap, cPart(imap)->filename.c_str(), *cPart(imap), true); + } + + int attach_count = 0; + int ccnt = 0; + + for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) + { + imap->_cPartIdx = j; + + if (cPart(imap)->rfc822_part || cPart(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_none) + continue; + + bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822 && cPart(imap)->attach_type != esp_mail_att_type_attachment; + + if (cPart(imap)->attach_type == esp_mail_att_type_none && (cPart(imap)->msg_type == esp_mail_msg_type_html || cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)) + { + + bool ret = ((imap->_imap_data->enable.rfc822 || imap->_imap_data->download.rfc822) && rfc822_body_subtype) || (!rfc822_body_subtype && ((imap->_imap_data->enable.text && (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)) || (imap->_imap_data->enable.html && cPart(imap)->msg_type == esp_mail_msg_type_html) || (cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_imap_data->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_imap_data->download.text))); + if (!ret) + continue; + +#if !defined(SILENT_MODE) + + if ((imap->_imap_data->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_imap_data->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_imap_data->download.text)))) + { + + if (ccnt == 0 && imap->_statusCallback) + sendCallback(imap, esp_mail_cb_str_43 /* "Downloading messages..." */, true, false); + + if (imap->_debug) + { + debugPrintNewLine(); + if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + esp_mail_debug_print_tag(esp_mail_dbg_str_74 /* "download plain TEXT message" */, esp_mail_debug_tag_type_client, true); + else if (cPart(imap)->msg_type == esp_mail_msg_type_html) + esp_mail_debug_print_tag(esp_mail_dbg_str_71 /* "download HTML message" */, esp_mail_debug_tag_type_client, true); + } + } + else + { + if (ccnt == 0) + sendCallback(imap, esp_mail_cb_str_28 /* "Reading messages..." */, true, false); + + if (imap->_debug) + { + debugPrintNewLine(); + if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + esp_mail_debug_print_tag(esp_mail_dbg_str_46 /* "reading plain TEXT message" */, esp_mail_debug_tag_type_client, true); + else if (cPart(imap)->msg_type == esp_mail_msg_type_html) + esp_mail_debug_print_tag(esp_mail_dbg_str_47 /* "reading HTML message" */, esp_mail_debug_tag_type_client, true); + } + } + +#endif + + ccnt++; + + if (!sendFetchCommand(imap, i, esp_mail_imap_cmd_fetch_body_text)) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_fetch_body_text; + if (!handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, closeSession)) + return false; + } + else if (cPart(imap)->attach_type != esp_mail_att_type_none && (imap->_storageReady || cPart(imap)->is_firmware_file)) + { + + if (cPart(imap)->is_firmware_file || (imap->_imap_data->download.attachment && cPart(imap)->attach_type == esp_mail_att_type_attachment) || (imap->_imap_data->download.inlineImg && cPart(imap)->attach_type == esp_mail_att_type_inline)) + { +#if !defined(SILENT_MODE) + if (cPart(imap)->save_to_file) + { + + if (attach_count == 0 && imap->_statusCallback) + sendCallback(imap, esp_mail_cb_str_19 /* "Downloading attachments..." */, true, false); + + if (imap->_debug) + { + debugPrintNewLine(); + int bufLen = 100; + char *buf = allocMem(bufLen); + snprintf(buf, bufLen, pgm2Str(esp_mail_dbg_str_70 /* "download attachment %d of %d" */), attach_count + 1, (int)cHeader(imap)->attachment_count); + esp_mail_debug_print_tag(buf, esp_mail_debug_tag_type_client, true); + // release memory + freeMem(&buf); + + MB_String filePath = imap->_imap_data->storage.saved_path; + filePath += esp_mail_str_10; /* "/" */ + filePath += cHeader(imap)->message_uid; + filePath += esp_mail_str_10; /* "/" */ + filePath += cPart(imap)->filename; + + esp_mail_debug_print_tag(filePath.c_str(), esp_mail_debug_tag_type_client, true); + } + } +#endif + + attach_count++; + + if (cPart(imap)->octetLen <= (int)imap->_imap_data->limit.attachment_size) + { + + if (imap->_storageReady || cPart(imap)->is_firmware_file) + { + + if ((int)j < (int)cHeader(imap)->part_headers.size() - 1) + if (cHeader(imap)->part_headers[j + 1].octetLen > (int)imap->_imap_data->limit.attachment_size) + cHeader(imap)->downloaded_bytes += cHeader(imap)->part_headers[j + 1].octetLen; + + if (!sendFetchCommand(imap, i, esp_mail_imap_cmd_fetch_body_attachment)) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_fetch_body_attachment; + if (!handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, closeSession)) + return false; + + yield_impl(); + } + } + else + { + if ((int)j == (int)cHeader(imap)->part_headers.size() - 1) + cHeader(imap)->downloaded_bytes += cPart(imap)->octetLen; + } + } + } + } + } + + if (imap->_storageReady && imap->_imap_data->download.header && !imap->_headerSaved) + { +#if !defined(SILENT_MODE) + if (imap->_statusCallback) + sendCallback(imap, esp_mail_cb_str_21 /* "Saving message header to file..." */, true, false); + else if (imap->_debug) + debugPrintNewLine(); +#endif + + saveHeader(imap, false); + saveHeader(imap, true); + } + + // save files list to file + if (imap->_storageReady && imap->_sdFileList.length() > 0) + { + MB_String filepath = cHeader(imap)->message_uid; + filepath += mimeinfo[esp_mail_file_extension_txt].endsWith; + if (mbfs->open(filepath, mbfs_type imap->_imap_data->storage.type, mb_fs_open_mode_write) > -1) + { + mbfs->print(mbfs_type imap->_imap_data->storage.type, imap->_sdFileList.c_str()); + mbfs->close(mbfs_type imap->_imap_data->storage.type); + } + } + + imap->_cMsgIdx++; + } +#if !defined(SILENT_MODE) + if (imap->_debug) + { + MB_String str = esp_mail_str_55; /* "Free Heap: " */ + str += MailClient.getFreeHeap(); + esp_mail_debug_print_tag(str.c_str(), esp_mail_debug_tag_type_client, true); + } +#endif + } +#if defined(MB_ARDUINO_ESP) || defined(MB_ARDUINO_PICO) +out: +#endif + if (readCount < imap->_imap_msg_num.size()) + { + imap->_mbif._availableItems = readCount; + imap->_imap_msg_num.erase(imap->_imap_msg_num.begin() + readCount, imap->_imap_msg_num.end()); + } + + if (closeSession) + { + if (!imap->closeSession()) + return false; + } + else + { +#if !defined(SILENT_MODE) + printDebug(imap, + esp_mail_cb_str_46 /* "Finished reading Email" */, + esp_mail_dbg_str_29 /* "finished reading Email" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + } + + imap->_cbData._success = true; + +#if !defined(SILENT_MODE) + if (imap->_statusCallback) + callBackSendNewLine(imap, true); +#endif + + return true; +} + +void ESP_Mail_Client::appendHeadersFetchCommand(IMAPSession *imap, MB_String &cmd, int index, bool debug) +{ + if (imap->_uidSearch || imap->_imap_msg_num[index].type == esp_mail_imap_msg_num_type_uid) + appendSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_uid].text, imap_commands[esp_mail_imap_command_fetch].text); + else + appendSpace(cmd, true, imap_commands[esp_mail_imap_command_fetch].text); +#if !defined(SILENT_MODE) + if (debug && imap->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_26 /* "fetch message header" */, esp_mail_debug_tag_type_client, true); +#endif + joinStringSpace(cmd, false, 2, MB_String((int)imap->_imap_msg_num[index].value).c_str(), imap_commands[esp_mail_imap_command_body].text); + + if (!imap->_imap_data->fetch.set_seen) + prependDot(cmd, imap_commands[esp_mail_imap_command_peek].text); +} + +void ESP_Mail_Client::appendRFC822HeadersFetchCommand(MB_String &cmd) +{ + joinStringDot(cmd, 2, imap_commands[esp_mail_imap_command_header].text, imap_commands[esp_mail_imap_command_fields].text); + appendSpace(cmd); + + MB_String cmd2; + + for (int i = 0; i < esp_mail_rfc822_header_field_maxType; i++) + appendSpace(cmd2, false, rfc822_headers[i].text); + + joinStringSpace(cmd2, false, 4, message_headers[esp_mail_message_header_field_content_type].text, + message_headers[esp_mail_message_header_field_content_transfer_encoding].text, + message_headers[esp_mail_message_header_field_content_language].text, + message_headers[esp_mail_message_header_field_accept_language].text); + + appendString(cmd, cmd2.c_str(), false, false, esp_mail_string_mark_type_round_bracket); +} + +bool ESP_Mail_Client::getMultipartFechCmd(IMAPSession *imap, int msgIdx, MB_String &partText) +{ + if (imap->_multipart_levels.size() == 0) + return false; + + int cLevel = imap->_multipart_levels.size() - 1; + + cHeader(imap)->partNumStr.clear(); + + appendHeadersFetchCommand(imap, partText, msgIdx, false); + + MB_String cmd1; + for (size_t i = 0; i < imap->_multipart_levels.size(); i++) + { + if (i > 0) + { + cmd1 += esp_mail_str_27; /* "." */ + cHeader(imap)->partNumStr += esp_mail_str_27; /* "." */ + } + + cmd1 += imap->_multipart_levels[i].level; + cHeader(imap)->partNumStr += imap->_multipart_levels[i].level; + } + + if (imap->_multipart_levels[cLevel].fetch_rfc822_header) + { + MB_String cmd2; + appendRFC822HeadersFetchCommand(cmd2); + prependDot(cmd1, cmd2.c_str()); + imap->_multipart_levels[cLevel].append_body_text = true; + } + else + prependDot(cmd1, imap_commands[esp_mail_imap_command_mime].text); + + appendString(partText, cmd1.c_str(), false, false, esp_mail_string_mark_type_square_bracket); + + imap->_multipart_levels[cLevel].fetch_rfc822_header = false; + + return true; +} + +bool ESP_Mail_Client::multipartMember(const MB_String &parent, const MB_String &child) +{ + if (parent.length() > child.length()) + return false; + + for (size_t i = 0; i < parent.length(); i++) + if (parent[i] != child[i]) + return false; + + return true; +} + +bool ESP_Mail_Client::fetchMultipartBodyHeader(IMAPSession *imap, int msgIdx) +{ + bool ret = true; + + if (!connected(imap)) + { + closeTCPSession(imap); + return false; + } + int cLevel = 0; + + // slower than BODYSTRUCTURE parsing but sure + do + { + +#if defined(MB_ARDUINO_ESP) || defined(MB_ARDUINO_PICO) + // Prevent stack overflow + if (MailClient.getFreeHeap() < ESP_MAIL_MIN_MEM) + { + errorStatusCB(imap, nullptr, MAIL_CLIENT_ERROR_OUT_OF_MEMORY, true); + break; + } +#endif + + struct esp_mail_message_part_info_t *_cpart = &cHeader(imap)->part_headers[cHeader(imap)->message_data_count - 1]; + bool rfc822_body_subtype = _cpart->message_sub_type == esp_mail_imap_message_sub_type_rfc822 && _cpart->attach_type != esp_mail_att_type_attachment; + + MB_String cmd; + if (!getMultipartFechCmd(imap, msgIdx, cmd)) + return true; + + if (imap->_debug) + printBodyPartFechingDubug(imap, cHeader(imap)->partNumStr.c_str(), imap->_multipart_levels.size() > 1); + + // Try fetching the part and its sub parts hierarchically + // Some sub part may not exist at the current multipart level + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_fetch_body_mime; + ret = handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, false); + + _cpart = &cHeader(imap)->part_headers[cHeader(imap)->message_data_count - 1]; + rfc822_body_subtype = _cpart->message_sub_type == esp_mail_imap_message_sub_type_rfc822 && _cpart->attach_type != esp_mail_att_type_attachment; + cLevel = imap->_multipart_levels.size() - 1; + + if (ret) + { + if (_cpart->multipart) + { + if (_cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_parallel || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_alternative || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_related || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_mixed) + { + struct esp_mail_imap_multipart_level_t mlevel; + mlevel.level = 1; + mlevel.fetch_rfc822_header = false; + mlevel.append_body_text = false; + imap->_multipart_levels.push_back(mlevel); + fetchMultipartBodyHeader(imap, msgIdx); + } + else + imap->_multipart_levels[cLevel].level++; + } + else + { + if (rfc822_body_subtype) + { + // Get additional rfc822 message header + imap->_multipart_levels[cLevel].fetch_rfc822_header = true; + fetchMultipartBodyHeader(imap, msgIdx); + } + else + { + if (imap->_multipart_levels[cLevel].append_body_text) + { + // single part rfc822 message body, append TEXT to the body fetch command + prependDot(_cpart->partNumFetchStr, imap_commands[esp_mail_imap_command_text].text); + imap->_multipart_levels[cLevel].append_body_text = false; + } + imap->_multipart_levels[cLevel].level++; + } + } + } + + } while (ret); + + imap->_multipart_levels.pop_back(); + + if (imap->_multipart_levels.size() > 0) + { + cLevel = imap->_multipart_levels.size() - 1; + imap->_multipart_levels[cLevel].level++; + } + + return true; +} + +void ESP_Mail_Client::printBodyPartFechingDubug(IMAPSession *imap, const char *partNum, bool multiLevel) +{ +#if !defined(SILENT_MODE) + MB_String str = multiLevel ? esp_mail_dbg_str_28 /* "fetch body sub part header, " */ : esp_mail_dbg_str_27; /* "fetch body part header, " */ + str += partNum; + esp_mail_debug_print_tag(str.c_str(), esp_mail_debug_tag_type_client, true); +#endif +} + +bool ESP_Mail_Client::imapAuth(IMAPSession *imap, bool &ssl) +{ + + if (!sessionExisted(imap)) + return false; + + imap->_auth_capability[esp_mail_auth_capability_login] = false; + + imap->_session_cfg->int_start_tls = imap->_session_cfg->secure.startTLS; + imap->_session_cfg->int_mode = imap->_session_cfg->secure.mode; + +#if !defined(ESP_MAIL_DISABLE_SSL) +unauthenticate: +#endif + + // capabilities may change after TLS negotiation + if (!imap->checkCapabilities()) + return false; + +#if !defined(ESP_MAIL_DISABLE_SSL) + + if (imap->_session_cfg->int_mode != esp_mail_secure_mode_nonsecure) + { + // start TLS when needed or the server issues + if ((imap->_auth_capability[esp_mail_auth_capability_starttls] || imap->_session_cfg->int_start_tls || imap->_session_cfg->int_mode == esp_mail_secure_mode_ssl_tls) && !ssl) + { +#if !defined(SILENT_MODE) + printDebug(imap, + esp_mail_cb_str_2 /* "Sending STARTTLS command..." */, + esp_mail_dbg_str_1 /* "send command, STARTTLS" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + imapSend(imap, imap->prependTag(imap_commands[esp_mail_imap_command_starttls].text).c_str(), true); + + // rfc2595 section 3.1 + imap->_imap_cmd = esp_mail_imap_cmd_starttls; + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false)) + return false; + +#if !defined(SILENT_MODE) + if (imap->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_22 /* "perform SSL/TLS handshake" */, esp_mail_debug_tag_type_client, true); +#endif + + // connect in secure mode + // do TLS handshake + + if (!imap->client.connectSSL(imap->_session_cfg->certificate.verify)) + return handleIMAPError(imap, MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP, false); + + // set the secure mode + imap->_session_cfg->int_start_tls = false; + imap->_session_cfg->int_mode = esp_mail_secure_mode_undefined; + ssl = true; + imap->_secure = true; + + // check the capabilitiy again to prevent the man in the middle attack + goto unauthenticate; + } + } + +#endif + + imap->clearMessageData(); + imap->_mailboxOpened = false; + + bool creds = imap->_session_cfg->login.email.length() > 0 && imap->_session_cfg->login.password.length() > 0; + bool sasl_auth_oauth = imap->_session_cfg->login.accessToken.length() > 0 && imap->_auth_capability[esp_mail_auth_capability_xoauth2]; + bool sasl_login = creds; + bool sasl_auth_plain = imap->_auth_capability[esp_mail_auth_capability_plain] && creds; + + bool supported_sasl = sasl_auth_oauth || sasl_login || sasl_auth_plain; + + if (!supported_sasl) + return handleIMAPError(imap, IMAP_STATUS_NO_SUPPORTED_AUTH, false); + + // rfc4959 + if (supported_sasl) + { +#if !defined(SILENT_MODE) + if (imap->_statusCallback) + sendCallback(imap, esp_mail_cb_str_14 /* "Logging in..." */, true, false); + else if (imap->_debug) + debugPrintNewLine(); +#endif + } + + if (sasl_auth_oauth) + { + + if (!imap->_auth_capability[esp_mail_auth_capability_xoauth2]) + { + handleIMAPError(imap, IMAP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED, false); + return false; + } + +#if !defined(SILENT_MODE) + if (imap->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_45 /* "send IMAP command, AUTH XOAUTH2" */, esp_mail_debug_tag_type_client, true); +#endif + + MB_String cmd; + joinStringSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_authenticate].text, imap_commands[esp_mail_imap_command_xoauth2].text); + + if (imap->_auth_capability[esp_mail_auth_capability_sasl_ir]) + { + prependSpace(cmd, getXOAUTH2String(imap->_session_cfg->login.email, imap->_session_cfg->login.accessToken).c_str()); + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + else + { + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_sasl_auth_oauth; + if (!handleIMAPResponse(imap, IMAP_STATUS_AUTHENTICATE_FAILED, true)) + return false; + + cmd = getXOAUTH2String(imap->_session_cfg->login.email, imap->_session_cfg->login.accessToken); + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + + imap->_imap_cmd = esp_mail_imap_cmd_sasl_auth_oauth; + if (!handleIMAPResponse(imap, IMAP_STATUS_AUTHENTICATE_FAILED, false)) + return false; + } + else if (sasl_auth_plain) + { + +#if !defined(SILENT_MODE) + if (imap->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_44 /* "send IMAP command, AUTHENTICATE PLAIN" */, esp_mail_debug_tag_type_client, true); +#endif + + int len = imap->_session_cfg->login.email.length() + imap->_session_cfg->login.password.length() + 2; + uint8_t *tmp = allocMem(len); + memset(tmp, 0, len); + int p = 1; + memcpy(tmp + p, imap->_session_cfg->login.email.c_str(), imap->_session_cfg->login.email.length()); + p += imap->_session_cfg->login.email.length() + 1; + memcpy(tmp + p, imap->_session_cfg->login.password.c_str(), imap->_session_cfg->login.password.length()); + p += imap->_session_cfg->login.password.length(); + + MB_String cmd; + joinStringSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_authenticate].text, imap_commands[esp_mail_imap_command_plain].text); + + if (imap->_auth_capability[esp_mail_auth_capability_sasl_ir]) + { + prependSpace(cmd, encodeBase64Str(tmp, p).c_str()); + // release memory + freeMem(&tmp); + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + else + { + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_sasl_auth_plain; + + if (!handleIMAPResponse(imap, IMAP_STATUS_AUTHENTICATE_FAILED, true)) + return false; + + cmd = encodeBase64Str(tmp, p); + // release memory + freeMem(&tmp); + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + } + + imap->_imap_cmd = esp_mail_imap_cmd_sasl_auth_plain; + if (!handleIMAPResponse(imap, IMAP_STATUS_AUTHENTICATE_FAILED, true)) + return false; + } + else if (sasl_login) + { + +#if !defined(SILENT_MODE) + if (imap->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_34 /* "send IMAP command, LOGIN" */, esp_mail_debug_tag_type_client, true); +#endif + MB_String cmd; + joinStringSpace(cmd, true, 3, imap_commands[esp_mail_imap_command_login].text, imap->_session_cfg->login.email.c_str(), imap->_session_cfg->login.password.c_str()); + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_sasl_login; + if (!handleIMAPResponse(imap, IMAP_STATUS_AUTHENTICATE_FAILED, true)) + return false; + } + + // auto capabilities after login? + if (!imap->_feature_capability[esp_mail_imap_read_capability_auto_caps]) + { + if (!imap->checkCapabilities()) + return false; + } + + if (imap->_feature_capability[esp_mail_imap_read_capability_id]) + { + if (!imap->id(&imap->_imap_data->identification)) + return false; + } + + if (supported_sasl) + imap->_authenticated = true; + + return true; +} + +bool ESP_Mail_Client::imapLogout(IMAPSession *imap) +{ + +#if defined(ESP8266) + return false; +#endif + + if (!sessionExisted(imap)) + return false; + +#if !defined(SILENT_MODE) + printDebug(imap, + esp_mail_cb_str_20 /* "Logging out..." */, + esp_mail_dbg_str_38 /* "send IMAP command, LOGOUT" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (imapSend(imap, imap->prependTag(imap_commands[esp_mail_imap_command_logout].text).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_logout; + if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + imap->_authenticated = false; + +#if !defined(SILENT_MODE) + printDebug(imap, + esp_mail_cb_str_47 /* "Log out completed" */, + esp_mail_dbg_str_31 /* "log out completed" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + return true; +} + +size_t ESP_Mail_Client::imapSend(IMAPSession *imap, PGM_P data, bool newline) +{ + if (!imap || !sessionReady(imap)) + return 0; + + int sent = 0; + + MB_String s = data; + + int toSend = newline ? s.length() + 2 : s.length(); + + if (imap->_debug && imap->_debugLevel > esp_mail_debug_level_maintainer && !imap->_customCmdResCallback) + esp_mail_debug_print(s.c_str(), newline); + + sent = newline ? imap->client.println(s.c_str()) : imap->client.print(s.c_str()); + + if (sent != toSend) + { + errorStatusCB(imap, nullptr, sent, true); + sent = 0; + } + + return sent; +} + +size_t ESP_Mail_Client::imapSend(IMAPSession *imap, int data, bool newline) +{ + MB_String s = data; + return imapSend(imap, s.c_str(), newline); +} + +size_t ESP_Mail_Client::imapSend(IMAPSession *imap, uint8_t *data, size_t size) +{ + if (!imap || !sessionReady(imap)) + return 0; + + int sent = 0; + + sent = imap->client.write(data, size); + + if (sent != (int)size) + { + errorStatusCB(imap, nullptr, sent, true); + sent = 0; + } + + return sent; +} + +bool ESP_Mail_Client::mSetFlag(IMAPSession *imap, MB_StringPtr sequenceSet, MB_StringPtr flag, esp_mail_imap_store_flag_type type, bool closeSession, bool silent, bool UID, int32_t modsequence) +{ + if (!reconnect(imap)) + return false; + + if (!imap->connected()) + { + imap->_mailboxOpened = false; + return false; + } + + if (imap->_currentFolder.length() == 0) + { +#if !defined(SILENT_MODE) + printDebug(imap, + esp_mail_error_imap_str_11 /* "no mailbox opened" */, + esp_mail_error_imap_str_11 /* "no mailbox opened" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + } + else + { + if (imap->_readOnlyMode || !imap->_mailboxOpened) + { + if (!imap->selectFolder(imap->_currentFolder.c_str(), false)) + return false; + } + } + +#if !defined(SILENT_MODE) + PGM_P p1 = NULL; + PGM_P p2 = NULL; + if (type == esp_mail_imap_store_flag_type_set) + { + p1 = esp_mail_cb_str_26; /* "Setting FLAG..." */ + p2 = esp_mail_dbg_str_41; /* "setting FLAG" */ + } + else if (type == esp_mail_imap_store_flag_type_add) + { + p1 = esp_mail_cb_str_24; /* "Adding FLAG..." */ + p2 = esp_mail_dbg_str_42; /* "adding FLAG" */ + } + else + { + p1 = esp_mail_cb_str_23; /* "Removing FLAG..." */ + p2 = esp_mail_dbg_str_43; /* "removing FLAG" */ + } + + printDebug(imap, + p1, + p2, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (!sessionExisted(imap)) + return false; + + MB_String cmd; + if (UID) + appendSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_uid].text, imap_commands[esp_mail_imap_command_store].text); + else + appendSpace(cmd, true, imap_commands[esp_mail_imap_command_store].text); + + cmd += sequenceSet; + + imap->addModifier(cmd, esp_mail_imap_command_unchangedsince, modsequence); + + if (type == esp_mail_imap_store_flag_type_set) + cmd += imap_cmd_pre_tokens[esp_mail_imap_command_flags]; + else if (type == esp_mail_imap_store_flag_type_add) + cmd += imap_cmd_pre_tokens[esp_mail_imap_command_plus_flags]; + else + cmd += imap_cmd_pre_tokens[esp_mail_imap_command_minus_flags]; + + if (silent) + prependDot(cmd, imap_commands[esp_mail_imap_command_silent].text); + + appendSpace(cmd); + appendString(cmd, MB_String(flag).c_str(), false, false, esp_mail_string_mark_type_round_bracket); + + if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + imap->_imap_cmd = esp_mail_imap_cmd_store; + + if (!handleIMAPResponse(imap, IMAP_STATUS_STORE_FAILED, false)) + return false; + + if (closeSession) + imap->closeSession(); + + return true; +} + +int ESP_Mail_Client::parseSearchResponse(IMAPSession *imap, esp_mail_imap_response_data &res, PGM_P tag, const char *key) +{ + int bufLen = res.chunkBufSize; + int ret = -1; + char c = 0; + int idx = 0; + int num = 0; + + size_t tagLen = strlen_P(tag); + MB_String _tag = tag; + + while (imap->client.available() > 0 && idx < bufLen) + { + yield_impl(); + + ret = imap->client.read(); + + if (ret > -1) + { + + if (idx >= bufLen - 1) + return idx; + + c = (char)ret; + + if (c == '\n') + c = ' '; + + res.response[idx++] = c; + + if (res.chunkIdx == 0) + { + // Search response parsing + if (strcmp(res.response, key) == 0) + { + res.chunkIdx++; + return 0; + } + else + { + // Status response parsing + res.imapResp = imapResponseStatus(imap, res.response, esp_mail_imap_tag_str); + + // Exit if error or complete (no messages found) + if (res.imapResp != esp_mail_imap_resp_unknown) + goto end_search; + } + } + else + { + if (c == ' ') + { + imap->_mbif._searchCount++; + if (imap->_imap_data->enable.recent_sort) + { + esp_mail_imap_msg_num_t msg_num; + msg_num.type = imap->_uidSearch ? esp_mail_imap_msg_num_type_uid : esp_mail_imap_msg_num_type_number; + msg_num.value = (uint32_t)atoi(res.response); + + imap->_imap_msg_num.push_back(msg_num); + + if (imap->_imap_msg_num.size() > imap->_imap_data->limit.search) + imap->_imap_msg_num.erase(imap->_imap_msg_num.begin()); + } + else + { + if (imap->_imap_msg_num.size() < imap->_imap_data->limit.search) + { + esp_mail_imap_msg_num_t msg_num; + msg_num.type = imap->_uidSearch ? esp_mail_imap_msg_num_type_uid : esp_mail_imap_msg_num_type_number; + msg_num.value = (uint32_t)atoi(res.response); + + imap->_imap_msg_num.push_back(msg_num); + } + } + + if (imap->_debug) + { + num = (float)(100.0f * imap->_mbif._searchCount / imap->_mbif._msgCount); + if (res.searchCount != num) + { + res.searchCount = num; + searchReport(imap, num); + } + } + + res.chunkIdx++; + return idx; + } + else if (idx >= (int)tagLen) + { + if (strpos(res.response, _tag.c_str(), 0, false) > -1) + { +#if defined(MB_USE_STD_VECTOR) + if (imap->_imap_data->enable.recent_sort) + std::sort(imap->_imap_msg_num.begin(), imap->_imap_msg_num.end(), compareMore); +#else + if (imap->_imap_data->enable.recent_sort) + numDecSort(imap->_imap_msg_num); +#endif + goto end_search; + } + } + } + } + } + + return idx; + +end_search: + + res.endSearch = true; + int read = imap->client.available(); + read = imap->client.readBytes(res.response + idx, read); + return idx + read; +} + +#if !defined(MB_USE_STD_VECTOR) +void ESP_Mail_Client::numDecSort(_vectorImpl &arr) +{ + + struct esp_mail_imap_msg_num_t tmp; + + for (size_t i = 0; i < arr.size(); ++i) + { + for (size_t j = i + 1; j < arr.size(); ++j) + { + if (arr[i].value < arr[j].value) + { + tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + } + } +} +#endif + +struct esp_mail_message_part_info_t *ESP_Mail_Client::cPart(IMAPSession *imap) +{ + if (cHeader(imap) && imap->_cPartIdx < (int)cHeader(imap)->part_headers.size()) + return &cHeader(imap)->part_headers[imap->_cPartIdx]; + return nullptr; +} + +struct esp_mail_message_header_t *ESP_Mail_Client::cHeader(IMAPSession *imap) +{ + if (cIdx(imap) < (int)imap->_headers.size()) + return &imap->_headers[cIdx(imap)]; + return nullptr; +} + +bool ESP_Mail_Client::parseHeaderField(IMAPSession *imap, const char *buf, PGM_P beginToken, bool caseSensitive, struct esp_mail_message_header_t &header, int &headerState, int state) +{ + if (strcmpP(buf, 0, beginToken, caseSensitive)) + { + headerState = state; + char *tmp = subStr(buf, beginToken, NULL, 0, -1, caseSensitive); + if (tmp) + { + collectHeaderField(imap, tmp, header, headerState); + // release memory + freeMem(&tmp); + return true; + } + } + + return false; +} + +void ESP_Mail_Client::parseHeaderResponse(IMAPSession *imap, esp_mail_imap_response_data &res, bool caseSensitive) +{ + char *tmp = nullptr; + if (res.chunkIdx == 0) + { + MB_String str; + joinStringDot(str, 2, imap_commands[esp_mail_imap_command_header].text, imap_commands[esp_mail_imap_command_fields].text); + + if (!res.isUntaggedResponse && strposP(res.response, str.c_str(), 0, caseSensitive) != -1 && res.response[0] == '*') + res.isUntaggedResponse = true; + + if (res.isUntaggedResponse && res.response[strlen(res.response) - 1] == '}') + res.untaggedRespCompleted = true; + + if (res.isUntaggedResponse && res.header.message_no == 0) + { + tmp = subStr(res.response, imap_responses[esp_mail_imap_response_untagged].text, imap_responses[esp_mail_imap_response_fetch].text, 0); + if (tmp) + { + res.header.message_no = atoi(tmp); + // release memory + freeMem(&tmp); + } + } + + if (res.isUntaggedResponse && res.untaggedRespCompleted) + { + tmp = subStr(res.response, esp_mail_str_36 /* "{" */, esp_mail_str_37 /* "}" */, 0, 0, caseSensitive); + if (tmp) + { + res.octetCount = 2; + res.header.header_data_len = atoi(tmp); + // release memory + freeMem(&tmp); + res.chunkIdx++; + } + } + } + else + { + if (res.octetCount > res.header.header_data_len + 2) + return; + + res.chunkIdx++; + + MB_String field; + + for (int i = esp_mail_rfc822_header_field_from; i < esp_mail_rfc822_header_field_maxType; i++) + { + appendHeaderName(field, rfc822_headers[i].text, true, false, false); + if (parseHeaderField(imap, res.response, field.c_str(), caseSensitive, res.header, res.headerState, i)) + return; + } + + appendHeaderName(field, message_headers[esp_mail_message_header_field_content_transfer_encoding].text, true, true, false); + + if (parseHeaderField(imap, res.response, field.c_str(), caseSensitive, res.header, res.headerState, esp_mail_imap_state_content_transfer_encoding)) + return; + + appendHeaderName(field, message_headers[esp_mail_message_header_field_accept_language].text, true, true, false); + + if (parseHeaderField(imap, res.response, field.c_str(), caseSensitive, res.header, res.headerState, esp_mail_imap_state_accept_language)) + return; + + appendHeaderName(field, message_headers[esp_mail_message_header_field_content_language].text, true, true, false); + + if (parseHeaderField(imap, res.response, field.c_str(), caseSensitive, res.header, res.headerState, esp_mail_imap_state_content_language)) + return; + + MB_String contentTypeName; + appendHeaderName(contentTypeName, message_headers[esp_mail_message_header_field_content_type].text, false, false, false); + if (strcmpP(res.response, 0, contentTypeName.c_str(), caseSensitive)) + { + res.headerState = esp_mail_imap_state_content_type; + tmp = subStr(res.response, contentTypeName.c_str(), esp_mail_str_35 /* ";" */, 0, 0, caseSensitive); + if (tmp) + { + // We set attachment status here as attachment should be included in multipart/mixed message, + // unless no real attachments included which we don't know until fetching the sub part. + if (strpos(tmp, esp_mail_imap_multipart_sub_type_t::mixed, 0, caseSensitive) != -1) + res.header.hasAttachment = true; + + collectHeaderField(imap, res.response, res.header, res.headerState); + // release memory + freeMem(&tmp); + } + } + } +} + +void ESP_Mail_Client::collectHeaderField(IMAPSession *imap, char *buf, struct esp_mail_message_header_t &header, int state) +{ + size_t i = 0; + while (buf[i] == ' ') + { + i++; + if (strlen(buf) <= i) + return; + } + + if (state < esp_mail_rfc822_header_field_maxType) + { + int ptr = getRFC822HeaderPtr(state, &header.header_fields); + if (ptr > 0) + { + *(addrTo(ptr)) += &buf[i]; + } + return; + } + + switch (state) + { + case esp_mail_imap_state_content_type: + header.content_type += &buf[i]; + break; + case esp_mail_imap_state_content_transfer_encoding: + header.content_transfer_encoding += &buf[i]; + break; + case esp_mail_imap_state_accept_language: + header.accept_language += &buf[i]; + break; + case esp_mail_imap_state_content_language: + header.content_language += &buf[i]; + break; + case esp_mail_imap_state_char_set: + header.char_set += &buf[i]; + break; + case esp_mail_imap_state_boundary: + header.boundary += &buf[i]; + break; + default: + break; + } +} + +bool ESP_Mail_Client::getDecodedHeader(IMAPSession *imap, const char *buf, PGM_P beginToken, MB_String &out, bool caseSensitive) +{ + if (getHeader(buf, beginToken, out, caseSensitive)) + { + // decode header text + decodeString(imap, out); + return true; + } + return false; +} + +void ESP_Mail_Client::checkFirmwareFile(IMAPSession *imap, const char *filename, struct esp_mail_message_part_info_t &part, bool defaultSize) +{ + if (strcmp(filename, imap->_imap_data->firmware_update.attach_filename.c_str()) == 0 && part.attach_type == esp_mail_att_type_attachment) + { + part.is_firmware_file = true; + // If no file size prop from Content-Disposition header + if (part.attach_data_size == 0 && defaultSize) + { +#if defined(ESP32) || defined(ESP8266) + int sketchFreeSpace = ESP.getFreeSketchSpace(); + part.attach_data_size = sketchFreeSpace ? sketchFreeSpace : 1024000; +#elif defined(MB_ARDUINO_PICO) + size_t spiffsSize = ((size_t)&_FS_end - (size_t)&_FS_start); + part.attach_data_size = spiffsSize ? spiffsSize / 2 : 1024000; +#endif + } + + if (!imap->_imap_data->firmware_update.save_to_file) + part.save_to_file = false; + } +} + +void ESP_Mail_Client::parsePartHeaderResponse(IMAPSession *imap, esp_mail_imap_response_data &res, bool caseSensitive) +{ + char *tmp = nullptr; + if (res.chunkIdx == 0) + { + tmp = subStr(res.response, imap_responses[esp_mail_imap_response_fetch].text, NULL, 0, -1); + if (tmp) + { + // release memory + freeMem(&tmp); + tmp = subStr(res.response, esp_mail_str_36 /* "{" */, esp_mail_str_37 /* "}" */, 0); + if (tmp) + { + res.chunkIdx++; + res.part.octetLen = atoi(tmp); + res.octetCount = 2; + // release memory + freeMem(&tmp); + } + } + } + else + { + MB_String value, old_value; + bool valueStored = false; + res.chunkIdx++; + + // if all octets read + + if (res.octetCount > res.part.octetLen) + { + + // Is inline attachment without content id or name or filename? + // It is supposed to be the inline message txt content, reset attach type to none + + if (res.part.attach_type == esp_mail_att_type_inline && res.part.CID.length() == 0) + res.part.attach_type = esp_mail_att_type_none; + + // Is attachment file extension missing? + // append extension + + if (res.part.attach_type == esp_mail_att_type_inline || res.part.attach_type == esp_mail_att_type_attachment) + { + if (res.part.filename.length() > 0 && res.part.filename.find('.') == MB_String::npos) + { + MB_String ext; + getExtfromMIME(res.part.content_type.c_str(), ext); + res.part.filename += ext; + } + + checkFirmwareFile(imap, res.part.filename.c_str(), res.part); + } + + return; + } + + // Content header field parse + if (strcmpP(res.response, 0, esp_mail_str_56 /* "content-" */, caseSensitive)) + { + // Content-Type + MB_String contentTypeName; + appendHeaderName(contentTypeName, message_headers[esp_mail_message_header_field_content_type].text, false, false, false); + if (strcmpP(res.response, 0, contentTypeName.c_str(), caseSensitive)) + { + + res.part.cur_content_hdr = esp_mail_message_part_info_t::content_header_field_type; + resetStringPtr(res.part); + + tmp = subStr(res.response, contentTypeName.c_str(), esp_mail_str_35 /* ";" */, 0, 0, caseSensitive); + if (tmp) + { + res.part.content_type = tmp; + // release memory + freeMem(&tmp); + int p1 = strposP(res.part.content_type.c_str(), esp_mail_imap_composite_media_type_t::multipart, 0, caseSensitive); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_composite_media_type_t::multipart) + 1; + res.part.multipart = true; + // inline or embedded images + if (strpos(res.part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::related, p1, caseSensitive) != -1) + res.part.multipart_sub_type = esp_mail_imap_multipart_sub_type_related; + // multiple text formats e.g. plain, html, enriched + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::alternative, p1, caseSensitive) != -1) + res.part.multipart_sub_type = esp_mail_imap_multipart_sub_type_alternative; + // medias + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::parallel, p1, caseSensitive) != -1) + res.part.multipart_sub_type = esp_mail_imap_multipart_sub_type_parallel; + // rfc822 encapsulated + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::digest, p1, caseSensitive) != -1) + res.part.multipart_sub_type = esp_mail_imap_multipart_sub_type_digest; + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::report, p1, caseSensitive) != -1) + res.part.multipart_sub_type = esp_mail_imap_multipart_sub_type_report; + // others can be attachments + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::mixed, p1, caseSensitive) != -1) + res.part.multipart_sub_type = esp_mail_imap_multipart_sub_type_mixed; + } + + p1 = strposP(res.part.content_type.c_str(), esp_mail_imap_composite_media_type_t::message, 0, caseSensitive); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_composite_media_type_t::message) + 1; + if (strpos(res.part.content_type.c_str(), esp_mail_imap_message_sub_type_t::rfc822, p1, caseSensitive) != -1) + res.part.message_sub_type = esp_mail_imap_message_sub_type_rfc822; + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_message_sub_type_t::Partial, p1, caseSensitive) != -1) + res.part.message_sub_type = esp_mail_imap_message_sub_type_partial; + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_message_sub_type_t::External_Body, p1, caseSensitive) != -1) + res.part.message_sub_type = esp_mail_imap_message_sub_type_external_body; + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_message_sub_type_t::delivery_status, p1, caseSensitive) != -1) + res.part.message_sub_type = esp_mail_imap_message_sub_type_delivery_status; + } + + p1 = strpos(res.part.content_type.c_str(), esp_mail_imap_descrete_media_type_t::text, 0, caseSensitive); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_descrete_media_type_t::text) + 1; + if (strpos(res.part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::plain, p1, caseSensitive) != -1) + res.part.msg_type = esp_mail_msg_type_plain; + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::enriched, p1, caseSensitive) != -1) + res.part.msg_type = esp_mail_msg_type_enriched; + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::html, p1, caseSensitive) != -1) + res.part.msg_type = esp_mail_msg_type_html; + else + res.part.msg_type = esp_mail_msg_type_plain; + } + } + } + + // Content-Description + MB_String contentDescrName; + appendHeaderName(contentDescrName, message_headers[esp_mail_message_header_field_content_description].text, false, true, false); + if (getDecodedHeader(imap, res.response, contentDescrName.c_str(), res.part.descr, caseSensitive)) + { + res.part.cur_content_hdr = esp_mail_message_part_info_t::content_header_field_description; + + tmp = subStr(res.response, contentDescrName.c_str(), NULL, 0, -1, caseSensitive); + if (tmp) + { + value = tmp; + // release memory + freeMem(&tmp); + + res.part.stringPtr = toAddr(res.part.content_description); + value.trim(); + if (value.length() == 0) + return; + } + } + + // Content-ID + MB_String contentIdName; + appendHeaderName(contentIdName, message_headers[esp_mail_message_header_field_content_id].text, false, true, false); + if (strcmpP(res.response, 0, contentIdName.c_str(), caseSensitive)) + { + tmp = subStr(res.response, contentIdName.c_str(), NULL, 0, -1, caseSensitive); + if (tmp) + { + res.part.CID = tmp; + // release memory + freeMem(&tmp); + res.part.CID.trim(); + + if (res.part.CID[0] == '<') + res.part.CID.erase(0, 1); + + if (res.part.CID[res.part.CID.length() - 1] == '>') + res.part.CID.erase(res.part.CID.length() - 1, 1); + + // if inline attachment file name was not assigned + if (res.part.attach_type == esp_mail_att_type_inline && res.part.filename.length() == 0) + { + // set filename from content id and append extension later + res.part.filename = res.part.CID; + res.part.name = res.part.filename; + } + } + + res.part.cur_content_hdr = esp_mail_message_part_info_t::content_header_field_id; + resetStringPtr(res.part); + } + + // Content-Disposition + MB_String contentDispositionName; + appendHeaderName(contentDispositionName, message_headers[esp_mail_message_header_field_content_disposition].text, false, true, false); + if (strcmpP(res.response, 0, contentDispositionName.c_str(), caseSensitive)) + { + + res.part.cur_content_hdr = esp_mail_message_part_info_t::content_header_field_disposition; + resetStringPtr(res.part); + + tmp = subStr(res.response, contentDispositionName.c_str(), esp_mail_str_35 /* ";" */, 0, 0, caseSensitive); + if (tmp) + { + // don't count altenative part text and html as embedded contents + if (cHeader(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_alternative) + { + res.part.content_disposition = tmp; + if (caseSensitive) + { + if (strcmp(tmp, esp_mail_content_disposition_type_t::attachment) == 0) + res.part.attach_type = esp_mail_att_type_attachment; + else if (strcmp(tmp, esp_mail_content_disposition_type_t::inline_) == 0) + res.part.attach_type = esp_mail_att_type_inline; + } + else + { + if (strcasecmp(tmp, esp_mail_content_disposition_type_t::attachment) == 0) + res.part.attach_type = esp_mail_att_type_attachment; + else if (strcasecmp(tmp, esp_mail_content_disposition_type_t::inline_) == 0) + res.part.attach_type = esp_mail_att_type_inline; + } + } + // release memory + freeMem(&tmp); + } + } + + // Content-Transfer-Encoding + MB_String contentTEName; + appendHeaderName(contentTEName, message_headers[esp_mail_message_header_field_content_transfer_encoding].text, false, true, false); + if (strcmpP(res.response, 0, contentTEName.c_str(), caseSensitive)) + { + // store last text field + + res.part.cur_content_hdr = esp_mail_message_part_info_t::content_header_field_transfer_enc; + resetStringPtr(res.part); + + tmp = subStr(res.response, contentTEName.c_str(), NULL, 0, -1, caseSensitive); + if (tmp) + { + res.part.content_transfer_encoding = tmp; + + if (strcmpP(tmp, 0, esp_mail_transfer_encoding_t::enc_base64)) + res.part.xencoding = esp_mail_msg_xencoding_base64; + else if (strcmpP(tmp, 0, esp_mail_transfer_encoding_t::enc_qp)) + res.part.xencoding = esp_mail_msg_xencoding_qp; + else if (strcmpP(tmp, 0, esp_mail_transfer_encoding_t::enc_7bit)) + res.part.xencoding = esp_mail_msg_xencoding_7bit; + else if (strcmpP(tmp, 0, esp_mail_transfer_encoding_t::enc_8bit)) + res.part.xencoding = esp_mail_msg_xencoding_8bit; + else if (strcmpP(tmp, 0, esp_mail_transfer_encoding_t::enc_binary)) + res.part.xencoding = esp_mail_msg_xencoding_binary; + // release memory + freeMem(&tmp); + } + } + } + else + { + + if (res.part.cur_content_hdr == esp_mail_message_part_info_t::content_header_field_none) + { + + resetStringPtr(res.part); + + MB_String field; + for (int i = esp_mail_rfc822_header_field_from; i < esp_mail_rfc822_header_field_maxType; i++) + { + field = rfc822_headers[i].text; + field += esp_mail_str_34; /* ":" */ + ; + + int ptr = getRFC822HeaderPtr(i, &res.part.rfc822_header); + if (ptr > 0) + { + if (getDecodedHeader(imap, res.response, field.c_str(), *(addrTo(ptr)), caseSensitive)) + return; + } + } + } + } + + // parse content type header sub type properties + if (res.part.cur_content_hdr == esp_mail_message_part_info_t::content_header_field_type) + { + + if (res.part.msg_type == esp_mail_msg_type_plain || res.part.msg_type == esp_mail_msg_type_enriched) + { + MB_String charset; + appendLowerCaseString(charset, message_headers[esp_mail_message_header_field_charset].text, false); + // We have to check for both quotes string or non quote string + if (getPartHeaderProperties(imap, res.response, charset.c_str(), esp_mail_str_11 /* "\"" */, false, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.charset = value; + resetStringPtr(res.part); + } + else if (getPartHeaderProperties(imap, res.response, charset.c_str(), esp_mail_str_35 /* ";" */, true, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.charset = value; + resetStringPtr(res.part); + } + + if (strposP(res.response, esp_mail_str_59 /* "format=flowed" */, 0, caseSensitive) > -1 || strposP(res.response, esp_mail_str_58 /* "format=\"flowed\"" */, 0, caseSensitive) > -1) + { + res.part.plain_flowed = true; + resetStringPtr(res.part); + } + + if (strposP(res.response, esp_mail_str_61 /* "delsp=yes" */, 0, caseSensitive) > -1 || strposP(res.response, esp_mail_str_60 /* "delsp=\"yes\"" */, 0, caseSensitive) > -1) + { + res.part.plain_delsp = true; + resetStringPtr(res.part); + } + } + + if (res.part.charset.length() == 0) + { + MB_String charset; + appendLowerCaseString(charset, message_headers[esp_mail_message_header_field_charset].text, false); + // We have to check for both quotes string or non quote string + if (getPartHeaderProperties(imap, res.response, charset.c_str(), esp_mail_str_11 /* "\"" */, false, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.charset = value; + resetStringPtr(res.part); + } + else if (getPartHeaderProperties(imap, res.response, charset.c_str(), esp_mail_str_35 /* ";" */, true, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.charset = value; + resetStringPtr(res.part); + } + } + + MB_String name; + appendLowerCaseString(name, message_headers[esp_mail_message_header_field_name].text, false); + // We have to check for both quotes string or non quote string + if (getPartHeaderProperties(imap, res.response, name.c_str(), esp_mail_str_11 /* "\"" */, false, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.stringPtr = toAddr(res.part.name); + value.trim(); + if (value.length() == 0) + return; + } + else if (getPartHeaderProperties(imap, res.response, name.c_str(), esp_mail_str_35 /* ";" */, true, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.stringPtr = toAddr(res.part.name); + value.trim(); + if (value.length() == 0) + return; + } + } + + // parse content disposition header sub type properties + if (res.part.cur_content_hdr == esp_mail_message_part_info_t::content_header_field_disposition && res.part.content_disposition.length() > 0) + { + // filename prop + MB_String filename; + appendLowerCaseString(filename, message_headers[esp_mail_message_header_field_filename].text, false); + // We have to check for both quotes string or non quote string + if (getPartHeaderProperties(imap, res.response, filename.c_str(), esp_mail_str_11 /* "\"" */, false, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.stringPtr = toAddr(res.part.filename); + value.trim(); + if (value.length() == 0) + return; + } + else if (getPartHeaderProperties(imap, res.response, filename.c_str(), esp_mail_str_35 /* ";" */, true, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.stringPtr = toAddr(res.part.filename); + value.trim(); + if (value.length() == 0) + return; + } + + // size prop + MB_String size; + appendLowerCaseString(size, message_headers[esp_mail_message_header_field_size].text, false); + + if (getPartHeaderProperties(imap, res.response, size.c_str(), esp_mail_str_35 /* ";" */, true, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.attach_data_size = atoi(value.c_str()); + cHeader(imap)->total_attach_data_size += res.part.attach_data_size; + res.part.sizeProp = true; + + if (!valueStored && old_value.length() > 0) + valueStored = storeStringPtr(imap, res.part.stringPtr, old_value, res.response); + resetStringPtr(res.part); + } + + // creation date prop + MB_String creationDate; + appendLowerCaseString(creationDate, message_headers[esp_mail_message_header_field_creation_date].text, false); + + if (getPartHeaderProperties(imap, res.response, creationDate.c_str(), esp_mail_str_11 /* "\"" */, false, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.creation_date = value; + if (!valueStored && old_value.length() > 0) + valueStored = storeStringPtr(imap, res.part.stringPtr, old_value, res.response); + resetStringPtr(res.part); + } + + // mod date prop + MB_String modDate; + appendLowerCaseString(modDate, message_headers[esp_mail_message_header_field_modification_date].text, false); + + if (getPartHeaderProperties(imap, res.response, modDate.c_str(), esp_mail_str_11 /* "\"" */, false, value, old_value, res.part.stringEnc, caseSensitive)) + { + res.part.modification_date = value; + if (!valueStored && old_value.length() > 0) + valueStored = storeStringPtr(imap, res.part.stringPtr, old_value, res.response); + resetStringPtr(res.part); + } + } + + if (!valueStored && (res.part.cur_content_hdr == esp_mail_message_part_info_t::content_header_field_description || res.part.cur_content_hdr == esp_mail_message_part_info_t::content_header_field_type || res.part.cur_content_hdr == esp_mail_message_part_info_t::content_header_field_disposition)) + storeStringPtr(imap, res.part.stringPtr, value, res.response); + } +} + +void ESP_Mail_Client::resetStringPtr(struct esp_mail_message_part_info_t &part) +{ + part.stringPtr = 0; + part.stringEnc = esp_mail_char_decoding_scheme_default; +} + +int ESP_Mail_Client::countChar(const char *buf, char find) +{ + if (!buf) + return 0; + + int count = 0; + + for (size_t i = 0; i < strlen(buf); i++) + { + if (buf[i] == find) + count++; + } + + return count; +} + +bool ESP_Mail_Client::storeStringPtr(IMAPSession *imap, uint32_t addr, MB_String &value, const char *buf) +{ + if (addr) + { + MB_String *a = addrTo(addr); + MB_String s = value.length() > 0 ? value : buf; + + // is value string contains double quotes? + // trim it + if (countChar(s.c_str(), '"') == 2) + s.trim(); + + if (s[0] == '"') + s.erase(0, 1); + + if (s[s.length() - 1] == '"') + s.erase(s.length() - 1, 1); + + decodeString(imap, s); + + *a += s; + + return true; + } + + return false; +} + +bool ESP_Mail_Client::getPartHeaderProperties(IMAPSession *imap, const char *buf, PGM_P p, PGM_P e, bool num, MB_String &value, MB_String &old_value, esp_mail_char_decoding_scheme &scheme, bool caseSensitive) +{ + + MB_String str = p; + str += esp_mail_str_7; /* "=" */ + if (!num) + str += esp_mail_str_11; /* "\"" */ + + char *tmp = subStr(buf, str.c_str(), e, 0, 0, caseSensitive); + if (!tmp) + { + str = p; + str += esp_mail_str_7; /* "=" */ + tmp = subStr(buf, str.c_str(), e, 0, 0, caseSensitive); + if (tmp) + { + // other sub headers found? + int p2 = strposP(tmp, esp_mail_str_35 /* ";" */, 0, caseSensitive); + if (p2 > -1) + { + // release memory + freeMem(&tmp); + tmp = subStr(buf, str.c_str(), esp_mail_str_35 /* ";" */, 0, 0, caseSensitive); + } + // release memory in case above condition does not match + freeMem(&tmp); + } + else + { + // Extended notation rfc5987 + str = p; + str += esp_mail_str_3; /* "*" */ + int p2 = strpos(buf, str.c_str(), 0, caseSensitive); + if (p2 > -1) + { + int p3 = strposP(buf, esp_mail_str_3 /* "*" */, p2 + str.length() + 1, caseSensitive); + if (p3 > -1 && p3 < (int)strlen(buf)) + { + MB_String charset; + + p3 += 2; + + int p4 = strpos(buf, "'", p3, caseSensitive); + if (p4 > -1) + { + + scheme = getEncodingFromCharset(buf); + int c1 = p4 + 1; + p4 = strpos(buf, "'", p4 + 1, caseSensitive); + int c2 = p4; + if (c2 > -1) + { + charset.append(buf + c1, c2 - c1); + } + p3 = p4 + 1; + } + + int len = strlen(buf) - p3; + tmp = allocMem(len + 1); + + if (buf[strlen(buf) - 1] == ';') + len--; + + memcpy(tmp, &buf[p3], len); + + if (scheme == esp_mail_char_decoding_scheme_utf_8) + { + char *buf2 = urlDecode(tmp); + // release memory and point to new buffer + freeMem(&tmp); + tmp = buf2; + } + else if (imap->_charDecCallback) + { + IMAP_Decoding_Info decoding; + decoding.charset = charset.c_str(); + decoding.data = tmp; + decoding.type = IMAP_Decoding_Info::message_part_type_header; + + imap->_charDecCallback(&decoding); + + if (decoding.decodedString.length() > 0) + { + char *buf2 = allocMem(decoding.decodedString.length() + 1); + strcpy(buf2, decoding.decodedString.c_str()); + // release memory and point to new buffer + freeMem(&tmp); + tmp = buf2; + } + } + else if (scheme == esp_mail_char_decoding_scheme_iso8859_1) + { + int ilen = strlen(tmp); + int olen = (ilen + 1) * 2; + char *buf2 = allocMem(olen); + decodeLatin1_UTF8((unsigned char *)buf2, &olen, (unsigned char *)tmp, &ilen); + // release memory and point to new buffer + freeMem(&tmp); + tmp = buf2; + } + else if (scheme == esp_mail_char_decoding_scheme_tis_620 || scheme == esp_mail_char_decoding_scheme_iso8859_11 || scheme == esp_mail_char_decoding_scheme_windows_874) + { + int ilen = strlen(tmp); + char *buf2 = allocMem((ilen + 1) * 3); + decodeTIS620_UTF8(buf2, tmp, ilen); + // release memory and point to new buffer + freeMem(&tmp); + tmp = buf2; + } + } + } + } + } + + if (tmp) + { + old_value = value; + value = tmp; + // release memory + freeMem(&tmp); + return true; + } + + return false; +} + +char *ESP_Mail_Client::urlDecode(const char *str) +{ + int d = 0; /* whether or not the string is decoded */ + char *dStr = allocMem(strlen(str) + 1); + char eStr[] = "00"; /* for a hex code */ + + strcpy(dStr, str); + + while (!d) + { + d = 1; + size_t i; /* the counter for the string */ + + for (i = 0; i < strlen(dStr); ++i) + { + + if (dStr[i] == '%') + { + if (dStr[i + 1] == 0) + return dStr; + + if (isxdigit(dStr[i + 1]) && isxdigit(dStr[i + 2])) + { + d = 0; + + /* combine the next to numbers into one */ + eStr[0] = dStr[i + 1]; + eStr[1] = dStr[i + 2]; + + /* convert it to decimal */ + long int x = strtol(eStr, NULL, 16); + + /* remove the hex */ + memmove(&dStr[i + 1], &dStr[i + 3], strlen(&dStr[i + 3]) + 1); + + dStr[i] = x; + } + } + } + } + + return dStr; +} + +bool ESP_Mail_Client::handleIMAPResponse(IMAPSession *imap, int errCode, bool closeSession) +{ + + if (!reconnect(imap)) + return false; + + esp_mail_imap_response_data res(imap->client.available()); + imap->_lastProgress = -1; + + // Flag used for CRLF inclusion in response reading in case 8bit/binary attachment and base64 encoded and binary messages + bool withLineBreak = imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text && (cPart(imap)->xencoding == esp_mail_msg_xencoding_base64 || cPart(imap)->xencoding == esp_mail_msg_xencoding_binary); + withLineBreak |= imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment && cPart(imap)->xencoding != esp_mail_msg_xencoding_base64; + + // custom cmd IDLE?, waiting incoming server response + if (res.chunkBufSize == 0 && imap->_prev_imap_custom_cmd == imap->_imap_custom_cmd && imap->_imap_custom_cmd == esp_mail_imap_cmd_idle) + { + if (!reconnect(imap)) + return false; + + return true; + } + + while (imap->connected() && res.chunkBufSize <= 0) + { + + if (!reconnect(imap, res.dataTime)) + return false; + + if (!connected(imap)) + { +#if defined(ESP32) + if (imap->_imap_cmd == esp_mail_imap_cmd_logout) // suppress the error due to server closes the connection immediately in ESP32 core v2.0.4 + return true; +#endif + if (millis() - imap->_last_network_error_ms > 1000) + { + imap->_last_network_error_ms = millis(); + errorStatusCB(imap, nullptr, MAIL_CLIENT_ERROR_CONNECTION_CLOSED, true); + } + + return false; + } + res.chunkBufSize = imap->client.available(); + yield_impl(); + } + + res.dataTime = millis(); + + if (res.chunkBufSize > 0) + { + if (imap->_imap_cmd == esp_mail_imap_cmd_examine) + { + imap->_mbif.clear(); + imap->_nextUID.clear(); + imap->_unseenMsgIndex.clear(); + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_search) + { + imap->_mbif._searchCount = 0; + imap->_imap_msg_num.clear(); + } + + // response buffer + res.chunkBufSize = ESP_MAIL_CLIENT_RESPONSE_BUFFER_SIZE; + res.response = allocMem(res.chunkBufSize + 1); + + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + res.lastBuf = allocMem(BASE64_CHUNKED_LEN + 1); + + while (!res.completedResponse) // looking for operation finishing + { + yield_impl(); + + if (imap->_imap_cmd == esp_mail_imap_cmd_append || (imap->_imap_custom_cmd == esp_mail_imap_cmd_append && imap->_imap_cmd == esp_mail_imap_cmd_custom && imap->_customCmdResCallback)) + { + // No waiting time out for APPEND + res.dataTime = millis(); + } + + if (!reconnect(imap, res.dataTime) || !connected(imap)) + { + + if (!connected(imap)) + { + + if (cPart(imap) && cPart(imap)->file_open_write) + mbfs->close(mbfs_type imap->_imap_data->storage.type); + +#if defined(ESP32) + if (imap->_imap_cmd == esp_mail_imap_cmd_logout) // suppress the error due to server closes the connection immediately in ESP32 core v2.0.4 + return true; +#endif + + if (millis() - imap->_last_network_error_ms > 1000) + { + imap->_last_network_error_ms = millis(); + errorStatusCB(imap, nullptr, MAIL_CLIENT_ERROR_CONNECTION_CLOSED, true); + } + + return false; + } + return false; + } + + res.chunkBufSize = imap->client.available(); + + if (res.chunkBufSize > 0) + { + res.chunkBufSize = ESP_MAIL_CLIENT_RESPONSE_BUFFER_SIZE; + + if (imap->_imap_cmd == esp_mail_imap_cmd_search) + { + + res.readLen = parseSearchResponse(imap, res, esp_mail_imap_tag_str, imap_responses[esp_mail_imap_response_search].text); + imap->_mbif._availableItems = imap->_imap_msg_num.size(); + + if (imap->_mbif._availableItems == 0) + { + res.imapResp = imapResponseStatus(imap, res.response, esp_mail_imap_tag_str); + + if (res.imapResp != esp_mail_imap_resp_unknown) + res.endSearch = true; + + if (res.imapResp == esp_mail_imap_resp_bad) + { + errorStatusCB(imap, nullptr, IMAP_STATUS_BAD_COMMAND, false); + return false; + } + } + } + else + { + // response read as chunk ended with CRLF or complete buffer size + int o = res.octetCount; + res.readLen = 0; + MB_String ovfBuf; + if (!readResponse(imap, res.response, res.chunkBufSize, res.readLen, withLineBreak, res.octetCount, ovfBuf)) + { + errorStatusCB(imap, nullptr, MAIL_CLIENT_ERROR_READ_TIMEOUT, true); + return false; + } + + // If buffer overflown, copy from overflow buffer + if (ovfBuf.length() > 0) + { + // release memory + freeMem(&res.response); + res.response = allocMem(ovfBuf.length() + 1); + strcpy(res.response, ovfBuf.c_str()); + ovfBuf.clear(); + } + + if (res.readLen == 0 && o != res.octetCount && res.octetCount <= res.octetLength && cPart(imap)->xencoding != esp_mail_msg_xencoding_base64 && cPart(imap)->xencoding != esp_mail_msg_xencoding_binary && cPart(imap)->xencoding != esp_mail_msg_xencoding_qp) + { + strcpy_P(res.response, esp_mail_str_42 /* "\r\n" */); + res.readLen = 2; + } + } + + if (res.readLen) + { + if (imap->_debug && imap->_debugLevel > esp_mail_debug_level_basic && !imap->_customCmdResCallback) + { + if (imap->_imap_cmd != esp_mail_imap_cmd_search && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_text && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_attachment && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_inline) + esp_mail_debug_print((const char *)res.response, true); + } + + if (imap->_imap_cmd != esp_mail_imap_cmd_search || (imap->_imap_cmd == esp_mail_imap_cmd_search && res.endSearch)) + res.imapResp = imapResponseStatus(imap, res.response, esp_mail_imap_tag_str); + + if (res.imapResp != esp_mail_imap_resp_unknown) + { + + // We've got the right response, + // prepare to exit + + res.completedResponse = true; + + if (imap->_debug && imap->_debugLevel > esp_mail_debug_level_basic && !imap->_customCmdResCallback) + { + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + esp_mail_debug_print((const char *)res.response, true); + } + + MB_String ovfBuf; + + while (imap->client.available()) + { + + if (!readResponse(imap, res.response, res.chunkBufSize, res.readLen, true, res.octetCount, ovfBuf)) + { + errorStatusCB(imap, nullptr, MAIL_CLIENT_ERROR_READ_TIMEOUT, true); + return false; + } + // If buffer overflown, copy from overflow buffer + if (ovfBuf.length() > 0) + { + // release memory + freeMem(&res.response); + res.response = allocMem(ovfBuf.length() + 1); + strcpy(res.response, ovfBuf.c_str()); + ovfBuf.clear(); + } + + if (res.readLen) + { + if (imap->_debug && imap->_debugLevel > esp_mail_debug_level_basic && !imap->_customCmdResCallback) + { + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + esp_mail_debug_print((const char *)res.response, true); + } + } + } + } + else + { + + // No response ever parsed + + if (imap->_imap_cmd == esp_mail_imap_cmd_sasl_auth_plain || imap->_imap_cmd == esp_mail_imap_cmd_sasl_auth_oauth) + { + if (imap->_imap_cmd == esp_mail_imap_cmd_sasl_auth_oauth) + { + if (isOAuthError(res.response, res.readLen, res.chunkIdx, 2)) + res.completedResponse = true; + } + + // In case SASL-IR extension does not support, check for initial zero-length server challenge first "+ " + if (!imap->_auth_capability[esp_mail_auth_capability_sasl_ir] && strcmp(res.response, pgm2Str(esp_mail_str_63 /* "+ " */)) == 0) + { + res.imapResp = esp_mail_imap_resp_ok; + res.completedResponse = true; + } + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_sasl_login || imap->_imap_cmd == esp_mail_imap_cmd_sasl_auth_oauth || imap->_imap_cmd == esp_mail_imap_cmd_sasl_auth_plain) + { + int i = 0; + if (parseCapabilityResponse(imap, res.response, i)) + imap->_feature_capability[esp_mail_imap_read_capability_auto_caps] = true; + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_custom && imap->_customCmdResCallback) + { + + res.imapResp = imapResponseStatus(imap, res.response, imap->_responseStatus.tag.c_str()); + + // get response or custom cmd APPEND or custom cmd IDLE? + if (res.imapResp > esp_mail_imap_resp_unknown || strposP(imap->_cmd.c_str(), imap_commands[esp_mail_imap_command_append].text, 0, false) > -1 || imap->_imap_custom_cmd == esp_mail_imap_cmd_idle) + res.completedResponse = true; + + imap->_responseStatus.text = res.response; + + imap->_customCmdResCallback(imap->_responseStatus); + + if (res.completedResponse) + return true; + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_append) + { + res.imapResp = esp_mail_imap_resp_ok; + res.completedResponse = true; + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_capability) + parseCapabilityResponse(imap, res.response, res.chunkIdx); + else if (imap->_imap_cmd == esp_mail_imap_cmd_list) + parseFoldersResponse(imap, res.response, true); + else if (imap->_imap_cmd == esp_mail_imap_cmd_lsub) + parseFoldersResponse(imap, res.response, false); + else if (imap->_imap_cmd == esp_mail_imap_cmd_select || imap->_imap_cmd == esp_mail_imap_cmd_examine) + parseExamineResponse(imap, res.response); + else if (imap->_imap_cmd == esp_mail_imap_cmd_get_uid) + { + MB_String str; + appendFetchString(str, true); + parseCmdResponse(imap, res.response, str.c_str()); + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_get_flags) + { + MB_String str; + appendFetchString(str, false); + parseCmdResponse(imap, res.response, str.c_str()); + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_get_quota) + parseCmdResponse(imap, res.response, imap_responses[esp_mail_imap_response_quota].text); + else if (imap->_imap_cmd == esp_mail_imap_cmd_id) + parseCmdResponse(imap, res.response, imap_responses[esp_mail_imap_response_id].text); + else if (imap->_imap_cmd == esp_mail_imap_cmd_get_quota_root) + { + parseCmdResponse(imap, res.response, imap_responses[esp_mail_imap_response_quotaroot].text); + imap->_quota_tmp.clear(); + parseCmdResponse(imap, res.response, imap_responses[esp_mail_imap_response_quota].text); + if (imap->_quota_tmp.length() > 0) + { + imap->_quota_root_tmp += (char)':'; + imap->_quota_root_tmp += imap->_quota_tmp; + } + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_get_acl || imap->_imap_cmd == esp_mail_imap_cmd_my_rights) + parseCmdResponse(imap, res.response, imap->_imap_cmd == esp_mail_imap_cmd_get_acl ? imap_responses[esp_mail_imap_response_acl].text : imap_responses[esp_mail_imap_response_myrights].text); + else if (imap->_imap_cmd == esp_mail_imap_cmd_namespace) + parseCmdResponse(imap, res.response, imap_responses[esp_mail_imap_response_namespace].text); + else if (imap->_imap_cmd == esp_mail_imap_cmd_idle) + { + res.completedResponse = res.response[0] == '+'; + res.imapResp = esp_mail_imap_resp_ok; + + imap->_last_host_check_ms = millis(); + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_sequence_set) + { + MB_String str; + appendFetchString(str, true); + parseCmdResponse(imap, res.response, str.c_str()); + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header) + { + + if (res.headerState == 0 && cMSG(imap).type == esp_mail_imap_msg_num_type_uid) + res.header.message_uid = cMSG(imap).value; + + int _st = res.headerState; + parseHeaderResponse(imap, res, imap->_imap_data->enable.header_case_sensitive); + if (_st == res.headerState && res.headerState > 0 && res.octetCount <= res.header.header_data_len) + collectHeaderField(imap, res.response, res.header, res.headerState); + } + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_mime) + parsePartHeaderResponse(imap, res, imap->_imap_data->enable.header_case_sensitive); + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text) + decodeText(imap, res); + else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + { + + if (cPart(imap)->xencoding == esp_mail_msg_xencoding_base64) + { + // Multi-line chunked base64 string attachment handle + if (res.octetCount < res.octetLength && res.readLen < BASE64_CHUNKED_LEN) + { + if (strlen(res.lastBuf) > 0) + { + res.buf = allocMem(res.readLen + strlen(res.lastBuf) + 2); + strcpy(res.buf, res.lastBuf); + strcat(res.buf, res.response); + res.readLen = strlen(res.buf); + res.tmo = parseAttachmentResponse(imap, res.buf, res); + // release memory + freeMem(&res.buf); + memset(res.lastBuf, 0, BASE64_CHUNKED_LEN + 1); + if (!res.tmo) + break; + } + else if (res.readLen < BASE64_CHUNKED_LEN + 1) + strcpy(res.lastBuf, res.response); + } + else + { + res.tmo = parseAttachmentResponse(imap, res.response, res); + if (!res.tmo) + break; + } + } + else + res.tmo = parseAttachmentResponse(imap, res.response, res); + } + + res.dataTime = millis(); + } + } + memset(res.response, 0, res.chunkBufSize); + } + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_search) + { + if (imap->_debug && res.searchCount > 0 && res.searchCount < 100) + { + searchReport(imap, 100); + } + } + } + + if ((res.imapResp != esp_mail_imap_resp_ok && imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header && res.header.header_data_len == 0) || res.imapResp == esp_mail_imap_resp_no) + { + // We don't get any response + + if (res.imapResp == esp_mail_imap_resp_no) + imap->_responseStatus.errorCode = IMAP_STATUS_IMAP_RESPONSE_FAILED; + else if (imap->_imap_data->fetch.modsequence > -1 && imap->isModseqSupported() && res.imapResp == esp_mail_imap_resp_ok && res.header.header_data_len == 0) + imap->_responseStatus.errorCode = IMAP_STATUS_CHANGEDSINC_MODSEQ_TEST_FAILED; + else + imap->_responseStatus.errorCode = IMAP_STATUS_NO_MESSAGE; + +#if !defined(SILENT_MODE) + + if (imap->_statusCallback && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_mime) + sendErrorCB(imap, imap->errorReason().c_str(), false, false); + + if (imap->_debug && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_mime) + esp_mail_debug_print_tag(imap->errorReason().c_str(), esp_mail_debug_tag_type_error, true); + +#endif + + return false; + } + + // We've got OK or NO responses + + if (res.imapResp == esp_mail_imap_resp_ok) + { + // Response OK + + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header) + { + // Headers management + + char *buf = allocMem(res.header.content_type.length() + 1); + strcpy(buf, res.header.content_type.c_str()); + res.header.content_type.clear(); + + MB_String contentTypeName; + appendHeaderName(contentTypeName, message_headers[esp_mail_message_header_field_content_type].text, false, false, false); + + res.buf = subStr(buf, contentTypeName.c_str(), esp_mail_str_35 /* ";" */, 0, 0, false); + if (res.buf) + { + res.headerState = esp_mail_imap_state_content_type; + collectHeaderField(imap, res.buf, res.header, res.headerState); + // release memory + freeMem(&res.buf); + + if (res.header.content_type.length() > 0) + { + int p1 = strposP(res.header.content_type.c_str(), esp_mail_imap_composite_media_type_t::multipart, 0); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_composite_media_type_t::multipart) + 1; + res.header.multipart = true; + // inline or embedded images + if (strpos(res.header.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::related, p1) != -1) + res.header.multipart_sub_type = esp_mail_imap_multipart_sub_type_related; + // multiple text formats e.g. plain, html, enriched + else if (strpos(res.header.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::alternative, p1) != -1) + res.header.multipart_sub_type = esp_mail_imap_multipart_sub_type_alternative; + // medias + else if (strpos(res.header.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::parallel, p1) != -1) + res.header.multipart_sub_type = esp_mail_imap_multipart_sub_type_parallel; + // rfc822 encapsulated + else if (strpos(res.header.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::digest, p1) != -1) + res.header.multipart_sub_type = esp_mail_imap_multipart_sub_type_digest; + else if (strpos(res.header.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::report, p1) != -1) + res.header.multipart_sub_type = esp_mail_imap_multipart_sub_type_report; + // others can be attachments + else if (strpos(res.header.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::mixed, p1) != -1) + res.header.multipart_sub_type = esp_mail_imap_multipart_sub_type_mixed; + } + + p1 = strposP(res.header.content_type.c_str(), esp_mail_imap_composite_media_type_t::message, 0); + if (p1 != -1) + { + p1 += strlen(esp_mail_imap_composite_media_type_t::message) + 1; + if (strpos(res.part.content_type.c_str(), esp_mail_imap_message_sub_type_t::rfc822, p1) != -1) + { + res.header.rfc822_part = true; + res.header.message_sub_type = esp_mail_imap_message_sub_type_rfc822; + } + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_message_sub_type_t::Partial, p1) != -1) + res.header.message_sub_type = esp_mail_imap_message_sub_type_partial; + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_message_sub_type_t::External_Body, p1) != -1) + res.header.message_sub_type = esp_mail_imap_message_sub_type_external_body; + else if (strpos(res.part.content_type.c_str(), esp_mail_imap_message_sub_type_t::delivery_status, p1) != -1) + res.header.message_sub_type = esp_mail_imap_message_sub_type_delivery_status; + } + } + + MB_String charset; + appendLowerCaseString(charset, message_headers[esp_mail_message_header_field_charset].text, false); + charset += esp_mail_str_7; /* "=" */ + + res.buf = subStr(buf, charset.c_str(), NULL, 0, -1, false); + if (res.buf) + { + res.headerState = esp_mail_imap_state_char_set; + collectHeaderField(imap, res.buf, res.header, res.headerState); + // release memory + freeMem(&res.buf); + } + + if (res.header.multipart) + { + if (strcmpP(buf, 0, esp_mail_str_64 /* "boundary=\"" */)) + { + res.buf = subStr(buf, esp_mail_str_64 /* "boundary=\"" */, esp_mail_str_11 /* "\"" */, 0, 0, false); + if (res.buf) + { + res.headerState = esp_mail_imap_state_boundary; + collectHeaderField(imap, res.buf, res.header, res.headerState); + // release memory + freeMem(&res.buf); + } + } + } + } + + // release memory + freeMem(&buf); + + // Decode the headers fields + + for (int i = esp_mail_rfc822_header_field_from; i < esp_mail_rfc822_header_field_maxType; i++) + { + if (i != esp_mail_rfc822_header_field_msg_id && i != esp_mail_rfc822_header_field_flags) + decodeString(imap, res.header.header_fields.header_items[i]); + } + + imap->_headers.push_back(res.header); + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_mime) + { + // Expect the octet length in the response for the existent part + if (res.part.octetLen > 0) + { + + res.part.partNumStr = cHeader(imap)->partNumStr; + res.part.partNumFetchStr = cHeader(imap)->partNumStr; + if (cHeader(imap)->part_headers.size() > 0) + { + + struct esp_mail_message_part_info_t *_part = &cHeader(imap)->part_headers[cHeader(imap)->part_headers.size() - 1]; + bool rfc822_body_subtype = _part->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + + if (rfc822_body_subtype) + { + if (!_part->rfc822_part) + { + // additional rfc822 message header, store it to the rfc822 part header + _part->rfc822_part = true; + _part->rfc822_header = res.part.rfc822_header; + imap->_rfc822_part_count++; + _part->rfc822_msg_Idx = imap->_rfc822_part_count; + } + } + } + + cHeader(imap)->part_headers.push_back(res.part); + cHeader(imap)->message_data_count = cHeader(imap)->part_headers.size(); + + if (res.part.msg_type != esp_mail_msg_type_none || + res.part.attach_type != esp_mail_att_type_none) + { + if (res.part.attach_type == esp_mail_att_type_attachment || + res.part.message_sub_type != esp_mail_imap_message_sub_type_rfc822) + { + if (res.part.attach_type != esp_mail_att_type_none && + cHeader(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_alternative) + { + cHeader(imap)->hasAttachment = true; + cHeader(imap)->attachment_count++; + } + } + } + } + else + { + // nonexistent part + // return false to exit the loop without closing the connection + if (closeSession) + imap->closeSession(); + return false; + } + } + + if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) + { + if (cPart(imap) && cPart(imap)->file_open_write) + mbfs->close(mbfs_type imap->_imap_data->storage.type); + } + + if (cPart(imap) && imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text) + cPart(imap)->text[cPart(imap)->textLen] = 0; + } + else + { + + // Response NO + + // Some server responses NO and should exit (false) from MIME feching loop without + // closing the session + if (imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_mime) + return handleIMAPError(imap, errCode, false); + + if (closeSession) + imap->closeSession(); + return false; + } + + return true; +} + +void ESP_Mail_Client::addHeader(MB_String &s, PGM_P name, const char *s_value, int num_value, bool trim, bool isJson) +{ + if (isJson) + { + s += (s.length() > 0) ? esp_mail_str_77 /* ",\"" */ : esp_mail_str_78 /* "{\"" */; + s += name; + + if (strlen(s_value) > 0) + { + s += esp_mail_str_79; /* "\":\"" */ + ; + if (trim) + { + MB_String t = s_value; + t.replaceAll("\"", ""); + s += t; + } + else + s += s_value; + s += esp_mail_str_11; /* "\"" */ + } + else + { + s += esp_mail_str_34 /* ":" */; + appendSpace(s); + s += num_value; + } + } + else + { + if (s.length() > 0) + appendNewline(s); + s += name; + s += esp_mail_str_34 /* ":" */; + appendSpace(s); + if (strlen(s_value) > 0) + s += s_value; + else + s += num_value; + } +} + +void ESP_Mail_Client::saveHeader(IMAPSession *imap, bool json) +{ + if (!imap->_storageReady) + return; + + MB_String headerFilePath; + + prepareFilePath(imap, headerFilePath, true); + + headerFilePath += json ? esp_mail_str_65 /* "/header.json" */ : esp_mail_str_66 /* "/header.txt" */; + + prepareFileList(imap, headerFilePath); + + int sz = mbfs->open(headerFilePath, mbfs_type imap->_imap_data->storage.type, mb_fs_open_mode_write); + if (sz < 0) + { + imap->_responseStatus.errorCode = sz; + imap->_responseStatus.text.clear(); +#if !defined(SILENT_MODE) + if (imap->_debug) + { + esp_mail_debug_print_tag(imap->errorReason().c_str(), esp_mail_debug_tag_type_error, true); + } +#endif + return; + } + + MB_String s; + for (size_t i = 0; i < imap->_headers.size(); i++) + addHeaderItem(s, &imap->_headers[i], json); + + if (json) + s += esp_mail_str_75; /* "]}" */ + + mbfs->print(mbfs_type imap->_imap_data->storage.type, s.c_str()); + + mbfs->close(mbfs_type imap->_imap_data->storage.type); + + imap->_headerSaved = true; +} + +void ESP_Mail_Client::addHeaderItem(MB_String &str, esp_mail_message_header_t *header, bool json) +{ + MB_String s; + if (json) + { + if (str.length() > 0) + str += esp_mail_str_8; /* "," */ + else + str = esp_mail_str_76; /* "{\"Messages\":[" */ + } + + addHeader(s, message_headers[esp_mail_message_header_field_number].text, "", header->message_no, false, json); + addHeader(s, message_headers[esp_mail_message_header_field_uid].text, "", header->message_uid, false, json); + + if (header->accept_language.length() > 0) + addHeader(s, message_headers[esp_mail_message_header_field_accept_language].text, header->accept_language.c_str(), 0, false, json); + + if (header->content_language.length() > 0) + addHeader(s, message_headers[esp_mail_message_header_field_content_language].text, header->content_language.c_str(), 0, false, json); + + addRFC822Headers(s, &header->header_fields, json); + + for (size_t j = 0; j < header->part_headers.size(); j++) + { + if (header->part_headers[j].rfc822_part) + { + MB_String s1; + addRFC822Headers(s1, &header->part_headers[j].rfc822_header, json); + + if (json) + { + s += esp_mail_str_69; /* ",\"RFC822\":" */ + s += s1; + s += esp_mail_str_36; /* "}" */ + } + else + { + s += esp_mail_str_70; /* "\r\n\r\nRFC822:\r\n" */ + s += s1; + } + } + } + + if (header->attachment_count > 0) + { + if (json) + { + s += esp_mail_str_71 /* ",\"Attachments\":{\"Count\":" */; + s += header->attachment_count; + s += esp_mail_str_72; /* ",\"Files\":[" */ + } + else + { + s += esp_mail_str_73; /* "\r\n\r\nAttachments (" */ + s += header->attachment_count; + s += esp_mail_str_74; /* ")\r\n" */ + } + + int index = 0; + for (size_t j = 0; j < header->part_headers.size(); j++) + { + + if (header->part_headers[j].attach_type == esp_mail_att_type_none || header->part_headers[j].rfc822_part) + continue; + + if (json) + { + if (index > 0) + s += esp_mail_str_8; /* "," */ + s += esp_mail_str_67; /* /"{\"Filename\":\"" */ + s += header->part_headers[j].filename; + s += esp_mail_str_11; /* "\"" */ + } + else + { + if (index > 0) + appendNewline(s); + appendNewline(s); + s += esp_mail_str_68; /* /"Index: " */ + s += index + 1; + addHeader(s, message_headers[esp_mail_message_header_field_filename].text, header->part_headers[j].filename.c_str(), 0, false, json); + } + + addHeader(s, message_headers[esp_mail_message_header_field_name].text, header->part_headers[j].name.c_str(), 0, false, json); + addHeader(s, message_headers[esp_mail_message_header_field_size].text, "", header->part_headers[j].attach_data_size, false, json); + addHeader(s, message_headers[esp_mail_message_header_field_mime].text, header->part_headers[j].content_type.c_str(), 0, false, json); + addHeader(s, message_headers[esp_mail_message_header_field_type].text, header->part_headers[j].attach_type == esp_mail_att_type_attachment ? esp_mail_content_disposition_type_t::attachment : esp_mail_content_disposition_type_t::inline_, 0, false, json); + addHeader(s, message_headers[esp_mail_message_header_field_description].text, header->part_headers[j].content_description.c_str(), 0, false, json); + addHeader(s, message_headers[esp_mail_message_header_field_creation_date].text, header->part_headers[j].creation_date.c_str(), 0, false, json); + + if (json) + s += esp_mail_str_36; /* "}" */ + + index++; + } + + if (json) + s += esp_mail_str_75; /* "]}" */ + } + + if (json) + { + s += esp_mail_str_36; /* "}" */ + } + + str += s; +} + +int ESP_Mail_Client::getRFC822HeaderPtr(int index, esp_mail_imap_rfc822_msg_header_item_t *header) +{ + if (index > esp_mail_rfc822_header_field_from && index < esp_mail_rfc822_header_field_maxType) + return toAddr(header->header_items[index]); + return 0; +} + +void ESP_Mail_Client::addRFC822Headers(MB_String &s, esp_mail_imap_rfc822_msg_header_item_t *header, bool json) +{ + for (int i = esp_mail_rfc822_header_field_from; i < esp_mail_rfc822_header_field_maxType; i++) + addRFC822HeaderItem(s, header, i, json); +} + +void ESP_Mail_Client::addRFC822HeaderItem(MB_String &s, esp_mail_imap_rfc822_msg_header_item_t *header, int index, bool json) +{ + int ptr = getRFC822HeaderPtr(index, header); + if (ptr > 0) + addHeader(s, rfc822_headers[index].text, addrTo(ptr)->c_str(), 0, rfc822_headers[index].trim, json); +} + +esp_mail_imap_response_status ESP_Mail_Client::imapResponseStatus(IMAPSession *imap, char *response, PGM_P tag) +{ + imap->_responseStatus.clear(false); + MB_String test; + esp_mail_imap_response_status status = esp_mail_imap_resp_unknown; + esp_mail_imap_response_types type = esp_mail_imap_response_maxType; + + if (strpos(response, imap->prependTag(imap_responses[esp_mail_imap_response_ok].text, tag).c_str(), 0) > -1) + { + status = esp_mail_imap_resp_ok; + type = esp_mail_imap_response_ok; + } + else if (strpos(response, imap->prependTag(imap_responses[esp_mail_imap_response_no].text, tag).c_str(), 0) > -1) + { + status = esp_mail_imap_resp_no; + type = esp_mail_imap_response_no; + } + else if (strpos(response, imap->prependTag(imap_responses[esp_mail_imap_response_bad].text, tag).c_str(), 0) > -1) + { + status = esp_mail_imap_resp_bad; + type = esp_mail_imap_response_bad; + } + + if (status != esp_mail_imap_resp_unknown) + { + test = imap->prependTag(imap_responses[type].text, tag); + + imap->_responseStatus.text = &response[test.length()]; + if (imap->_responseStatus.text[imap->_responseStatus.text.length() - 2] == '\r') + imap->_responseStatus.text[imap->_responseStatus.text.length() - 2] = 0; + + test = imap_responses[type].text; + test.trim(); + imap->_responseStatus.status = test; + imap->_responseStatus.completed = true; + } + return status; +} + +bool ESP_Mail_Client::parseCapabilityResponse(IMAPSession *imap, const char *buf, int &chunkIdx) +{ + if (chunkIdx == 0) + { + MB_String res; + // We add white space to make post token checking to work in all capabilities. + // This will allow us to check "IDLE " and "ID " correctly. + appendSpace(res, false, buf); + + if (strposP(res.c_str(), imap_responses[esp_mail_imap_response_capability_untagged].text, 0) > -1 || strposP(res.c_str(), imap_responses[esp_mail_imap_response_capability].text, 0) > -1) + { + for (int i = esp_mail_auth_capability_plain; i < esp_mail_auth_capability_maxType; i++) + { + if (strposP(res.c_str(), imap_auth_cap_pre_tokens[i].c_str(), 0) > -1) + imap->_auth_capability[i] = true; + } + + for (int i = esp_mail_imap_read_capability_imap4; i < esp_mail_imap_read_capability_maxType; i++) + { + if (strposP(res.c_str(), imap_read_cap_post_tokens[i].c_str(), 0) > -1) + { + imap->_feature_capability[i] = true; + if (i == esp_mail_imap_read_capability_logindisable) + imap->_auth_capability[esp_mail_auth_capability_login] = false; + } + } + + return true; + } + } + + return false; +} + +char *ESP_Mail_Client::getList(char *buf, bool &isList) +{ + if (buf[0] == '(' && buf[1] != ')') + { + if (buf[strlen(buf) - 1] == ')') + buf[strlen(buf) - 1] = 0; + else + isList = true; + + return &buf[1]; + } + else if (isList) + { + if (buf[strlen(buf) - 1] == ')') + { + buf[strlen(buf) - 1] = 0; + isList = false; + } + } + + return buf; +} + +void ESP_Mail_Client::parseFoldersResponse(IMAPSession *imap, char *buf, bool list) +{ + struct esp_mail_folder_info_t fd; + int pos = list ? strposP(buf, imap_responses[esp_mail_imap_response_list].text, 0) : strposP(buf, imap_responses[esp_mail_imap_response_lsub].text, 0); + bool isList = false, delimOk = false; + if (pos != -1) + { + char *p = allocMem(strlen(buf)); + strcpy(p, buf); + char *pp = p; + char *end = p; + int count = 0; + int tkPos = 3; + + while (pp != NULL) + { + // See RFC2047.h + ESP_MAIL_STRSEP(&end, " "); + count++; + + if (count >= tkPos && strlen(pp) > 0) + { + if (count == tkPos && pp[0] == '(' && pp[1] != ')') + fd.attributes = getList(pp, isList); + else if (isList) + { + fd.attributes += ' '; + fd.attributes += getList(pp, isList); + } + else + { + if (pp[strlen(pp) - 1] == '"') + pp[strlen(pp) - 1] = 0; + + const char *ptr = pp[0] == '"' ? &pp[1] : &pp[0]; + + if (!delimOk) + { + delimOk = true; + fd.delimiter = ptr; + } + else + { + if (fd.name.length() > 0) + fd.name += ' '; + fd.name += ptr; + } + } + } + pp = end; + } + + // release memory + freeMem(&p); + + imap->_folders.add(fd); + } +} + +bool ESP_Mail_Client::parseIdleResponse(IMAPSession *imap) +{ + + int chunkBufSize = 0; + + if (!reconnect(imap)) + return false; + + if (imap->client.connected()) + chunkBufSize = imap->client.available(); + else + return false; + + if (chunkBufSize > 0) + { + chunkBufSize = ESP_MAIL_CLIENT_RESPONSE_BUFFER_SIZE; + + char *buf = allocMem(chunkBufSize + 1); + + int octetCount = 0; + + int readLen = 0; + + MB_String ovfBuf; + readResponse(imap, buf, chunkBufSize, readLen, false, octetCount, ovfBuf); + + // If buffer overflown, copy from overflow buffer + if (ovfBuf.length() > 0) + { + // release memory + freeMem(&buf); + buf = allocMem(ovfBuf.length() + 1); + strcpy(buf, ovfBuf.c_str()); + ovfBuf.clear(); + } + + if (readLen > 0) + { + + if (imap->_debug && imap->_debugLevel > esp_mail_debug_level_basic) + esp_mail_debug_print((const char *)buf, true); + + char *tmp = nullptr; + int p1 = -1; + bool exists = false; + + tmp = subStr(buf, NULL, imap_responses[esp_mail_imap_response_exists].text, 0); + if (tmp) + { + int numMsg = imap->_mbif._msgCount; + imap->_mbif._msgCount = atoi(tmp); + // release memory + freeMem(&tmp); + exists = true; + imap->_mbif._folderChanged |= (int)imap->_mbif._msgCount != numMsg; + if ((int)imap->_mbif._msgCount > numMsg) + { + imap->_mbif._polling_status.type = imap_polling_status_type_new_message; + imap->_mbif._polling_status.messageNum = imap->_mbif._msgCount; + } + goto ex; + } + + tmp = subStr(buf, NULL, imap_responses[esp_mail_imap_response_expunge].text, 0); + if (tmp) + { + imap->_mbif._polling_status.type = imap_polling_status_type_remove_message; + imap->_mbif._polling_status.messageNum = atoi(tmp); + + if (imap->_mbif._polling_status.messageNum == imap->_mbif._msgCount && imap->_mbif._nextUID > 0) + imap->_mbif._nextUID--; + + // release memory + freeMem(&tmp); + imap->_mbif._folderChanged = true; + goto ex; + } + + tmp = subStr(buf, NULL, imap_responses[esp_mail_imap_response_recent].text, 0); + if (tmp) + { + imap->_mbif._recentCount = atoi(tmp); + // release memory + freeMem(&tmp); + goto ex; + } + + tmp = subStr(buf, NULL, imap_responses[esp_mail_imap_response_fetch].text, 0); + if (tmp) + { + imap->_mbif._polling_status.messageNum = atoi(tmp); + // release memory + freeMem(&tmp); + + imap->_mbif._polling_status.argument = buf; + imap->_mbif._polling_status.argument.erase(0, p1 + 8); + imap->_mbif._polling_status.argument.pop_back(); + imap->_mbif._folderChanged = true; + imap->_mbif._polling_status.type = imap_polling_status_type_fetch_message; + goto ex; + } + + ex: + + imap->_mbif._floderChangedState = (imap->_mbif._folderChanged && exists) || imap->_mbif._polling_status.type == imap_polling_status_type_fetch_message; + } + + // release memory + freeMem(&buf); + } + + size_t imap_idle_tmo = imap->_imap_data->limit.imap_idle_timeout; + + if (imap_idle_tmo < 60 * 1000 || imap_idle_tmo > 29 * 60 * 1000) + imap_idle_tmo = 10 * 60 * 1000; + + if (millis() - imap->_mbif._idleTimeMs > imap_idle_tmo) + { + if (imap->mStopListen(true)) + return imap->mListen(true); + return false; + } + + return true; +} + +void ESP_Mail_Client::appendFetchString(MB_String &buf, bool uid) +{ + if (uid) + buf += imap_cmd_post_tokens[esp_mail_imap_command_uid]; + else + joinStringSpace(buf, false, 2, imap_commands[esp_mail_imap_command_flags].text, esp_mail_str_38 /* "(" */); +} + +void ESP_Mail_Client::parseCmdResponse(IMAPSession *imap, char *buf, PGM_P find) +{ + if (imap->_imap_cmd == esp_mail_imap_cmd_get_uid) + imap->_uid_tmp = 0; + + char *tmp = nullptr; + int p1 = strposP(buf, find, 0); + if (p1 != -1) + { + if (imap->_imap_cmd == esp_mail_imap_cmd_get_quota_root || + imap->_imap_cmd == esp_mail_imap_cmd_get_acl || + imap->_imap_cmd == esp_mail_imap_cmd_my_rights) + { + int ofs = imap->_imap_cmd == esp_mail_imap_cmd_get_quota_root ? 0 : 1; + int p2 = strposP(buf, esp_mail_str_2 /* " " */, p1 + strlen_P(find) + ofs); + if (p2 != -1) + { + int len = strlen(buf) - p2 - 1; + tmp = allocMem(len); + strncpy(tmp, buf + p2 + 1, strlen(buf) - p2 - 1); + if (imap->_imap_cmd == esp_mail_imap_cmd_get_quota_root) + { + if (imap->_quota_root_tmp.length() > 0) + imap->_quota_root_tmp += esp_mail_str_8; /* ";" */ + imap->_quota_root_tmp += tmp; + } + else + { + imap->_acl_tmp = tmp; + } + + // release memory + freeMem(&tmp); + } + } + else + { + int len = imap->_imap_cmd == esp_mail_imap_cmd_get_uid ? 20 : strlen(buf) - p1 - strlen_P(find); + int ofs = imap->_imap_cmd == esp_mail_imap_cmd_get_uid || + imap->_imap_cmd == esp_mail_imap_cmd_fetch_sequence_set + ? 1 + : imap->_imap_cmd == esp_mail_imap_cmd_namespace || imap->_imap_cmd == esp_mail_imap_cmd_id ? 0 + : 2; + tmp = allocMem(len); + + strncpy(tmp, buf + p1 + strlen_P(find), strlen(buf) - p1 - strlen_P(find) - ofs); + + esp_mail_imap_msg_num_t msg_num; + + switch ((int)imap->_imap_cmd) + { + case esp_mail_imap_cmd_get_uid: + imap->_uid_tmp = atoi(tmp); + break; + case esp_mail_imap_cmd_get_flags: + imap->_flags_tmp = tmp; + break; + case esp_mail_imap_cmd_get_quota: + imap->_quota_tmp = tmp; + break; + case esp_mail_imap_cmd_id: + imap->_server_id_tmp = tmp; + break; + case esp_mail_imap_cmd_namespace: + imap->_ns_tmp += tmp; + break; + case esp_mail_imap_cmd_fetch_sequence_set: + + msg_num.type = esp_mail_imap_msg_num_type_uid; + msg_num.value = (uint32_t)atoi(tmp); + imap->_imap_msg_num.push_back(msg_num); + + if (imap->_imap_msg_num.size() > imap->_imap_data->limit.fetch) + imap->_imap_msg_num.erase(imap->_imap_msg_num.begin()); + + break; + default: + break; + } + } + + // release memory + freeMem(&tmp); + } +} + +bool ESP_Mail_Client::getFlags(IMAPSession *imap, char *buf, esp_mail_imap_response_types type) +{ + if (strposP(buf, imap_responses[type].text, 0) != -1) + { + char *p = allocMem(strlen(buf)); + strcpy(p, buf); + char *pp = p; + char *end = p; + int count = 0; + bool isList = false; + int tkPos = (type == esp_mail_imap_response_permanent_flags) ? 4 : 3; + + while (pp != NULL) + { + // See RFC2047.h + ESP_MAIL_STRSEP(&end, " "); + count++; + if (count >= tkPos && strlen(pp) > 0) + { + if (type == esp_mail_imap_response_permanent_flags && pp[strlen(pp) - 1] == ']') + pp[strlen(pp) - 1] = 0; + + if (count == tkPos && pp[0] == '(' && pp[1] != ')') + imap->_mbif.addFlag(getList(pp, isList), type == esp_mail_imap_response_permanent_flags); + else if (isList) + imap->_mbif.addFlag(getList(pp, isList), type == esp_mail_imap_response_permanent_flags); + } + pp = end; + } + + // release memory + freeMem(&p); + + return true; + } + + return false; +} + +void ESP_Mail_Client::parseExamineResponse(IMAPSession *imap, char *buf) +{ + char *tmp = NULL; + + tmp = subStr(buf, NULL, imap_responses[esp_mail_imap_response_exists].text, 0); + if (tmp) + { + imap->_mbif._msgCount = atoi(tmp); + // release memory + freeMem(&tmp); + return; + } + + tmp = subStr(buf, NULL, imap_responses[esp_mail_imap_response_recent].text, 0); + if (tmp) + { + imap->_mbif._recentCount = atoi(tmp); + // release memory + freeMem(&tmp); + return; + } + + if (imap->_mbif._flags.size() == 0 && getFlags(imap, buf, esp_mail_imap_response_flags)) + return; + + if (imap->_mbif._permanent_flags.size() == 0 && getFlags(imap, buf, esp_mail_imap_response_permanent_flags)) + return; + + if (imap->_mbif._uidValidity == 0) + { + tmp = subStr(buf, imap_responses[esp_mail_imap_response_uidvalidity].text, esp_mail_str_41 /* "]" */, 0, 0); + if (tmp) + { + imap->_mbif._uidValidity = atoi(tmp); + // release memory + freeMem(&tmp); + return; + } + } + + if (imap->_nextUID.length() == 0) + { + tmp = subStr(buf, imap_responses[esp_mail_imap_response_uidnext].text, esp_mail_str_41 /* "]" */, 0, 0); + if (tmp) + { + imap->_nextUID = tmp; + imap->_mbif._nextUID = atoi(tmp); + // release memory + freeMem(&tmp); + return; + } + } + + if (imap->_unseenMsgIndex.length() == 0) + { + tmp = subStr(buf, imap_responses[esp_mail_imap_response_unseen].text, esp_mail_str_41 /* "]" */, 0, 0); + if (tmp) + { + imap->_unseenMsgIndex = tmp; + imap->_mbif._unseenMsgIndex = atoi(tmp); + // release memory + freeMem(&tmp); + return; + } + } + + if (imap->isCondStoreSupported()) + { + tmp = subStr(buf, imap_responses[esp_mail_imap_response_highest_modsec].text, esp_mail_str_41 /* "]" */, 0, 0); + if (tmp) + { + imap->_mbif._highestModSeq = tmp; + // release memory + freeMem(&tmp); + return; + } + + tmp = subStr(buf, imap_responses[esp_mail_imap_response_nomodsec].text, nullptr, 0, 0); + if (tmp) + { + imap->_mbif._nomodsec = true; + // release memory + freeMem(&tmp); + return; + } + } +} + +bool ESP_Mail_Client::handleIMAPError(IMAPSession *imap, int err, bool ret) +{ + if (err < 0) + { + errorStatusCB(imap, nullptr, err, true); + + if (imap->_headers.size() > 0 && cHeader(imap)) + { + if ((imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) && (imap->_imap_data->download.attachment || imap->_imap_data->download.inlineImg)) + { + if (cPart(imap) && cHeader(imap)->part_headers.size() > 0) + cPart(imap)->download_error = imap->errorReason().c_str(); + } + else if (cHeader(imap)) + cHeader(imap)->error_msg = imap->errorReason().c_str(); + + cHeader(imap)->error = true; + } + } + + closeTCPSession(imap); + + imap->_cbData.empty(); + + return ret; +} + +void ESP_Mail_Client::prepareFileList(IMAPSession *imap, MB_String &filePath) +{ +#if defined(MBFS_SD_FS) + if (!mbfs->longNameSupported()) + { + cHeader(imap)->sd_alias_file_count++; + MB_String alias = cHeader(imap)->message_uid; + alias += esp_mail_str_83; /* "_" */ + alias += cHeader(imap)->sd_alias_file_count; + + if (imap->_sdFileList.length() > 0) + { + if (imap->_sdFileList[imap->_sdFileList.length() - 1] == ']') + { + imap->_sdFileList[imap->_sdFileList.length() - 1] = 0; + imap->_sdFileList += esp_mail_str_8; /* "," */ + } + } + imap->_sdFileList += esp_mail_str_80; /* "{\"Renamed\":\"" */ + imap->_sdFileList += alias; + imap->_sdFileList += esp_mail_str_81; /* "\",\"Original\":\"" */ + imap->_sdFileList += filePath; + imap->_sdFileList += esp_mail_str_82; /* "\"}]" */ + // rename the original file + filePath = alias; + } +#endif +} + +bool ESP_Mail_Client::parseAttachmentResponse(IMAPSession *imap, char *buf, esp_mail_imap_response_data &res) +{ + int bufLen = res.readLen; + + if (res.chunkIdx == 0) + { + char *tmp = subStr(buf, esp_mail_str_36 /* "{" */, esp_mail_str_37 /* "}" */, 0); + if (tmp) + { + res.chunkIdx++; + res.octetCount = 0; // CRLF counted from first line + res.octetLength = atoi(tmp); + // release memory + freeMem(&tmp); + cPart(imap)->octetLen = res.octetLength; + cPart(imap)->octetCount = 0; + cHeader(imap)->total_download_size += res.octetLength; + imap->_lastProgress = -1; + +#if defined(ESP_MAIL_OTA_UPDATE_ENABLED) + if (cPart(imap)->is_firmware_file) + { + cPart(imap)->is_firmware_file = Update.begin(cPart(imap)->attach_data_size); + + if (!cPart(imap)->is_firmware_file) + { + imap->_responseStatus.errorCode = IMAP_STATUS_FIRMWARE_UPDATE_INIT_FAILED; + imap->_responseStatus.text.clear(); + } + +#if !defined(SILENT_MODE) + + sendCallback(imap, esp_mail_cb_str_42 /* "Updating firmware..." */, true, false); + + if (!cPart(imap)->is_firmware_file) + { + printDebug(imap, + imap->errorReason().c_str(), + imap->errorReason().c_str(), + esp_mail_debug_tag_type_error, + true, + false); + } + +#endif + } +#endif + + if (!cPart(imap)->file_open_write) + { + + if (imap->_storageReady && cPart(imap)->save_to_file) + { + res.downloadRequest = true; + + res.filePath.clear(); + + res.filePath += imap->_imap_data->storage.saved_path; + res.filePath += esp_mail_str_10; /* "/" */ + res.filePath += cHeader(imap)->message_uid; + res.filePath += esp_mail_str_10; /* "/" */ + res.filePath += cPart(imap)->filename; + + prepareFileList(imap, res.filePath); + + int sz = mbfs->open(res.filePath, mbfs_type imap->_imap_data->storage.type, mb_fs_open_mode_write); + + if (sz < 0) + { + imap->_responseStatus.errorCode = sz; + imap->_responseStatus.text.clear(); +#if !defined(SILENT_MODE) + printDebug(imap, + imap->errorReason().c_str(), + imap->errorReason().c_str(), + esp_mail_debug_tag_type_error, + true, + false); +#endif + } + + cPart(imap)->file_open_write = true; + } + } + } + return true; + } + + yield_impl(); + + if (res.octetLength == 0) + return true; + + if (cPart(imap)->octetCount <= res.octetLength) + { + if (cPart(imap)->octetCount + bufLen > res.octetLength) + { + bufLen = res.octetLength - cPart(imap)->octetCount; + buf[bufLen] = 0; + cPart(imap)->octetCount += bufLen; + } + else + cPart(imap)->octetCount = res.octetCount; + + if (imap->_imap_data->enable.download_status) + { + if (imap->_debug) + downloadReport(imap, 100 * cPart(imap)->octetCount / res.octetLength); + } + + if (cPart(imap)->octetCount > res.octetLength) + return true; + + bool write_error = false, fw_write_error = false; + + if (cPart(imap)->xencoding == esp_mail_msg_xencoding_base64) + { + + size_t olen = 0; + unsigned char *decoded = decodeBase64((const unsigned char *)buf, bufLen, &olen); + + if (decoded) + { + + if (!cPart(imap)->sizeProp) + { + cPart(imap)->attach_data_size += olen; + cHeader(imap)->total_attach_data_size += cPart(imap)->attach_data_size; + } + + sendStreamCB(imap, (void *)decoded, olen, res.chunkIdx, false); + + size_t write = olen; + + if (cPart(imap)->is_firmware_file) + { +#if defined(ESP_MAIL_OTA_UPDATE_ENABLED) + size_t fw_write = Update.write((uint8_t *)decoded, olen); + cPart(imap)->firmware_downloaded_byte += fw_write == olen ? olen : 0; + fw_write_error = fw_write != olen; +#endif + } + + if (cPart(imap)->save_to_file) + { + if (mbfs->ready(mbfs_type imap->_imap_data->storage.type)) + write = mbfs->write(mbfs_type imap->_imap_data->storage.type, (uint8_t *)decoded, olen); + } + + yield_impl(); + // release memory + freeMem(&decoded); + + write_error = write != olen; + } + + if (!reconnect(imap)) + return false; + } + else + { + // binary content + if (!cPart(imap)->sizeProp) + { + cPart(imap)->attach_data_size += bufLen; + cHeader(imap)->total_attach_data_size += cPart(imap)->attach_data_size; + } + + sendStreamCB(imap, (void *)buf, bufLen, res.chunkIdx, false); + + int write = bufLen; + + if (cPart(imap)->is_firmware_file) + { +#if defined(ESP_MAIL_OTA_UPDATE_ENABLED) + int fw_write = Update.write((uint8_t *)buf, bufLen); + cPart(imap)->firmware_downloaded_byte += fw_write == bufLen ? (size_t)bufLen : 0; + fw_write_error = fw_write != bufLen; +#endif + } + + if (cPart(imap)->save_to_file) + { + if (mbfs->ready(mbfs_type imap->_imap_data->storage.type)) + write = mbfs->write(mbfs_type imap->_imap_data->storage.type, (uint8_t *)buf, bufLen); + } + + yield_impl(); + + write_error = write != bufLen; + + if (!reconnect(imap)) + return false; + } + +#if defined(ESP_MAIL_OTA_UPDATE_ENABLED) + if (cPart(imap)->is_firmware_file) + { + bool update_result_ok = !fw_write_error; + + if (!imap->_isFirmwareUpdated && update_result_ok && + (cPart(imap)->firmware_downloaded_byte == (size_t)cPart(imap)->attach_data_size || cPart(imap)->octetCount >= res.octetLength)) + { + update_result_ok = Update.end(cPart(imap)->octetCount >= res.octetLength); + if (update_result_ok) + imap->_isFirmwareUpdated = true; + } + + if (!update_result_ok) + { + cPart(imap)->is_firmware_file = false; + + imap->_responseStatus.errorCode = fw_write_error ? IMAP_STATUS_FIRMWARE_UPDATE_WRITE_FAILED : IMAP_STATUS_FIRMWARE_UPDATE_END_FAILED; + imap->_responseStatus.text.clear(); + +#if !defined(SILENT_MODE) + printDebug(imap, + imap->_responseStatus.text.c_str(), + imap->errorReason().c_str(), + esp_mail_debug_tag_type_error, + !imap->_debug, + false); +#endif + } + } +#endif + + if (write_error || fw_write_error) + return false; + } + + res.chunkIdx++; + return true; +} + +void ESP_Mail_Client::downloadReport(IMAPSession *imap, int progress) +{ + printProgress(progress, imap->_lastProgress); +} + +void ESP_Mail_Client::fetchReport(IMAPSession *imap, int progress, bool download) +{ +#if !defined(SILENT_MODE) + if (imap->_debug && imap->_lastProgress == -1 && strcmp_P(cPart(imap)->filename.c_str(), esp_mail_str_84 /* "message" */) != 0) + esp_mail_debug_print_tag(cPart(imap)->filename.c_str(), esp_mail_debug_tag_type_client, true); + printProgress(progress, imap->_lastProgress); +#endif +} + +void ESP_Mail_Client::searchReport(IMAPSession *imap, int progress) +{ + printProgress(progress, imap->_lastProgress); +} + +struct esp_mail_imap_msg_num_t ESP_Mail_Client::cMSG(IMAPSession *imap) +{ + return imap->_imap_msg_num[cIdx(imap)]; +} + +int ESP_Mail_Client::cIdx(IMAPSession *imap) +{ + return imap->_cMsgIdx; +} + +void ESP_Mail_Client::decodeText(IMAPSession *imap, esp_mail_imap_response_data &res) +{ + int bufLen = res.readLen; + bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + if (res.chunkIdx == 0) + { + + imap->_lastProgress = -1; + char *tmp = subStr(res.response, esp_mail_str_36 /* "{" */, esp_mail_str_37 /* "}" */, 0); + if (tmp) + { + res.chunkIdx++; + res.octetCount = 0; + res.octetLength = atoi(tmp); + // release memory + freeMem(&tmp); + cPart(imap)->octetLen = res.octetLength; + cPart(imap)->octetCount = 0; + + bool dlMsg = (rfc822_body_subtype && imap->_imap_data->download.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_imap_data->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_imap_data->download.text))); + if (dlMsg) + prepareFilePath(imap, res.filePath, false); + + if (res.filePath.length() == 0) + { + if (!rfc822_body_subtype) + res.filePath += esp_mail_str_84; /* "message" */ + else + joinStringSpace(res.filePath, false, 2, esp_mail_str_85 /* "rfc822" */, esp_mail_str_84 /* "message" */); + } + cPart(imap)->filename = res.filePath; + + if (imap->_storageReady && !cPart(imap)->file_open_write && dlMsg) + { + + prepareFileList(imap, res.filePath); + + int sz = mbfs->open(res.filePath, mbfs_type imap->_imap_data->storage.type, mb_fs_open_mode_write); + if (sz > -1) + { + res.downloadRequest = true; + cPart(imap)->file_open_write = true; + } + else + { + imap->_responseStatus.errorCode = sz; + imap->_responseStatus.text.clear(); +#if !defined(SILENT_MODE) + if (imap->_debug) + esp_mail_debug_print_tag(imap->errorReason().c_str(), esp_mail_debug_tag_type_error, true); +#endif + } + } + + return; + } + else + { +#if !defined(SILENT_MODE) + if (imap->_debug) + esp_mail_debug_print_tag(esp_mail_error_imap_str_12 /* "no centent" */, esp_mail_debug_tag_type_client, false); +#endif + } + } + + yield_impl(); + + if (res.octetLength == 0) + return; + + bool enableDownloads = (imap->_imap_data->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_imap_data->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_imap_data->download.text))); + + if (imap->_imap_data->download.rfc822 || imap->_imap_data->download.html || imap->_imap_data->download.text || (rfc822_body_subtype && imap->_imap_data->enable.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_imap_data->enable.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_imap_data->enable.text)))) + { + + if (cPart(imap)->octetCount + bufLen >= res.octetLength) + { + bufLen = res.octetLength - cPart(imap)->octetCount; + cPart(imap)->octetCount += bufLen; + + if (res.octetLength <= res.octetCount && cPart(imap)->xencoding != esp_mail_msg_xencoding_base64 && cPart(imap)->xencoding != esp_mail_msg_xencoding_qp) + bufLen = 0; + + res.response[bufLen] = 0; + } + else + cPart(imap)->octetCount = res.octetCount; + + if (imap->_debug) + fetchReport(imap, 100 * cPart(imap)->octetCount / res.octetLength, enableDownloads); + + if (cPart(imap)->octetCount <= res.octetLength) + { + bool hrdBrk = cPart(imap)->xencoding == esp_mail_msg_xencoding_qp; + hrdBrk &= cPart(imap)->octetCount < res.octetLength; + hrdBrk &= bufLen == 2 && res.response[bufLen - 2] != '\r' && res.response[bufLen - 1] != '\n'; + + // remove soft break for QP + if (bufLen <= QP_ENC_MSG_LEN && res.response[bufLen - 1] == '=' && cPart(imap)->xencoding == esp_mail_msg_xencoding_qp) + { + hrdBrk = false; + res.response[bufLen - 1] = 0; + bufLen--; + } + + size_t olen = 0; + char *decoded = nullptr; + MB_String str; + bool dontDeleteOrModify = false; + + // decode the content based on the transfer decoding + if (cPart(imap)->xencoding == esp_mail_msg_xencoding_base64) + { + decoded = (char *)decodeBase64((const unsigned char *)res.response, bufLen, &olen); + } + else if (cPart(imap)->xencoding == esp_mail_msg_xencoding_qp) + { + decoded = allocMem(bufLen + 10); + decodeQP_UTF8(res.response, decoded); + olen = strlen(decoded); + } + else if (cPart(imap)->xencoding == esp_mail_msg_xencoding_7bit) + { + decoded = decode7Bit_UTF8(res.response); + olen = strlen(decoded); + } + else if (cPart(imap)->xencoding == esp_mail_msg_xencoding_8bit) + { + decoded = decode8Bit_UTF8(res.response); + olen = strlen(decoded); + } + else + { + // binary + dontDeleteOrModify = true; + decoded = res.response; + olen = bufLen; + } + + if (decoded) + { + // charset? apply character decoding to the decoded or nonencoded content + if ((rfc822_body_subtype && imap->_imap_data->enable.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_imap_data->enable.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_imap_data->enable.text)))) + { + if (imap->_charDecCallback) + { + IMAP_Decoding_Info decoding; + decoding.charset = cPart(imap)->charset.c_str(); + decoding.data = decoded; + decoding.type = IMAP_Decoding_Info::message_part_type_text; + + imap->_charDecCallback(&decoding); + + if (decoding.decodedString.length() > 0) + { + char *buf2 = allocMem(decoding.decodedString.length() + 1); + strcpy(buf2, decoding.decodedString.c_str()); + + if (decoded && !dontDeleteOrModify) + // release memory + freeMem(&decoded); + + decoded = buf2; + olen = strlen(buf2); + } + } + else + { + esp_mail_char_decoding_scheme scheme = getEncodingFromCharset(cPart(imap)->charset.c_str()); + + if (scheme == esp_mail_char_decoding_scheme_iso8859_1) + { + int ilen = olen; + int olen2 = (ilen + 1) * 2; + unsigned char *tmp = allocMem(olen2); + decodeLatin1_UTF8(tmp, &olen2, (unsigned char *)decoded, &ilen); + + if (decoded && !dontDeleteOrModify) + // release memory + freeMem(&decoded); + + olen = olen2; + decoded = (char *)tmp; + } + else if (scheme == esp_mail_char_decoding_scheme_tis_620 || scheme == esp_mail_char_decoding_scheme_iso8859_11 || scheme == esp_mail_char_decoding_scheme_windows_874) + { + char *out = allocMem((olen + 1) * 3); + decodeTIS620_UTF8(out, decoded, olen); + olen = strlen(out); + if (decoded && !dontDeleteOrModify) + // release memory + freeMem(&decoded); + decoded = out; + } + } + + if (cPart(imap)->text.length() < imap->_imap_data->limit.msg_size) + { + + if (cPart(imap)->text.length() + olen < imap->_imap_data->limit.msg_size) + { + cPart(imap)->textLen += olen; + cPart(imap)->text.append(decoded, olen); + if (hrdBrk) + { + appendNewline(cPart(imap)->text); + cPart(imap)->textLen += 2; + } + } + else + { + int d = imap->_imap_data->limit.msg_size - cPart(imap)->text.length(); + cPart(imap)->textLen += d; + if (d > 0) + cPart(imap)->text.append(decoded, d); + + if (hrdBrk) + { + appendNewline(cPart(imap)->text); + cPart(imap)->textLen += 2; + } + } + } + } + + if (res.filePath.length() > 0 && res.downloadRequest) + { + if (mbfs->ready(mbfs_type imap->_imap_data->storage.type)) + { + if (olen > 0) + mbfs->write(mbfs_type imap->_imap_data->storage.type, (uint8_t *)decoded, olen); + if (hrdBrk) + mbfs->write(mbfs_type imap->_imap_data->storage.type, (uint8_t *)"\r\n", 2); + } + } + + sendStreamCB(imap, (void *)decoded, olen, res.chunkIdx, hrdBrk); + + if (decoded && !dontDeleteOrModify) + // release memory + freeMem(&decoded); + } + } + } + + res.chunkIdx++; +} + +void ESP_Mail_Client::sendStreamCB(IMAPSession *imap, void *buf, size_t len, int chunkIndex, bool hrdBrk) +{ + if (imap->_mimeDataStreamCallback && len > 0) + { + MIME_Data_Stream_Info streaminfo; + streaminfo.uid = cHeader(imap)->message_uid; + streaminfo.disposition = cPart(imap)->content_disposition.c_str(); + streaminfo.type = cPart(imap)->content_type.c_str(); + streaminfo.charSet = cPart(imap)->charset.c_str(); + streaminfo.transfer_encoding = cPart(imap)->content_transfer_encoding.c_str(); + streaminfo.cid = cPart(imap)->CID.c_str(); + streaminfo.description = cPart(imap)->content_description.c_str(); + streaminfo.date = cPart(imap)->creation_date.c_str(); + streaminfo.filename = cPart(imap)->filename.c_str(); + streaminfo.size = (cPart(imap)->sizeProp) ? cPart(imap)->attach_data_size : cPart(imap)->octetLen; + streaminfo.name = cPart(imap)->name.c_str(); + streaminfo.octet_size = cPart(imap)->octetLen; + streaminfo.octet_count = cPart(imap)->octetCount; + streaminfo.isFirstData = chunkIndex == 1; + streaminfo.isLastData = !hrdBrk ? cPart(imap)->octetLen == cPart(imap)->octetCount : false; + streaminfo.data_size = len; + streaminfo.data = buf; + streaminfo.flowed = cPart(imap)->plain_flowed; + streaminfo.delsp = cPart(imap)->plain_delsp; + + imap->_mimeDataStreamCallback(streaminfo); + + if (hrdBrk) + { + streaminfo.isFirstData = false; + streaminfo.isLastData = cPart(imap)->octetLen == cPart(imap)->octetCount; + streaminfo.data_size = 2; + streaminfo.data = (void *)"\r\n"; + imap->_mimeDataStreamCallback(streaminfo); + } + } +} + +void ESP_Mail_Client::prepareFilePath(IMAPSession *imap, MB_String &filePath, bool header) +{ + bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822; + MB_String fpath = imap->_imap_data->storage.saved_path; + fpath += esp_mail_str_10; /* "/" */ + fpath += cHeader(imap)->message_uid; + + if (!header) + { + if (!rfc822_body_subtype) + { + fpath += esp_mail_str_86; /* "/msg" */ + if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + fpath += mimeinfo[esp_mail_file_extension_txt].endsWith; + else if (cPart(imap)->msg_type == esp_mail_msg_type_html) + fpath += mimeinfo[esp_mail_file_extension_htm].endsWith; + } + else + { + fpath += esp_mail_str_87; /* "/rfc822_msg" */ + + if (cPart(imap)->rfc822_msg_Idx > 0) + fpath += cPart(imap)->rfc822_msg_Idx; + + if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) + fpath += mimeinfo[esp_mail_file_extension_txt].endsWith; + else if (cPart(imap)->msg_type == esp_mail_msg_type_html) + fpath += mimeinfo[esp_mail_file_extension_htm].endsWith; + else + // possible rfc822 encapsulated message which cannot fetch its header + fpath += mimeinfo[esp_mail_file_extension_dat].endsWith; + } + } + + filePath = fpath; +} + +void ESP_Mail_Client::sendStorageNotReadyError(IMAPSession *imap, esp_mail_file_storage_type storageType) +{ + +#if defined(MBFS_FLASH_FS) || defined(MBFS_SD_FS) +#if !defined(SILENT_MODE) + if (imap->_debug && (storageType == esp_mail_file_storage_type_flash || storageType == esp_mail_file_storage_type_sd)) + { + if (storageType == esp_mail_file_storage_type_flash) + { + esp_mail_debug_print_tag(esp_mail_error_mem_str_1 /* "flash Storage is not ready." */, esp_mail_debug_tag_type_error, true); +#if defined(MB_ARDUINO_PICO) + esp_mail_debug_print_tag(esp_mail_error_mem_str_10 /* "please make sure that the size of flash filesystem is not 0 in Pico." */, esp_mail_debug_tag_type_error, true); +#endif + } + else if (storageType == esp_mail_file_storage_type_sd) + esp_mail_debug_print_tag(esp_mail_error_mem_str_2 /* "SD Storage is not ready." */, esp_mail_debug_tag_type_error, true); + } +#endif +#endif +} + +IMAPSession::IMAPSession(Client *client) +{ + setClient(client); +} + +IMAPSession::IMAPSession() +{ +} + +IMAPSession::~IMAPSession() +{ + empty(); +} + +bool IMAPSession::closeSession() +{ + _prev_imap_cmd = esp_mail_imap_cmd_sasl_login; + _prev_imap_custom_cmd = esp_mail_imap_cmd_custom; + + if (!connected()) + return false; + + if (_mbif._idleTimeMs > 0) + mStopListen(false); + + if (_loginStatus) + { +#if !defined(ESP8266) + /** + * The strange behavior in ESP8266 SSL client, BearSSLWiFiClientSecure + * The client disposed without memory released after the server close + * the connection due to LOGOUT command, which caused the memory leaks. + */ + if (!MailClient.imapLogout(this)) + return false; +#endif + } + + return MailClient.handleIMAPError(this, 0, true); +} + +bool IMAPSession::connected() +{ + return client.connected(); +} + +bool IMAPSession::connect(Session_Config *session_config, IMAP_Data *imap_data, bool login) +{ + _sessionSSL = false; + _sessionLogin = login; + + if (session_config) + session_config->clearPorts(); + + this->_customCmdResCallback = NULL; + + int ptr = toAddr(*session_config); + session_config->addPtr(&_configPtrList, ptr); + + if (!handleConnection(session_config, imap_data, _sessionSSL)) + return false; + + if (!_sessionLogin) + return true; + + _loginStatus = MailClient.imapAuth(this, _sessionSSL); + + return _loginStatus; +} + +bool IMAPSession::mLogin(MB_StringPtr email, MB_StringPtr password, bool isToken) +{ + if (_loginStatus) + return true; + + if (!MailClient.sessionExisted(this)) + return false; + + _session_cfg->login.email = email; + + _session_cfg->login.accessToken.clear(); + _session_cfg->login.password.clear(); + + if (isToken) + _session_cfg->login.accessToken = password; + else + _session_cfg->login.password = password; + + _loginStatus = MailClient.imapAuth(this, _sessionSSL); + + return _loginStatus; +} + +void IMAPSession::appendIdList(MB_String &list, IMAP_Identification *identification) +{ + + if (identification->name.length() > 0 && identification->name.length() <= 1024) + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_name].text, identification->name.c_str()); + + if (identification->version.length() > 0 && identification->version.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_version].text, identification->version.c_str()); + } + + if (identification->os.length() > 0 && identification->os.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_os].text, identification->os.c_str()); + } + + if (identification->vendor.length() > 0 && identification->vendor.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_vendor].text, identification->vendor.c_str()); + } + + if (identification->support_url.length() > 0 && identification->support_url.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_support_url].text, identification->support_url.c_str()); + } + + if (identification->address.length() > 0 && identification->address.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_address].text, identification->address.c_str()); + } + + if (identification->date.length() > 0 && identification->date.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_date].text, identification->date.c_str()); + } + + if (identification->command.length() > 0 && identification->command.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_command].text, identification->command.c_str()); + } + + if (identification->arguments.length() > 0 && identification->arguments.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_arguments].text, identification->arguments.c_str()); + } + + if (identification->environment.length() > 0 && identification->environment.length() <= 1024) + { + if (list.length() > 0) + MailClient.appendSpace(list); + MailClient.appendImap4KeyValue(list, imap_identification_keys[esp_mail_imap_identification_key_environment].text, identification->environment.c_str()); + } +} + +bool IMAPSession::id(IMAP_Identification *identification) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_61 /* "Send client identification..." */, + esp_mail_dbg_str_82 /* "send IMAP command, ID" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + if (!_feature_capability[esp_mail_imap_read_capability_id]) + { +#if !defined(SILENT_MODE) + printDebugNotSupported(); +#endif + return false; + } + + if (!MailClient.reconnect(this)) + return false; + + MB_String cmd, idList; + + appendIdList(idList, identification); + + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_id].text); + + if (idList.length() > 0) + MailClient.appendString(cmd, idList.c_str(), false, false, esp_mail_string_mark_type_round_bracket); + else + { + int bufLen = 50; + char *buf = MailClient.allocMem(bufLen); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_21 /* "(\"name\" \"ESP Mail Client\" \"version\" \"%s\")" */), ESP_MAIL_VERSION); + cmd += buf; + // release memory + MailClient.freeMem(&buf); + } + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_id; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +String IMAPSession::serverID() +{ + return _server_id_tmp.c_str(); +} + +bool IMAPSession::isAuthenticated() +{ + return _authenticated; +} + +bool IMAPSession::isLoggedIn() +{ + return _loginStatus; +} + +bool IMAPSession::isFirmwareUpdateSuccess() +{ + return _isFirmwareUpdated; +} + +bool IMAPSession::mCustomConnect(Session_Config *session_config, imapResponseCallback callback, MB_StringPtr tag) +{ + this->_customCmdResCallback = callback; + this->_responseStatus.tag = tag; + + bool ssl = false; + if (!handleConnection(session_config, NULL, ssl)) + return false; + + return true; +} + +bool IMAPSession::handleConnection(Session_Config *session_config, IMAP_Data *imap_data, bool &ssl) +{ + + _session_cfg = session_config; + + if (!client.isInitialized()) + return MailClient.handleIMAPError(this, TCP_CLIENT_ERROR_NOT_INITIALIZED, false); + + // Resources are also released if network disconnected. + if (!MailClient.reconnect(this)) + return false; + + // Need to close previous connection first to free resources. + MailClient.closeTCPSession(this); + + _session_cfg = session_config; + _imap_data = imap_data; + + MailClient.setCert(_session_cfg, _session_cfg->certificate.cert_data); + + ssl = false; + if (!connect(ssl)) + { + MailClient.closeTCPSession(this); + return false; + } + + return true; +} + +bool IMAPSession::connect(bool &ssl) +{ + ssl = false; + MB_String buf; + + if (_imap_data) + { + if (_imap_data->fetch.sequence_set.string.length() > 0 || _imap_data->fetch.uid.length() > 0 || _imap_data->fetch.number.length() > 0) + _headerOnly = false; + else + _headerOnly = true; + } + + _totalRead = 0; + _secure = true; + bool secureMode = true; + + client.txBufDivider = 16; // minimum, tx buffer size for ssl data and request command data + client.rxBufDivider = 1; + if (_imap_data) + { + if (!_headerOnly && !_imap_data->firmware_update.attach_filename.length() == 0 && !_imap_data->enable.html && !_imap_data->enable.text && !_imap_data->download.attachment && !_imap_data->download.inlineImg && !_imap_data->download.html && !_imap_data->download.text) + client.rxBufDivider = 16; // minimum rx buffer size for only message header + } + + MailClient.preparePortFunction(_session_cfg, false, _secure, secureMode, ssl); + +#if !defined(SILENT_MODE) + MailClient.printLibInfo(this); +#endif + + MailClient.prepareTime(_session_cfg, this); + + MailClient.setSecure(client, _session_cfg); + + if (!MailClient.beginConnection(_session_cfg, this, secureMode)) + return false; + + // server connected + + client.setTimeout(tcpTimeout); + + // wait for greeting + unsigned long dataMs = millis(); + while (client.connected() && client.available() == 0 && millis() - dataMs < 2000) + { + yield_impl(); + } + + int chunkBufSize = client.available(); + + if (chunkBufSize > 0) + { + char *buf = MailClient.allocMem(chunkBufSize + 1); + client.readBytes(buf, chunkBufSize); + if (_debug && _debugLevel > esp_mail_debug_level_basic && !_customCmdResCallback) + esp_mail_debug_print((const char *)buf, true); + + if (_customCmdResCallback) + { + MailClient.imapResponseStatus(this, buf, esp_mail_str_3 /* "*" */); + _responseStatus.text = buf; + + if (_responseStatus.text[_responseStatus.text.length() - 2] == '\r' && _responseStatus.text[_responseStatus.text.length() - 1] == '\n') + _responseStatus.text[_responseStatus.text.length() - 2] = 0; + + if (_responseStatus.tag.length() == 0) + this->_responseStatus.tag = esp_mail_imap_tag_str; + + _customCmdResCallback(_responseStatus); + } + + // release memory + MailClient.freeMem(&buf); + } + + if (!_customCmdResCallback) + { +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_48 /* "IMAP server connected" */, + esp_mail_dbg_str_33 /* "IMAP server connected" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + } + + return true; +} + +void IMAPSession::debug(int level) +{ + if (level > esp_mail_debug_level_none) + { + if (level > esp_mail_debug_level_basic && level < esp_mail_debug_level_maintainer) + level = esp_mail_debug_level_basic; + _debugLevel = level; + _debug = true; + client.setDebugLevel(level); + } + else + { + _debugLevel = esp_mail_debug_level_none; + _debug = false; + client.setDebugLevel(0); + } +} + +String IMAPSession::errorReason() +{ + return MailClient.errorReason(false, _responseStatus.errorCode, _responseStatus.text.c_str()); +} + +int IMAPSession::errorCode() +{ + return _responseStatus.errorCode; +} + +bool IMAPSession::mSelectFolder(MB_StringPtr folderName, bool readOnly) +{ + if (connected()) + { + if (!openFolder(folderName, readOnly)) + return false; + } + else + { + _currentFolder = folderName; + } + + if (!connected()) + { + _responseStatus.errorCode = IMAP_STATUS_OPEN_MAILBOX_FAILED; + _responseStatus.clear(); + } + + return connected(); +} + +void IMAPSession::setTCPTimeout(unsigned long timeoutSec) +{ + tcpTimeout = timeoutSec; +} + +void IMAPSession::setClient(Client *client) +{ + this->client.setClient(client); +} + +void IMAPSession::setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password) +{ + this->client.setGSMClient(client, modem, pin, apn, user, password); +} + +void IMAPSession::networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB) +{ + this->client.networkConnectionRequestCallback(networkConnectionCB); +} + +void IMAPSession::networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB) +{ + this->client.networkStatusRequestCallback(networkStatusCB); +} + +void IMAPSession::setNetworkStatus(bool status) +{ + this->client.setNetworkStatus(status); + MailClient.networkStatus = status; +} + +void IMAPSession::setSSLBufferSize(int rx, int tx) +{ + this->client.setIOBufferSize(rx, tx); +} + +bool IMAPSession::mOpenFolder(MB_StringPtr folderName, bool readOnly) +{ + if (!connected()) + { + _responseStatus.errorCode = IMAP_STATUS_OPEN_MAILBOX_FAILED; + _responseStatus.clear(); + return false; + } + + if (readOnly) + return openMailbox(folderName, esp_mail_imap_auth_mode::esp_mail_imap_mode_examine, true, false); + else + return openMailbox(folderName, esp_mail_imap_auth_mode::esp_mail_imap_mode_select, true, false); +} + +bool IMAPSession::getFolders(FoldersCollection &folders) +{ + if (!connected()) + return false; + return getMailboxes(folders); +} + +bool IMAPSession::mCloseFolder(bool expunge) +{ + + // no folder opened + if (_currentFolder.length() == 0) + { +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_error_imap_str_11 /* "no mailbox opened" */, + esp_mail_error_imap_str_11 /* "no mailbox opened" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + return false; + } + + return closeMailbox(expunge); +} + +bool IMAPSession::mListen(bool recon) +{ + if (!MailClient.sessionExisted(this)) + return false; + + if (_currentFolder.length() == 0) + { + _mbif._floderChangedState = false; + _mbif._folderChanged = false; + return false; + } + + if (!MailClient.reconnect(this)) + return false; + + if (!connected()) + { + if (!_imap_data || (millis() - _last_server_connect_ms < 2000 && _last_server_connect_ms > 0)) + return false; + + _last_server_connect_ms = millis(); + + bool ssl = false; + + if (!connect(ssl)) + { + MailClient.closeTCPSession(this); + return false; + } + + // re-authenticate after session closed + if (!MailClient.imapAuth(this, ssl)) + { + MailClient.closeTCPSession(this); + return false; + } + + // re-open folder + if (!selectFolder(_currentFolder.c_str())) + return false; + } + + // no IDLE was not supported (should be checked after imapAuth) + if (!_feature_capability[esp_mail_imap_read_capability_idle]) + { +#if !defined(SILENT_MODE) + printDebugNotSupported(); +#endif + } + + if (_mbif._idleTimeMs == 0) + { + _mbif._polling_status.messageNum = 0; + _mbif._polling_status.type = imap_polling_status_type_undefined; + _mbif._polling_status.argument.clear(); + _mbif._recentCount = 0; + _mbif._folderChanged = false; + +#if !defined(SILENT_MODE) + MB_String dbMsg; + + if (!recon) + { + + dbMsg = esp_mail_dbg_str_51; /* "listening to " */ + dbMsg += _currentFolder; + dbMsg += esp_mail_dbg_str_52; /* " folder changes" */ + MailClient.printDebug(this, + esp_mail_cb_str_29 /* "Listening to mailbox changes..." */, + dbMsg.c_str(), + esp_mail_debug_tag_type_client, + true, + false); + } + +#endif + + if (MailClient.imapSend(this, prependTag(imap_commands[esp_mail_imap_command_idle].text).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_idle; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + +#if !defined(SILENT_MODE) + if (!recon) + { + + dbMsg = esp_mail_str_88 /* "polling established on " */; + dbMsg += MailClient.Time.getDateTimeString(MailClient.Time.getCurrentTimestamp(), "%B %d, %Y %H:%M:%S"); + MailClient.printDebug(this, + esp_mail_cb_str_49 /* "Polling established" */, + dbMsg.c_str(), + esp_mail_debug_tag_type_client, + true, + false); + } + +#endif + + _mbif._idleTimeMs = millis(); + } + else + { + if (_mbif._floderChangedState) + { + _mbif._floderChangedState = false; + _mbif._folderChanged = false; + _mbif._polling_status.messageNum = 0; + _mbif._polling_status.type = imap_polling_status_type_undefined; + _mbif._polling_status.argument.clear(); + _mbif._recentCount = 0; + } + + size_t imap_idle_tmo = _imap_data->limit.imap_idle_timeout; + + if (imap_idle_tmo < 60 * 1000 || imap_idle_tmo > 29 * 60 * 1000) + imap_idle_tmo = 10 * 60 * 1000; + + size_t host_check_interval = _imap_data->limit.imap_idle_host_check_interval; + + if (host_check_interval < 30 * 1000 || host_check_interval > imap_idle_tmo) + host_check_interval = 60 * 1000; + + if (millis() - _last_host_check_ms > host_check_interval && connected()) + { + _last_host_check_ms = millis(); + + IPAddress ip; + + if (client.hostByName(_session_cfg->server.host_name.c_str(), ip) != 1) + { + closeSession(); + _mbif._idleTimeMs = millis(); + return false; + } + } + + return MailClient.parseIdleResponse(this); + } + + return true; +} + +bool IMAPSession::mStopListen(bool recon) +{ + _mbif._idleTimeMs = 0; + _mbif._floderChangedState = false; + _mbif._folderChanged = false; + _mbif._polling_status.messageNum = 0; + _mbif._polling_status.type = imap_polling_status_type_undefined; + _mbif._polling_status.argument.clear(); + _mbif._recentCount = 0; + + if (!connected() || _currentFolder.length() == 0 || !_feature_capability[esp_mail_imap_read_capability_idle]) + return false; + + if (MailClient.imapSend(this, imap_commands[esp_mail_imap_command_done].text, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_done; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + +#if !defined(SILENT_MODE) + if (!recon) + { + MailClient.printDebug(this, + esp_mail_cb_str_50 /* "Mailbox listening stopped" */, + esp_mail_dbg_str_54 /* "Mailbox listening stopped" */, + esp_mail_debug_tag_type_client, + true, + false); + } +#endif + + return true; +} + +bool IMAPSession::folderChanged() +{ + return _mbif._floderChangedState; +} + +bool IMAPSession::noop() +{ + +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_62 /* "Sending noop..." */, + esp_mail_dbg_str_83 /* "send IMAP command, NOOP" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (MailClient.imapSend(this, prependTag(imap_commands[esp_mail_imap_command_noop].text).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_noop; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +void IMAPSession::checkUID() +{ + if (MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, imap_commands[esp_mail_imap_command_uid].text) || MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, imap_commands[esp_mail_imap_command_flags].text) || + MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, imap_commands[esp_mail_imap_command_body].text) || MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, imap_commands[esp_mail_imap_command_peek].text) || MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, imap_commands[esp_mail_imap_command_text].text) || + MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, imap_commands[esp_mail_imap_command_header].text) || MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, imap_commands[esp_mail_imap_command_fields].text) || MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, esp_mail_str_40 /* "[" */) || + MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, esp_mail_str_41 /* "]" */) || MailClient.strcmpP(_imap_data->fetch.uid.c_str(), 0, imap_commands[esp_mail_imap_command_mime].text)) + _imap_data->fetch.uid = esp_mail_str_3; /* "*" */ +} + +void IMAPSession::checkPath() +{ + MB_String path = _imap_data->storage.saved_path; + if (path[0] != '/') + { + path = '/'; + path += _imap_data->storage.saved_path; + path = path.c_str(); + } +} + +bool IMAPSession::headerOnly() +{ + return _headerOnly; +} + +struct esp_mail_imap_msg_list_t IMAPSession::data() +{ + struct esp_mail_imap_msg_list_t ret; + + for (size_t i = 0; i < _headers.size(); i++) + { + +#if defined(MB_ARDUINO_ESP) || defined(MB_ARDUINO_PICO) + if (MailClient.getFreeHeap() < ESP_MAIL_MIN_MEM) + continue; +#endif + struct esp_mail_imap_msg_item_t itm; + itm.setRFC822Headers(&_headers[i].header_fields); + itm.UID = _headers[i].message_uid; + itm.msgNo = _headers[i].message_no; + itm.flags = _headers[i].flags.c_str(); + itm.acceptLang = _headers[i].accept_language.c_str(); + itm.contentLang = _headers[i].content_language.c_str(); + itm.hasAttachment = _headers[i].hasAttachment; + itm.fetchError = _headers[i].error_msg.c_str(); + + getMessages(i, itm); + + getRFC822Messages(i, itm); + + ret.msgItems.push_back(itm); + } + + return ret; +} + +SelectedFolderInfo IMAPSession::selectedFolder() +{ + return _mbif; +} + +void IMAPSession::callback(imapStatusCallback imapCallback) +{ + _statusCallback = imapCallback; +} + +void IMAPSession::characterDecodingCallback(imapCharacterDecodingCallback callback) +{ + _charDecCallback = callback; +} + +void IMAPSession::mimeDataStreamCallback(MIMEDataStreamCallback mimeDataStreamCallback) +{ + _mimeDataStreamCallback = mimeDataStreamCallback; +} + +void IMAPSession::setSystemTime(time_t ts, float gmtOffset) +{ + MailClient.Time.setTimestamp(ts, gmtOffset); +} + +void IMAPSession::keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount) +{ + this->client.keepAlive(tcpKeepIdleSeconds, tcpKeepIntervalSeconds, tcpKeepCount); +} + +bool IMAPSession::isKeepAlive() +{ + return this->client.isKeepAlive(); +} + +void IMAPSession::getMessages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg) +{ + msg.text.content = ""; + msg.text.charSet = ""; + msg.text.content_type = ""; + msg.text.transfer_encoding = ""; + msg.html.content = ""; + msg.html.charSet = ""; + msg.html.content_type = ""; + msg.html.transfer_encoding = ""; + + if (messageIndex < _headers.size()) + { + int sz = _headers[messageIndex].part_headers.size(); + if (sz > 0) + { + for (int i = 0; i < sz; i++) + { + if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_attachment || (!_headers[messageIndex].part_headers[i].rfc822_part && _headers[messageIndex].part_headers[i].message_sub_type != esp_mail_imap_message_sub_type_rfc822)) + { + if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_none) + { + if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_plain || _headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_enriched) + { + msg.text.content = _headers[messageIndex].part_headers[i].text.c_str(); + msg.text.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); + msg.text.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); + msg.text.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); + } + + if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_html) + { + msg.html.content = _headers[messageIndex].part_headers[i].text.c_str(); + msg.html.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); + msg.html.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); + msg.html.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); + } + } + else + { + struct esp_mail_attachment_info_t att; + att.filename = _headers[messageIndex].part_headers[i].filename.c_str(); + att.mime = _headers[messageIndex].part_headers[i].content_type.c_str(); + att.name = _headers[messageIndex].part_headers[i].name.c_str(); + att.size = _headers[messageIndex].part_headers[i].attach_data_size; + att.description = _headers[messageIndex].part_headers[i].content_description.c_str(); + att.creationDate = _headers[messageIndex].part_headers[i].creation_date.c_str(); + att.type = _headers[messageIndex].part_headers[i].attach_type; + msg.attachments.push_back(att); + } + } + } + } + } +} + +void IMAPSession::getRFC822Messages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg) +{ + if (messageIndex < _headers.size()) + { + int size = _headers[messageIndex].part_headers.size(); + int partIdx = 0; + int cIdx = 0; + IMAP_MSG_Item *_rfc822 = nullptr; + if (size > 0) + { + for (int i = 0; i < size; i++) + { + if (_headers[messageIndex].part_headers[i].message_sub_type == esp_mail_imap_message_sub_type_rfc822 && _headers[messageIndex].part_headers[i].attach_type != esp_mail_att_type_attachment) + { + if (_headers[messageIndex].part_headers[i].rfc822_part) + { + if (partIdx > 0) + msg.rfc822.push_back(*_rfc822); + cIdx = i; + partIdx++; + _rfc822 = new IMAP_MSG_Item(); + _rfc822->setRFC822Headers(&_headers[messageIndex].part_headers[i].rfc822_header); + } + else + { + if (MailClient.multipartMember(_headers[messageIndex].part_headers[cIdx].partNumStr, _headers[messageIndex].part_headers[i].partNumStr)) + { + if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_none) + { + if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_plain || _headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_enriched) + { + _rfc822->text.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); + _rfc822->text.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); + _rfc822->text.content = _headers[messageIndex].part_headers[i].text.c_str(); + _rfc822->text.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); + } + if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_html) + { + _rfc822->html.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); + _rfc822->html.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); + _rfc822->html.content = _headers[messageIndex].part_headers[i].text.c_str(); + _rfc822->html.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); + } + } + else + { + struct esp_mail_attachment_info_t att; + att.filename = _headers[messageIndex].part_headers[i].filename.c_str(); + att.mime = _headers[messageIndex].part_headers[i].content_type.c_str(); + att.name = _headers[messageIndex].part_headers[i].name.c_str(); + att.size = _headers[messageIndex].part_headers[i].attach_data_size; + att.description = _headers[messageIndex].part_headers[i].content_description.c_str(); + att.creationDate = _headers[messageIndex].part_headers[i].creation_date.c_str(); + att.type = _headers[messageIndex].part_headers[i].attach_type; + _rfc822->attachments.push_back(att); + } + } + } + } + } + + if ((int)msg.rfc822.size() < partIdx && _rfc822 != nullptr) + msg.rfc822.push_back(*_rfc822); + } + } +} + +bool IMAPSession::closeMailbox(bool expunge) +{ +#if !defined(SILENT_MODE) + MB_String dbMsg = esp_mail_dbg_str_32; /* "closing the " */ + dbMsg += _currentFolder; + dbMsg += esp_mail_str_89; /* " folder..." */ + + MailClient.printDebug(this, + esp_mail_cb_str_27 /* "Closing the mailbox folder..." */, + dbMsg.c_str(), + esp_mail_debug_tag_type_client, + true, + false); +#endif + if (!MailClient.reconnect(this)) + return false; + + // If folder was opened in readonly mode, use CLOSE command will not expunge the deleted messages + // Or user intent to expunge the deleted message after close the folder. + if (expunge || _readOnlyMode) + { + + if (MailClient.imapSend(this, prependTag(imap_commands[esp_mail_imap_command_close].text).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_close; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CLOSE_MAILBOX_FAILED, false)) + return false; + } + else + { + // Close folder without expunge + if (_feature_capability[esp_mail_imap_read_capability_unselect]) + { + if (MailClient.imapSend(this, prependTag(imap_commands[esp_mail_imap_command_unselect].text).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_unselect; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CLOSE_MAILBOX_FAILED, false)) + return false; + } + else + { + // Open non-existing folder + MB_String folder = esp_mail_str_84 /* "message" */; + folder += MailClient.Time.getCurrentTimestamp(); + MB_StringPtr folderPtr; + folderPtr = toStringPtr(folder); + openMailbox(folderPtr, esp_mail_imap_auth_mode::esp_mail_imap_mode_examine, true, true); + } + } + + _currentFolder.clear(); + _mailboxOpened = false; + + return true; +} + +bool IMAPSession::openMailbox(MB_StringPtr folder, esp_mail_imap_auth_mode mode, bool waitResponse, bool unselect) +{ + + if (!MailClient.sessionExisted(this)) + return false; + + MB_String _folder = folder; + + if (!MailClient.reconnect(this)) + return false; + + if (_folder.length() == 0) + return false; + + bool _dbg = _debug; + imapStatusCallback _cb = _statusCallback; + + // The SELECT/EXAMINE command automatically deselects any currently selected mailbox + // before attempting the new selection (RFC3501 p.33) + + // folder should not close for re-selection otherwise the server returned * BAD Command Argument Error. 12 + + if (!unselect) + { + + bool sameFolder = strcmp(_currentFolder.c_str(), _folder.c_str()) == 0; + + // guards 3 seconds to prevent accidently frequently select the same folder with the same mode + if (!_mailboxOpened && sameFolder && millis() - _lastSameFolderOpenMillis < 3000) + { + if ((_readOnlyMode && mode == esp_mail_imap_mode_examine) || (!_readOnlyMode && mode == esp_mail_imap_mode_select)) + return true; + } + + if (!sameFolder) + _currentFolder = folder; + +#if !defined(SILENT_MODE) + MB_String dbMsg = esp_mail_dbg_str_68; /* "selecting the " */ + dbMsg += _currentFolder; + dbMsg += esp_mail_str_89; /* " folder..." */ + + MailClient.printDebug(this, + esp_mail_cb_str_51 /* "Open the mailbox folder..." */, + dbMsg.c_str(), + esp_mail_debug_tag_type_client, + true, + false); +#endif + } + else + { + // Hide the callback and debug info + _debug = false; + _statusCallback = NULL; + _currentFolder = folder; + } + + MB_String cmd; + MailClient.appendSpace(cmd, true, mode == esp_mail_imap_mode_examine ? imap_commands[esp_mail_imap_command_examine].text : imap_commands[esp_mail_imap_command_select].text); + MailClient.appendString(cmd, _currentFolder.c_str(), false, false, esp_mail_string_mark_type_double_quote); + + if (isCondStoreSupported()) + { + MailClient.appendSpace(cmd); + MailClient.appendString(cmd, imap_commands[esp_mail_imap_command_condstore].text, false, false, esp_mail_string_mark_type_round_bracket); + } + + _imap_cmd = mode == esp_mail_imap_mode_examine ? esp_mail_imap_cmd_examine : esp_mail_imap_cmd_select; + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!unselect) + _lastSameFolderOpenMillis = millis(); + + if (waitResponse && !MailClient.handleIMAPResponse(this, IMAP_STATUS_OPEN_MAILBOX_FAILED, false)) + { + if (!unselect) + return false; + } + + if (unselect) + { + _statusCallback = _cb; + _debug = _dbg; + } + + if (mode == esp_mail_imap_mode_examine) + _readOnlyMode = true; + else if (mode == esp_mail_imap_mode_select) + _readOnlyMode = false; + + _mailboxOpened = !unselect; + + return true; +} + +bool IMAPSession::getMailboxes(FoldersCollection &folders) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_16 /* "Reading the list of mailboxes..." */, + esp_mail_dbg_str_35 /* "send IMAP command, LIST" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + _folders.clear(); + + MB_String cmd; + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_list].text); + MailClient.appendString(cmd, NULL, false, false, esp_mail_string_mark_type_double_quote); + MailClient.prependSpace(cmd, esp_mail_str_3 /* "*" */); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_list; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_LIST_MAILBOXS_FAILED, false)) + return false; + + folders = _folders; + return true; +} + +bool IMAPSession::mGetSubscribesMailboxes(MB_StringPtr reference, MB_StringPtr mailbox, FoldersCollection &folders) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_30 /* "Listing the subscribed mailboxes..." */, + esp_mail_dbg_str_56 /* "send IMAP command, LSUB" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + folders.clear(); + + MB_String cmd; + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_lsub].text); + MailClient.appendString(cmd, MB_String(reference).c_str(), false, false, esp_mail_string_mark_type_double_quote); + MailClient.appendSpace(cmd); + MailClient.appendString(cmd, MB_String(mailbox).c_str(), false, false, esp_mail_string_mark_type_double_quote); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + FoldersCollection tmp; + + for (size_t i = 0; i < this->_folders.size(); i++) + tmp.add(this->_folders[i]); + + this->_folders.clear(); + + _imap_cmd = esp_mail_imap_cmd_lsub; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_LIST_MAILBOXS_FAILED, false)) + return false; + + for (size_t i = 0; i < this->_folders.size(); i++) + folders.add(this->_folders[i]); + + this->_folders.clear(); + + for (size_t i = 0; i < tmp.size(); i++) + this->_folders.add(tmp[i]); + + tmp.clear(); + + return true; +} + +bool IMAPSession::mSubscribe(MB_StringPtr folder) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_31 /* "Subscribe mailbox..." */, + esp_mail_dbg_str_57 /* "send IMAP command, SUBSCRIBE" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + MB_String cmd; + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_subscribe].text); + MailClient.appendString(cmd, MB_String(folder).c_str(), false, false, esp_mail_string_mark_type_double_quote); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_subscribe; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_LIST_MAILBOXS_FAILED, false)) + return false; + + return true; +} + +bool IMAPSession::mUnSubscribe(MB_StringPtr folder) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_32 /* "Unsubscribe mailbox..." */, + esp_mail_dbg_str_58 /* "send IMAP command, UNSUBSCRIBE" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + MB_String cmd; + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_unsubscribe].text); + MailClient.appendString(cmd, MB_String(folder).c_str(), false, false, esp_mail_string_mark_type_double_quote); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_unsubscribe; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_LIST_MAILBOXS_FAILED, false)) + return false; + + return true; +} + +bool IMAPSession::mFetchSequenceSet() +{ + + MB_String cmd; + if (_imap_data->fetch.sequence_set.UID) + MailClient.appendSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_uid].text, imap_commands[esp_mail_imap_command_fetch].text); + else + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_fetch].text); + + MailClient.appendSpace(cmd, false, _imap_data->fetch.sequence_set.string.c_str()); + MailClient.appendString(cmd, imap_commands[esp_mail_imap_command_uid].text, false, false, esp_mail_string_mark_type_round_bracket); + + addModifier(cmd, esp_mail_imap_command_changedsince, _imap_data->fetch.modsequence); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_msg_num.clear(); + + _imap_cmd = esp_mail_imap_cmd_fetch_sequence_set; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_LIST_MAILBOXS_FAILED, false)) + return false; + + return true; +} + +MB_String IMAPSession::prependTag(PGM_P cmd, PGM_P tag) +{ + MB_String s = (tag == NULL) ? esp_mail_imap_tag_str : tag; + MailClient.appendSpace(s); + s += cmd; + return s; +} + +bool IMAPSession::checkCapabilities() +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_52 /* "Checking the capability..." */, + esp_mail_dbg_str_76 /* "check the capability" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + if (MailClient.imapSend(this, prependTag(imap_commands[esp_mail_imap_command_capability].text).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_capability; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CHECK_CAPABILITIES_FAILED, false)) + return false; + + return true; +} + +bool IMAPSession::mCreateFolder(MB_StringPtr folderName) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_59 /* "Creating folder..." */, + esp_mail_dbg_str_49 /* "creating folder" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + MB_String cmd; + MailClient.joinStringSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_create].text, folderName); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_create; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +bool IMAPSession::mRenameFolder(MB_StringPtr currentFolderName, MB_StringPtr newFolderName) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_53 /* "Renaming folder..." */, + esp_mail_dbg_str_55 /* "renaming folder" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + MB_String o = currentFolderName; + MB_String n = newFolderName; + + o.trim(); + n.trim(); + + if (o == n) + return true; + + if (o.length() == 0 || n.length() == 0) + return false; + + MB_String cmd; + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_rename].text); + MailClient.appendString(cmd, o.c_str(), false, false, esp_mail_string_mark_type_double_quote); + MailClient.appendSpace(cmd); + MailClient.appendString(cmd, n.c_str(), false, false, esp_mail_string_mark_type_double_quote); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_rename; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + if (_currentFolder == o) + selectFolder(n.c_str(), false); + + return true; +} + +int IMAPSession::getUID(int msgNum) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_25 /* "Get UID..." */, + esp_mail_dbg_str_79 /* "get UID" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + int uid = mGetUID(msgNum); + + if (!MailClient.sessionExisted(this)) + return false; + +#if !defined(SILENT_MODE) + MB_String dbMsg = esp_mail_cb_str_54; /* "UID is " */ + dbMsg += uid; + + MailClient.printDebug(this, + dbMsg.c_str(), + dbMsg.c_str(), + esp_mail_debug_tag_type_client, + true, + false); +#endif + return uid; +} + +int IMAPSession::mGetUID(int msgNum) +{ + + if (_currentFolder.length() == 0) + return 0; + + MB_String cmd; + MailClient.joinStringSpace(cmd, true, 3, imap_commands[esp_mail_imap_command_fetch].text, MB_String(msgNum).c_str(), imap_commands[esp_mail_imap_command_uid].text); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return 0; + + _imap_cmd = esp_mail_imap_cmd_get_uid; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return 0; + + return _uid_tmp; +} + +const char *IMAPSession::getFlags(int msgNum) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_55 /* "Get Flags..." */, + esp_mail_dbg_str_80 /* "get flags" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + _flags_tmp.clear(); + if (_currentFolder.length() == 0) + return _flags_tmp.c_str(); + + MB_String cmd, cmd2; + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_fetch].text); + MailClient.appendString(cmd2, imap_commands[esp_mail_imap_command_flags].text, false, false, esp_mail_string_mark_type_round_bracket); + MailClient.joinStringSpace(cmd, false, 2, MB_String(msgNum).c_str(), cmd2.c_str()); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return _flags_tmp.c_str(); + + _imap_cmd = esp_mail_imap_cmd_get_flags; + MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false); + + return _flags_tmp.c_str(); +} + +bool IMAPSession::mSendCustomCommand(MB_StringPtr cmd, imapResponseCallback callback, MB_StringPtr tag) +{ + + _customCmdResCallback = callback; + _cmd = cmd; + _cmd.trim(); + + MB_String _tag = cmd; + _tag.trim(); + + MB_String _tag2 = tag; + _tag2.trim(); + + if (_tag2.length() == 0) + { + int p = MailClient.strpos(_tag.c_str(), " ", 0); + if (p > -1) + { + _tag.erase(p, _tag.length() - p); + _tag.trim(); + _responseStatus.tag = _tag; + } + } + else + { + _responseStatus.tag = tag; + _responseStatus.tag.trim(); + if (MailClient.strpos(_cmd.c_str(), _responseStatus.tag.c_str(), 0, false) == -1) + _cmd = prependTag(_cmd.c_str(), _responseStatus.tag.c_str()); + } + + // filter for specific command + if (_cmd.find(imap_cmd_pre_tokens[esp_mail_imap_command_idle].c_str()) != MB_String::npos) + _imap_custom_cmd = esp_mail_imap_cmd_idle; + else if (_cmd.find(imap_cmd_pre_tokens[esp_mail_imap_command_append].c_str()) != MB_String::npos) + _imap_custom_cmd = esp_mail_imap_cmd_append; + else if (_cmd.find(imap_cmd_pre_tokens[esp_mail_imap_command_login].c_str()) != MB_String::npos) + _imap_custom_cmd = esp_mail_imap_cmd_sasl_login; + else if (_cmd.find(imap_cmd_pre_tokens[esp_mail_imap_command_logout].c_str()) != MB_String::npos) + _imap_custom_cmd = esp_mail_imap_cmd_logout; + else + _imap_custom_cmd = esp_mail_imap_cmd_custom; + + if (_prev_imap_custom_cmd != _imap_custom_cmd || _imap_custom_cmd != esp_mail_imap_cmd_idle) + { + if (MailClient.imapSend(this, _cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + { + _prev_imap_custom_cmd = esp_mail_imap_cmd_custom; + return false; + } + } + + _imap_cmd = esp_mail_imap_cmd_custom; + + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + { + _prev_imap_custom_cmd = esp_mail_imap_cmd_custom; + return false; + } + + if (_imap_custom_cmd == esp_mail_imap_cmd_sasl_login) + { + _authenticated = true; + _loginStatus = true; + } + else if (_imap_custom_cmd == esp_mail_imap_cmd_logout) + { + _authenticated = false; + _loginStatus = false; + } + + _prev_imap_custom_cmd = _imap_custom_cmd; + + if (MailClient.strposP(_cmd.c_str(), imap_auth_capabilities[esp_mail_auth_capability_starttls].text, 0, false) == 0) + { + bool verify = false; + + if (_session_cfg) + verify = _session_cfg->certificate.verify; + + if (!client.connectSSL(verify)) + return false; + + // set the secure mode + if (_session_cfg) + { + // We reset the prefer connection mode in case user set it. + _session_cfg->secure.startTLS = false; + _session_cfg->secure.mode = esp_mail_secure_mode_undefined; + } + + _secure = true; + } + + return true; +} + +bool IMAPSession::mSendData(MB_StringPtr data, bool lastData, esp_mail_imap_command cmd) +{ + MB_String _data = data; + if (MailClient.imapSend(this, _data.c_str(), lastData) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (lastData) + { + _imap_cmd = cmd; + _cmd.clear(); + + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + } + + return true; +} + +bool IMAPSession::mSendData(uint8_t *data, size_t size, bool lastData, esp_mail_imap_command cmd) +{ + + if (MailClient.imapSend(this, data, size) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (lastData) + { + if (MailClient.imapSend(this, pgm2Str(esp_mail_str_42 /* "\r\n" */), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = cmd; + _cmd.clear(); + + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + } + + return true; +} + +bool IMAPSession::mDeleteFolder(MB_StringPtr folderName) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_56 /* "Deleting folder..." */, + esp_mail_dbg_str_81 /* "delete folder" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + MB_String cmd; + MailClient.joinStringSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_delete].text, MB_String(folderName).c_str()); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_delete; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +bool IMAPSession::isCondStoreSupported() +{ + return _feature_capability[esp_mail_imap_read_capability_condstore]; +} + +bool IMAPSession::isModseqSupported() +{ + return isCondStoreSupported() && !_mbif._nomodsec; +} + +void IMAPSession::addModifier(MB_String &cmd, esp_mail_imap_command_types type, int32_t modsequence) +{ + if (modsequence > -1 && isModseqSupported()) + { + MB_String modifier; + MailClient.joinStringSpace(modifier, false, 2, imap_commands[type].text, MB_String(modsequence).c_str()); + MailClient.appendSpace(cmd); + MailClient.appendString(cmd, modifier.c_str(), false, false, esp_mail_string_mark_type_round_bracket); + } +} + +bool IMAPSession::deleteMsg(MessageList *toDelete, const char *sequenceSet, bool UID, bool expunge, int32_t modsequence) +{ + if ((toDelete && toDelete->_list.size() == 0) || (!toDelete && strlen(sequenceSet) == 0)) + return false; + + if (!selectFolder(_currentFolder.c_str(), false)) + return false; + +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_57 /* "Deleting message(s)..." */, + esp_mail_dbg_str_75 /* "delete message(s)" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (!MailClient.sessionExisted(this)) + return false; + + MB_String cmd; + if (UID || toDelete) + { + MailClient.appendSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_uid].text, imap_commands[esp_mail_imap_command_store].text); + + if (toDelete && toDelete->_list.size() > 0) + MailClient.appendList(cmd, toDelete->_list); + } + else if (!toDelete && strlen(sequenceSet) > 0) + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_store].text); + + if (!toDelete && strlen(sequenceSet) > 0) + cmd += sequenceSet; + + addModifier(cmd, esp_mail_imap_command_unchangedsince, modsequence); + + cmd += imap_cmd_pre_tokens[esp_mail_imap_command_plus_flags]; + MailClient.prependDot(cmd, imap_commands[esp_mail_imap_command_silent].text); + MailClient.appendSpace(cmd); + MailClient.appendString(cmd, esp_mail_str_91 /* "\\Deleted" */, false, false, esp_mail_string_mark_type_round_bracket); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_store; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + if (expunge) + { + if (MailClient.imapSend(this, prependTag(imap_commands[esp_mail_imap_command_expunge].text).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_expunge; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + } + + return true; +} + +bool IMAPSession::mDeleteMessages(MessageList *toDelete, bool expunge, int32_t modsequence) +{ + if (toDelete->_list.size() > 0) + return deleteMsg(toDelete, "", false, expunge); + return true; +} + +bool IMAPSession::mDeleteMessagesSet(MB_StringPtr sequenceSet, bool UID, bool expunge, int32_t modsequence) +{ + return deleteMsg(nullptr, MB_String(sequenceSet).c_str(), UID, expunge); +} + +bool IMAPSession::copyMsg(MessageList *toCopy, const char *sequenceSet, bool UID, MB_StringPtr dest) +{ +#if !defined(SILENT_MODE) + MB_String dbMsg = esp_mail_dbg_str_48; /* "copying message(s) to " */ + dbMsg += dest; + + MailClient.printDebug(this, + esp_mail_cb_str_58 /* "Copying message(s)..." */, + dbMsg.c_str(), + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (!MailClient.sessionExisted(this)) + return false; + + if ((toCopy && toCopy->_list.size() == 0) || (!toCopy && strlen(sequenceSet) == 0)) + return false; + + if (!selectFolder(_currentFolder.c_str(), false)) + return false; + + MB_String cmd; + if (UID || toCopy) + { + MailClient.appendSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_uid].text, imap_commands[esp_mail_imap_command_copy].text); + + if (toCopy && toCopy->_list.size() > 0) + MailClient.appendList(cmd, toCopy->_list); + } + else if (!toCopy && strlen(sequenceSet) > 0) + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_copy].text); + + if (!toCopy && strlen(sequenceSet) > 0) + cmd += sequenceSet; + + MailClient.prependSpace(cmd, MB_String(dest).c_str()); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_copy; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +bool IMAPSession::mCopyMessages(MessageList *toCopy, MB_StringPtr dest) +{ + return copyMsg(toCopy, "", false, dest); +} + +bool IMAPSession::mCopyMessagesSet(MB_StringPtr sequenceSet, bool UID, MB_StringPtr dest) +{ + return copyMsg(nullptr, MB_String(sequenceSet).c_str(), UID, dest); +} + +bool IMAPSession::moveMsg(MessageList *toMove, const char *sequenceSet, bool UID, MB_StringPtr dest) +{ +#if !defined(SILENT_MODE) + MB_String dbMsg = esp_mail_dbg_str_59; /* "moving message(s) to " */ + dbMsg += dest; + + MailClient.printDebug(this, + esp_mail_cb_str_60 /* "Moving message(s)..." */, + dbMsg.c_str(), + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (!MailClient.sessionExisted(this)) + return false; + + if ((toMove && toMove->_list.size() == 0) || (!toMove && strlen(sequenceSet) == 0)) + return false; + + if (!_feature_capability[esp_mail_imap_read_capability_move]) + { + + bool ret = mCopyMessages(toMove, dest); + + if (ret) + ret = mDeleteMessages(toMove, true); + + return ret; + } + + if (!selectFolder(_currentFolder.c_str(), false)) + return false; + + MB_String cmd; + if (UID || toMove) + { + MailClient.appendSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_uid].text, imap_commands[esp_mail_imap_command_move].text); + if (toMove && toMove->_list.size() > 0) + MailClient.appendList(cmd, toMove->_list); + } + else if (!toMove && strlen(sequenceSet) > 0) + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_move].text); + + if (!toMove && strlen(sequenceSet) > 0) + cmd += sequenceSet; + + MailClient.prependSpace(cmd, MB_String(dest).c_str()); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_move; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +bool IMAPSession::mMoveMessages(MessageList *toMove, MB_StringPtr dest) +{ + return moveMsg(toMove, "", false, dest); +} + +bool IMAPSession::mMoveMessagesSet(MB_StringPtr sequenceSet, bool UID, MB_StringPtr dest) +{ + return moveMsg(nullptr, MB_String(sequenceSet).c_str(), UID, dest); +} + +bool IMAPSession::mGetSetQuota(MB_StringPtr quotaRoot, IMAP_Quota_Root_Info *data, bool getMode) +{ + +#if !defined(SILENT_MODE) + PGM_P p1 = getMode ? esp_mail_cb_str_33 /* "Get quota root resource usage and limit..." */ : esp_mail_cb_str_34 /* "Set quota root resource usage and limit..." */; + PGM_P p2 = getMode ? esp_mail_dbg_str_60 /* "send IMAP command, GETQUOTA" */ : esp_mail_dbg_str_61 /* "send IMAP command, SETQUOTA" */; + MailClient.printDebug(this, p1, p2, esp_mail_debug_tag_type_client, true, false); +#endif + + if (!_feature_capability[esp_mail_imap_read_capability_quota]) + { +#if !defined(SILENT_MODE) + printDebugNotSupported(); +#endif + return false; + } + + MB_String _quotaRoot = quotaRoot; + + MB_String cmd; + if (getMode) + { + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_getquota].text); + MailClient.appendString(cmd, _quotaRoot.c_str(), false, false, esp_mail_string_mark_type_double_quote); + } + else + { + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_setquota].text); + MailClient.appendString(cmd, _quotaRoot.c_str(), false, false, esp_mail_string_mark_type_double_quote); + MailClient.appendSpace(cmd); + + MB_String cmd2; + MailClient.joinStringSpace(cmd2, false, 2, data->name.c_str(), MB_String((int)data->limit).c_str()); + MailClient.appendString(cmd, cmd2.c_str(), false, false, esp_mail_string_mark_type_round_bracket); + } + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _quota_tmp.clear(); + + _imap_cmd = (getMode) ? esp_mail_imap_cmd_get_quota : esp_mail_imap_cmd_set_quota; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + if (getMode) + { + mParseQuota(_quota_tmp.c_str(), data); + } + + _quota_tmp.clear(); + + return true; +} + +void IMAPSession::mParseQuota(const char *quota, IMAP_Quota_Root_Info *data) +{ + _vectorImpl tokens; + MailClient.splitToken(quota, tokens, " "); + data->quota_root = tokens[0]; + tokens[1].erase(0, 1); + data->name = tokens[1]; + data->usage = atoi(tokens[2].c_str()); + data->limit = atoi(tokens[3].c_str()); +} + +bool IMAPSession::mGetQuotaRoots(MB_StringPtr mailbox, IMAP_Quota_Roots_List *quotaRootsList) +{ +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_35 /* "Get the list of quota roots..." */, + esp_mail_dbg_str_62 /* "send IMAP command, GETQUOTAROOT" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (!MailClient.sessionExisted(this)) + return false; + + if (!_feature_capability[esp_mail_imap_read_capability_quota]) + { +#if !defined(SILENT_MODE) + printDebugNotSupported(); +#endif + return false; + } + + MB_String _mailbox = mailbox; + + MB_String cmd; + MailClient.appendSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_getquota].text, imap_commands[esp_mail_imap_command_root].text); + MailClient.appendString(cmd, _mailbox.c_str(), false, false, esp_mail_string_mark_type_double_quote); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _quota_root_tmp.clear(); + _quota_tmp.clear(); + + _imap_cmd = esp_mail_imap_cmd_get_quota_root; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + _vectorImpl tokens; + MailClient.splitToken(_quota_root_tmp.c_str(), tokens, ","); + + for (size_t i = 0; i < tokens.size(); i++) + { + _vectorImpl tk; + MailClient.splitToken(tokens[i].c_str(), tk, ":"); + IMAP_Quota_Root_Info data; + if (tk.size() > 1) + mParseQuota(tk[1].c_str(), &data); + else + data.quota_root = tk[0]; + + quotaRootsList->add(data); + } + + _quota_root_tmp.clear(); + _quota_tmp.clear(); + + return true; +} + +bool IMAPSession::mManageACL(MB_StringPtr mailbox, IMAP_Rights_List *acl_list, IMAP_Rights_Info *acl, MB_StringPtr identifier, esp_mail_imap_command type) +{ + +#if !defined(SILENT_MODE) + + PGM_P p1 = NULL; + PGM_P p2 = NULL; + if (type == esp_mail_imap_cmd_get_acl) + { + p1 = esp_mail_cb_str_36; /* "Get the ACL..." */ + p2 = esp_mail_dbg_str_77; /* "get the ACL" */ + } + else if (type == esp_mail_imap_cmd_set_acl) + { + p1 = esp_mail_cb_str_37; /* "Setting the ACL..." */ + p2 = esp_mail_dbg_str_78; /* "set the ACL" */ + } + else if (type == esp_mail_imap_cmd_delete_acl) + { + p1 = esp_mail_cb_str_38; /* "Deleting the ACL..." */ + p2 = esp_mail_dbg_str_72; /* "delete the ACL" */ + } + else if (type == esp_mail_imap_cmd_my_rights) + { + p1 = esp_mail_cb_str_39; /* "Get my ACL..." */ + p2 = esp_mail_dbg_str_23; /* "get my ACL" */ + } + + MailClient.printDebug(this, p1, p2, esp_mail_debug_tag_type_client, true, false); + +#endif + + if (!MailClient.sessionExisted(this)) + return false; + + if (!_feature_capability[esp_mail_imap_read_capability_acl]) + { +#if !defined(SILENT_MODE) + printDebugNotSupported(); +#endif + return false; + } + + MB_String _mailbox = mailbox; + MB_String _identifier = identifier; + + MB_String cmd; + if (type == esp_mail_imap_cmd_get_acl) + { + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_get_acl].text); + MailClient.appendString(cmd, _mailbox.c_str(), false, false, esp_mail_string_mark_type_double_quote); + } + else if (type == esp_mail_imap_cmd_set_acl) + { + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_set_acl].text); + MailClient.appendString(cmd, MB_String(mailbox).c_str(), false, false, esp_mail_string_mark_type_double_quote); + MailClient.appendSpace(cmd); + MailClient.appendString(cmd, acl->identifier.c_str(), false, false, esp_mail_string_mark_type_double_quote); + MailClient.appendSpace(cmd); + MB_String rights; + getRights(rights, acl); + MailClient.appendString(cmd, rights.c_str(), false, false, esp_mail_string_mark_type_double_quote); + } + else if (type == esp_mail_imap_cmd_delete_acl) + { + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_delete_acl].text); + MailClient.appendString(cmd, _mailbox.c_str(), false, false, esp_mail_string_mark_type_double_quote); + MailClient.appendSpace(cmd); + MailClient.appendString(cmd, _identifier.c_str(), false, false, esp_mail_string_mark_type_double_quote); + } + else if (type == esp_mail_imap_cmd_my_rights) + { + MailClient.appendSpace(cmd, true, imap_commands[esp_mail_imap_command_myrights].text); + MailClient.appendString(cmd, _mailbox.c_str(), false, false, esp_mail_string_mark_type_double_quote); + } + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _acl_tmp.clear(); + + _imap_cmd = type; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + if (type == esp_mail_imap_cmd_get_acl) + parseACL(_acl_tmp, acl_list); + else if (type == esp_mail_imap_cmd_my_rights) + parseRights(_acl_tmp, acl); + + _acl_tmp.clear(); + + return true; +} + +void IMAPSession::parseACL(MB_String &acl_str, IMAP_Rights_List *right_list) +{ + _vectorImpl tokens; + MailClient.splitToken(acl_str.c_str(), tokens, " "); + + for (size_t i = 0; i < tokens.size(); i += 2) + { + IMAP_Rights_Info info; + info.identifier = tokens[i]; + parseRights(tokens[i + 1], &info); + right_list->add(info); + } +} + +void IMAPSession::parseRights(MB_String &righs_str, IMAP_Rights_Info *info) +{ + for (size_t i = 0; i < righs_str.length(); i++) + { + uint8_t c = righs_str[i] - 97; + if (c >= esp_mail_imap_rights_administer && c < esp_mail_imap_rights_maxType) + info->rights[c] = true; + } +} + +void IMAPSession::getRights(MB_String &righs_str, IMAP_Rights_Info *info) +{ + for (size_t i = esp_mail_imap_rights_administer; i < esp_mail_imap_rights_maxType; i++) + { + if (info->rights[i]) + righs_str += (char)(i + 97); + } +} + +bool IMAPSession::mNamespace(IMAP_Namespaces_List *ns) +{ + +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_40 /* "Get namespace..." */, + esp_mail_dbg_str_67 /* "send IMAP command, NAMESPACE" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (!MailClient.sessionExisted(this)) + return false; + + if (!_feature_capability[esp_mail_imap_read_capability_namespace]) + { +#if !defined(SILENT_MODE) + printDebugNotSupported(); +#endif + return false; + } + + if (MailClient.imapSend(this, prependTag(imap_commands[esp_mail_imap_command_namespace].text).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _ns_tmp.clear(); + + _imap_cmd = esp_mail_imap_cmd_namespace; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + int cnt = 0; + MB_String personal, other, shared; + + for (size_t i = 0; i < _ns_tmp.length(); i++) + { + if (i > 0 && i < _ns_tmp.length() - 1 && _ns_tmp[i] == ' ' && _ns_tmp[i - 1] != '"' && _ns_tmp[i + 1] != '"') + { + if (cnt == 0) + personal = _ns_tmp.substr(0, i); + else if (cnt == 1) + { + other = _ns_tmp.substr(personal.length() + 1, i - personal.length() - 1); + shared = _ns_tmp.substr(i + 1, _ns_tmp.length() - i - 1); + } + cnt++; + } + } + + if (personal.length() > 4) + parseNamespaces(personal, &(ns->personal_namespaces)); + + if (other.length() > 4) + parseNamespaces(other, &(ns->other_users_namespaces)); + + if (shared.length() > 4) + parseNamespaces(shared, &(ns->shared_namespaces)); + + return true; +} + +bool IMAPSession::mEnable(MB_StringPtr capability) +{ + +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_41 /* "Enable capability..." */, + esp_mail_dbg_str_68 /* "send IMAP command, ENABLE" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + if (!_feature_capability[esp_mail_imap_read_capability_enable]) + { +#if !defined(SILENT_MODE) + printDebugNotSupported(); +#endif + return false; + } + + MB_String _cap = capability; + + MB_String cmd; + MailClient.joinStringSpace(cmd, true, 2, imap_commands[esp_mail_imap_command_enable].text, _cap.c_str()); + + if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + _imap_cmd = esp_mail_imap_cmd_enable; + if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) + return false; + + return true; +} + +void IMAPSession::parseNamespaces(MB_String &ns_str, IMAP_Namespaces *ns) +{ + MB_String tmp = ns_str.substr(2, ns_str.length() - 4); + tmp.replaceAll(")(", " "); + _vectorImpl tokens; + MailClient.splitToken(tmp.c_str(), tokens, " "); + + for (size_t i = 0; i < tokens.size(); i += 2) + { + IMAP_Namespace_Info info; + info.prefix = tokens[i]; + info.delimiter = tokens[i + 1]; + ns->add(info); + } +} + +void IMAPSession::empty() +{ + _nextUID.clear(); + _unseenMsgIndex.clear(); + _flags_tmp.clear(); + _quota_tmp.clear(); + _quota_root_tmp.clear(); + _acl_tmp.clear(); + _ns_tmp.clear(); + _server_id_tmp.clear(); + _sdFileList.clear(); + clearMessageData(); +} + +IMAP_Status IMAPSession::status() +{ + return _cbData; +} + +String IMAPSession::fileList() +{ + return _sdFileList.c_str(); +} + +void IMAPSession::clearMessageData() +{ + for (size_t i = 0; i < _headers.size(); i++) + { + _headers[i].part_headers.clear(); + } + + _headers.clear(); + _imap_msg_num.clear(); + _mbif._searchCount = 0; + _flags_tmp.clear(); + +#if defined(MB_USE_STD_VECTOR) + _folders.clear(); + _mbif._flags.clear(); +#endif +} + +void IMAPSession::printDebugNotSupported() +{ + +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_error_imap_str_13 /* "not supported by IMAP server" */, + esp_mail_error_imap_str_13 /* "not supported by IMAP server" */, + esp_mail_debug_tag_type_error, + true, + false); +#endif +} + +IMAP_Status::IMAP_Status() +{ +} + +IMAP_Status::~IMAP_Status() +{ + empty(); +} + +const char *IMAP_Status::info() +{ + return _info.c_str(); +} + +bool IMAP_Status::success() +{ + return _success; +} + +void IMAP_Status::empty() +{ + _info.clear(); +} + +#endif + +#endif /* ESP_MAIL_IMAP_H */ \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_SMTP.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_SMTP.h new file mode 100644 index 000000000..8371e95ca --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_SMTP.h @@ -0,0 +1,3631 @@ + +#ifndef ESP_MAIL_SMTP_H +#define ESP_MAIL_SMTP_H + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +/** + * Mail Client Arduino Library for Espressif's ESP32 and ESP8266, Raspberry Pi RP2040 Pico, and SAMD21 with u-blox NINA-W102 WiFi/Bluetooth module + * + * Created August 28, 2023 + * + * This library allows Espressif's ESP32, ESP8266, SAMD and RP2040 Pico devices to send and read Email through the SMTP and IMAP servers. + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "ESP_Mail_Client_Version.h" +#include "ESP_Mail_Client.h" + +#if defined(ENABLE_SMTP) + +void ESP_Mail_Client::mimeFromFile(const char *name, MB_String &mime) +{ + MB_String ext = name; + size_t p = ext.find_last_of("."); + if (p != MB_String::npos) + { + ext = ext.substr(p, ext.length() - p); + if (ext.length() > 0) + getMIME(ext.c_str(), mime); + } +} + +void ESP_Mail_Client::getMIME(const char *ext, MB_String &mime) +{ + mime.clear(); + for (int i = 0; i < esp_mail_file_extension_maxType; i++) + { + if (strcmp_P(ext, mimeinfo[i].endsWith) == 0) + { + mime = mimeinfo[i].mimeType; + break; + } + } +} + +bool ESP_Mail_Client::smtpAuth(SMTPSession *smtp, bool &ssl) +{ + if (!smtp) + return false; + + smtp->_auth_capability[esp_mail_auth_capability_login] = false; + + smtp->_session_cfg->int_start_tls = smtp->_session_cfg->secure.startTLS; + smtp->_session_cfg->int_mode = smtp->_session_cfg->secure.mode; + +#if !defined(ESP_MAIL_DISABLE_SSL) +initial_stage: +#endif + +// Sending greeting helo response +#if !defined(SILENT_MODE) + printDebug(smtp, + esp_mail_cb_str_3 /* "Sending greeting response..." */, + esp_mail_dbg_str_5 /* "send SMTP command, EHLO" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + // The Extended HELLO (EHLO) and HELLO (HELO) commands are used to identify Client (ourself) + + // Since we support ESMTP (rfc5321), let server knows by sending EHLO first + + // If server was not support ESMTP (rfc5321) the failure 501, 500, 502, or 550 would be replied. + + // To prevent connection rejection, EHLO/HELO command parameter should be primary host name (domain name) of client system. + // Otherwise client public IP address string (IPv4 or IPv6) can be assign when no host name is available + + MB_String s = smtp_cmd_post_tokens[esp_mail_smtp_command_ehlo]; + appendDomain(s, smtp->_session_cfg->login.user_domain.c_str()); + + if (smtpSend(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + // expected success status code 250 + // expected error status code 500, 501, 504, 421 + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_greeting, esp_mail_smtp_status_code_250, 0)) + { + +#if !defined(SILENT_MODE) + if (smtp->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_17 /* "No ESMTP supported, send SMTP command, HELO" */, esp_mail_debug_tag_type_client, true); +#endif + // In case EHLO (rfc5321) is not acceptable, + // send HELO command (rfc821) instead. + s = smtp_cmd_post_tokens[esp_mail_smtp_command_helo]; + appendDomain(s, smtp->_session_cfg->login.user_domain.c_str()); + + if (!smtpSend(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + // expected success status code 250 + // expected error status code 500, 501, 504, 421 + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_greeting, esp_mail_smtp_status_code_250, SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED)) + return false; + + smtp->_feature_capability[esp_mail_smtp_send_capability_esmtp] = false; + smtp->_auth_capability[esp_mail_auth_capability_login] = true; + } + else + smtp->_feature_capability[esp_mail_smtp_send_capability_esmtp] = true; + +#if !defined(ESP_MAIL_DISABLE_SSL) + + if (smtp->_session_cfg->int_mode != esp_mail_secure_mode_nonsecure) + { + // start TLS when needed + // rfc3207 + if ((smtp->_auth_capability[esp_mail_auth_capability_starttls] || smtp->_session_cfg->int_start_tls || smtp->_session_cfg->int_mode == esp_mail_secure_mode_ssl_tls) && !ssl) + { +// send starttls command +#if !defined(SILENT_MODE) + printDebug(smtp, + esp_mail_cb_str_2 /* "Sending STARTTLS command..." */, + esp_mail_dbg_str_1 /* "send command, STARTTLS" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + // expected success status code 250 for complete the request + // some server returns 220 to restart to initial state + + // expected error status code 500, 501, 504, 421 + smtpSend(smtp, smtp_commands[esp_mail_smtp_command_starttls].text, true); + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_start_tls, esp_mail_smtp_status_code_250, SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED)) + return false; + +#if !defined(SILENT_MODE) + if (smtp->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_22 /* "perform SSL/TLS handshake" */, esp_mail_debug_tag_type_client, true); +#endif + + // connect in secure mode + // do TLS handshake + if (!smtp->client.connectSSL(smtp->_session_cfg->certificate.verify)) + return handleSMTPError(smtp, MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP); + + // set the secure mode + smtp->_session_cfg->int_start_tls = false; + smtp->_session_cfg->int_mode = esp_mail_secure_mode_undefined; + ssl = true; + smtp->_secure = true; + + // return to initial stage if the response status is 220. + if (smtp->_responseStatus.statusCode == esp_mail_smtp_status_code_220) + goto initial_stage; + } + } + +#endif + + bool creds = smtp->_session_cfg->login.email.length() > 0 && smtp->_session_cfg->login.password.length() > 0; + bool sasl_auth_oauth = smtp->_session_cfg->login.accessToken.length() > 0 && smtp->_auth_capability[esp_mail_auth_capability_xoauth2]; + bool sasl_login = smtp->_auth_capability[esp_mail_auth_capability_login] && creds; + bool sasl_auth_plain = smtp->_auth_capability[esp_mail_auth_capability_plain] && creds; + + if (sasl_auth_oauth || sasl_login || sasl_auth_plain) + { +#if !defined(SILENT_MODE) + if (smtp->_statusCallback) + sendCB(smtp, esp_mail_cb_str_14 /* "Logging in..." */, true, false); +#endif + + // log in + if (sasl_auth_oauth) + { +#if !defined(SILENT_MODE) + if (smtp->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_15 /* "send smtp command, AUTH XOAUTH2" */, esp_mail_debug_tag_type_client, true); +#endif + if (!smtp->_auth_capability[esp_mail_auth_capability_xoauth2]) + return handleSMTPError(smtp, SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED, false); + + MB_String cmd = smtp_cmd_post_tokens[esp_mail_smtp_command_auth]; + cmd += smtp_auth_cap_post_tokens[esp_mail_auth_capability_xoauth2]; + + if (smtpSend(smtp, cmd.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (smtpSend(smtp, getXOAUTH2String(smtp->_session_cfg->login.email, smtp->_session_cfg->login.accessToken).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_auth_xoauth2, esp_mail_smtp_status_code_235, SMTP_STATUS_AUTHEN_FAILED)) + return false; + } + else if (sasl_auth_plain) + { +#if !defined(SILENT_MODE) + if (smtp->_debug) + { + esp_mail_debug_print_tag(esp_mail_dbg_str_7 /* "send SMTP command, AUTH PLAIN" */, esp_mail_debug_tag_type_client, true); + esp_mail_debug_print_tag(smtp->_session_cfg->login.email.c_str(), esp_mail_debug_tag_type_client, true); + MB_String mask; + maskString(mask, smtp->_session_cfg->login.password.length()); + esp_mail_debug_print_tag(mask.c_str(), esp_mail_debug_tag_type_client, true); + } +#endif + // rfc4616 + int len = smtp->_session_cfg->login.email.length() + smtp->_session_cfg->login.password.length() + 2; + uint8_t *tmp = allocMem(len); + memset(tmp, 0, len); + int p = 1; + memcpy(tmp + p, smtp->_session_cfg->login.email.c_str(), smtp->_session_cfg->login.email.length()); + p += smtp->_session_cfg->login.email.length() + 1; + memcpy(tmp + p, smtp->_session_cfg->login.password.c_str(), smtp->_session_cfg->login.password.length()); + p += smtp->_session_cfg->login.password.length(); + + MB_String cmd = smtp_cmd_post_tokens[esp_mail_smtp_command_auth]; + cmd += smtp_cmd_post_tokens[esp_mail_smtp_command_plain]; + cmd += encodeBase64Str(tmp, p); + // release memory + freeMem(&tmp); + + if (smtpSend(smtp, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_auth_plain, esp_mail_smtp_status_code_235, SMTP_STATUS_USER_LOGIN_FAILED)) + return false; + } + else if (sasl_login) + { +#if !defined(SILENT_MODE) + if (smtp->_debug) + esp_mail_debug_print_tag(esp_mail_dbg_str_6 /* "send SMTP command, AUTH LOGIN" */, esp_mail_debug_tag_type_client, true); +#endif + MB_String cmd = smtp_cmd_post_tokens[esp_mail_smtp_command_auth]; + cmd += smtp_commands[esp_mail_smtp_command_login].text; + + if (smtpSend(smtp, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + // expected server challenge response + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_auth_login, esp_mail_smtp_status_code_334, SMTP_STATUS_AUTHEN_FAILED)) + return false; + +#if !defined(SILENT_MODE) + if (smtp->_debug) + esp_mail_debug_print_tag(smtp->_session_cfg->login.email.c_str(), esp_mail_debug_tag_type_client, true); +#endif + if (smtpSend(smtp, encodeBase64Str((const unsigned char *)smtp->_session_cfg->login.email.c_str(), smtp->_session_cfg->login.email.length()).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + // expected server challenge response + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_login_user, esp_mail_smtp_status_code_334, SMTP_STATUS_USER_LOGIN_FAILED)) + return false; + +#if !defined(SILENT_MODE) + if (smtp->_debug) + { + MB_String mask; + maskString(mask, smtp->_session_cfg->login.password.length()); + esp_mail_debug_print_tag(mask.c_str(), esp_mail_debug_tag_type_client, true); + } +#endif + if (smtpSend(smtp, encodeBase64Str((const unsigned char *)smtp->_session_cfg->login.password.c_str(), smtp->_session_cfg->login.password.length()).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_login_psw, esp_mail_smtp_status_code_235, SMTP_STATUS_PASSWORD_LOGIN_FAILED)) + return false; + } + + smtp->_authenticated = true; + } + + return true; +} + +bool ESP_Mail_Client::addSendingResult(SMTPSession *smtp, SMTP_Message *msg, bool result, bool showResult) +{ + if (!smtp) + return false; + + if (result) + smtp->_sentSuccessCount++; + else + smtp->_sentFailedCount++; + + if (smtp->_session_cfg->sentLogs.filename.length() > 0 && smtp->_session_cfg->sentLogs.storage_type != esp_mail_file_storage_type_none) + saveSendingLogs(smtp, msg, result); + + // Store only tatest result + smtp->sendingResult.clear(); + + SMTP_Result status; + status.completed = result; + status.timestamp = smtp->ts; + status.subject = msg->subject.c_str(); + + if (msg->timestamp.tag.length() && msg->timestamp.format.length()) + status.subject.replaceAll(msg->timestamp.tag, Time.getDateTimeString(Time.getCurrentTimestamp(), msg->timestamp.format.c_str())); + + status.recipients = msg->_rcp[0].email.c_str(); + smtp->sendingResult.add(&status); + + smtp->_cbData._sentSuccess = smtp->_sentSuccessCount; + smtp->_cbData._sentFailed = smtp->_sentFailedCount; + +#if !defined(SILENT_MODE) + if (smtp->_statusCallback) + { + if (showResult) + { + int bufLen = 512; + char *buf = allocMem(bufLen); + time_t ts = (time_t)smtp->ts; + MB_String sep; + for (int i = 0; i < 25; i++) + sep += '-'; + + sendCallback(smtp, sep.c_str(), true, false); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_93 /* "Message sent success: %d" */), smtp->_sentSuccessCount); + sendCallback(smtp, buf, false, false); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_94 /* "Message sent failed: %d" */), smtp->_sentFailedCount); + sendCallback(smtp, buf, false, false); + sendCallback(smtp, sep.c_str(), false, false); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_95 /* "Status: %s" */), result ? pgm2Str(esp_mail_str_98 /* "success" */) : pgm2Str(esp_mail_str_99 /* "failed" */)); + sendCallback(smtp, buf, false, false); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_96 /* "Date/Time: %s" */), Time.getDateTimeString(ts, "%B %d, %Y %H:%M:%S").c_str()); + sendCallback(smtp, buf, false, false); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_97 /* "Recipient: %s" */), msg->_rcp[0].email.c_str()); + sendCallback(smtp, buf, false, false); + snprintf(buf, bufLen, pgm2Str(esp_mail_str_92 /* "Subject: %s" */), msg->subject.c_str()); + sendCallback(smtp, buf, false, false); + freeMem(&buf); + } + } +#endif + + return result; +} + +void ESP_Mail_Client::saveSendingLogs(SMTPSession *smtp, SMTP_Message *msg, bool result) +{ + if (!smtp->_session_cfg || smtp->_session_cfg->sentLogs.filename.length() == 0 || smtp->_session_cfg->sentLogs.storage_type == esp_mail_file_storage_type_none) + return; + + int sz = mbfs->open(smtp->_session_cfg->sentLogs.filename.c_str(), mbfs_type smtp->_session_cfg->sentLogs.storage_type, mb_fs_open_mode_append); + if (sz < 0) + return; + + MB_String cm = esp_mail_str_8; /* "," */ + mbfs->print(mbfs_type smtp->_session_cfg->sentLogs.storage_type, (int)result); + mbfs->print(mbfs_type smtp->_session_cfg->sentLogs.storage_type, cm.c_str()); + mbfs->print(mbfs_type smtp->_session_cfg->sentLogs.storage_type, (int)smtp->ts); + mbfs->print(mbfs_type smtp->_session_cfg->sentLogs.storage_type, cm.c_str()); + mbfs->print(mbfs_type smtp->_session_cfg->sentLogs.storage_type, msg->_rcp[0].email.c_str()); + mbfs->print(mbfs_type smtp->_session_cfg->sentLogs.storage_type, cm.c_str()); + mbfs->println(mbfs_type smtp->_session_cfg->sentLogs.storage_type, msg->subject.c_str()); + mbfs->close(mbfs_type smtp->_session_cfg->sentLogs.storage_type); +} + +bool ESP_Mail_Client::sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession) +{ + if (!smtp || !sessionExisted(smtp)) + return false; + + smtp->_customCmdResCallback = NULL; + + return mSendMail(smtp, msg, closeSession); +} + +size_t ESP_Mail_Client::numAtt(SMTPSession *smtp, esp_mail_attach_type type, SMTP_Message *msg) +{ + size_t count = 0; + for (size_t i = 0; i < msg->_att.size(); i++) + { + if (msg->_att[i]._int.att_type == type) + count++; + } + return count; +} + +bool ESP_Mail_Client::checkEmail(SMTPSession *smtp, SMTP_Message *msg) +{ + bool validRecipient = false; + + if (!validEmail(msg->sender.email.c_str())) + { + errorStatusCB(smtp, this->imap, SMTP_STATUS_NO_VALID_SENDER_EXISTED, false); + return addSendingResult(smtp, msg, false, true); + } + + for (uint8_t i = 0; i < msg->_rcp.size(); i++) + { + if (validEmail(msg->_rcp[i].email.c_str())) + validRecipient = true; + } + + if (!validRecipient) + { + errorStatusCB(smtp, this->imap, SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED, false); + return addSendingResult(smtp, msg, false, true); + } + + return true; +} + +bool ESP_Mail_Client::mSendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession) +{ + if (!smtp) + return false; + + smtp->_responseStatus.errorCode = 0; + smtp->_responseStatus.statusCode = 0; + smtp->_responseStatus.text.clear(); + smtp->_cbData._success = false; + bool rfc822MSG = false; + + if (!checkEmail(smtp, msg)) + return false; + + smtp->_chunkedEnable = false; + smtp->_chunkCount = 0; + + if (!smtp->connected() && !smtp->_loginStatus) + { +#if !defined(SILENT_MODE) + if (smtp->_debug && smtp->_statusCallback && !smtp->_customCmdResCallback) + { + esp_mail_debug_print(); + errorStatusCB(smtp, this->imap, MAIL_CLIENT_ERROR_NOT_YET_LOGIN, false); + } +#endif + return false; + } + + // new session + if (!smtp->connected()) + { + bool ssl = false; + + if (!smtp->connect(ssl)) + { + closeTCPSession(smtp); + return addSendingResult(smtp, msg, false, true); + } + + if (!smtpAuth(smtp, ssl)) + { + closeTCPSession(smtp); + return addSendingResult(smtp, msg, false, true); + } + smtp->_sentSuccessCount = 0; + smtp->_sentFailedCount = 0; + smtp->sendingResult.clear(); + } + else + { + // If time config changed, we will update time + MailClient.prepareTime(smtp->_session_cfg, smtp); + // reuse session +#if !defined(SILENT_MODE) + PGM_P p1 = smtp->_sentSuccessCount || smtp->_sentFailedCount ? esp_mail_cb_str_10 /* "Sending next Email..." */ : esp_mail_cb_str_9 /* "Sending Email..." */; + PGM_P p2 = smtp->_sentSuccessCount || smtp->_sentFailedCount ? esp_mail_dbg_str_13 /* "send next Email" */ : esp_mail_dbg_str_3 /* "send Email" */; + + printDebug(smtp, + p1, + p2, + esp_mail_debug_tag_type_client, + true, + false); +#endif + } + +#if !defined(SILENT_MODE) + printDebug(smtp, + esp_mail_cb_str_4 /* "Sending message header..." */, + esp_mail_dbg_str_8 /* "send message header" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + imap = nullptr; + calDataLen = false; + dataLen = 0; + + return sendContent(smtp, msg, closeSession, rfc822MSG); +} + +bool ESP_Mail_Client::sendContent(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG) +{ + + if (msg->html.content.length() > 0 || strlen(msg->html.nonCopyContent) > 0 || msg->html.blob.size > 0 || msg->html.file.name.length() > 0) + msg->type |= esp_mail_msg_type_html; + + if (msg->text.content.length() > 0 || strlen(msg->text.nonCopyContent) > 0 || msg->text.blob.size > 0 || msg->text.file.name.length() > 0) + msg->type |= esp_mail_msg_type_plain; + + for (size_t i = 0; i < msg->_rfc822.size(); i++) + { + if (msg->_rfc822[i].html.content.length() > 0) + msg->_rfc822[i].type |= esp_mail_msg_type_html; + + if (msg->_rfc822[i].text.content.length() > 0) + msg->_rfc822[i].type |= esp_mail_msg_type_plain; + } + + MB_String buf; + MB_String buf2; + checkUnencodedData(smtp, msg); + + if (msg->priority >= esp_mail_smtp_priority_high && msg->priority <= esp_mail_smtp_priority_low) + { + appendHeaderField(buf2, message_headers[esp_mail_message_header_field_x_priority].text, MB_String(msg->priority).c_str(), false, true); + + PGM_P p = nullptr; + if (msg->priority == esp_mail_smtp_priority_high) + p = esp_mail_str_4; /* "High" */ + else if (msg->priority == esp_mail_smtp_priority_normal) + p = esp_mail_str_5; /* "Normal" */ + else if (msg->priority == esp_mail_smtp_priority_low) + p = esp_mail_str_6; /* "Low" */ + + if (p) + { + appendHeaderField(buf2, message_headers[esp_mail_message_header_field_x_msmail_priority].text, p, false, true); + appendHeaderField(buf2, message_headers[esp_mail_message_header_field_importance].text, p, false, true); + } + } + + // If author and transmitter (sender or agent) are not identical, send both 'From' and 'Sender' headers + if (msg->sender.email.length() > 0 && msg->author.email.length() > 0 && + strcmp(msg->sender.email.c_str(), msg->author.email.c_str()) != 0) + { + appendAddressHeaderField(buf2, msg->author, esp_mail_rfc822_header_field_from, true, false, true); + appendAddressHeaderField(buf2, msg->sender, esp_mail_rfc822_header_field_sender, true, false, true); + } + // If author and transmitter (agent) are identical, send only 'From' header + else if (msg->sender.email.length() > 0) + appendAddressHeaderField(buf2, msg->sender, esp_mail_rfc822_header_field_from, true, false, true); + + if (!imap && smtp) + { + + buf = smtp_cmd_post_tokens[esp_mail_smtp_command_mail]; + buf += smtp_commands[esp_mail_smtp_command_from].text; + + appendString(buf, msg->author.email.length() ? msg->author.email.c_str() : msg->sender.email.c_str(), false, false, esp_mail_string_mark_type_angle_bracket); + + if (msg->text._int.xencoding == esp_mail_msg_xencoding_binary || msg->html._int.xencoding == esp_mail_msg_xencoding_binary) + { + if (smtp->_feature_capability[esp_mail_smtp_send_capability_binary_mime] || (smtp->_feature_capability[esp_mail_smtp_send_capability_chunking] && msg->enable.chunking)) + { + buf += smtp_cmd_pre_tokens[esp_mail_smtp_command_body]; + buf += esp_mail_str_7; /* "=" */ + buf += smtp_send_capabilities[esp_mail_smtp_send_capability_binary_mime].text; + } + } + else if (msg->text._int.xencoding == esp_mail_msg_xencoding_8bit || msg->html._int.xencoding == esp_mail_msg_xencoding_8bit) + { + if (smtp->_feature_capability[esp_mail_smtp_send_capability_8bit_mime]) + { + buf += smtp_cmd_pre_tokens[esp_mail_smtp_command_body]; + buf += esp_mail_str_7; /* "=" */ + buf += smtp_send_capabilities[esp_mail_smtp_send_capability_8bit_mime].text; + } + } + + // expected success status code 250 + // expected failure status code 552, 451, 452 + // expected error status code 500, 501, 421 + if (!altSendData(buf, true, smtp, msg, true, true, esp_mail_smtp_cmd_send_header_sender, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_SENDER_FAILED)) + return false; + } + + // Construct 'To' header fields. + + for (uint8_t i = 0; i < msg->_rcp.size(); i++) + { + appendAddressHeaderField(buf2, msg->_rcp[i], esp_mail_rfc822_header_field_to, i == 0, i > 0, i == msg->_rcp.size() - 1); + if (!imap && smtp) + { + // only address + buf = smtp_cmd_post_tokens[esp_mail_smtp_command_rcpt]; + buf += smtp_commands[esp_mail_smtp_command_to].text; + appendString(buf, msg->_rcp[i].email.c_str(), false, false, esp_mail_string_mark_type_angle_bracket); + + // rfc3461, rfc3464 + if (smtp->_feature_capability[esp_mail_smtp_send_capability_dsn]) + { + if (msg->response.notify != esp_mail_smtp_notify_never) + { + buf += smtp_cmd_pre_tokens[esp_mail_smtp_command_notify]; + buf += esp_mail_str_7; /* "=" */ + + MB_String notify; + + if ((msg->response.notify & esp_mail_smtp_notify_success) == esp_mail_smtp_notify_success) + notify = smtp_commands[esp_mail_smtp_command_success].text; + + if (notify.length()) + notify += esp_mail_str_8; /* "," */ + + if ((msg->response.notify & esp_mail_smtp_notify_failure) == esp_mail_smtp_notify_failure) + notify += smtp_commands[esp_mail_smtp_command_failure].text; + + if (notify.length()) + notify += esp_mail_str_8; /* "," */ + + if ((msg->response.notify & esp_mail_smtp_notify_delay) == esp_mail_smtp_notify_delay) + notify += smtp_commands[esp_mail_smtp_command_delay].text; + + buf += notify; + } + } + + smtp->_canForward = true; + + // expected success status code 250, 251 + // expected failure status code 550, 551, 552, 553, 450, 451, 452 + // expected error status code 500, 501, 503, 421 + if (!altSendData(buf, true, smtp, msg, true, true, esp_mail_smtp_cmd_send_header_recipient, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) + return false; + } + } + + // Construct 'Cc' header field. + for (uint8_t i = 0; i < msg->_cc.size(); i++) + { + appendAddressHeaderField(buf2, msg->_cc[i], esp_mail_rfc822_header_field_cc, i == 0, i > 0, i == msg->_cc.size() - 1); + if (!imap) + { + // only address + buf = smtp_cmd_post_tokens[esp_mail_smtp_command_rcpt]; + buf += smtp_commands[esp_mail_smtp_command_to].text; + appendString(buf, msg->_cc[i].email.c_str(), false, false, esp_mail_string_mark_type_angle_bracket); + + smtp->_canForward = true; + + // expected success status code 250, 251 + // expected failure status code 550, 551, 552, 553, 450, 451, 452 + // expected error status code 500, 501, 503, 421 + if (!altSendData(buf, true, smtp, msg, true, true, esp_mail_smtp_cmd_send_header_recipient, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) + return false; + } + } + + if (!imap && smtp) + { + for (uint8_t i = 0; i < msg->_bcc.size(); i++) + { + // only address + buf = smtp_cmd_post_tokens[esp_mail_smtp_command_rcpt]; + buf += smtp_commands[esp_mail_smtp_command_to].text; + appendString(buf, msg->_bcc[i].email.c_str(), false, false, esp_mail_string_mark_type_angle_bracket); + + smtp->_canForward = true; + + // expected success status code 250, 251 + // expected failure status code 550, 551, 552, 553, 450, 451, 452 + // expected error status code 500, 501, 503, 421 + if (!altSendData(buf, true, smtp, msg, true, true, esp_mail_smtp_cmd_send_header_recipient, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) + return false; + } + +#if !defined(SILENT_MODE) + altSendCallback(smtp, esp_mail_cb_str_5 /* "Sending message body..." */, esp_mail_dbg_str_9 /* "send message body" */, esp_mail_debug_tag_type_client, true, false); +#endif + if (smtp->_feature_capability[esp_mail_smtp_send_capability_chunking] && msg->enable.chunking) + { + smtp->_chunkedEnable = true; + if (!sendBDAT(smtp, msg, buf2.length(), false)) + return false; + } + else + { + // expected success status code 354 + // expected failure status code 451, 554 + // expected error status code 500, 501, 503, 421 + MB_String sdata = smtp_commands[esp_mail_smtp_command_data].text; + if (!altSendData(sdata, true, smtp, msg, true, true, esp_mail_smtp_cmd_send_body, esp_mail_smtp_status_code_354, SMTP_STATUS_SEND_BODY_FAILED)) + return false; + } + } + +#if defined(ENABLE_IMAP) && !defined(SILENT_MODE) + if (imap) + altSendCallback(smtp, esp_mail_cb_str_14 /* "Appending message..." */, esp_mail_dbg_str_69 /* "appending message" */, esp_mail_debug_tag_type_client, true, false); + +#endif + + if (!altSendData(buf2, false, smtp, msg, true, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + MB_String s; + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_subject].text, msg->subject.c_str(), false, true); + + if (msg->timestamp.tag.length() && msg->timestamp.format.length()) + s.replaceAll(msg->timestamp.tag, Time.getDateTimeString(Time.getCurrentTimestamp(), msg->timestamp.format.c_str())); + + // Construct the 'Date' header field. + // The 'Date' header field should be valid and should be included in the message headers to + // prevent the 'spam' or 'junk' message considered by mail server. + + bool dateHdr = false; + MB_String dt; + + uint32_t ts = 0; + + if (smtp) + smtp->ts = ts; + + // Check if valid 'Date' field assigned from custom headers. + if (msg->_hdr.size() > 0) + { + for (uint8_t k = 0; k < msg->_hdr.size(); k++) + { + appendString(s, msg->_hdr[k].c_str(), false, true); + + if (getHeader(msg->_hdr[k].c_str(), rfc822_headers[esp_mail_rfc822_header_field_date].text, dt, false)) + { + ts = Time.getTimestamp(dt.c_str(), true); + dateHdr = ts > ESP_MAIL_CLIENT_VALID_TS; + if (smtp) + smtp->ts = ts; + } + } + } + + // Check if valid 'Date' field assigned from SMTP_Message's date property. + if (!dateHdr && msg->date.length() > 0) + { + dt = msg->date; + ts = Time.getTimestamp(msg->date.c_str(), true); + dateHdr = ts > ESP_MAIL_CLIENT_VALID_TS; + if (smtp) + smtp->ts = ts; + } + + if (dateHdr) + { + // 'Date' header field assigned. + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_date].text, dt.c_str(), false, true); + } + else + { + // If there is no 'Date' field assigned, get time from system and construct 'Date' header field. + if (smtp) + { + ts = MailClient.Time.getCurrentTimestamp(); + smtp->ts = ts; + } + else if (imap) + { +#if defined(ENABLE_IMAP) + if (calDataLen) + { + ts = MailClient.Time.getCurrentTimestamp(); + imap_ts = ts; + } + else + ts = imap_ts; +#endif + } + + if (ts > ESP_MAIL_CLIENT_VALID_TS) + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_date].text, Time.getDateTimeString().c_str(), false, true); + } + + if (msg->response.reply_to.length() > 0) + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_reply_to].text, msg->response.reply_to.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); + + if (msg->response.return_path.length() > 0) + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_return_path].text, msg->response.return_path.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); + + if (msg->in_reply_to.length() > 0) + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_in_reply_to].text, msg->in_reply_to.c_str(), false, true); + + if (msg->references.length() > 0) + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_references].text, msg->references.c_str(), false, true); + + if (msg->comments.length() > 0) + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_comments].text, msg->comments.c_str(), false, true); + + if (msg->keywords.length() > 0) + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_keywords].text, msg->keywords.c_str(), false, true); + + if (msg->messageID.length() > 0) + appendHeaderField(s, rfc822_headers[esp_mail_rfc822_header_field_msg_id].text, msg->messageID.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); + + appendHeaderField(s, message_headers[esp_mail_message_header_field_mime_version].text, esp_mail_str_51 /* "1.0" */, false, true); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, true, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + return sendMSGData(smtp, msg, closeSession, rfc822MSG); +} + +void ESP_Mail_Client::altSendCallback(SMTPSession *smtp, PGM_P cbMsg, PGM_P dbMsg, esp_mail_debug_tag_type type, bool prependCRLF, bool success) +{ +#if !defined(SILENT_MODE) + if (smtp) + printDebug(smtp, cbMsg, dbMsg, type, prependCRLF, success); + else if (imap && !calDataLen) + { +#if defined(ENABLE_IMAP) + printDebug(imap, cbMsg, dbMsg, type, prependCRLF, success); +#endif + } +#endif +} + +bool ESP_Mail_Client::sendMSGData(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG) +{ + MB_String s; + MB_String mixed = getMIMEBoundary(15); + MB_String alt = getMIMEBoundary(15); + + if (numAtt(smtp, esp_mail_att_type_attachment, msg) == 0 && msg->_parallel.size() == 0 && msg->_rfc822.size() == 0) + { + if (msg->type == (esp_mail_msg_type_plain | esp_mail_msg_type_html | esp_mail_msg_type_enriched) || numAtt(smtp, esp_mail_att_type_inline, msg) > 0) + { + if (!sendMSG(smtp, msg, alt)) + return addSendingResult(smtp, msg, false, true); + } + else if (msg->type != esp_mail_msg_type_none) + { + if (!sendPartText(smtp, msg, msg->type, "")) + return addSendingResult(smtp, msg, false, true); + } + } + else + { + s.clear(); + appendMultipartContentType(s, esp_mail_multipart_type_mixed, mixed.c_str()); + appendBoundaryString(s, mixed.c_str(), false, true); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, true, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + if (!sendMSG(smtp, msg, alt)) + return addSendingResult(smtp, msg, false, true); + + if (!sendBDAT(smtp, msg, 2, false)) + return false; + + MB_String str; + appendNewline(str); + + if (!altSendData(str, false, smtp, msg, true, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + +#if !defined(SILENT_MODE) + altSendCallback(smtp, esp_mail_cb_str_6 /* "Sending attachments..." */, esp_mail_dbg_str_10 /* "send attachments" */, esp_mail_debug_tag_type_client, true, false); +#endif + if (!sendAttachments(smtp, msg, mixed)) + return addSendingResult(smtp, msg, false, true); + + if (!sendParallelAttachments(smtp, msg, mixed)) + return addSendingResult(smtp, msg, false, true); + + if (!sendRFC822Msg(smtp, msg, mixed, closeSession, msg->_rfc822.size() > 0)) + return addSendingResult(smtp, msg, false, true); + + s.clear(); + appendBoundaryString(s, mixed.c_str(), true, false); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, true, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + } + + if (!rfc822MSG && !imap && smtp) + { +#if !defined(SILENT_MODE) + altSendCallback(smtp, esp_mail_cb_str_11 /* "Finishing the message sending..." */, esp_mail_dbg_str_16 /* "finishing the message sending" */, esp_mail_debug_tag_type_client, true, false); +#endif + if (smtp->_chunkedEnable) + { + + if (!sendBDAT(smtp, msg, 0, true)) + return false; + + // expected success status code 250 + // expected failure status code 451, 554 + // expected error status code 500, 501, 503, 421 + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_chunk_termination, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) + return false; + } + else + { + // expected success status code 250 + // expected failure status code 451, 554 + // expected error status code 500, 501, 503, 421 + MB_String str = smtp_commands[esp_mail_smtp_command_terminate].text; + if (!altSendData(str, false, smtp, msg, true, true, esp_mail_smtp_cmd_send_body, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) + return false; + } + + addSendingResult(smtp, msg, true, !closeSession); + + if (closeSession && smtp) + { + if (!smtp->closeSession()) + return false; + } + } + if (smtp) + smtp->_cbData._success = true; + return true; +} + +bool ESP_Mail_Client::sendRFC822Msg(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, bool closeSession, bool rfc822MSG) +{ + if (msg->_rfc822.size() == 0) + return true; + + MB_String buf; + + for (uint8_t i = 0; i < msg->_rfc822.size(); i++) + { + buf.clear(); + getRFC822PartHeader(smtp, buf, boundary); + + getRFC822MsgEnvelope(smtp, &msg->_rfc822[i], buf); + + if (!sendBDAT(smtp, msg, buf.length(), false)) + return false; + + if (!altSendData(buf, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + if (!sendMSGData(smtp, &msg->_rfc822[i], closeSession, rfc822MSG)) + return false; + } + + return true; +} + +void ESP_Mail_Client::getRFC822MsgEnvelope(SMTPSession *smtp, SMTP_Message *msg, MB_String &buf) +{ + if (msg->date.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_date].text, msg->date.c_str(), false, true); + else + { + time_t now = 0; + if (smtp) + now = MailClient.Time.getCurrentTimestamp(); + else if (imap) + { +#if defined(ENABLE_IMAP) + if (calDataLen) + { + now = MailClient.Time.getCurrentTimestamp(); + imap_ts = now; + } + else + now = imap_ts; +#endif + } + + if (now > ESP_MAIL_CLIENT_VALID_TS) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_date].text, Time.getDateTimeString().c_str(), false, true); + } + + // Construct 'From' header field. + if (msg->from.email.length() > 0) + appendAddressHeaderField(buf, msg->from, esp_mail_rfc822_header_field_from, true, false, true); + + // Construct 'Sender' header field. + if (msg->sender.email.length() > 0) + appendAddressHeaderField(buf, msg->sender, esp_mail_rfc822_header_field_sender, true, false, true); + + if (msg->response.reply_to.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_reply_to].text, msg->response.reply_to.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); + + if (msg->response.return_path.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_return_path].text, msg->response.return_path.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); + + // Construct 'To' header field. + for (uint8_t i = 0; i < msg->_rcp.size(); i++) + appendAddressHeaderField(buf, msg->_rcp[i], esp_mail_rfc822_header_field_to, i == 0, i > 0, i == msg->_rcp.size() - 1); + + for (uint8_t i = 0; i < msg->_cc.size(); i++) + appendAddressHeaderField(buf, msg->_cc[i], esp_mail_rfc822_header_field_cc, i == 0, i > 0, i == msg->_cc.size() - 1); + + for (uint8_t i = 0; i < msg->_bcc.size(); i++) + appendAddressHeaderField(buf, msg->_bcc[i], esp_mail_rfc822_header_field_bcc, i == 0, i > 0, i == msg->_bcc.size() - 1); + + if (msg->subject.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_subject].text, msg->subject.c_str(), false, true); + + if (msg->keywords.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_keywords].text, msg->keywords.c_str(), false, true); + + if (msg->comments.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_comments].text, msg->comments.c_str(), false, true); + + if (msg->in_reply_to.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_in_reply_to].text, msg->in_reply_to.c_str(), false, true); + + if (msg->references.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_references].text, msg->references.c_str(), false, true); + + if (msg->messageID.length() > 0) + appendHeaderField(buf, rfc822_headers[esp_mail_rfc822_header_field_msg_id].text, msg->messageID.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); +} + +void ESP_Mail_Client::appendBoundaryString(MB_String &buf, const char *value, bool endMark, bool newLine) +{ + buf += esp_mail_str_9; /* "--" */ + buf += value; + if (endMark) + buf += esp_mail_str_9; /* "--" */ + if (newLine) + appendNewline(buf); +} + +bool ESP_Mail_Client::sendBDAT(SMTPSession *smtp, SMTP_Message *msg, int len, bool last) +{ + if (!smtp) + return true; + + if (!smtp->_chunkedEnable || !msg->enable.chunking) + return true; + + smtp->_chunkCount++; + + MB_String bdat = smtp_cmd_post_tokens[esp_mail_smtp_command_bdat]; + bdat += len; + if (last) + bdat += smtp_cmd_pre_tokens[esp_mail_smtp_command_last]; + + if (smtpSend(smtp, bdat.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return addSendingResult(smtp, msg, false, true); + + if (!smtp->_feature_capability[esp_mail_smtp_send_capability_pipelining]) + { + // expected success status code 250 + // expected failure status code 451, 554 + // expected error status code 500, 501, 503, 421 + if (!handleSMTPResponse(smtp, esp_mail_smtp_cmd_send_body, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) + return addSendingResult(smtp, msg, false, true); + smtp->_chunkCount = 0; + } + return true; +} + +void ESP_Mail_Client::getXEncoding(esp_mail_msg_xencoding &xencoding, const char *enc) +{ + if (strcmp(enc, Content_Transfer_Encoding::enc_binary) == 0) + xencoding = esp_mail_msg_xencoding_binary; + else if (strcmp(enc, Content_Transfer_Encoding::enc_8bit) == 0) + xencoding = esp_mail_msg_xencoding_8bit; + else if (strcmp(enc, Content_Transfer_Encoding::enc_7bit) == 0) + xencoding = esp_mail_msg_xencoding_7bit; +} + +void ESP_Mail_Client::checkUnencodedData(SMTPSession *smtp, SMTP_Message *msg) +{ + if (msg->type & esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type & esp_mail_msg_type_html) + { + if ((msg->type & esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched) > 0 && msg->text.transfer_encoding.length() > 0) + getXEncoding(msg->text._int.xencoding, msg->text.transfer_encoding.c_str()); + + if ((msg->type & esp_mail_msg_type_html) > 0 && msg->html.transfer_encoding.length() > 0) + getXEncoding(msg->html._int.xencoding, msg->html.transfer_encoding.c_str()); + } + + for (size_t i = 0; i < msg->_att.size(); i++) + getXEncoding(msg->_att[i]._int.xencoding, msg->_att[i].descr.transfer_encoding.c_str()); +} + +bool ESP_Mail_Client::altIsCB(SMTPSession *smtp) +{ + bool cb = false; + if (smtp) + cb = smtp->_statusCallback != NULL; + else if (imap && !calDataLen) + { +#if defined(ENABLE_IMAP) + cb = imap->_statusCallback != NULL; +#endif + } + + return cb; +} + +bool ESP_Mail_Client::altIsDebug(SMTPSession *smtp) +{ + bool dbg = false; + if (smtp) + dbg = smtp->_debug; + else if (imap && !calDataLen) + { +#if defined(ENABLE_IMAP) + dbg = imap->_debug; +#endif + } + + return dbg; +} + +bool ESP_Mail_Client::sendBlobAttachment(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att) +{ + bool cb = altIsCB(smtp); + uint32_t addr = altProgressPtr(smtp); + + if (strcmp(att->descr.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0 && strcmp(att->descr.transfer_encoding.c_str(), att->descr.content_encoding.c_str()) != 0) + { + esp_mail_smtp_send_base64_data_info_t data_info; + + data_info.rawPtr = att->blob.data; + data_info.size = att->blob.size; + data_info.flashMem = att->_int.flash_blob; + data_info.filename = att->descr.filename.c_str(); + + if (!sendBase64(smtp, msg, data_info, true, cb)) + return false; + + return true; + } + else + { + if (att->blob.size > 0) + { + if (strcmp(att->descr.content_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0) + { + esp_mail_smtp_send_base64_data_info_t data_info; + + data_info.rawPtr = att->blob.data; + data_info.size = att->blob.size; + data_info.flashMem = att->_int.flash_blob; + data_info.filename = att->descr.filename.c_str(); + + if (!sendBase64(smtp, msg, data_info, false, cb)) + return false; + + return true; + } + else + { + + size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE; + size_t writeLen = 0; + uint8_t *buf = allocMem(chunkSize); + while (writeLen < att->blob.size) + { + if (writeLen > att->blob.size - chunkSize) + chunkSize = att->blob.size - writeLen; + + if (!sendBDAT(smtp, msg, chunkSize, false)) + break; + memcpy_P(buf, att->blob.data, chunkSize); + + if (!altSendData(buf, chunkSize, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + break; + + if (smtp->_debug) + uploadReport(att->descr.filename.c_str(), addr, 100 * writeLen / att->blob.size); + + writeLen += chunkSize; + } + + // release memory + freeMem(&buf); + + if (smtp->_debug) + uploadReport(att->descr.filename.c_str(), addr, 100); + + return writeLen >= att->blob.size; + } + } + } + return false; +} + +bool ESP_Mail_Client::sendFile(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att) +{ + bool cb = altIsCB(smtp); + uint32_t addr = altProgressPtr(smtp); + + if (strcmp(att->descr.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0 && strcmp(att->descr.transfer_encoding.c_str(), att->descr.content_encoding.c_str()) != 0) + { + esp_mail_smtp_send_base64_data_info_t data_info; + + data_info.filename = att->descr.filename.c_str(); + data_info.storageType = att->file.storage_type; + + if (!sendBase64(smtp, msg, data_info, true, cb)) + return false; + + return true; + } + else + { + if (mbfs->size(mbfs_type att->file.storage_type) > 0) + { + if (strcmp(att->descr.content_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0) + { + esp_mail_smtp_send_base64_data_info_t data_info; + + data_info.filename = att->descr.filename.c_str(); + data_info.storageType = att->file.storage_type; + + if (!sendBase64(smtp, msg, data_info, false, cb)) + return false; + + return true; + } + else + { + int chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE; + int writeLen = 0; + + int fileSize = mbfs->size(mbfs_type att->file.storage_type); + + if (fileSize < chunkSize) + chunkSize = fileSize; + + uint8_t *buf = allocMem(chunkSize); + + while (writeLen < fileSize && mbfs->available(mbfs_type att->file.storage_type)) + { + if (writeLen > fileSize - chunkSize) + chunkSize = fileSize - writeLen; + int readLen = mbfs->read(mbfs_type att->file.storage_type, buf, chunkSize); + if (readLen != chunkSize) + { + errorStatusCB(smtp, this->imap, MB_FS_ERROR_FILE_IO_ERROR, false); + break; + } + + if (!sendBDAT(smtp, msg, chunkSize, false)) + break; + + if (!altSendData(buf, chunkSize, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + break; + + if (smtp->_debug) + uploadReport(att->descr.filename.c_str(), addr, 100 * writeLen / fileSize); + + writeLen += chunkSize; + } + + // release memory + freeMem(&buf); + + if (smtp->_debug) + uploadReport(att->descr.filename.c_str(), addr, 100); + + return writeLen == fileSize; + } + } + return false; + } + return false; +} + +bool ESP_Mail_Client::sendParallelAttachments(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary) +{ + if (msg->_parallel.size() == 0) + return true; + + MB_String parallel = getMIMEBoundary(15); + MB_String buf; + + appendBoundaryString(buf, boundary.c_str(), false, true); + + appendMultipartContentType(buf, esp_mail_multipart_type_parallel, parallel.c_str()); + + if (!sendBDAT(smtp, msg, buf.length(), false)) + return false; + + if (!altSendData(buf, false, smtp, msg, true, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + if (!sendAttachments(smtp, msg, parallel, true)) + return addSendingResult(smtp, msg, false, true); + + buf.clear(); + appendBoundaryString(buf, parallel.c_str(), true, false); + + if (!sendBDAT(smtp, msg, buf.length(), false)) + return false; + + if (!altSendData(buf, false, smtp, msg, true, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + return true; +} + +bool ESP_Mail_Client::sendAttachments(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, bool parallel) +{ + MB_String s; + MB_String buf; + int cnt = 0; + + SMTP_Attachment *att = nullptr; + + size_t sz = msg->_att.size(); + if (parallel) + sz = msg->_parallel.size(); + + for (size_t i = 0; i < sz; i++) + { + if (parallel) + att = &msg->_parallel[i]; + else + att = &msg->_att[i]; + + if (att->_int.att_type == esp_mail_att_type_attachment) + { +#if !defined(SILENT_MODE) + altSendCallback(smtp, att->descr.filename.c_str(), att->descr.filename.c_str(), esp_mail_debug_tag_type_client, true, false); +#endif + cnt++; + + if (att->file.storage_type == esp_mail_file_storage_type_none) + { + if (!att->blob.data) + continue; + + if (att->blob.size == 0) + continue; + + buf.clear(); + getAttachHeader(buf, boundary, att, att->blob.size, false); + + if (!sendBDAT(smtp, msg, buf.length(), false)) + return false; + + if (!altSendData(buf, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + if (!sendBlobAttachment(smtp, msg, att)) + return false; + + if (!sendBDAT(smtp, msg, 2, false)) + return false; + + MB_String str; + appendNewline(str); + + if (!altSendData(str, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + } + else + { + if (att->file.storage_type == esp_mail_file_storage_type_sd && !smtp->_sdStorageChecked && !smtp->_sdStorageReady) + { + smtp->_sdStorageChecked = true; + smtp->_sdStorageReady = mbfs->sdReady(); + } + else if (att->file.storage_type == esp_mail_file_storage_type_flash && !smtp->_flashStorageChecked && !smtp->_flashStorageReady) + { + smtp->_flashStorageChecked = true; + smtp->_flashStorageReady = mbfs->flashReady(); + } + + if (!smtp->_flashStorageReady && !smtp->_sdStorageReady) + { + sendStorageNotReadyError(smtp, att->file.storage_type); + continue; + } + + if (openFileRead(smtp, msg, att, buf, boundary, false)) + { + + if (!sendFile(smtp, msg, att)) + return false; + + if (!sendBDAT(smtp, msg, 2, false)) + return false; + + MB_String str; + appendNewline(str); + + if (!altSendData(str, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + } + } + } + } + return true; +} + +void ESP_Mail_Client::altSendStorageErrorCB(SMTPSession *smtp, int err) +{ +#if defined(MBFS_FLASH_FS) || defined(MBFS_SD_FS) + + if (smtp) + { + smtp->_responseStatus.errorCode = err; + smtp->_responseStatus.text.clear(); + +#if !defined(SILENT_MODE) + if (smtp->_statusCallback) + esp_mail_debug_print_tag(esp_mail_error_mem_str_3 /* "file does not exist or can't access" */, esp_mail_debug_tag_type_client, true); + + if (smtp->_debug) + esp_mail_debug_print_tag(smtp->errorReason().c_str(), esp_mail_debug_tag_type_error, true); +#endif + } + else if (imap && !calDataLen) + { +#if defined(ENABLE_IMAP) + + imap->_responseStatus.errorCode = err; + imap->_responseStatus.text.clear(); + +#if !defined(SILENT_MODE) + if (imap->_statusCallback) + esp_mail_debug_print_tag(esp_mail_error_mem_str_3 /* "file does not exist or can't access" */, esp_mail_debug_tag_type_client, true); + + if (imap->_debug) + { + esp_mail_debug_print_tag(smtp->errorReason().c_str(), esp_mail_debug_tag_type_error, true); + } +#endif +#endif + } + +#endif +} + +bool ESP_Mail_Client::openFileRead(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, MB_String &buf, const MB_String &boundary, bool inlined) +{ + int sz = -1; + MB_String filepath; + + if (att->file.path.length() > 0) + { + if (att->file.path[0] != '/') + filepath = esp_mail_str_10; /* "/" */ + filepath += att->file.path; + } + + sz = mbfs->open(filepath, mbfs_type att->file.storage_type, mb_fs_open_mode_read); + if (sz < 0) + { + + if (strlen(att->descr.filename.c_str()) > 0) + { + filepath.clear(); + if (att->descr.filename[0] != '/') + filepath = esp_mail_str_10; /* "/" */ + filepath += att->descr.filename; + } + + sz = mbfs->open(filepath, mbfs_type att->file.storage_type, mb_fs_open_mode_read); + } + + if (sz < 0) + { + altSendStorageErrorCB(smtp, sz); + } + else + { + + buf.clear(); + + getAttachHeader(buf, boundary, att, sz, inlined); + + if (!sendBDAT(smtp, msg, buf.length(), false)) + return false; + + if (!altSendData(buf, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + return true; + } + + return false; +} + +bool ESP_Mail_Client::openFileRead2(SMTPSession *smtp, SMTP_Message *msg, const char *path, esp_mail_file_storage_type storageType) +{ + + MB_String filepath; + + if (strlen(path) > 0) + { + if (path[0] != '/') + filepath = esp_mail_str_10; /* "/" */ + filepath += path; + } + + int sz = mbfs->open(filepath, mbfs_type storageType, mb_fs_open_mode_read); + if (sz < 0) + { + altSendStorageErrorCB(smtp, sz); + return false; + } + + return true; +} + +void ESP_Mail_Client::sendStorageNotReadyError(SMTPSession *smtp, esp_mail_file_storage_type storageType) +{ + +#if defined(MBFS_FLASH_FS) || defined(MBFS_SD_FS) + +#if !defined(SILENT_MODE) + if (altIsCB(smtp)) + { + if (storageType == esp_mail_file_storage_type_flash) + { + esp_mail_debug_print_tag(esp_mail_error_mem_str_1 /* "flash Storage is not ready." */, esp_mail_debug_tag_type_error, true); +#if defined(MB_ARDUINO_PICO) + esp_mail_debug_print_tag(esp_mail_error_mem_str_10 /* "please make sure that the size of flash filesystem is not 0 in Pico." */, esp_mail_debug_tag_type_error, true); +#endif + } + else if (storageType == esp_mail_file_storage_type_sd) + esp_mail_debug_print_tag(esp_mail_error_mem_str_2 /* "SD Storage is not ready." */, esp_mail_debug_tag_type_error, true); + } + + if (altIsDebug(smtp)) + { + if (storageType == esp_mail_file_storage_type_flash) + { + esp_mail_debug_print_tag(esp_mail_error_mem_str_1 /* "flash Storage is not ready." */, esp_mail_debug_tag_type_error, true); +#if defined(MB_ARDUINO_PICO) + esp_mail_debug_print_tag(esp_mail_error_mem_str_10 /* "please make sure that the size of flash filesystem is not 0 in Pico." */, esp_mail_debug_tag_type_error, true); +#endif + } + else if (storageType == esp_mail_file_storage_type_sd) + esp_mail_debug_print_tag(esp_mail_error_mem_str_2 /* "SD Storage is not ready." */, esp_mail_debug_tag_type_error, true); + } +#endif + +#endif +} + +bool ESP_Mail_Client::sendInline(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary, byte type) +{ + size_t num = numAtt(smtp, esp_mail_att_type_inline, msg) > 0; + +#if !defined(SILENT_MODE) + if (num > 0) + altSendCallback(smtp, esp_mail_cb_str_8 /* "Sending inline data..." */, esp_mail_dbg_str_14 /* "send inline data" */, esp_mail_debug_tag_type_client, true, false); +#endif + MB_String buf; + MB_String related = getMIMEBoundary(15); + int cnt = 0; + SMTP_Attachment *att = nullptr; + + MB_String s; + + appendBoundaryString(s, boundary.c_str(), false, true); + + appendMultipartContentType(s, esp_mail_multipart_type_related, related.c_str()); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + if (!sendPartText(smtp, msg, type, related.c_str())) + return false; + +#if !defined(SILENT_MODE) + bool cb = altIsCB(smtp); + + if (cb && numAtt(smtp, esp_mail_att_type_inline, msg) > 0) + esp_mail_debug_print(); +#endif + + if (num > 0) + { + for (uint8_t i = 0; i < msg->_att.size(); i++) + { + att = &msg->_att[i]; + if (att->_int.att_type == esp_mail_att_type_inline) + { +#if !defined(SILENT_MODE) + altSendCallback(smtp, att->descr.filename.c_str(), att->descr.filename.c_str(), esp_mail_debug_tag_type_client, true, false); +#endif + cnt++; + + if (att->file.storage_type == esp_mail_file_storage_type_none) + { + if (!att->blob.data) + continue; + + if (att->blob.size == 0) + continue; +#if !defined(SILENT_MODE) + altSendCallback(smtp, att->descr.filename.c_str(), att->descr.filename.c_str(), esp_mail_debug_tag_type_client, true, false); +#endif + buf.clear(); + getAttachHeader(buf, related, att, att->blob.size, true); + + if (!sendBDAT(smtp, msg, buf.length(), false)) + return false; + + if (!altSendData(buf, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + if (!sendBlobAttachment(smtp, msg, att)) + return false; + + if (!sendBDAT(smtp, msg, 2, false)) + return false; + + MB_String str; + appendNewline(str); + + if (!altSendData(str, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + } + else + { + + if (att->file.storage_type == esp_mail_file_storage_type_sd && !smtp->_sdStorageChecked && !smtp->_sdStorageReady) + { + smtp->_sdStorageChecked = true; + smtp->_sdStorageReady = mbfs->sdReady(); + } + else if (att->file.storage_type == esp_mail_file_storage_type_flash && !smtp->_flashStorageChecked && !smtp->_flashStorageReady) + { + smtp->_flashStorageChecked = true; + smtp->_flashStorageReady = mbfs->flashReady(); + } + + if (!smtp->_flashStorageReady && !smtp->_sdStorageReady) + { + sendStorageNotReadyError(smtp, att->file.storage_type); + continue; + } + + if (openFileRead(smtp, msg, att, buf, related, true)) + { + if (!sendFile(smtp, msg, att)) + return false; + + if (!sendBDAT(smtp, msg, 2, false)) + return false; + + MB_String str; + appendNewline(str); + + if (!altSendData(str, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + } + } + } + } + } + + appendNewline(s); + + appendBoundaryString(s, related.c_str(), true, true); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + return true; +} + +size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, PGM_P data, bool newline) +{ + if (!smtp || !sessionReady(smtp)) + return 0; + + int sent = 0; + + MB_String s = data; + + int toSend = newline ? s.length() + 2 : s.length(); + +#if !defined(SILENT_MODE) + if (!smtp->_customCmdResCallback && smtp->_debugLevel > esp_mail_debug_level_maintainer) + esp_mail_debug_print(s.c_str(), newline); +#endif + + sent = newline ? smtp->client.println(s.c_str()) : smtp->client.print(s.c_str()); + + if (sent != toSend) + { + errorStatusCB(smtp, this->imap, sent, false); + sent = 0; + } + + return sent; +} + +size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, int data, bool newline) +{ + MB_String s = data; + return smtpSend(smtp, s.c_str(), newline); +} + +size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, uint8_t *data, size_t size) +{ + if (!smtp || !sessionReady(smtp)) + return 0; + + size_t sent = smtp->client.write(data, size); + + if (sent != size) + { + errorStatusCB(smtp, this->imap, sent, false); + sent = 0; + } + + return sent; +} + +bool ESP_Mail_Client::handleSMTPError(SMTPSession *smtp, int err, bool ret) +{ + + if (err < 0) + errorStatusCB(smtp, this->imap, err, false); + + if (smtp) + { + closeTCPSession(smtp); + } + else if (imap && !calDataLen) + { +#if defined(ENABLE_IMAP) + if (imap->connected()) + closeTCPSession(imap); +#endif + } + + return ret; +} + +bool ESP_Mail_Client::sendPartText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, const char *boundary) +{ + MB_String header; + + if (strlen(boundary) > 0) + appendBoundaryString(header, boundary, false, true); + + if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) + { + if (msg->text.content_type.length() > 0) + { + appendHeaderField(header, message_headers[esp_mail_message_header_field_content_type].text, msg->text.content_type.c_str(), false, false); + + bool firstProp = true; + + if (msg->text.charSet.length() > 0) + appendHeaderProp(header, message_headers[esp_mail_message_header_field_charset].text, msg->text.charSet.c_str(), firstProp, true, true, false); + + if (msg->text.flowed) + { + appendHeaderProp(header, message_headers[esp_mail_message_header_field_format].text, "flowed", firstProp, true, true, false); + appendHeaderProp(header, message_headers[esp_mail_message_header_field_delsp].text, "no", firstProp, true, true, false); + } + + if (msg->text.embed.enable) + { + appendHeaderProp(header, message_headers[esp_mail_message_header_field_name].text, esp_mail_str_13 /* "msg.txt" */, firstProp, false, true, false); + char *uid = getRandomUID(); + msg->text._int.cid = uid; + // release memory + freeMem(&uid); + } + + appendNewline(header); + } + + if (msg->text.transfer_encoding.length() > 0) + appendHeaderField(header, message_headers[esp_mail_message_header_field_content_transfer_encoding].text, msg->text.transfer_encoding.c_str(), false, true); + } + else if (type == esp_mail_msg_type_html) + { + if (msg->text.content_type.length() > 0) + { + appendHeaderField(header, message_headers[esp_mail_message_header_field_content_type].text, msg->html.content_type.c_str(), false, false); + bool firstProp = true; + + if (msg->html.charSet.length() > 0) + appendHeaderProp(header, message_headers[esp_mail_message_header_field_charset].text, msg->html.charSet.c_str(), firstProp, true, true, false); + + if (msg->html.embed.enable) + { + appendHeaderProp(header, message_headers[esp_mail_message_header_field_name].text, esp_mail_str_14 /* "msg.html" */, firstProp, true, true, false); + char *uid = getRandomUID(); + msg->html._int.cid = uid; + // release memory + freeMem(&uid); + } + + appendNewline(header); + } + + if (msg->html.transfer_encoding.length() > 0) + appendHeaderField(header, message_headers[esp_mail_message_header_field_content_transfer_encoding].text, msg->html.transfer_encoding.c_str(), false, true); + } + + if ((type == esp_mail_msg_type_html && msg->html.embed.enable) || ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.embed.enable)) + { + + if ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.embed.enable) + appendEmbedMessage(header, msg->text, false); + else if (type == esp_mail_msg_type_html && msg->html.embed.enable) + appendEmbedMessage(header, msg->html, true); + } + + appendNewline(header); + + bool rawBlob = (msg->text.blob.size > 0 && (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)) || (msg->html.blob.size > 0 && type == esp_mail_msg_type_html); + bool rawFile = (msg->text.file.name.length() > 0 && (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)) || (msg->html.file.name.length() > 0 && type == esp_mail_msg_type_html); + bool rawContent = ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.content.length() > 0) || (type == esp_mail_msg_type_html && msg->html.content.length() > 0); + bool nonCopyContent = ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && strlen(msg->text.nonCopyContent) > 0) || (type == esp_mail_msg_type_html && strlen(msg->html.nonCopyContent) > 0); + + if (rawBlob || rawFile || nonCopyContent) + { + if (!sendBDAT(smtp, msg, header.length(), false)) + return false; + + if (!altSendData(header, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + header.clear(); + + if (rawBlob || nonCopyContent) + { + if (!sendBlobBody(smtp, msg, type)) + return false; + } + else if (rawFile) + { + if (!sendFileBody(smtp, msg, type)) + return false; + } + } + else if (rawContent) + encodingText(smtp, msg, type, header); + + appendNewline(header); + + if (strlen(boundary) > 0) + appendNewline(header); + + if (!sendBDAT(smtp, msg, header.length(), false)) + return false; + + if (!altSendData(header, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + return true; +} + +bool ESP_Mail_Client::sendBlobBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type) +{ + + bool cb = altIsCB(smtp); + uint32_t addr = altProgressPtr(smtp); + + if (msg->text.blob.size == 0 && msg->html.blob.size == 0 && strlen(msg->text.nonCopyContent) == 0 && strlen(msg->html.nonCopyContent) == 0) + return true; + + bool ret = true; + int bufLen = 512; + size_t pos = 0; + + const uint8_t *raw = NULL; + int len = 0; + bool base64 = false; + + if ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)) + { + if (strlen(msg->text.nonCopyContent) > 0) + { + raw = (const uint8_t *)msg->text.nonCopyContent; + len = strlen(msg->text.nonCopyContent); + } + else + { + raw = msg->text.blob.data; + len = msg->text.blob.size; + } + base64 = msg->text.transfer_encoding.length() > 0 && strcmp(msg->text.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0; + } + else if (type == esp_mail_msg_type_html) + { + if (strlen(msg->html.nonCopyContent) > 0) + { + raw = (const uint8_t *)msg->html.nonCopyContent; + len = strlen(msg->html.nonCopyContent); + } + else + { + raw = msg->html.blob.data; + len = msg->html.blob.size; + } + base64 = msg->html.transfer_encoding.length() > 0 && strcmp(msg->html.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0; + } + + if (base64) + { + MB_String s1 = esp_mail_str_15; /* "flash content message" */ + + esp_mail_smtp_send_base64_data_info_t data_info; + + data_info.flashMem = true; + data_info.filename = s1.c_str(); + data_info.rawPtr = raw; + data_info.size = len; + + return sendBase64(smtp, msg, data_info, true, cb); + } + + int available = len; + int sz = len; + uint8_t *buf = allocMem(bufLen + 1); + while (available) + { + if (available > bufLen) + available = bufLen; + + memcpy_P(buf, raw + pos, available); + + if (!sendBDAT(smtp, msg, available, false)) + { + ret = false; + break; + } + + if (!altSendData(buf, available, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + { + ret = false; + break; + } + + pos += available; + len -= available; + available = len; + + if (smtp->_debug) + { + MB_String s1 = esp_mail_str_15; /* "flash content message" */ + uploadReport(s1.c_str(), addr, 100 * pos / sz); + } + } + + // release memory + freeMem(&buf); + + return ret; +} + +bool ESP_Mail_Client::sendFileBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type) +{ + bool cb = altIsCB(smtp); + uint32_t addr = altProgressPtr(smtp); + + if (msg->text.file.name.length() == 0 && msg->html.file.name.length() == 0) + return true; + + bool ret = true; + int chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE; + int writeLen = 0; + + if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) + { + + if (!openFileRead2(smtp, msg, msg->text.file.name.c_str(), msg->text.file.type)) + return false; + + if (msg->text.transfer_encoding.length() > 0) + { + if (strcmp(msg->text.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0) + { + MB_String s1 = esp_mail_str_16; /* "file content message" */ + + esp_mail_smtp_send_base64_data_info_t data_info; + + data_info.filename = s1.c_str(); + data_info.storageType = msg->text.file.type; + + return sendBase64(smtp, msg, data_info, true, cb); + } + } + + int fileSize = mbfs->size(mbfs_type msg->text.file.type); + + if (fileSize > 0) + { + + if (fileSize < chunkSize) + chunkSize = fileSize; + + uint8_t *buf = allocMem(chunkSize); + + while (writeLen < fileSize && mbfs->available(mbfs_type msg->text.file.type)) + { + if (writeLen > fileSize - chunkSize) + chunkSize = fileSize - writeLen; + int readLen = mbfs->read(mbfs_type msg->text.file.type, buf, chunkSize); + + if (readLen != chunkSize) + { + errorStatusCB(smtp, this->imap, MB_FS_ERROR_FILE_IO_ERROR, false); + break; + } + + if (!sendBDAT(smtp, msg, chunkSize, false)) + { + ret = false; + break; + } + + if (!altSendData(buf, chunkSize, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + { + ret = false; + break; + } + + if (smtp->_debug) + uploadReport(pgm2Str(esp_mail_str_16 /* "file content message" */), addr, 100 * writeLen / fileSize); + + writeLen += chunkSize; + } + + // release memory + freeMem(&buf); + + if (smtp->_debug) + uploadReport(pgm2Str(esp_mail_str_16 /* "file content message" */), addr, 100); + + return ret && writeLen == fileSize; + } + } + else if (type == esp_mail_message_type::esp_mail_msg_type_html) + { + + if (!openFileRead2(smtp, msg, msg->html.file.name.c_str(), msg->html.file.type)) + return false; + + if (msg->html.transfer_encoding.length() > 0) + { + if (strcmp(msg->html.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0) + { + MB_String s1 = esp_mail_str_16; /* "file content message" */ + + esp_mail_smtp_send_base64_data_info_t data_info; + + data_info.filename = s1.c_str(); + data_info.storageType = msg->html.file.type; + + return sendBase64(smtp, msg, data_info, true, cb); + } + } + + int fileSize = mbfs->size(mbfs_type msg->html.file.type); + + if (fileSize > 0) + { + + if (fileSize < chunkSize) + chunkSize = fileSize; + + uint8_t *buf = allocMem(chunkSize); + + while (writeLen < fileSize && mbfs->available(mbfs_type msg->html.file.type)) + { + if (writeLen > fileSize - chunkSize) + chunkSize = fileSize - writeLen; + int readLen = mbfs->read(mbfs_type msg->html.file.type, buf, chunkSize); + + if (readLen != chunkSize) + { + errorStatusCB(smtp, this->imap, MB_FS_ERROR_FILE_IO_ERROR, false); + break; + } + + if (!sendBDAT(smtp, msg, chunkSize, false)) + { + ret = false; + break; + } + + if (!altSendData(buf, chunkSize, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + { + ret = false; + break; + } + + if (cb) + uploadReport(pgm2Str(esp_mail_str_16 /* "file content message" */), addr, 100 * writeLen / fileSize); + + writeLen += chunkSize; + } + + // release memory + freeMem(&buf); + + if (cb) + uploadReport(pgm2Str(esp_mail_str_16 /* "file content message" */), addr, 100); + + return ret && writeLen == fileSize; + } + } + + return false; +} + +void ESP_Mail_Client::encodingText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, MB_String &content) +{ + if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) + { + MB_String s = msg->text.content; + + if (msg->text.flowed) + formatFlowedText(s); + + if (msg->text.transfer_encoding.length() > 0) + { + if (strcmp(msg->text.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0) + content += encodeBase64Str((const unsigned char *)s.c_str(), s.length()); + else if (strcmp(msg->text.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_qp) == 0) + { + char *out = allocMem(s.length() * 3 + 1); + encodeQP(s.c_str(), out); + content += out; + + // release memory + freeMem(&out); + } + else + content += s; + } + else + content += s; + } + else if (type == esp_mail_message_type::esp_mail_msg_type_html) + { + MB_String s = msg->html.content; + MB_String fnd, rep; + SMTP_Attachment *att = nullptr; + for (uint8_t i = 0; i < msg->_att.size(); i++) + { + att = &msg->_att[i]; + if (att->_int.att_type == esp_mail_att_type_inline) + { + MB_String filename(att->descr.filename); + + size_t found = filename.find_last_of("/\\"); + if (found != MB_String::npos) + filename = filename.substr(found + 1); + + appendString(fnd, filename.c_str(), false, false, esp_mail_string_mark_type_double_quote); + + MB_String cid = esp_mail_str_17; /* "cid:" */ + cid += att->descr.content_id.length() > 0 ? att->descr.content_id : att->_int.cid; + + appendString(rep, cid.c_str(), false, false, esp_mail_string_mark_type_double_quote); + + s.replaceAll(fnd, rep); + } + } + + if (msg->html.transfer_encoding.length() > 0) + { + if (strcmp(msg->html.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_base64) == 0) + content += encodeBase64Str((const unsigned char *)s.c_str(), s.length()); + else if (strcmp(msg->html.transfer_encoding.c_str(), Content_Transfer_Encoding::enc_qp) == 0) + { + char *out = allocMem(msg->html.content.length() * 3 + 1); + encodeQP(msg->html.content.c_str(), out); + content += out; + + // release memory + freeMem(&out); + } + else + content += s; + } + else + content += s; + s.clear(); + } + + if (msg->timestamp.tag.length() && msg->timestamp.format.length()) + content.replaceAll(msg->timestamp.tag, Time.getDateTimeString(Time.getCurrentTimestamp(), msg->timestamp.format.c_str())); +} + +void ESP_Mail_Client::encodeQP(const char *buf, char *out) +{ + int n = 0, p = 0, pos = 0; + for (n = 0; *buf; buf++) + { + if (n >= 73 && *buf != 10 && *buf != 13) + { + p = sprintf(out + pos, "=\r\n"); + pos += p; + n = 0; + } + + if (*buf == 10 || *buf == 13) + { + out[pos++] = *buf; + n = 0; + } + else if (*buf < 32 || *buf == 61 || *buf > 126) + { + p = sprintf(out + pos, "=%02X", (unsigned char)*buf); + n += p; + pos += p; + } + else if (*buf != 32 || (*(buf + 1) != 10 && *(buf + 1) != 13)) + { + out[pos++] = *buf; + n++; + } + else + { + p = sprintf(out + pos, "=20"); + n += p; + pos += p; + } + } +} + +/** Add the soft line break to the long text line (rfc 3676) + * and add Format=flowed parameter in the plain text content-type header. + * We use the existing white space as a part of this soft line break + * and set delSp="no" parameter to the header. + * + * Some servers are not rfc 3676 compliant. + * This causes the text lines are wrapped instead of joined. + * + * Some mail clients trim the space before the line break + * which makes the soft line break cannot be seen. + */ +void ESP_Mail_Client::formatFlowedText(MB_String &content) +{ + int count = 0; + MB_String qms; + int j = 0; + _vectorImpl tokens; + char *stk = strP(esp_mail_str_18); /* "\r\n" */ + char *qm = strP(esp_mail_str_20); /* ">" */ + splitToken(content.c_str(), tokens, stk); + content.clear(); + for (size_t i = 0; i < tokens.size(); i++) + { + if (tokens[i].length() > 0) + { + j = 0; + qms.clear(); + while (tokens[i][j] == qm[0]) + { + qms += qm; + j++; + } + softBreak(tokens[i], qms.c_str()); + if (count > 0) + content += stk; + content += tokens[i]; + } + else if (count > 0) + content += stk; + count++; + } + + // release memory + freeMem(&stk); + freeMem(&qm); + tokens.clear(); +} + +void ESP_Mail_Client::softBreak(MB_String &content, const char *quoteMarks) +{ + size_t len = 0; + char *stk = strP(esp_mail_str_2); /* " " */ + _vectorImpl tokens; + splitToken(content.c_str(), tokens, stk); + content.clear(); + for (size_t i = 0; i < tokens.size(); i++) + { + if (tokens[i].length() > 0) + { + if (len + tokens[i].length() + 3 > FLOWED_TEXT_LEN) + { + /* insert soft crlf */ + content += stk; + appendNewline(content); + + /* insert quote marks */ + if (strlen(quoteMarks) > 0) + content += quoteMarks; + content += tokens[i]; + len = tokens[i].length(); + } + else + { + if (len > 0) + { + content += stk; + len += strlen(stk); + } + content += tokens[i]; + len += tokens[i].length(); + } + } + } + + // release memory + freeMem(&stk); + tokens.clear(); +} + +bool ESP_Mail_Client::altSendData(MB_String &s, bool newLine, SMTPSession *smtp, SMTP_Message *msg, bool addSendResult, bool getResponse, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode) +{ + if (!imap && smtp) + { + if (smtpSend(smtp, s.c_str(), newLine) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + { + if (addSendResult) + return addSendingResult(smtp, msg, false, true); + else + return false; + } + + if (getResponse) + { + if (!handleSMTPResponse(smtp, cmd, statusCode, errCode)) + { + if (addSendResult) + return addSendingResult(smtp, msg, false, true); + else + return false; + } + } + } + else if (imap) + { +#if defined(ENABLE_IMAP) + if (newLine) + appendNewline(s); + MB_StringPtr data = toStringPtr(s); + + if (calDataLen) + dataLen += s.length(); + else + return imap->mSendData(data, false, esp_mail_imap_cmd_append); +#endif + } + + return true; +} + +bool ESP_Mail_Client::altSendData(uint8_t *data, size_t size, SMTPSession *smtp, SMTP_Message *msg, bool addSendResult, bool getResponse, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode) +{ + if (!imap && smtp) + { + if (smtpSend(smtp, data, size) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + { + if (addSendResult) + return addSendingResult(smtp, msg, false, true); + else + return false; + } + + if (getResponse) + { + if (!handleSMTPResponse(smtp, cmd, statusCode, errCode)) + { + if (addSendResult) + return addSendingResult(smtp, msg, false, true); + else + return false; + } + } + } + else if (imap) + { +#if defined(ENABLE_IMAP) + + if (calDataLen) + dataLen += size; + else + return imap->mSendData(data, size, false, esp_mail_imap_cmd_append); +#endif + } + + return true; +} + +bool ESP_Mail_Client::sendMSG(SMTPSession *smtp, SMTP_Message *msg, const MB_String &boundary) +{ + MB_String s; + + if (numAtt(smtp, esp_mail_att_type_inline, msg) > 0) + { + appendMultipartContentType(s, esp_mail_multipart_type_alternative, boundary.c_str()); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + if (msg->type == esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type == esp_mail_msg_type_html) + { + if (!sendInline(smtp, msg, boundary, msg->type)) + return false; + } + else if (msg->type == (esp_mail_msg_type_html | esp_mail_msg_type_enriched | esp_mail_msg_type_plain)) + { + if (!sendPartText(smtp, msg, esp_mail_msg_type_plain, boundary.c_str())) + return false; + if (!sendInline(smtp, msg, boundary, esp_mail_msg_type_html)) + return false; + } + + appendBoundaryString(s, boundary.c_str(), true, true); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + } + else + { + if (msg->type == esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type == esp_mail_msg_type_html) + { + if (!sendPartText(smtp, msg, msg->type, "")) + return false; + } + else if (msg->type == (esp_mail_msg_type_html | esp_mail_msg_type_enriched | esp_mail_msg_type_plain)) + { + appendMultipartContentType(s, esp_mail_multipart_type_alternative, boundary.c_str()); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + + if (!sendPartText(smtp, msg, esp_mail_msg_type_plain, boundary.c_str())) + return false; + + if (!sendPartText(smtp, msg, esp_mail_msg_type_html, boundary.c_str())) + return false; + + s.clear(); + appendBoundaryString(s, boundary.c_str(), true, false); + + if (!sendBDAT(smtp, msg, s.length(), false)) + return false; + + if (!altSendData(s, false, smtp, msg, true, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + return false; + } + } + return true; +} + +void ESP_Mail_Client::getAttachHeader(MB_String &header, const MB_String &boundary, SMTP_Attachment *attach, size_t size, bool isInline) +{ + appendBoundaryString(header, boundary.c_str(), false, true); + + appendHeaderName(header, message_headers[esp_mail_message_header_field_content_type].text); + + if (attach->descr.mime.length() == 0) + { + MB_String mime; + mimeFromFile(attach->descr.filename.c_str(), mime); + if (mime.length() > 0) + appendString(header, mime.c_str(), false, false); + else + appendString(header, mimeinfo[esp_mail_file_extension_binary].mimeType, false, false); + } + else + appendString(header, attach->descr.mime.c_str(), false, false); + + MB_String filename = attach->descr.filename; + + size_t found = filename.find_last_of("/\\"); + if (found != MB_String::npos) + filename = filename.substr(found + 1); + + bool firstProp = true; + + appendHeaderProp(header, message_headers[esp_mail_message_header_field_name].text, filename.c_str(), firstProp, false, true, true); + + if (isInline || (!isInline && !attach->_int.parallel)) + { + appendHeaderName(header, message_headers[esp_mail_message_header_field_content_disposition].text); + appendString(header, isInline ? esp_mail_content_disposition_type_t::inline_ : esp_mail_content_disposition_type_t::attachment, false, false); + + firstProp = true; + appendHeaderProp(header, message_headers[esp_mail_message_header_field_filename].text, filename.c_str(), firstProp, true, true, false); + appendHeaderProp(header, message_headers[esp_mail_message_header_field_size].text, MB_String((int)size).c_str(), firstProp, true, false, true); + } + + if (isInline) + { + + appendHeaderField(header, message_headers[esp_mail_message_header_field_content_location].text, filename.c_str(), false, true); + + appendHeaderName(header, message_headers[esp_mail_message_header_field_content_id].text); + if (attach->descr.content_id.length() > 0) + appendString(header, attach->descr.content_id.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); + else + appendString(header, attach->_int.cid.c_str(), false, true, esp_mail_string_mark_type_angle_bracket); + } + + if (attach->descr.transfer_encoding.length() > 0) + appendHeaderField(header, message_headers[esp_mail_message_header_field_content_transfer_encoding].text, attach->descr.transfer_encoding.c_str(), false, true); + + if (attach->descr.description.length() > 0) + appendHeaderField(header, message_headers[esp_mail_message_header_field_content_description].text, attach->descr.description.c_str(), false, true); + + appendNewline(header); +} + +void ESP_Mail_Client::getRFC822PartHeader(SMTPSession *smtp, MB_String &header, const MB_String &boundary) +{ + appendBoundaryString(header, boundary.c_str(), false, true); + + appendHeaderName(header, message_headers[esp_mail_message_header_field_content_type].text); + appendString(header, esp_mail_str_22 /* "message/rfc822" */, false, true); + + appendHeaderName(header, message_headers[esp_mail_message_header_field_content_disposition].text); + appendString(header, esp_mail_content_disposition_type_t::attachment, false, true); + appendNewline(header); +} + +uint32_t ESP_Mail_Client::altProgressPtr(SMTPSession *smtp) +{ + uint32_t addr = 0; + if (smtp) + { + smtp->_lastProgress = -1; + addr = toAddr(smtp->_lastProgress); + } + else if (imap && !calDataLen) + { +#if defined(ENABLE_IMAP) + imap->_lastProgress = -1; + addr = toAddr(imap->_lastProgress); +#endif + } + + return addr; +} + +void ESP_Mail_Client::parseAuthCapability(SMTPSession *smtp, char *buf) +{ + if (!smtp) + return; + + if (strposP(buf, smtp_cmd_post_tokens[esp_mail_smtp_command_auth].c_str(), 0) > -1) + { + for (int i = esp_mail_auth_capability_plain; i < esp_mail_auth_capability_maxType; i++) + { + if (strposP(buf, smtp_auth_cap_pre_tokens[i].c_str(), 0) > -1) + { + smtp->_auth_capability[i] = true; + // Don't exit the loop + // and continue checking for all auth types + } + } + } + else if (strposP(buf, smtp_auth_capabilities[esp_mail_auth_capability_starttls].text, 0) > -1) + { + smtp->_auth_capability[esp_mail_auth_capability_starttls] = true; + return; + } + + for (int i = esp_mail_smtp_send_capability_binary_mime; i < esp_mail_smtp_send_capability_maxType; i++) + { + if (strposP(buf, smtp_send_cap_pre_tokens[i].c_str(), 0) > -1) + { + smtp->_feature_capability[i] = true; + return; + } + } +} + +bool ESP_Mail_Client::handleSMTPResponse(SMTPSession *smtp, esp_mail_smtp_command cmd, esp_mail_smtp_status_code statusCode, int errCode) +{ + if (!smtp) + return false; + + smtp->_smtp_cmd = cmd; + + if (!reconnect(smtp)) + return false; + + bool ret = false; + char *response = nullptr; + int readLen = 0; + long dataTime = millis(); + int chunkBufSize = 0; + MB_String s, r, err; + int chunkIndex = 0; + int count = 0; + bool completedResponse = false; + smtp->_responseStatus.errorCode = 0; + smtp->_responseStatus.statusCode = 0; + smtp->_responseStatus.text.clear(); + uint8_t minResLen = 5; + struct esp_mail_smtp_response_status_t status; + + bool canForward = smtp->_canForward; + smtp->_canForward = false; + + status.id = smtp->_commandID; + + chunkBufSize = smtp->client.available(); + + while (smtp->connected() && chunkBufSize <= 0) + { + if (!reconnect(smtp, dataTime)) + return false; + if (!connected(smtp)) + { + if (cmd != esp_mail_smtp_cmd_logout) + errorStatusCB(smtp, this->imap, MAIL_CLIENT_ERROR_CONNECTION_CLOSED, false); + + return false; + } + chunkBufSize = smtp->client.available(); + yield_impl(); + } + + dataTime = millis(); + + if (chunkBufSize > 1) + { + while (!completedResponse) + { + yield_impl(); + + if (!reconnect(smtp, dataTime)) + return false; + + if (!connected(smtp)) + { + if (cmd != esp_mail_smtp_cmd_logout) + errorStatusCB(smtp, this->imap, MAIL_CLIENT_ERROR_CONNECTION_CLOSED, false); + return false; + } + + chunkBufSize = smtp->client.available(); + + if (chunkBufSize <= 0) + break; + + if (chunkBufSize > 0) + { + + chunkBufSize = ESP_MAIL_CLIENT_RESPONSE_BUFFER_SIZE; + response = allocMem(chunkBufSize + 1); + + read_line: + + MB_String ovfBuf; + if (!readResponse(smtp, response, chunkBufSize, readLen, false, count, ovfBuf)) + { + closeTCPSession(smtp); + errorStatusCB(smtp, this->imap, MAIL_CLIENT_ERROR_READ_TIMEOUT, false); + return false; + } + + // If buffer overflown, copy from overflow buffer + if (ovfBuf.length() > 0) + { + // release memory + freeMem(&response); + response = allocMem(ovfBuf.length() + 1); + strcpy(response, ovfBuf.c_str()); + ovfBuf.clear(); + } + + if (readLen) + { + if (smtp->_smtp_cmd != esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state) + { + // sometimes server sent multiple lines response + // sometimes rx buffer is not ready for a while + + if (strlen(response) < minResLen) + { + r += response; + chunkBufSize = 0; + while (chunkBufSize == 0) + { + yield_impl(); + if (!reconnect(smtp, dataTime)) + return false; + chunkBufSize = smtp->client.available(); + } + } + else + { + if (r.length() > 0) + { + r += response; + memset(response, 0, chunkBufSize); + strcpy(response, r.c_str()); + } +#if !defined(SILENT_MODE) + if (!smtp->_customCmdResCallback && smtp->_debugLevel > esp_mail_debug_level_basic) + esp_mail_debug_print((const char *)response, true); +#endif + } + + if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_greeting) + parseAuthCapability(smtp, response); + } + + getResponseStatus(response, statusCode, 0, status); + + // No response code from greeting? + // Assumed multi-line greeting responses. + + if (status.statusCode == 0 && smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state) + { + +#if !defined(SILENT_MODE) + if (smtp->_debug && !smtp->_customCmdResCallback) + esp_mail_debug_print_tag(response, esp_mail_debug_tag_type_server, true); +#endif + + memset(response, 0, chunkBufSize + 1); + + // read again until we get the response code + goto read_line; + } + + // get the status code again for unexpected return code + if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_start_tls || status.statusCode == 0) + getResponseStatus(response, esp_mail_smtp_status_code_0, 0, status); + + smtp->_responseStatus = status; + + if ((status.statusCode > 0 && status.statusCode == statusCode) || + (smtp->_smtp_cmd == esp_mail_smtp_cmd_start_tls && status.statusCode == esp_mail_smtp_status_code_220) || + (canForward && statusCode == esp_mail_smtp_status_code_250 && status.statusCode == esp_mail_smtp_status_code_251) + + ) + { + ret = true; + } + + if (strlen(response) >= minResLen) + { +#if !defined(SILENT_MODE) + if (smtp->_debug) + { + if (!smtp->_customCmdResCallback) + { + appendDebugTag(s, esp_mail_debug_tag_type_server, true); + if (smtp->_responseStatus.statusCode != esp_mail_smtp_status_code_334) + s += response; + else + { + // base64 encoded server challenge message + size_t olen = 0; + char *decoded = (char *)decodeBase64((const unsigned char *)status.text.c_str(), status.text.length(), &olen); + if (decoded && olen > 0) + { + s.append(decoded, olen); + err = decoded; + } + + // release memory + freeMem(&decoded); + } + esp_mail_debug_print(s.c_str(), true); + } + } + +#endif + r.clear(); + } + + if (smtp->_customCmdResCallback && (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state || smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_custom)) + { + struct esp_mail_smtp_response_status_t res = status; + res.text = response; + smtp->_customCmdResCallback(res); + } + + completedResponse = smtp->_responseStatus.statusCode > 0 && status.text.length() > minResLen; + + if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_auth_xoauth2 && smtp->_responseStatus.statusCode == esp_mail_smtp_status_code_334) + { + if (isOAuthError(response, readLen, chunkIndex, 4)) + { + smtp->_responseStatus.text = err; + smtp->_responseStatus.errorCode = SMTP_STATUS_XOAUTH2_AUTH_FAILED; + ret = false; + } + } + + chunkIndex++; + + if (smtp->_chunkedEnable && smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_chunk_termination) + completedResponse = smtp->_chunkCount == chunkIndex; + } + + // release memory + freeMem(&response); + } + } + + if (!ret && !smtp->_customCmdResCallback) + handleSMTPError(smtp, errCode, false); + } + + return ret; +} + +void ESP_Mail_Client::getResponseStatus(const char *buf, esp_mail_smtp_status_code statusCode, int beginPos, struct esp_mail_smtp_response_status_t &status) +{ + if (statusCode > esp_mail_smtp_status_code_0) + { + int codeLength = 3; + int textLength = strlen(buf) - codeLength - 1; + + if ((int)strlen(buf) > codeLength && (buf[codeLength] == ' ' || buf[codeLength] == '-') && textLength > 0) + { + char *tmp = nullptr; + tmp = allocMem(codeLength + 1); + memcpy(tmp, &buf[0], codeLength); + + int code = atoi(tmp); + + // release memory + freeMem(&tmp); + + if (buf[codeLength] == ' ') + status.statusCode = code; + + int i = codeLength + 1; + + // We will collect the status text starting from status code 334 and 4xx + // The status text of 334 will be used for debugging display of the base64 server challenge + if (code == esp_mail_smtp_status_code_334 || code >= esp_mail_smtp_status_code_421) + { + // find the next sp + while (i < (int)strlen(buf) && buf[i] != ' ') + i++; + + // if sp found, set index to the next pos, otherwise set index to num length + 1 + i = (i < (int)strlen(buf) - 1) ? i + 1 : codeLength + 1; + + tmp = allocMem(textLength + 1); + memcpy(tmp, &buf[i], strlen(buf) - i - 1); + status.text += tmp; + // release memory + freeMem(&tmp); + } + } + } +} + +void ESP_Mail_Client::uploadReport(const char *filename, uint32_t pgAddr, int progress) +{ + if (pgAddr == 0) + return; + + int *lastProgress = addrTo(pgAddr); + + printProgress(progress, *lastProgress); +} + +MB_String ESP_Mail_Client::getMIMEBoundary(size_t len) +{ + MB_String tmp = boundary_table; + char *buf = allocMem(len); + if (len) + { + --len; + buf[0] = tmp[0]; + buf[1] = tmp[1]; + for (size_t n = 2; n < len; n++) + { + int key = rand() % (int)(tmp.length() - 1); + buf[n] = tmp[key]; + } + buf[len] = '\0'; + } + MB_String s = buf; + // release memory + freeMem(&buf); + return s; +} + +int ESP_Mail_Client::chunkAvailable(SMTPSession *smtp, esp_mail_smtp_send_base64_data_info_t &data_info) +{ + if (!data_info.rawPtr) + { + int fileSize = mbfs->size(mbfs_type data_info.storageType); + if (!fileSize) + { + errorStatusCB(smtp, this->imap, MB_FS_ERROR_FILE_IO_ERROR, false); + return -1; + } + + return mbfs->available(mbfs_type data_info.storageType); + } + + return data_info.size - data_info.dataIndex; +} + +int ESP_Mail_Client::getChunk(SMTPSession *smtp, esp_mail_smtp_send_base64_data_info_t &data_info, unsigned char *rawChunk, bool base64) +{ + int available = chunkAvailable(smtp, data_info); + + if (available <= 0) + return available; + + size_t size = base64 ? 3 : 4; + + if (data_info.dataIndex + size > data_info.size) + size = data_info.size - data_info.dataIndex; + + if (!data_info.rawPtr) + { + + int readLen = mbfs->read(mbfs_type data_info.storageType, rawChunk, size); + + if (readLen >= 0) + data_info.dataIndex += readLen; + + return readLen; + } + + if (data_info.flashMem) + memcpy_P(rawChunk, data_info.rawPtr + data_info.dataIndex, size); + else + memcpy(rawChunk, data_info.rawPtr + data_info.dataIndex, size); + + data_info.dataIndex += size; + + return size; +} + +void ESP_Mail_Client::closeChunk(esp_mail_smtp_send_base64_data_info_t &data_info) +{ + if (!data_info.rawPtr) + { + mbfs->close(mbfs_type data_info.storageType); + } +} + +bool ESP_Mail_Client::sendBase64(SMTPSession *smtp, SMTP_Message *msg, esp_mail_smtp_send_base64_data_info_t &data_info, bool base64, bool report) +{ + int size = chunkAvailable(smtp, data_info); + + if (size <= 0) + return false; + + data_info.size = size; + + bool ret = false; + + uint32_t addr = altProgressPtr(smtp); + + size_t chunkSize = (BASE64_CHUNKED_LEN * UPLOAD_CHUNKS_NUM) + (2 * UPLOAD_CHUNKS_NUM); + int bufIndex = 0; + bool dataReady = false; + int encodedCount = 0; + int read = 0; + + if (!base64) + { + if (data_info.size < chunkSize) + chunkSize = data_info.size; + } + + uint8_t *buf = allocMem(chunkSize); + memset(buf, 0, chunkSize); + + uint8_t *rawChunk = allocMem(base64 ? 3 : 4); + + if (report) + uploadReport(data_info.filename, addr, data_info.dataIndex / data_info.size); + + int min = base64 ? 3 : 1; + + while (chunkAvailable(smtp, data_info)) + { + + if (chunkAvailable(smtp, data_info) >= min) + { + + read = getChunk(smtp, data_info, rawChunk, base64); + + if (!read) + goto ex; + + getBuffer(base64, buf, rawChunk, encodedCount, bufIndex, dataReady, read, chunkSize); + + if (dataReady) + { + + if (!sendBDAT(smtp, msg, base64 ? bufIndex : bufIndex + 1, false)) + goto ex; + + if (!altSendData(buf, base64 ? bufIndex : bufIndex + 1, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + goto ex; + + memset(buf, 0, chunkSize); + bufIndex = 0; + } + + if (report) + uploadReport(data_info.filename, addr, 100 * data_info.dataIndex / data_info.size); + } + else if (base64) + { + read = getChunk(smtp, data_info, rawChunk, base64); + if (!read) + goto ex; + } + } + + closeChunk(data_info); + + if (base64) + { + if (bufIndex > 0) + { + if (!sendBDAT(smtp, msg, bufIndex, false)) + goto ex; + + if (!altSendData(buf, bufIndex, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + goto ex; + } + + if (read) + { + memset(buf, 0, chunkSize); + bufIndex = 0; + buf[bufIndex++] = b64_index_table[rawChunk[0] >> 2]; + if (read == 1) + { + buf[bufIndex++] = b64_index_table[(rawChunk[0] & 0x03) << 4]; + buf[bufIndex++] = '='; + } + else + { + buf[bufIndex++] = b64_index_table[((rawChunk[0] & 0x03) << 4) | (rawChunk[1] >> 4)]; + buf[bufIndex++] = b64_index_table[(rawChunk[1] & 0x0f) << 2]; + } + buf[bufIndex++] = '='; + + if (!sendBDAT(smtp, msg, bufIndex, false)) + goto ex; + + if (!altSendData(buf, bufIndex, smtp, msg, false, false, esp_mail_smtp_cmd_undefined, esp_mail_smtp_status_code_0, SMTP_STATUS_UNDEFINED)) + goto ex; + } + } + + ret = true; + + if (report) + uploadReport(data_info.filename, addr, 100); + +ex: + // release memory + freeMem(&buf); + freeMem(&rawChunk); + + if (!ret) + closeChunk(data_info); + + return ret; +} + +void ESP_Mail_Client::getBuffer(bool base64, uint8_t *out, uint8_t *in, int &encodedCount, int &bufIndex, bool &dataReady, int &size, size_t chunkSize) +{ + if (base64) + { + size = 0; + out[bufIndex++] = b64_index_table[in[0] >> 2]; + out[bufIndex++] = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + out[bufIndex++] = b64_index_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + out[bufIndex++] = b64_index_table[in[2] & 0x3f]; + + encodedCount += 4; + + if (encodedCount == BASE64_CHUNKED_LEN) + { + if (bufIndex + 1 < (int)chunkSize) + { + out[bufIndex++] = 0x0d; + out[bufIndex++] = 0x0a; + } + encodedCount = 0; + } + + dataReady = bufIndex >= (int)chunkSize - 4; + } + else + { + memcpy(out + bufIndex, in, size); + bufIndex += size; + + if (bufIndex + 1 == BASE64_CHUNKED_LEN) + { + if (bufIndex + 2 < (int)chunkSize) + { + out[bufIndex++] = 0x0d; + out[bufIndex++] = 0x0a; + } + } + + dataReady = bufIndex + 1 >= (int)chunkSize - size; + } +} + +MB_FS *ESP_Mail_Client::getMBFS() +{ + return mbfs; +} + +SMTPSession::SMTPSession(Client *client) +{ + setClient(client); +} + +SMTPSession::SMTPSession() +{ +} + +SMTPSession::~SMTPSession() +{ + closeSession(); +} + +bool SMTPSession::connect(Session_Config *session_config, bool login) +{ + _sessionSSL = false; + _sessionLogin = login; + + if (session_config) + session_config->clearPorts(); + + this->_customCmdResCallback = NULL; + + int ptr = toAddr(*session_config); + session_config->addPtr(&_configPtrList, ptr); + + if (!handleConnection(session_config, _sessionSSL)) + return false; + + if (!_sessionLogin) + return true; + + _loginStatus = MailClient.smtpAuth(this, _sessionSSL); + + return _loginStatus; +} + +bool SMTPSession::mLogin(MB_StringPtr email, MB_StringPtr password, bool isToken) +{ + if (_loginStatus) + return true; + + if (!MailClient.sessionExisted(this)) + return false; + + _session_cfg->login.email = email; + + _session_cfg->login.accessToken.clear(); + _session_cfg->login.password.clear(); + + if (isToken) + _session_cfg->login.accessToken = password; + else + _session_cfg->login.password = password; + + _loginStatus = MailClient.smtpAuth(this, _sessionSSL); + + return _loginStatus; +} + +bool SMTPSession::isAuthenticated() +{ + return _authenticated; +} + +bool SMTPSession::isLoggedIn() +{ + return _loginStatus; +} + +int SMTPSession::customConnect(Session_Config *session_config, smtpResponseCallback callback, int commandID) +{ + this->_customCmdResCallback = callback; + + if (commandID > -1) + this->_commandID = commandID; + else + this->_commandID++; + + bool ssl = false; + if (!handleConnection(session_config, ssl)) + return -1; + + return this->_responseStatus.statusCode; +} + +bool SMTPSession::handleConnection(Session_Config *session_config, bool &ssl) +{ + _session_cfg = session_config; + + if (!client.isInitialized()) + return MailClient.handleSMTPError(this, TCP_CLIENT_ERROR_NOT_INITIALIZED); + + // Resources are also released if network disconnected. + if (!MailClient.reconnect(this)) + return false; + + // Close previous connection first to free resources. + MailClient.closeTCPSession(this); + + _session_cfg = session_config; + + MailClient.setCert(_session_cfg, _session_cfg->certificate.cert_data); + + ssl = false; + + if (!connect(ssl)) + { + MailClient.closeTCPSession(this); + return false; + } + + return true; +} + +bool SMTPSession::connect(bool &ssl) +{ + if (!MailClient.reconnect(this)) + return false; + + ssl = false; + _secure = true; + bool secureMode = true; + + MB_String s; + + client.rxBufDivider = 16; // minimum rx buffer for smtp status response + client.txBufDivider = 8; // medium tx buffer for faster attachment/inline data transfer + + MailClient.preparePortFunction(_session_cfg, true, _secure, secureMode, ssl); + +#if !defined(SILENT_MODE) + MailClient.printLibInfo(this); +#endif + + MailClient.prepareTime(_session_cfg, this); + + MailClient.setSecure(client, _session_cfg); + + if (!MailClient.beginConnection(_session_cfg, this, secureMode)) + return false; + + // server connected +#if !defined(SILENT_MODE) + if (!_customCmdResCallback) + { + + MailClient.printDebug(this, + esp_mail_dbg_str_4 /* "SMTP server connected" */, + esp_mail_cb_str_12 /* "SMTP server connected, wait for greeting..." */, + esp_mail_debug_tag_type_client, + true, + false); + } +#endif + + client.setTimeout(tcpTimeout); + + // expected success status code 220 for ready to service + // expected failure status code 421 + if (!MailClient.handleSMTPResponse(this, esp_mail_smtp_cmd_initial_state, esp_mail_smtp_status_code_220, SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED)) + return false; + + return true; +} + +int SMTPSession::mSendCustomCommand(MB_StringPtr cmd, smtpResponseCallback callback, int commandID) +{ + _customCmdResCallback = callback; + + if (commandID > -1) + _commandID = commandID; + else + _commandID++; + + MB_String _cmd = cmd; + + if (MailClient.smtpSend(this, _cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return -1; + + if (!MailClient.handleSMTPResponse(this, esp_mail_smtp_cmd_custom, esp_mail_smtp_status_code_0, SMTP_STATUS_SEND_CUSTOM_COMMAND_FAILED)) + return -1; + + bool tlsCmd = false; + for (int i = esp_mail_auth_capability_plain; i < esp_mail_auth_capability_maxType; i++) + { + if (MailClient.strposP(_cmd.c_str(), smtp_auth_capabilities[i].text, 0) > -1) + { + if (i == esp_mail_auth_capability_starttls) + tlsCmd = true; + else + _waitForAuthenticate = true; + } + } + + if (MailClient.strposP(_cmd.c_str(), smtp_commands[esp_mail_smtp_command_quit].text, 0, false) > -1) + { + _authenticated = false; + _waitForAuthenticate = false; + } + + if (_waitForAuthenticate && _responseStatus.statusCode == esp_mail_smtp_status_code_235) + { + _authenticated = true; + _waitForAuthenticate = false; + _loginStatus = true; + } + + if (tlsCmd) + { + bool verify = false; + + if (_session_cfg) + verify = _session_cfg->certificate.verify; + + if (!client.connectSSL(verify)) + return false; + + // set the secure mode + if (_session_cfg) + { + // We reset the prefer connection mode in case user set it. + _session_cfg->secure.startTLS = false; + _session_cfg->secure.mode = esp_mail_secure_mode_undefined; + } + + _secure = true; + } + + return this->_responseStatus.statusCode; +} + +bool SMTPSession::mSendData(MB_StringPtr data) +{ + + MB_String _data = data; + + if (MailClient.smtpSend(this, _data.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + return true; +} + +bool SMTPSession::mSendData(uint8_t *data, size_t size) +{ + + if (MailClient.smtpSend(this, data, size) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) + return false; + + return true; +} + +void SMTPSession::debug(int level) +{ + if (level > esp_mail_debug_level_none) + { + if (level > esp_mail_debug_level_basic && level < esp_mail_debug_level_maintainer) + level = esp_mail_debug_level_basic; + _debugLevel = level; + _debug = true; + client.setDebugLevel(level); + } + else + { + _debugLevel = esp_mail_debug_level_none; + _debug = false; + client.setDebugLevel(0); + } +} + +String SMTPSession::errorReason() +{ + String s = MailClient.errorReason(true, _responseStatus.errorCode, ""); + return s; +} + +int SMTPSession::statusCode() +{ + return _responseStatus.statusCode; +} + +String SMTPSession::statusMessage() +{ + return _responseStatus.text.c_str(); +} + +int SMTPSession::errorCode() +{ + return _responseStatus.errorCode; +} + +bool SMTPSession::closeSession() +{ + + if (!connected()) + return false; + + _cbData._sentSuccess = _sentSuccessCount; + _cbData._sentFailed = _sentFailedCount; + +#if !defined(SILENT_MODE) + MailClient.printDebug(this, + esp_mail_cb_str_7 /* "Closing the session..." */, + esp_mail_dbg_str_11 /* "terminate the SMTP session" */, + esp_mail_debug_tag_type_client, + true, + false); +#endif + + bool ret = true; + + if (_loginStatus) + { + +/* Sign out */ +#if !defined(ESP8266) + + // QUIT command asks SMTP server to close the TCP session. + // The connection may drop immediately. + + // There is memory leaks bug in ESP8266 BearSSLWiFiClientSecure class when the remote server + // drops the connection. + + ret = MailClient.smtpSend(this, smtp_commands[esp_mail_smtp_command_quit].text, true) > 0; + + // This may return false due to connection drops before get any response. + + // expected success status code 221 + // expected error status code 500 + MailClient.handleSMTPResponse(this, esp_mail_smtp_cmd_logout, esp_mail_smtp_status_code_221, SMTP_STATUS_SEND_BODY_FAILED); + + if (_responseStatus.statusCode == esp_mail_smtp_status_code_500) + return false; +#endif + + if (ret) + { + +#if !defined(SILENT_MODE) + if (_sentSuccessCount > 0) + { + MailClient.printDebug(this, + esp_mail_cb_str_13 /* "Message sent successfully" */, + esp_mail_dbg_str_12 /* "message sent successfully" */, + esp_mail_debug_tag_type_client, + true, + false); + } + + if (_statusCallback) + MailClient.callBackSendNewLine(this, true); +#endif + + _authenticated = false; + _waitForAuthenticate = false; + } + } + +#if !defined(SILENT_MODE) + if (_statusCallback) + sendingResult.clear(); +#endif + + return MailClient.handleSMTPError(this, 0, ret); +} + +bool SMTPSession::connected() +{ + return client.connected(); +} + +void SMTPSession::callback(smtpStatusCallback smtpCallback) +{ + _statusCallback = smtpCallback; +} + +SMTP_Status SMTPSession::status() +{ + return _cbData; +} + +void SMTPSession::setSystemTime(time_t ts, float gmtOffset) +{ + MailClient.Time.setTimestamp(ts, gmtOffset); +} + +void SMTPSession::keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount) +{ + this->client.keepAlive(tcpKeepIdleSeconds, tcpKeepIntervalSeconds, tcpKeepCount); +} + +bool SMTPSession::isKeepAlive() +{ + return this->client.isKeepAlive(); +} + +void SMTPSession::setTCPTimeout(unsigned long timeoutSec) +{ + tcpTimeout = timeoutSec; +} + +void SMTPSession::setClient(Client *client) +{ + this->client.setClient(client); +} + +void SMTPSession::setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password) +{ + this->client.setGSMClient(client, modem, pin, apn, user, password); +} + +void SMTPSession::networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB) +{ + this->client.networkConnectionRequestCallback(networkConnectionCB); +} + +void SMTPSession::networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB) +{ + this->client.networkStatusRequestCallback(networkStatusCB); +} + +void SMTPSession::setNetworkStatus(bool status) +{ + this->client.setNetworkStatus(status); + MailClient.networkStatus = status; +} + +void SMTPSession::setSSLBufferSize(int rx, int tx) +{ + this->client.setIOBufferSize(rx, tx); +} + +SMTP_Status::SMTP_Status() +{ +} + +SMTP_Status::~SMTP_Status() +{ + empty(); +} + +const char *SMTP_Status::info() +{ + return _info.c_str(); +} + +bool SMTP_Status::success() +{ + return _success; +} + +size_t SMTP_Status::completedCount() +{ + return _sentSuccess; +} + +size_t SMTP_Status::failedCount() +{ + return _sentFailed; +} + +void SMTP_Status::empty() +{ + _info.clear(); +} + +#endif + +#endif /* ESP_MAIL_SMTP_H */ diff --git a/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_TCPClient.h b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_TCPClient.h new file mode 100644 index 000000000..9302f6d4e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/ESP_Mail_TCPClient.h @@ -0,0 +1,1093 @@ +/** + * + * The Network Upgradable Arduino Secure TCP Client Class, ESP_Mail_TCPClient.h v1.0.1 + * + * Created August 27, 2023 + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ESP_MAIL_TCPCLIENT_H +#define ESP_MAIL_TCPCLIENT_H + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" + +#include "ESP_Mail_Const.h" + +#if defined(ESP32) && (defined(ENABLE_SMTP) || defined(ENABLE_IMAP)) +#include "IPAddress.h" +#include "lwip/sockets.h" +#endif + +#if defined(ESP32) + +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) +#define WIFI_HAS_HOST_BY_NAME +#endif +#include "extras/WiFiClientImpl.h" +#define BASE_WIFICLIENT WiFiClientImpl + +#elif defined(ESP_MAIL_WIFI_IS_AVAILABLE) +#include "WiFiClient.h" +#define BASE_WIFICLIENT WiFiClient +#endif + +#include "SSLClient/ESP_SSLClient.h" + +class ESP_Mail_TCPClient +{ +public: + ESP_Mail_TCPClient() + { +#if !defined(ESP_MAIL_DISABLE_SSL) + _tcp_client = new ESP_SSLClient(); +#endif + } + + ~ESP_Mail_TCPClient() + { + clear(); +#if !defined(ESP_MAIL_DISABLE_SSL) + if (_tcp_client) + delete _tcp_client; + _tcp_client = nullptr; +#endif + } + + /** + * Set the client. + * @param client The Client interface. + */ + void setClient(Client *client) + { + clear(); + _basic_client = client; + _client_type = esp_mail_client_type_external_basic_client; + } + + /** Assign TinyGsm Clients. + * + * @param client The pointer to TinyGsmClient. + * @param modem The pointer to TinyGsm modem object. Modem should be initialized and/or set mode before transfering data + * @param pin The SIM pin. + * @param apn The GPRS APN (Access Point Name). + * @param user The GPRS user. + * @param password The GPRS password. + */ + void setGSMClient(Client *client, void *modem = nullptr, const char *pin = nullptr, const char *apn = nullptr, const char *user = nullptr, const char *password = nullptr) + { +#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE) + _pin = pin; + _apn = apn; + _user = user; + _password = password; + _modem = modem; + _client_type = esp_mail_client_type_external_gsm_client; + _basic_client = client; +#endif + } + + /** + * Set Root CA certificate to verify. + * @param caCert The certificate. + */ + void setCACert(const char *caCert) + { +#if !defined(ESP_MAIL_DISABLE_SSL) + if (caCert) + { + if (_x509) + delete _x509; + + _x509 = new X509List(caCert); + _tcp_client->setTrustAnchors(_x509); + + setCertType(esp_mail_cert_type_data); + setTA(true); + } + else + { + setCertType(esp_mail_cert_type_none); + setInSecure(); + } +#endif + } + + /** + * Set Root CA certificate to verify. + * @param certFile The certificate file path. + * @param storageType The storage type mb_fs_mem_storage_type_flash or mb_fs_mem_storage_type_sd. + * @return true when certificate loaded successfully. + */ + bool setCertFile(const char *certFile, mb_fs_mem_storage_type storageType) + { +#if !defined(ESP_MAIL_DISABLE_SSL) + if (!_mbfs) + return false; + + if (_clock_ready && strlen(certFile) > 0) + { + MB_String filename = certFile; + if (filename.length() > 0) + { + if (filename[0] != '/') + filename.prepend('/'); + } + + int len = _mbfs->open(filename, storageType, mb_fs_open_mode_read); + if (len > -1) + { + uint8_t *der = (uint8_t *)_mbfs->newP(len); + if (_mbfs->available(storageType)) + _mbfs->read(storageType, der, len); + _mbfs->close(storageType); + + if (_x509) + delete _x509; + + _x509 = new X509List(der, len); + _tcp_client->setTrustAnchors(_x509); + setTA(true); + _mbfs->delP(&der); + + setCertType(esp_mail_cert_type_file); + } + } +#endif + + return getCertType() == esp_mail_cert_type_file; + } + + /** + * Set TCP connection time out in seconds. + * @param timeoutSec The time out in seconds. + */ + void setTimeout(uint32_t timeoutSec) + { + _tcp_client->setTimeout(timeoutSec); + } + + /** Set the BearSSL IO buffer size. + * + * @param rx The BearSSL receive buffer size in bytes. + * @param tx The BearSSL trasmit buffer size in bytes. + */ + void setIOBufferSize(int rx, int tx) + { + _rx_size = rx; + _tx_size = tx; + } + + /** + * Get the ethernet link status. + * @return true for link up or false for link down. + */ + bool ethLinkUp() + { + bool ret = false; + +#if !defined(ESP_MAIL_DISABLE_NATIVE_ETHERNET) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + +#if defined(ESP_MAIL_ETH_IS_AVAILABLE) + +#if defined(ESP32) + if (validIP(ETH.localIP())) + { + ETH.linkUp(); + ret = true; + } +#elif defined(ESP8266) + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + if (!_session_config) + return false; +#endif + +#if defined(ESP8266) && defined(ESP8266_CORE_SDK_V3_X_X) + +#if defined(INC_ENC28J60_LWIP) + if (_session_config->spi_ethernet_module.enc28j60) + { + ret = _session_config->spi_ethernet_module.enc28j60->status() == WL_CONNECTED; + goto ex; + } +#endif +#if defined(INC_W5100_LWIP) + if (_session_config->spi_ethernet_module.w5100) + { + ret = _session_config->spi_ethernet_module.w5100->status() == WL_CONNECTED; + goto ex; + } +#endif +#if defined(INC_W5500_LWIP) + if (_session_config->spi_ethernet_module.w5500) + { + ret = _session_config->spi_ethernet_module.w5500->status() == WL_CONNECTED; + goto ex; + } +#endif +#elif defined(MB_ARDUINO_PICO) + +#endif + + return ret; + +#if defined(INC_ENC28J60_LWIP) || defined(INC_W5100_LWIP) || defined(INC_W5500_LWIP) + ex: +#endif + // workaround for ESP8266 Ethernet + delayMicroseconds(0); +#endif + +#endif + +#endif + + return ret; + } + + /** + * Checking for valid IP. + * @return true for valid. + */ + bool validIP(IPAddress ip) + { + char buf[16]; + sprintf(buf, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); + return strcmp(buf, "0.0.0.0") != 0; + } + + /** + * Ethernet DNS workaround. + */ + void ethDNSWorkAround() + { + +#if !defined(ESP_MAIL_DISABLE_NATIVE_ETHERNET) && (defined(ENABLE_SMTP) || defined(ENABLE_IMAP)) + if (!_session_config) + return; + +#if defined(ESP8266_CORE_SDK_V3_X_X) + +#if defined(INC_ENC28J60_LWIP) + if (_session_config->spi_ethernet_module.enc28j60) + goto ex; +#endif +#if defined(INC_W5100_LWIP) + if (_session_config->spi_ethernet_module.w5100) + goto ex; +#endif +#if defined(INC_W5500_LWIP) + if (_session_config->spi_ethernet_module.w5500) + goto ex; +#endif + +#elif defined(MB_ARDUINO_PICO) + +#endif + + return; + +#if defined(INC_ENC28J60_LWIP) || defined(INC_W5100_LWIP) || defined(INC_W5500_LWIP) + ex: +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) + BASE_WIFICLIENT client; + client.connect(_session_config->server.host_name.c_str(), _session_config->server.port); + client.stop(); +#endif +#endif + +#endif + } + + /** + * Get the network status. + * @return true for connected or false for not connected. + */ + bool networkReady() + { + + // We will not invoke the network status request when device has built-in WiFi or Ethernet and it is connected. + if (_client_type == esp_mail_client_type_external_gsm_client) + { + _network_status = gprsConnected(); + if (!_network_status) + gprsConnect(); + } + else if (WiFI_CONNECTED || ethLinkUp()) + _network_status = true; + else if (_client_type == esp_mail_client_type_external_basic_client) + { + if (!_network_status_cb) + _last_error = 1; + else + _network_status_cb(); + } + + return _network_status; + } + + /** + * Reconnect the network. + */ + void networkReconnect() + { + + if (_client_type == esp_mail_client_type_external_basic_client) + { +#if defined(ESP_MAIL_HAS_WIFI_DISCONNECT) + // We can reconnect WiFi when device connected via built-in WiFi that supports reconnect + if (WiFI_CONNECTED) + { + WiFi.reconnect(); + return; + } + +#endif + + if (_network_connection_cb) + _network_connection_cb(); + } + else if (_client_type == esp_mail_client_type_external_gsm_client) + { + gprsDisconnect(); + gprsConnect(); + } + else if (_client_type == esp_mail_client_type_internal_basic_client) + { + +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) +#if defined(ESP32) || defined(ESP8266) + WiFi.reconnect(); +#else + if (_wifi_multi && _wifi_multi->credentials.size()) + _wifi_multi->reconnect(); +#endif +#endif + } + } + + /** + * Disconnect the network. + */ + void networkDisconnect() {} + + /** + * Get the Client type. + * @return The esp_mail_client_type enum value. + */ + esp_mail_client_type type() { return _client_type; } + + /** + * Get the Client initialization status. + * @return The initialization status. + */ + bool isInitialized() + { + bool rdy = true; +#if !defined(ESP_MAIL_WIFI_IS_AVAILABLE) + if (_client_type == esp_mail_client_type_external_basic_client && + (!_network_connection_cb || !_network_status_cb)) + rdy = false; + else if (_client_type != esp_mail_client_type_external_basic_client || + _client_type != esp_mail_client_type_external_gsm_client) + rdy = false; +#else + // assume external client is WiFiClient and network status request callback is not required + // when device was connected to network using on board WiFi + if (_client_type == esp_mail_client_type_external_basic_client && + (!_network_connection_cb || (!_network_status_cb && !WiFI_CONNECTED && !ethLinkUp()))) + { + rdy = false; + } + +#endif + + if (!rdy) + { +#if !defined(SILENT_MODE) && (defined(ENABLE_SMTP) || defined(ENABLE_IMAP)) + if (_debug_level > 0) + { + if (!_network_connection_cb) + esp_mail_debug_print_tag(esp_mail_error_client_str_2 /* "network connection callback is required" */, esp_mail_debug_tag_type_error, true); + if (!WiFI_CONNECTED && !ethLinkUp()) + { + if (!_network_status_cb) + esp_mail_debug_print_tag(esp_mail_error_client_str_3 /* "network connection status callback is required" */, esp_mail_debug_tag_type_error, true); + } + } +#endif + } + + return rdy; + } + + /** + * Set Root CA certificate to verify. + * @param name The host name. + * @param ip The ip address result. + * @return 1 for success or 0 for failed. + */ + int hostByName(const char *name, IPAddress &ip) + { +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) + return WiFi.hostByName(name, ip); +#else + return 1; +#endif + } + + /** + * Store the host name and port. + * @param host The host name to connect. + * @param port The port to connect. + * @return true. + */ + bool begin(const char *host, uint16_t port) + { + _host = host; + _port = port; +#if !defined(ESP_MAIL_DISABLE_SSL) + _tcp_client->setBufferSizes(_rx_size >= _minRXTXBufSize && _rx_size <= _maxRXBufSize ? _rx_size : _maxRXBufSize / rxBufDivider, + _tx_size >= _minRXTXBufSize && _tx_size <= _maxTXBufSize ? _tx_size : _maxTXBufSize / txBufDivider); +#endif + _last_error = 0; + return true; + } + + /** + * Start TCP connection using stored host name and port. + * @param secure The secure mode option. + * @param verify The Root CA certificate verification option. + * @return true for success or false for error. + */ + + bool connect(bool secured, bool verify) + { + bool ret = false; + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + _last_error = 0; + +#if !defined(ESP_MAIL_DISABLE_SSL) + _tcp_client->enableSSL(secured); + setSecure(secured); + setVerify(verify); +#endif + + if (connected()) + { + flush(); + return true; + } + + if (!_basic_client) + { + if (_client_type == esp_mail_client_type_external_basic_client) + { + _last_error = 1; + return false; + } + else if (_client_type != esp_mail_client_type_external_gsm_client) + { +// Device has no built-in WiFi, external client required. +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) + _basic_client = new BASE_WIFICLIENT(); + _client_type = esp_mail_client_type_internal_basic_client; +#else + _last_error = 1; + return false; +#endif + } + } + +#if defined(ESP_MAIL_DISABLE_SSL) + _tcp_client = _basic_client; +#else + _tcp_client->setClient(_basic_client); +#endif + + if (!_tcp_client->connect(_host.c_str(), _port)) + return false; + +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) && (defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO)) + if (_client_type == esp_mail_client_type_internal_basic_client) + reinterpret_cast(_basic_client)->setNoDelay(true); +#endif + + // For TCP keepalive should work in ESP8266 core > 3.1.2. + // https://github.com/esp8266/Arduino/pull/8940 + + // Not currently supported by WiFiClientSecure in Arduino Pico core + + if (_client_type == esp_mail_client_type_internal_basic_client) + { + if (isKeepAliveSet()) + { +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) + +#if defined(ESP8266) + if (_tcpKeepIdleSeconds == 0 || _tcpKeepIntervalSeconds == 0 || _tcpKeepCount == 0) + reinterpret_cast(_basic_client)->disableKeepAlive(); + else + reinterpret_cast(_basic_client)->keepAlive(_tcpKeepIdleSeconds, _tcpKeepIntervalSeconds, _tcpKeepCount); + +#elif defined(ESP32) + + if (_tcpKeepIdleSeconds == 0 || _tcpKeepIntervalSeconds == 0 || _tcpKeepCount == 0) + { + _tcpKeepIdleSeconds = 0; + _tcpKeepIntervalSeconds = 0; + _tcpKeepCount = 0; + } + + bool success = setOption(TCP_KEEPIDLE, &_tcpKeepIdleSeconds) > -1 && + setOption(TCP_KEEPINTVL, &_tcpKeepIntervalSeconds) > -1 && + setOption(TCP_KEEPCNT, &_tcpKeepCount) > -1; + if (!success) + _isKeepAlive = false; +#endif + +#endif + } + } + + ret = connected(); + if (!ret) + stop(); +#endif + return ret; + } + + /** + * Upgrade the current connection by setting up the SSL and perform the SSL handshake. + * + * @param verify The Root CA certificate verification option + * @return operating result. + */ + + bool connectSSL(bool verify) + { +#if !defined(ESP_MAIL_DISABLE_SSL) + _tcp_client->setDebugLevel(2); + + bool ret = _tcp_client->connected(); + + if (ret) + { + setVerify(verify); + ret = _tcp_client->connectSSL(_host.c_str(), _port); + if (ret) + _secured = true; + } + + if (!ret) + stop(); + + return ret; +#endif + return false; + } + + /** + * Stop TCP connection. + */ + void stop() + { + if (_tcp_client) + _tcp_client->stop(); + } + + /** + * Get the TCP connection status. + * @return true for connected or false for not connected. + */ + bool connected() { return _tcp_client && _tcp_client->connected(); }; + + /** + * The TCP data write function. + * @param data The data to write. + * @param len The length of data to write. + * @return The size of data that was successfully written or 0 for error. + */ + int write(uint8_t *data, int len) + { + if (!_tcp_client) + return TCP_CLIENT_ERROR_NOT_INITIALIZED; + + if (!data) + return TCP_CLIENT_ERROR_SEND_DATA_FAILED; + + if (len == 0) + return TCP_CLIENT_ERROR_SEND_DATA_FAILED; + + if (!networkReady()) + return TCP_CLIENT_ERROR_NOT_CONNECTED; + + if (!connect(isSecure(), isVerify())) + return TCP_CLIENT_ERROR_CONNECTION_REFUSED; + + int toSend = _chunkSize; + int sent = 0; + while (sent < len) + { + if (sent + toSend > len) + toSend = len - sent; + + if ((int)_tcp_client->write(data + sent, toSend) != toSend) + return TCP_CLIENT_ERROR_SEND_DATA_FAILED; + + sent += toSend; + } + + return len; + } + + /** + * The TCP data send function. + * @param data The data to send. + * @return The size of data that was successfully sent or 0 for error. + */ + int send(const char *data) { return write((uint8_t *)data, strlen(data)); } + + /** + * The TCP data print function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int print(const char *data) { return send(data); } + + /** + * The TCP data print function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int print(int data) + { + char buf[64]; + memset(buf, 0, 64); + sprintf(buf, (const char *)FPSTR("%d"), data); + int ret = send(buf); + return ret; + } + + /** + * The TCP data print with new line function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int println(const char *data) + { + int len = send(data); + if (len < 0) + return len; + int sz = send((const char *)FPSTR("\r\n")); + if (sz < 0) + return sz; + return len + sz; + } + + /** + * The TCP data print with new line function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int println(int data) + { + char buf[64]; + memset(buf, 0, 64); + sprintf(buf, (const char *)FPSTR("%d\r\n"), data); + int ret = send(buf); + return ret; + } + + /** + * Get available data size to read. + * @return The avaiable data size. + */ + int available() + { + if (!_basic_client) + return TCP_CLIENT_ERROR_NOT_INITIALIZED; + + return _tcp_client->available(); + } + + /** + * The TCP data read function. + * @return The read value or -1 for error. + */ + int read() + { + if (!_basic_client) + return TCP_CLIENT_ERROR_NOT_INITIALIZED; + + return _tcp_client->read(); + } + + /** + * The TCP data read function. + * @param buf The data buffer. + * @param len The length of data that read. + * @return The size of data that was successfully read or negative value for error. + */ + int readBytes(uint8_t *buf, int len) + { + if (!_basic_client) + return TCP_CLIENT_ERROR_NOT_INITIALIZED; + + return _tcp_client->read(buf, len); + } + + /** + * The TCP data read function. + * @param buf The data buffer. + * @param len The length of data that read. + * @return The size of data that was successfully read or negative value for error. + */ + int readBytes(char *buf, int len) + { + return readBytes((uint8_t *)buf, len); + } + + /** + * Wait for all receive buffer data read. + */ + void flush() + { + if (_tcp_client) + _tcp_client->flush(); + } + + /** + * Set the network connection request callback. + * @param networkConnectionCB The callback function that handles the network connection. + */ + void networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB) + { + _network_connection_cb = networkConnectionCB; + } + + /** + * Set the network status request callback. + * @param networkStatusCB The callback function that calls the setNetworkStatus function to set the network status. + */ + void networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB) + { + _network_status_cb = networkStatusCB; + } + + /** + * Set the network status which should call in side the networkStatusRequestCallback function. + * @param status The status of network. + */ + void setNetworkStatus(bool status) + { + _network_status = status; + } + + void setMBFS(MB_FS *mbfs) { _mbfs = mbfs; } + +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + void setSession(Session_Config *session_config) + { + _session_config = session_config; + } +#endif + + void setClockReady(bool rdy) + { + _clock_ready = rdy; + } + + void setCertType(esp_mail_cert_type type) { _cert_type = type; } + + esp_mail_cert_type getCertType() { return _cert_type; } + + void setDebugLevel(int debug) { _debug_level = debug; } + + unsigned long tcpTimeout() + { + if (_tcp_client) + return 1000 * _tcp_client->getTimeout(); + return 0; + } + + void disconnect(){}; + + void keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount) + { + _tcpKeepIdleSeconds = tcpKeepIdleSeconds; + _tcpKeepIntervalSeconds = tcpKeepIntervalSeconds; + _tcpKeepCount = tcpKeepCount; + _isKeepAlive = tcpKeepIdleSeconds > 0 && tcpKeepIntervalSeconds > 0 && tcpKeepCount > 0; + } + + bool isKeepAliveSet() { return _tcpKeepIdleSeconds > -1 && _tcpKeepIntervalSeconds > -1 && _tcpKeepCount > -1; }; + + bool isKeepAlive() { return _isKeepAlive; }; + + void clear() + { +#if !defined(ESP_MAIL_DISABLE_SSL) + if (_basic_client && _client_type == esp_mail_client_type_internal_basic_client) + { +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) + delete (BASE_WIFICLIENT *)_basic_client; +#else + delete _basic_client; +#endif + _basic_client = nullptr; + } +#else + _basic_client = nullptr; +#endif + _client_type = esp_mail_client_type_undefined; + } + + void setWiFi(esp_mail_wifi_credentials_t *wifi) { _wifi_multi = wifi; } + + bool gprsConnect() + { +#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE) + TinyGsm *gsmModem = (TinyGsm *)_modem; + if (gsmModem) + { + // Unlock your SIM card with a PIN if needed + if (_pin.length() && gsmModem->getSimStatus() != 3) + gsmModem->simUnlock(_pin.c_str()); + +#if defined(TINY_GSM_MODEM_XBEE) + // The XBee must run the gprsConnect function BEFORE waiting for network! + gsmModem->gprsConnect(_apn.c_str(), _user.c_str(), _password.c_str()); +#endif + +#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + if (_debug_level > 0 && _last_error == 0) + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR("Waiting for network..."), esp_mail_debug_tag_type_info, false); +#endif + if (!gsmModem->waitForNetwork()) + { +#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + if (_debug_level > 0 && _last_error == 0) + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR(" fail"), esp_mail_debug_tag_type_info, true, false); +#endif + _last_error = 1; + _network_status = false; + return false; + } + +#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + if (_debug_level > 0 && _last_error == 0) + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR(" success"), esp_mail_debug_tag_type_info, true, false); +#endif + + if (gsmModem->isNetworkConnected()) + { +#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + if (_debug_level > 0 && _last_error == 0) + { + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR("Connecting to "), esp_mail_debug_tag_type_info, false); + esp_mail_debug_print_tag(_apn.c_str(), esp_mail_debug_tag_type_info, false, false); + } +#endif + _network_status = gsmModem->gprsConnect(_apn.c_str(), _user.c_str(), _password.c_str()) && + gsmModem->isGprsConnected(); + +#if !defined(SILENT_MODE) && (defined(ENABLE_IMAP) || defined(ENABLE_SMTP)) + if (_debug_level > 0 && _last_error == 0) + { + if (_network_status) + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR(" success"), esp_mail_debug_tag_type_info, true, false); + else + esp_mail_debug_print_tag((const char *)MBSTRING_FLASH_MCR(" fail"), esp_mail_debug_tag_type_info, true, false); + } +#endif + } + + if (!_network_status) + _last_error = 1; + + return _network_status; + } + +#endif + return false; + } + + bool gprsConnected() + { +#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE) + TinyGsm *gsmModem = (TinyGsm *)_modem; + _network_status = gsmModem && gsmModem->isGprsConnected(); +#endif + return _network_status; + } + + bool gprsDisconnect() + { +#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE) + TinyGsm *gsmModem = (TinyGsm *)_modem; + _network_status = gsmModem && gsmModem->gprsDisconnect(); +#endif + return !_network_status; + } + + bool gprsGetTime(int &year, int &month, int &day, int &hour, int &min, int &sec, float &timezone) + { +#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE) && defined(TINY_GSM_MODEM_HAS_TIME) + + if (!gprsConnected()) + return 0; + + TinyGsm *gsmModem = (TinyGsm *)_modem; + year = 0; + month = 0; + day = 0; + hour = 0; + min = 0; + sec = 0; + timezone = 0; + for (int8_t i = 5; i; i--) + { + if (gsmModem->getNetworkTime(&year, &month, &day, &hour, &min, &sec, &timezone)) + { + return true; + } + } +#endif + return false; + } + + int setOption(int option, int *value) + { +#if defined(ESP32) && defined(ESP_MAIL_WIFI_IS_AVAILABLE) + // Actually we wish to use setSocketOption directly but it is ambiguous in old ESP32 core v1.0.x.; + // Use setOption instead for old core support. + return reinterpret_cast(_basic_client)->setOption(option, value); +#endif + return 0; + } + + void setTA(bool hasTA) + { + _has_ta = hasTA; + } + + void setSecure(bool secure) + { + _secured = secure; + } + + void setInSecure() + { +#if !defined(ESP_MAIL_DISABLE_SSL) + _use_insecure = true; + setTA(false); +#endif + } + + void setVerify(bool verify) + { +#if !defined(ESP_MAIL_DISABLE_SSL) + if (_has_ta) + _use_insecure = !verify; + + if (_use_insecure) + _tcp_client->setInsecure(); +#endif + } + + bool isSecure() + { + return _secured; + } + + bool isVerify() + { + return !_use_insecure; + } + + int rxBufDivider = 16; + int txBufDivider = 32; + +private: + // lwIP TCP Keepalive idle in seconds. + int _tcpKeepIdleSeconds = -1; + // lwIP TCP Keepalive interval in seconds. + int _tcpKeepIntervalSeconds = -1; + // lwIP TCP Keepalive count. + int _tcpKeepCount = -1; + bool _isKeepAlive = false; + + uint16_t _bsslRxSize = 1024; + uint16_t _bsslTxSize = 1024; + const int _maxRXBufSize = 16384; // SSL full supported 16 kB + const int _maxTXBufSize = 16384; + const int _minRXTXBufSize = 512; +#if defined(ESP_MAIL_DISABLE_SSL) + Client *_tcp_client = nullptr; +#else + ESP_SSLClient *_tcp_client = nullptr; + X509List *_x509 = nullptr; +#endif + + MB_String _host; + uint16_t _port = 443; + + MB_FS *_mbfs = nullptr; + Client *_basic_client = nullptr; + esp_mail_wifi_credentials_t *_wifi_multi = nullptr; +#if defined(ENABLE_SMTP) || defined(ENABLE_IMAP) + Session_Config *_session_config = nullptr; +#endif + NetworkConnectionRequestCallback _network_connection_cb = NULL; + NetworkStatusRequestCallback _network_status_cb = NULL; +#if defined(ESP_MAIL_HAS_WIFIMULTI) + WiFiMulti *_multi = nullptr; +#endif +#if defined(ESP_MAIL_GSM_MODEM_IS_AVAILABLE) + MB_String _pin, _apn, _user, _password; + void *_modem = nullptr; +#endif + + bool _has_ta = false; + bool _secured = false; + bool _use_insecure = false; + int _debug_level = 0; + int _chunkSize = 1024; + bool _clock_ready = false; + int _last_error = 0; + volatile bool _network_status = false; + int _rx_size = -1, _tx_size = -1; + + esp_mail_cert_type _cert_type = esp_mail_cert_type_undefined; + esp_mail_client_type _client_type = esp_mail_client_type_undefined; +}; + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/HeapStat.h b/lib/libesp32/ESP-Mail-Client/src/HeapStat.h new file mode 100644 index 000000000..c6ed4e865 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/HeapStat.h @@ -0,0 +1,146 @@ +/** Memory usage info for debugging purpose + +#include "HeapStat.h" + +HeapStat heapInfo; + +void setup() +{ + Serial.begin(115200); +} + +void loop() +{ + // Other codes here + + // Collect memory info + heapInfo.collect(); + + // Print memory info + heapInfo.print(); + +} + +*/ + +#ifndef HEAP_STAT_H +#define HEAP_STAT_H + +#if defined(ESP8266) || defined(ESP32) +#ifndef MB_ARDUINO_ESP +#define MB_ARDUINO_ESP +#endif +#endif + +#if defined(ARDUINO_ARCH_RP2040) + +#if defined(ARDUINO_NANO_RP2040_CONNECT) +#ifndef MB_ARDUINO_NANO_RP2040_CONNECT +#define MB_ARDUINO_NANO_RP2040_CONNECT +#endif +#else +#ifndef MB_ARDUINO_PICO +#define MB_ARDUINO_PICO +#endif +#endif + +#endif + +#include "ESP_Mail_Client.h" + +class HeapStat +{ +private: + int current_heap = 0; + int first_round_heap = 0; + int min_heap = 0; + int max_heap = 0; + int diff_heap_from_first_round = 0; + int diff_heap_from_current_round = 0; + int _count = 0; + + int getFreeHeap() + { +#if defined(MB_ARDUINO_ESP) + return ESP.getFreeHeap(); +#elif defined(MB_ARDUINO_PICO) + return rp2040.getFreeHeap(); +#else + return 0; +#endif + } + +public: + HeapStat() {} + ~HeapStat() {} + + void reset() + { + current_heap = 0; + first_round_heap = 0; + min_heap = 0; + max_heap = 0; + diff_heap_from_first_round = 0; + diff_heap_from_current_round = 0; + _count = 0; + } + + void collect() + { + _count++; + + if (max_heap < getFreeHeap()) + max_heap = getFreeHeap(); + + if (min_heap == 0 || min_heap > getFreeHeap()) + min_heap = getFreeHeap(); + + if (first_round_heap == 0) + first_round_heap = getFreeHeap(); + + if (current_heap > 0) + { + diff_heap_from_first_round = getFreeHeap() - first_round_heap; + diff_heap_from_current_round = getFreeHeap() - current_heap; + } + + current_heap = getFreeHeap(); + } + + int current() + { + return current_heap; + } + + int min() + { + return min_heap; + } + + int max() + { + return max_heap; + } + + int diff1() + { + return diff_heap_from_first_round; + } + + int diffN() + { + return diff_heap_from_current_round; + } + + int count() + { + return _count; + } + + void print() + { + MailClient.printf("#### Heap Info\n#### Current: %d, Min: %d, Max: %d, Diff_1: %d, Diff_%d: %d\n", current(), min(), max(), diff1(), count(), diffN()); + } +}; + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/README.md b/lib/libesp32/ESP-Mail-Client/src/README.md new file mode 100644 index 000000000..8fe315876 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/README.md @@ -0,0 +1,3416 @@ +# ESP Mail Client Arduino Library + + +The description of the available functions in the current reease are shown below. + + +## Global functions + + +#### Sending Email through the SMTP server. + +param **`smtp`** The pointer to SMTP session object which holds the data and the TCP client. + +param **`msg`** The pointer to SMTP_Message class which contains the header, body, and attachments. + +param **`closeSession`** The option to Close the SMTP session after sent. + +return **`boolean`** The boolean value indicates the success of operation. + +```cpp +bool sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true); +``` + + + +#### Append message to the mailbox + +param **`imap`** The pointer to IMAP sesssion object which holds the data and the TCP client. + +param **`msg`** The pointer to SMTP_Message class which contains the header, body, and attachments. + +param **`lastAppend`** The last message to append (optional). In case MULTIAPPEND extension + +is supported, set this to false will append messages in single APPEND command. + +param **`flags`** The flags to set to this message. + + param **`dateTime`** The date/time to set to this message (optional). + +return **`boolean`** The boolean value indicates the success of operation. + +```cpp +bool appendMessage(IMAPSession *imap, SMTP_Message *msg, T flags = ""); +``` + + +#### Reading Email through IMAP server. + +param **`imap`** The pointer to IMAP sesssion object which holds the data and the TCP client. + +param **`closeSession`** The option to close the IMAP session after fetching or searching the Email. + +return **`boolean`** The boolean value indicates the success of operation. + +```cpp +bool readMail(IMAPSession *imap, bool closeSession = true); +``` + + + + + +#### Set the argument to the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`msgUID`** The UID of the message. + +param **`flags`** The flag list to set. + +param **`closeSession`** The option to close the IMAP session after set flag. + +param **`silent`** The option to ignore the response. + +param **`modsequence`** The int32_t option for UNCHANGESINCE conditional test. + +return **`boolean`** The boolean value indicates the success of operation. + +The modsequence value can be used only if IMAP server supports Conditional STORE extension and the selected mailbox supports modsequences. + +```cpp +bool setFlag(IMAPSession *imap, int msgUID, flags, bool closeSession, bool silent = false, int32_t modsequence = -1); +``` + + + + + +#### Set the argument to the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`sequenceSet`** The sequence set string i.g., unique identifier (UID) or +message sequence number or ranges of UID or sequence number. + +param **`UID`** The option for sequenceSet whether it is UID or message sequence number. + +param **`flags`** The flag list to set. + +param **`closeSession`** The option to close the IMAP session after set flag. + +param **`silent`** The option to ignore the response. + +param **`modsequence`** The int32_t option for UNCHANGESINCE conditional test. + +return **`boolean`** The boolean value indicates the success of operation. + +The modsequence value can be used only if IMAP server supports Conditional STORE extension and the selected mailbox supports modsequences. + +```cpp +bool setFlag(IMAPSession *imap, sequenceSet, bool UID, flags, bool closeSession, bool silent = false, int32_t modsequence = -1); +``` + + + + + +#### Add the argument to the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`msgUID`** The UID of the message. + +param **`flags`** The flag list to add. + +param **`closeSession`** The option to close the IMAP session after add flag. + +param **`silent`** The option to ignore the response. + +param **`modsequence`** The int32_t option for UNCHANGESINCE conditional test. + +return **`boolean`** The boolean value indicates the success of operation. + +The modsequence value can be used only if IMAP server supports Conditional STORE extension and the selected mailbox supports modsequences. + +```cpp +bool addFlag(IMAPSession *imap, int msgUID, flags, bool closeSession, int32_t modsequence = -1); +``` + + + + + +#### Add the argument to the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`sequenceSet`** The sequence set string i.g., unique identifier (UID) or +message sequence number or ranges of UID or sequence number. + +param **`UID`** The option for sequenceSet whether it is UID or message sequence number. + +param **`flags`** The flag list to add. + +param **`closeSession`** The option to close the IMAP session after set flag. + +param **`silent`** The option to ignore the response. + +param **`modsequence`** The int32_t option for UNCHANGESINCE conditional test. + +return **`boolean`** The boolean value indicates the success of operation. + +The modsequence value can be used only if IMAP server supports Conditional STORE extension and the selected mailbox supports modsequences. + +```cpp +bool addFlag(IMAPSession *imap, sequenceSet, bool UID, flags, bool closeSession, bool silent = false, int32_t modsequence = -1); +``` + + + + + +#### Remove the argument from the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`msgUID`** The UID of the message that flags to be removed. + +param **`flags`** The flag list to remove. + +param **`closeSession`** The option to close the IMAP session after remove flag. + +param **`silent`** The option to ignore the response. + +param **`modsequence`** The int32_t option for UNCHANGESINCE conditional test. + +return **`boolean`** The boolean value indicates the success of operation. + +The modsequence value can be used only if IMAP server supports Conditional STORE extension and the selected mailbox supports modsequences. + +```cpp +bool removeFlag(IMAPSession *imap, int msgUID, flags, bool closeSession, int32_t modsequence = -1); +``` + + + + + +#### Remove the argument from the Flags for the specified message. + +param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. + +param **`sequenceSet`** The sequence set string i.g., unique identifier (UID) or +message sequence number or ranges of UID or sequence number. + +param **`UID`** The option for sequenceSet whether it is UID or message sequence number. + +param **`flags`** The flag list to remove. + +param **`closeSession`** The option to close the IMAP session after set flag. + +param **`silent`** The option to ignore the response. + +param **`modsequence`** The int32_t option for UNCHANGESINCE conditional test. + +return **`boolean`** The boolean value indicates the success of operation. + +The modsequence value can be used only if IMAP server supports Conditional STORE extension and the selected mailbox supports modsequences. + +```cpp +bool removeFlag(IMAPSession *imap, sequenceSet, bool UID, flags, bool closeSession, bool silent = false, int32_t modsequence = -1); +``` + + + + + + +#### Reconnect WiFi or network if lost connection. + +param **`reconnect`** The boolean to set/unset WiFi AP reconnection. + +```cpp +void networkReconnect(bool reconnect); +``` + + + + +#### Initiate SD card with SPI port configuration. + +param **`ss`** The SPI Chip/Slave Select pin. + +param **`sck`** The SPI Clock pin. + +param **`miso`** The SPI MISO pin. + +param **`mosi`** The SPI MOSI pin. + +aram **`frequency`** The SPI frequency. + +return **`boolean`** The boolean value indicates the success of operation. + +```cpp +bool sdBegin(int8_t ss = -1, int8_t sck = -1, int8_t miso = -1, int8_t mosi = -1, uint32_t frequency = 4000000); +``` + + + + + +#### Initiate SD card with SD FS configurations (ESP8266 only). + +param **`ss`** SPI Chip/Slave Select pin. + +param **`sdFSConfig`** The pointer to SDFSConfig object (ESP8266 only). + +return **`boolean`** type status indicates the success of the operation. + +```cpp + bool sdBegin(SDFSConfig *sdFSConfig); +``` + + + + + +#### Initiate SD card with chip select and SPI configuration (ESP32 only). + +param **`ss`** The SPI Chip/Slave Select pin. + +param **`spiConfig`** The pointer to SPIClass object for SPI configuartion. + +param **`frequency`** The SPI frequency. + +return **`boolean`** The boolean value indicates the success of operation. + +```cpp +bool sdBegin(int8_t ss, SPIClass *spiConfig = nullptr, uint32_t frequency = 4000000); +``` + + + + + +#### Initiate SD card with SdFat SPI and pins configurations (with SdFat included only). + +param **`sdFatSPIConfig`** The pointer to SdSpiConfig object for SdFat SPI configuration. + +param **`ss`** The SPI Chip/Slave Select pin. + +param **`sck`** The SPI Clock pin. + +param **`miso`** The SPI MISO pin. + +param **`mosi`** The SPI MOSI pin. + +return **`boolean`** The boolean value indicates the success of operation. + +```cpp + bool sdBegin(SdSpiConfig *sdFatSPIConfig, int8_t ss = -1, int8_t sck = -1, int8_t miso = -1, int8_t mosi = -1); +``` + + + + + +#### Initiate SD card with SdFat SDIO configuration (with SdFat included only). + +param **`sdFatSDIOConfig`** The pointer to SdioConfig object for SdFat SDIO configuration. + +return **`boolean`** The boolean value indicates the success of operation. + +```cpp + bool sdBegin(SdioConfig *sdFatSDIOConfig); +``` + + + + +#### Initialize the SD_MMC card (ESP32 only). + +param **`mountpoint`** The mounting point. + +param **`mode1bit`** Allow 1 bit data line (SPI mode). + +param **`format_if_mount_failed`** Format SD_MMC card if mount failed. + +return **`Boolean`** type status indicates the success of the operation. + +```cpp +bool sdMMCBegin(const char *mountpoint = "/sdcard", bool mode1bit = false, bool format_if_mount_failed = false); +``` + + + + +#### Get free Heap memory. + +return **`int`** Free memory amount in byte. + +```cpp +int getFreeHeap(); +``` + + + + + +## IMAPSession class functions + + +The following functions are available from the IMAP Session class. + +This class used for controlling IMAP transports and retrieving the data from the IMAP server. + + + + +#### Set the tcp timeout. + +param **`timeoutSec`** The tcp timeout in seconds. + +```cpp +void setTCPTimeout(unsigned long timeoutSec); +``` + + + +#### Assign custom Client from Arduino Clients. + +param **`client`** The pointer to Arduino Client derived class e.g. WiFiClient, WiFiClientSecure, EthernetClient or GSMClient. + +```cpp +void setClient(Client *client); +``` + + +#### Assign TinyGsm Clients. + +param **`client`** The pointer to TinyGsmClient. + +param **`modem`** The pointer to TinyGsm modem object. Modem should be initialized and/or set mode before transfering data. + +param **`pin`** The SIM pin. + +param **`apn`** The GPRS APN (Access Point Name). + +param **`user`** The GPRS user. + +param **`password`** The GPRS password. + +```cpp +void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password); +``` + + +#### Assign the callback function to handle the network connection for custom Client. + +param **`networkConnectionCB`** The function that handles the network connection. + +```cpp +void networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB); +``` + + + +#### Assign the callback function to handle the network connection status acknowledgement. + +param **`networkStatusCB`** The function that handle the network connection status acknowledgement. + +```cpp +void networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB); +``` + + + +#### Set the network status acknowledgement. + +param **`status`** The network status. + +```cpp +void setNetworkStatus(bool status); +``` + + + +#### Set the BearSSL IO buffer size. + +param **`rx`** The BearSSL receive buffer size in bytes. + +param **`tx`** The BearSSL trasmit buffer size in bytes. + +```cpp +void setSSLBufferSize(int rx = -1, int tx = -1); +``` + + + +#### Set system time with timestamp. + +param **`ts`** timestamp in seconds from midnight Jan 1, 1970. + +param **`gmtOffset`** The GMT offset. + +This function allows the internal time setting by timestamp i.e. timestamp from external RTC. + +```cpp +void setSystemTime(time_t ts, float gmtOffset = 0); +``` + + + +#### Begin the IMAP server connection. + +param **`session_config`** The pointer to Session_Config structured data that keeps the server and log in details. + +param **`imap_data`** The pointer to IMAP_Data structured data that keeps the operation options. + +param **`login`** The bool option for login after server connection. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool connect(Session_Config *session_config, IMAP_Data *imap_data, bool login = true); +``` + + + +#### Login to IMAP server using Email and password. + +param **`email`** The IMAP server account email. + +param **`password`** The IMAP server account password. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bbool loginWithPassword( email, password); +``` + + + +#### Login to IMAP server using Email and access token. + +param **`email`** The IMAP server account email. + +param **`token`** The Access token to log in. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bbool loginWithAccessToken( email, token); +``` + + +#### Send the client identification to the server + +param **`identification`** The pointer to IMAP_Identification structured data that keeps + +the key properties e.g., name, version, os, os_version, vendor, support_url, address, + +date, command, arguments, and environment. + +```cpp +bool id(IMAP_Identification *identification); +``` + + +#### Return the server ID returns from ID command. + +return **`The server ID string.`** + +```cpp +String serverID(); +``` + + +#### Return the SASL authentication status. + +return **`boolean`** The boolean value indicates SASL authentication status. + +```cpp +bool isAuthenticated(); +``` + + +#### Return the log in status. + +return **`boolean`** The boolean value indicates log in status. + +```cpp +bool isLoggedIn(); +``` + + +#### Return firmware update result when attachment filename matches. + +return **`boolean`** The boolean value indicates the firmware update status. + +```cpp +bool isFirmwareUpdateSuccess(); +``` + + +#### Close the IMAP session. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool closeSession(); +``` + + +#### Setup TCP KeepAlive for internal TCP client. + +param **`tcpKeepIdleSeconds`** lwIP TCP Keepalive idle in seconds. + +param **`tcpKeepIntervalSeconds`** lwIP TCP Keepalive interval in seconds. + +param **`tcpKeepCount`** lwIP TCP Keepalive count. + +For the TCP (KeepAlive) options, see [this doc](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/lwip.html#tcp-options). + +If value of one of these parameters is zero, the TCP KeepAlive will be disabled. + +You can check the server connecting status, by exexuting `.connected()` which will return true when connection to the server is still alive. + +```cpp +void keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount); +``` + + + +#### Get TCP KeepAlive status. + +return **`Boolean`** status of TCP Keepalive. + +```cpp +bool isKeepAlive(); +``` + + + +#### Get TCP connection status. + +return **`boolean`** The boolean value indicates the connection status. + +```cpp +bool connected(); +``` + + + + + + +#### Set to enable the debug. + +param **`level`** The level to enable the debug message + +level = 0, no debugging + +level = 1, basic level debugging + +```cpp +void debug(int level); +``` + + + + + +#### Get the list of all the mailbox folders since the TCP session was opened and user was authenticated. + +param **`folders`** The FoldersCollection class that contains the collection of the +FolderInfo structured data. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool getFolders(FoldersCollection &folders); +``` + + + + + +#### Select or open the mailbox folder to search or fetch the message inside. + +param **`folderName`** The known mailbox folder name. The default name is INBOX. + +param **`readOnly`** The option to open the mailbox for read only. Set this option to false when you wish +to modify the Flags using the setFlag, addFlag and removeFlag functions. + +return **`boolean`** The boolean value which indicates the success of operation. + +note: the function will exit immediately and return true if the time since previous success folder selection (open) with the same readOnly mode, is less than 5 seconds. + +```cpp +bool selectFolder( folderName, bool readOnly = true); +``` + + + + + +#### Open the mailbox folder to read or search the mesages. + +param **`folderName`** The name of known mailbox folder to be opened. + +param **`readOnly`** The option to open the mailbox for reading only. Set this option to false when you wish +to modify the flags using the setFlag, addFlag and removeFlag functions. + +return **`boolean`** The boolean value which indicates the success of operation. + +note: the function will exit immediately and return true if the time since previous success folder selection (open) with the same readOnly mode, is less than 5 seconds. + +```cpp +bool openFolder( folderName, bool readOnly = true); +``` + + + + + +#### Close the mailbox folder that was opened. + +param **`expunge`** The option to allow emty the deleted flag set messages in case folder was open with editable mode. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool closeFolder(bool expunge = false); +``` + + + + + + +#### Create folder. + +param **`folderName`** The name of folder to create. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool createFolder( folderName); +``` + + + + + +#### Get subscribes mailboxes. + +param **`reference`** The reference name. + +param **`mailbox`** The mailbox name with possible wildcards. + +param **`folders`** The return FoldersCollection that contains the folder info e.g., name, attribute and delimiter. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool getSubscribesMailboxes( reference, mailbox, FoldersCollection &folders); +``` + + + + +#### Subscribe mailbox. + +param **`folderName`** The name of folder to subscribe. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool subscribe( folderName) +``` + + + + +#### Unsubscribe mailbox. + +param **`folderName`** The name of folder to unsubscribe. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool unSubscribe( folderName) +``` + + + + + +#### Rename folder. + +param **`currentFolderName`** The name of folder to create. + +param **`newFolderName`** The new name of folder to create. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool renameFolder( currentFolderName, newFolderName); +``` + + + +#### Delete folder. + +param **`folderName`** The name of folder to delete.. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool deleteFolder( folderName); +``` + + + + + + +#### Get UID number in selected or opened mailbox. + +param **`msgNum`** The message number or order in the total message numbers. + +return **`boolean`** The boolean value which indicates the success of operation. + +Returns 0 when fail to get UID. + +```cpp +int getUID(int msgNum); +``` + + + + + + + +#### Get message flags in selected or opened mailbox. + +param **`msgNum`** The message number or order in the total message numbers. + +return **`string`** Message flags in selected or opened mailbox. + +empty string when fail to get flags. + +```cpp +const char *getFlags(int msgNum); +``` + + + + + + +#### Send the custom IMAP command and get the result via callback. + +param **`cmd`** The command string. + +param **`callback`** The function that accepts IMAP_Response as parameter. + +param **`tag`** The tag string to pass to the callback function. + +return **`boolean`** The boolean value which indicates the success of operation. + +imap.connect and imap.selectFolder or imap.openFolder are needed to call once prior to call this function. + +```cpp +bool sendCustomCommand( cmd, imapResponseCallback callback, tag); +``` + + + + + +#### Send the custom IMAP command data string. + +param **`data`** The string data. + +param **`lastData`** The flag represents the last data to send (optional). + +return **`boolean`** The boolean value which indicates the success of operation. + +Should be used after calling sendCustomCommand("APPEND xxxxxx"); + +```cpp +bool sendCustomData(T data, bool lastData = false); +``` + + + + + +#### Send the custom IMAP command data. + +param **`data`** The byte data. + +param **`size`** The data size. + +param **`lastData`** The flag represents the last data to send (optional). + +return **`boolean`** The boolean value which indicates the success of operation. + +Should be used after calling ssendCustomCommand("APPEND xxxxxx"); + +```cpp +bool sendCustomData(uint8_t *data, size_t size, bool lastData = false); +``` + + + + +#### Begin the IMAP server connection without authentication. + +param **`session_config`** The pointer to Session_Config structured data that keeps the server and log in details. + +param **`callback`** The callback function that accepts IMAP_Response as parameter. + +param **`tag`** The tag that pass to the callback function. + +return **`The boolean`** value indicates the success of operation. + +```cpp +bool customConnect(Session_Config *session_config, imapResponseCallback callback, tag); +``` + + + + +#### Copy the messages to the defined mailbox folder. + +param **`toCopy`** The pointer to the MessageList class that contains the list of messages to copy. + +param **`dest`** The destination folder that the messages to copy to. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool copyMessages(MessageList *toCopy, dest); +``` + + + + + +#### Copy the messages to the defined mailbox folder. + +param **`sequenceSet`** The sequence set string i.g., unique identifier (UID) or +message sequence number or ranges of UID or sequence number. + +param **`UID`** The option for sequenceSet whether it is UID or message sequence number. + +param **`dest`** The destination folder that the messages to copy to. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool copyMessages( sequenceSet, bool UID, dest); +``` + + + + + + +#### Move the messages to the defined mailbox folder. + +param **`toMove`** The pointer to the MessageList class that contains the list of messages to move. + +param **`dest`** The destination folder that the messages to move to. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool moveMessages(MessageList *toMove, dest); +``` + + + + + +#### Move the messages to the defined mailbox folder. + +param **`sequenceSet`** The sequence set string i.g., unique identifier (UID) or +message sequence number or ranges of UID or sequence number. + +param **`UID`** The option for sequenceSet whether it is UID or message sequence number. + +param **`dest`** The destination folder that the messages to move to. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool moveMessages( sequenceSet, bool UID, dest); +``` + + + + + + +#### Delete the messages in the opened mailbox folder. + +param **`toDelete`** The pointer to the MessageList class that contains the list of messages to delete. + +param **`expunge`** The boolean option to expunge all messages. + +param **`modsequence`** The int32_t option for UNCHANGESINCE conditional test. + +return **`boolean`** The boolean value indicates the success of operation. + +The modsequence value can be used only if IMAP server supports Conditional STORE extension and the selected mailbox supports modsequences. + +```cpp +bool deleteMessages(MessageList *toDelete, bool expunge = false, int32_t modsequence = -1); +``` + + + + + + +#### Delete the messages in the opened mailbox folder. + +param **`sequenceSet`** The sequence set string i.g., unique identifier (UID) or +message sequence number or ranges of UID or sequence number. + +param **`UID`** The option for sequenceSet whether it is UID or message sequence number. + +param **`expunge`** The boolean option to expunge all messages. + +param **`modsequence`** The int32_t option for UNCHANGESINCE conditional test. + +return **`boolean`** The boolean value indicates the success of operation. + +The modsequence value can be used only if IMAP server supports Conditional STORE extension and the selected mailbox supports modsequences. + +```cpp +bool deleteMessages( sequenceSet, bool UID, bool expunge = false, int32_t modsequence = -1); +``` + + + + + + +#### Get the quota root's resource usage and limits. + +param **`quotaRoot`** The quota root to get. + +param **`info`** The pointer to `IMAP_Quota_Root_Info` that contains quota root's resource name, usage and limit. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool getQuota( quotaRoot, IMAP_Quota_Root_Info *info); +``` + + + + + +#### Set the quota root's resource usage and limits. + +param **`quotaRoot`** The quota root to set. + +param **`data`** The pointer to `IMAP_Quota_Root_Info` that contains quota root's resource name, usage and limit. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool setQuota( quotaRoot, IMAP_Quota_Root_Info *data); +``` + + + + + +#### Get the list of quota roots for the named mailbox. + +param **`mailbox`** The mailbox name. + +param **`quotaRootsList`** The pointer to `IMAP_Quota_Roots_List` that contains the list of `IMAP_Quota_Root_Info`. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool getQuotaRoot( mailbox, IMAP_Quota_Roots_List *quotaRootsList); +``` + + + + + +#### Get the ACLs for a mailbox. + +param **`mailbox`** The mailbox name. + +param **`aclList`** The pointer to the returning `IMAP_Rights_List` object. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool getACL( mailbox, IMAP_Rights_List *aclList); +``` + + + + + + +#### Get the ACLs for a mailbox. + +param **`mailbox`** The mailbox name. + +param **`acl`** The pointer to the acl IMAP_Rights_Info to set. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool setACL( mailbox, IMAP_Rights_Info *acl); +``` + + + + + + +#### Delete the ACLs set for identifier on mailbox. + +param **`mailbox`** The mailbox name. + +param **`identifier`** The identifier (user) to remove the rights. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool deleteACL( mailbox, identifier); +``` + + + + + +#### Show my ACLs for a mailbox. + +param **`mailbox`** The mailbox name. + +param **`acl`** The pointer to the returning `IMAP_Rights_Info` object. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool myRights( mailbox, IMAP_Rights_Info *acl); +``` + + + + + +#### Returns IMAP namespaces. + +param **`mailbox`** The mailbox name. + +param **`ns`** The pointer to the returning `IMAP_Namespaces_List` object. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool getNamespace(IMAP_Namespaces_List *ns); +``` + + + + + + +#### Enable IMAP capability. + +param **`capability`** The mailbox name. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool enable( capability); +``` + + + + + +#### Listen for the selected or open mailbox for updates. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool listen(); +``` + + + + + + +#### Stop listen for the mailbox for updates. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool stopListen(); +``` + + + + + + + +#### Check for the selected or open mailbox updates. + +return **`boolean`** The boolean value which indicates the changes status of mailbox. + +```cpp +bool folderChanged(); +``` + + + + + + +#### Assign the callback function that returns the operating status when fetching or reading the Email. + +param **`imapCallback`** The function that accepts the `imapStatusCallback` as parameter. + +```cpp +void callback(imapStatusCallback imapCallback); +``` + + + + +#### Assign the callback function to decode the string based on the character set. + +param **`callback`** The function that accepts the pointer to `IMAP_Decoding_Info` as parameter. + +```cpp +void characterDecodingCallback(imapCharacterDecodingCallback callback); +``` + + + +#### Assign the callback function that returns the MIME data stream from fetching or reading the Email. + +param **`mimeDataStreamCallback`** The function that accepts the `MIME_Stream_Info` as parameter. + +```cpp +void mimeDataStreamCallback(MIMEDataStreamCallback mimeDataStreamCallback); +``` + + + + + +#### Determine if no message body contained in the search result and only the message header is available. + +```cpp +bool headerOnly(); +``` + + + + + +#### Get the message list from search or fetch the Emails + +return **`The IMAP_MSG_List structured`** data which contains the text and html contents, +attachments, inline images, embedded rfc822 messages details for each message. + +```cpp +IMAP_MSG_List data(); +``` + + + + +#### Get the details of the selected or opned mailbox folder + +return **`The SelectedFolderInfo class`** instance which contains the info about flags, total messages, next UID, +earch count and the available messages count. + +```cpp +SelectedFolderInfo selectedFolder(); +``` + + + + + +#### Get the error details when readingg the Emails. + +return **`String`** The string of error details. + +```cpp +String errorReason(); +``` + + +#### Get the operating status error code. + +return **`int`** The value of operating status error code. + +The negative value indicated error. + +See src/ESP_Mail_Error.h and extras/MB_FS.h + +```cpp +int errorCode(); +``` + + + +#### Clear all the cache data stored in the IMAP session object. + +```cpp +void empty(); +``` + + + +#### Get the status of message fetching and searching. + +return **`IMAP_Status`** The IMAP_Status object contains the fetching and searching statuses. + +```cpp +IMAP_Status status(); +``` + + + +#### Get the JSON string of file name list of files that stored in SD card. + +return **`The JSON string`** of filenames. + +note This will available only when standard SD library was used and file storage is SD. + +```cpp +String fileList(); +``` + + +## SMTPSession class functions + + +The following functions are available from the SMTP Session class. + +This class is similar to the IMAP session class, used for controlling SMTP transports +and retrieving the data from the SMTP server. + + + + +#### Set the tcp timeout. + +param **`timeoutSec`** The tcp timeout in seconds. + +```cpp +void setTCPTimeout(unsigned long timeoutSec); +``` + + + +#### Assign custom Client from Arduino Clients. + +param **`client`** The pointer to Arduino Client derived class e.g. WiFiClient, WiFiClientSecure, EthernetClient or GSMClient. + +```cpp +void setClient(Client *client); +``` + + +#### Assign TinyGsm Clients. + +param **`client`** The pointer to TinyGsmClient. + +param **`modem`** The pointer to TinyGsm modem object. Modem should be initialized and/or set mode before transfering data. + +param **`pin`** The SIM pin. + +param **`apn`** The GPRS APN (Access Point Name). + +param **`user`** The GPRS user. + +param **`password`** The GPRS password. + +```cpp +void setGSMClient(Client *client, void *modem, const char *pin, const char *apn, const char *user, const char *password); +``` + + + +#### Assign the callback function to handle the network connection for custom Client. + +param **`networkConnectionCB`** The function that handles the network connection. + +```cpp +void networkConnectionRequestCallback(NetworkConnectionRequestCallback networkConnectionCB); +``` + + +#### Assign the callback function to handle the network connection status acknowledgement. + +param **`networkStatusCB`** The function that handle the network connection status acknowledgement. + +```cpp +void networkStatusRequestCallback(NetworkStatusRequestCallback networkStatusCB); +``` + + + +#### Set the network status acknowledgement. + +param **`status`** The network status. + +```cpp +void setNetworkStatus(bool status); +``` + + + +#### Set the BearSSL IO buffer size. + +param **`rx`** The BearSSL receive buffer size in bytes. + +param **`tx`** The BearSSL trasmit buffer size in bytes. + +```cpp +void setSSLBufferSize(int rx = -1, int tx = -1); +``` + + + +#### Set system time with timestamp. + +param **`ts`** timestamp in seconds from midnight Jan 1, 1970. + +param **`gmtOffset`** The GMT offset. + +This function allows the internal time setting by timestamp i.e. timestamp from external RTC. + +```cpp +void setSystemTime(time_t ts, float gmtOffset = 0); +``` + + + +#### Begin the SMTP server connection. + +param **`session_config`** The pointer to Session_Config structured data that keeps the server and log in details. + +param **`login`** The bool option for login after server connection. + +return **`boolean`** The boolean value indicates the success of operation. + +```cpp +bool connect(Session_Config *session_config, bool login = true); +``` + + + +#### Login to SMTP server using Email and password. + +param **`email`** The SMTP server account email. + +param **`password`** The SMTP server account password. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool loginWithPassword( email, password); +``` + + + +#### Login to SMTP server using Email and access token. + +param **`email`** The SMTP server account email. + +param **`token`** The Access token to log in. + +return **`boolean`** The boolean value which indicates the success of operation. + +```cpp +bool loginWithAccessToken( email, token); +``` + + +#### Return the SASL authentication status. + +return **`boolean`** The boolean value indicates SASL authentication status. + +```cpp +bool isAuthenticated(); +``` + + + +#### Return the log in status. + +return **`boolean`** The boolean value indicates log in status. + +```cpp +bool isLoggedIn(); +``` + + +#### Close the SMTP session. + +```cpp +bool closeSession(); +``` + + + +#### Setup TCP KeepAlive for internal TCP client. + +param **`tcpKeepIdleSeconds`** lwIP TCP Keepalive idle in seconds. + +param **`tcpKeepIntervalSeconds`** lwIP TCP Keepalive interval in seconds. + +param **`tcpKeepCount`** lwIP TCP Keepalive count. + +For the TCP (KeepAlive) options, see [this doc](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/lwip.html#tcp-options). + +If value of one of these parameters is zero, the TCP KeepAlive will be disabled. + +You can check the server connecting status, by exexuting `.connected()` which will return true when connection to the server is still alive. + +```cpp +void keepAlive(int tcpKeepIdleSeconds, int tcpKeepIntervalSeconds, int tcpKeepCount); +``` + + + +#### Get TCP KeepAlive status. + +return **`Boolean`** status of TCP Keepalive. + +```cpp +bool isKeepAlive(); +``` + + + +#### Get TCP connection status. + +return **`boolean`** The boolean value indicates the connection status. + +```cpp +bool connected(); +``` + + + + +#### Begin the SMTP server connection without authentication. + +param **`session_config`** The pointer to Session_Config structured data that keeps the server and log in details. + +param **`callback`** The callback function that accepts the SMTP_Response as parameter. + +param **`commandID`** The command identifier number that will pass to the callback. + +return **`The int`** value of response code. + +If commandID was not set or set to -1, the command identifier will be auto increased started from zero. + +```cpp +int customConnect(Session_Config *session_config, smtpResponseCallback callback, int commandID = -1); +``` + + + + + + +#### Send the custom SMTP command and get the result via callback. + +param **`cmd`** The command string. + +param **`callback`** The function that accepts the SMTP_Response as parameter. + +return **`boolean`** The boolean value which indicates the success of operation. + +smtp.connect or smtp.customConnect is needed to call once prior to call this function. + +```cpp +bool sendCustomCommand( cmd, smtpResponseCallback callback); +``` + + + + + +#### Send the custom SMTP command data string. + +param **`data`** The string data. + +return **`The boolean`** value which indicates the success of operation. + +Should be used after calling sendCustomCommand("DATA"); + +```cpp +bool sendCustomData( data); +``` + + + + +#### Send the custom SMTP command data. + +param **`data`** The byte data. + +param **`size`** The data size. + +return **`The boolean`** value which indicates the success of operation. + +Should be used after calling sendCustomCommand("DATA"); + +```cpp +bool sendCustomData(uint8_t *data, size_t size); +``` + + + + + +#### Set to enable the debug. + +param **`level`** The level to enable the debug message + +level = 0, no debugging + +level = 1, basic level debugging + +```cpp +void debug(int level); +``` + + + + + +#### Get the error details when sending the Email + +return **`String`** The string of error details. + +```cpp +String errorReason(); +``` + + +#### Get the operating status error code. + +return **`int`** The value of operating status error code. + +The negative value indicated error. + +See src/ESP_Mail_Error.h and extras/MB_FS.h + +```cpp +int errorCode(); +``` + + + +#### Get the SMTP server response status code. + +return **`int`** The value of SMTP server response status code. + +See RFC 5321 standard's documentation. + +```cpp +int statusCode(); +``` + + + +#### Get the SMTP server response status message. + +return **`String`** The value of SMTP server response status message. + +```cpp +String statusMessage(); +``` + + + +#### Set the Email sending status callback function. + +param **`smtpCallback`** The callback function that accept the `smtpStatusCallback` param. + +```cpp +void callback(smtpStatusCallback smtpCallback); +``` + + +#### Get the status of message fetching and searching. + +return **`SMTP_Status`** The SMTP_Status object contains the sending status. + +```cpp +SMTP_Status status(); +``` + +## SMTP_Message class functions + + +The following functions are available from the SMTP Message class. + +This class is used for storing the message data including headers, body and attachments +which will be processed with the SMTP session class. + + + + +#### To reset the SMTP_Attachment item data + +param **`att`** The SMTP_Attachment class that stores the info about attachment + +This function was used for clear the internal data of attachment item to be ready for reuse. + +```cpp +void resetAttachItem(SMTP_Attachment &att); +``` + + + +#### To clear all data in SMTP_Message class included headers, bodies and attachments + +```cpp +void clear(); +``` + + + + +#### To clear all the inline images in SMTP_Message class. + +```cpp +void clearInlineimages(); +``` + + + + + +#### To clear all the attachments. + +```cpp +void clearAttachments(); +``` + + + + + +#### To clear all rfc822 message attachment. + +```cpp +void clearRFC822Messages(); +``` + + + + + +#### To clear the primary recipient mailboxes. + +```cpp +void clearRecipients(); +``` + + + + + +#### To clear the Carbon-copy recipient mailboxes. + +```cpp +void clearCc(); +``` + + + + + +#### To clear the Blind-carbon-copy recipient mailboxes. + +```cpp +void clearBcc(); +``` + + +#### To clear the custom message headers. + +```cpp +void clearHeader(); +``` + + + + +#### To add attachment to the message. + +param **`att`** The SMTP_Attachment data item + +```cpp +void addAttachment(SMTP_Attachment &att); +``` + + + + + +#### To add parallel attachment to the message. + +param **`att`** The SMTP_Attachment data item + +```cpp +void addParallelAttachment(SMTP_Attachment &att); +``` + + + + + +#### To add inline image to the message. + +param **`att`** The SMTP_Attachment data item + +```cpp +void addInlineImage(SMTP_Attachment &att); +``` + + + + + +#### To add rfc822 message to the message. + +param **`msg`** The RFC822_Message class object + +```cpp +void addMessage(SMTP_Message &msg); +``` + + + + + +#### To add the primary recipient mailbox to the message. + +param **`name`** The name of primary recipient + +param **`email`** The Email address of primary recipient + +```cpp +void addRecipient( name, email); +``` + + + + + +#### To add Carbon-copy recipient mailbox. + +param **`email`** The Email address of secondary recipient + +```cpp +void addCc( email); +``` + + + + + +#### To add Blind-carbon-copy recipient mailbox. + +param **`email`** The Email address of the tertiary recipient + +```cpp +void addBcc( email); +``` + + + + + +#### To add the custom header to the message. + +param **`hdr`** The header name and value + +```cpp +void addHeader( hdr); +``` + + + + +##### [properties] The message author config + +This property has the sub properties + +###### [const char*] name - The sender name. + +###### [const char*] email - The sender Email address. + +```cpp +esp_mail_email_info_t sender; +``` + + +##### [properties] The topic of message + +```cpp +const char *subject; +``` + + +##### [properties] The message type + +```cpp +byte type; +``` + + +##### [properties] The PLAIN text message + +This property has the sub properties + +###### [esp_mail_smtp_embed_message_body_t] embed - The option to embed this message content as a file. + +###### [const char*] content - The PLAIN text content of the message. + +###### [esp_mail_blob_message_content_t] blob - The blob that contins PLAIN text content of the message. + +###### [esp_mail_file_message_content_t] file - The file that contins PLAIN text content of the message. + +###### [const char*] charSet - The character transcoding of the PLAIN text content of the message. + +###### [const char*] content_type - The content type of message. + +###### [const char*] transfer_encoding - The option to encode the content for data transfer. + +###### [boolean] flowed - The option to send the PLAIN text with wrapping. + +```cpp +esp_mail_plain_body_t text; +``` + + +##### [properties] The HTML text message + +This propery has the sub properties + +###### [const char*] content - The HTML content of the message. + +###### [esp_mail_blob_message_content_t] blob - The blob that contins HTML content of the message. + +###### [esp_mail_file_message_content_t] file - The file that contins HTML content of the message. + +###### [const char*] charSet - The character transcoding of the HTML content of the message. + +###### [const char*] content_type - The content type of message. + +###### [const char*] transfer_encoding - The option to encode the content for data transfer. + +```cpp +esp_mail_html_body_t html; +``` + + +##### [properties] The response config + +This propery has the sub properties + +###### [const char*] reply_to - The author Email address to reply. + +###### [const char*] return_path - The sender Email address to return the message. + +###### [int] notify - The Delivery Status Notifications enumeration e.g. + +esp_mail_smtp_notify_never = 0, + +esp_mail_smtp_notify_success = 1, + +esp_mail_smtp_notify_failure = 2, and + +esp_mail_smtp_notify_delay = 4 + +```cpp +esp_mail_smtp_msg_response_t response; +``` + + +##### [properties] The priority of the message + +This property has the enumeration values + +esp_mail_smtp_priority_high = 1, + +esp_mail_smtp_priority_normal = 3, + +esp_mail_smtp_priority_low = 5 + +```cpp +esp_mail_smtp_priority priority; +``` + + +##### [properties] The enable options + +This propery has the sub property + +###### [boolean] chunking - enable chunk data sending for large message. + +```cpp +esp_mail_smtp_enable_option_t enable; +``` + + +##### [properties] The message from config + +This property has the sub properties + +###### [const char*] name - The messsage author name. + +###### [const char*] email - The message author Email address. + +```cpp +esp_mail_email_info_t from; +``` + + +##### [properties] The message identifier + +```cpp +const char *ID; +``` + +##### [properties] The keywords or phrases, separated by commas + +```cpp +const char *keywords; +``` + + +##### [properties] The comments about message + +```cpp +const char *comments; +``` + + +##### [properties] The date of message + +```cpp +const char *date; +``` + + +##### [properties] The return recipient of the message + +```cpp +const char *return_path; +``` + + + +##### [properties] The field that contains the parent's message ID of the message to which this one is a reply + +```cpp +const char *in_reply_to; +``` + + + +##### [properties] The field that contains the parent's references (if any) and followed by the parent's message ID (if any) of the message to which this one is a reply + +```cpp +const char *references; +``` + + +## IMAP_Status class functions + + +The following functions are available from the IMAP Status class. + +This class is used as the callback parameter for retrieving the status while reading the Email. + + + + +#### Get the information of each process in the reading operation. + +return **`string`** The info for each process + +```cpp +const char *info(); +``` + + + + +#### Get the status of completion. + +return **`boolean`** The bool value indicates that all reading processes are finished + +```cpp +bool success(); +``` + + + + + +#### To clear all data store in this class. + +```cpp +void empty(); +``` + + + + + + +## SMTP_Status class functions + + +The following functions are available from the SMTP Status class. + +This class is used as the callback parameter for retrieving the status while sending the Email. + + + + +#### Get the information of each process in the sending operation. + +return **`string`** The info for each process + +```cpp +const char *info(); +``` + + + + +#### Get the status of completion. + +return **`boolean`** The bool value indicates that all sending processes are finished + +```cpp +bool success(); +``` + + + + + +#### To clear all data store in this class. + +```cpp +void empty(); +``` + + + + +#### Get the number of complete sending message. + +return **`number`** The number of message that was sent + +```cpp +size_t completedCount(); +``` + + + + + +#### Get the number of failed sending message. + +return **`number`** The number of message that was not sent + +```cpp +size_t failedCount(); +``` + + + + +## SendingResult class functions + + +The following functions are available from the SendingResult class. + +This class is used for retrieving the info about the result of sending the messages. + + + + +#### Get the information of a message sending status. + +param **`index`** The index number of a message sending status + +return **`SMTP_Result`** The SMTP_Result type data that provides these properties + +##### [bool] completed - The status of the message + +#### [MB_String] recipients - The primary recipient mailbox of the message + +#### [MB_String] subject - The topic of the message + +#### [time_t] timesstamp - The timestamp of the message + +```cpp +SMTP_Result getItem(size_t index); +``` + + + + + +#### Get the amount of the result data. + +return **`number`** The number of result item + +```cpp +size_t size(); +``` + + + + +## SMTP_Response type data + +The following properties are available from the SMTP_Response data type. + +This data type obtains the response from sending custom SMTP commands. + + +#### [Properties] The command identifier + +```cpp +int id; +``` + +#### [Properties] The response text + +```cpp +MB_String text; +``` + + +#### [Properties] The response code + +```cpp +int respCode; +``` + + + + +## FoldersCollection class functions + + +The following functions are available from the FoldersCollection class. + +This class is used for retrieving the info about the mailbox folders which available to read or serach +in the user Email mailbox. + + + + +#### Get the information of a folder in a folder collection. + +param **`index`** The index number of folders + +return **`esp_mail_folder_info_item_t`** The esp_mail_folder_info_item_t structured data that provides these properties + +#### [MB_String] name - The name of folder + +#### [MB_String] attributes - The attributes of folder + +#### [MB_String] delimiter - The delimeter of folder + +```cpp +esp_mail_folder_info_item_t info(size_t index); +``` + + + + + +#### Get the number of folders in the collection. + +return **`number`** The number of folder in the collection + +```cpp +size_t size(); +``` + + + + + + +## SelectedFolderInfo class functions + + +The following functions are available from the SelectedFolderInfo class. + +This class is used for retrieving the info about the sselected or opened mailbox folder. + + + + +#### Get the numbers of flags in the user Email mailbox. + +return **`number`** The numbers of flags + +```cpp +size_t flagCount(); +``` + + + + + +#### Get the numbers of messages in this mailbox. + +return **`number`** The numbers of messages in the selected mailbox folder + +```cpp +size_t msgCount(); +``` + + + + + + +#### Get the numbers of messages in this mailbox that recent flag was set. + +return **`number`** The numbers of messages in the selected mailbox folder that recent flag was set + +```cpp +size_t recentCount(); +``` + + + + + + +#### Get the order of message in number of message in this mailbox that reoved. + +return **`IMAP_Polling_Status`** The data that holds the polling status. + +The IMAP_Polling_Status has the properties e.g. type, messageNum, and argument. + +The type property is the type of status e.g.imap_polling_status_type_undefined, imap_polling_status_type_new_message, +imap_polling_status_type_remove_message, and imap_polling_status_type_fetch_message. + +The messageNum property is message number or order from the total number of message that added, fetched or deleted. + +The argument property is the argument of commands e.g. FETCH + +```cpp +struct IMAP_Polling_Status pollingStatus(); +``` + + + + + + + + +#### Get the predicted next message UID in the sselected folder. + +return **`number`** The number represents the next message UID number + +```cpp +size_t nextUID(); +``` + + + + + + + +#### Get the numbers of messages from search result based on the search criteria. + +return **`number`** The total number of messsages from search + +```cpp +size_t searchCount(); +``` + + + + + +#### Get the numbers of messages to be stored in the ressult. + +return **`number`** The number of messsage stored from search + +```cpp +size_t availableMessages(); +``` + + + + + +#### Get the flag argument at the specified index. + +return **`index`** The index of flag in the flags list + +return **`String`** The argument of selected flag + +```cpp +String flag(size_t index); +``` + + + + +## Session_Config type data + + +The following properties are available from the Session_Config data type. + +This data type is used for storing the session info about the server and login credentials. + + +#### [Properties] The server config + +This property has the sub properties + +##### [MB_String] host_name - The hostName of the server. + +##### [uint16_t] port - The port on the server to connect to. + +```cpp +esp_mail_sesson_sever_config_t server; +``` + + +#### [Properties] The log in config + +This property has the sub properties + +##### [MB_String] email - The user Email address to log in. + +##### [consst char *] password - The user password to log in. + +##### [consst char *] accessToken - The OAuth2.0 access token to log in. + +##### [consst char *] user_domain - The host name or public IP of client system. + +```cpp +esp_mail_sesson_login_config_t login; +``` + + +#### [Properties] The secure config + +This property has the sub properties + +##### [bool] startTLS - The option to send the command to start the TLS connection. + +```cpp +esp_mail_sesson_secure_config_t secure; +``` + + +#### [Properties] The ports and protocols config + +This property has the sub properties + +##### [port_function *] list - The list (aray) of port_function. + +##### [size_t] size - The size of array. + +```cpp +esp_mail_ports_functions ports_functions; +``` + + + + +#### [Properties] The certificate config + +##### [const char *] cert_data - The certificate data (base64 data). + +##### [const char *] cert_file - The certificate file (DER format). + +##### [esp_mail_file_storage_type] cert_file_storage_type - The storage type. + +##### [bool] verify - The cerificate verification option. + +```cpp +esp_mail_sesson_cert_config_t certificate; +``` + + + +#### [Properties] SPI Ethernet Module config for ESP8266 + +##### [ENC28J60lwIP *] enc28j60 - The ENC28J60 Ethernet module lwip interfac. + +##### [Wiznet5100lwIP *] w5100 - The W5100 Ethernet module lwip interfac. + +##### [Wiznet5500lwIP *] w5500 - The W5500 Ethernet module lwip interfac. + +```cpp +esp_mail_spi_ethernet_module_t spi_ethernet_module; +``` + + + +#### [Properties] The callback function for WiFi connection + +```cpp +NetworkConnectionHandler network_connection_handler; +``` + + + + +## port_function type data + +#### [Properties] The port number + +```cpp +uint16_t port; +``` + +#### [Properties] The protocol + +The port protocol e.g. esp_mail_protocol_plain_text, esp_mail_protocol_ssl and esp_mail_protocol_tls. + +```cpp +esp_mail_protocol protocol; +``` + + + + +## IMAP_Data type data + + +The following properties are available from the IMAP_Data data type. + +This data type is used for storing the IMAP transport and operating options to +control and store the operation result e.g. the messahe contents from search and fetch. + + + + +#### [Properties] The config for fetching + +This property has the sub properties + +##### [MB_String] uid - The UID of message to fetch. + +##### [MB_String] number - The message sequence number to fetch. + +##### [esp_mail_imap_sequence_set_t] sequence_set - The sequence set options. + +##### [MB_String] set_seen - Set the message flag as seen. + +```cpp +esp_mail_imap_fetch_config_t fetch; +``` + + +#### [Properties] The config for IMAP sequence set fetching + +This property has the sub properties + +##### [MB_String] string - The sequence set string i.g., unique identifier (UID) +or message sequence number or ranges of UID or sequence number. + +##### [bool] UID - The option for sequenceSet whether it is UID or message sequence number. + +##### [bool] headerOnly - The option for header only fetching. + +```cpp +esp_mail_imap_sequence_set_t fetch; +``` + + +#### [Properties] The config for search + +This property has the sub properties + +##### [MB_String] criteria - The search criteria. + +##### [boolean] unseen_msg - The option to search the unseen message. + +```cpp +esp_mail_imap_search_config_t search; +``` + + +#### [Properties] The config about the limits + +This property has the sub properties + +##### [size_t] search - The maximum messages from the search result. + +##### [size_t] fetch - The maximum messages from the sequence set fetching result. + +##### [size_t] msg_size - The maximum size of the memory buffer to store the message content. + +This is only limit for data to be stored in the IMAPSession. + +##### [size_t] attachment_size - The maximum size of each attachment to download. + +The IMAP idle (polling) timeout in ms (1 min to 29 min). Default is 10 min. + +##### [size_t] imap_idle_timeout - The IMAP idle timeout in ms. + +The IMAP idle (polling) host check interval in ms (30 sec to imap_idle_timeout) +for internet availability checking to ensure the connection is active. + +Default is 1 min. + +##### [size_t] imap_idle_host_check_interval - The IMAP idle host check interval in ms. + + +```cpp +esp_mail_imap_limit_config_t limit; +``` + + + +#### [Properties] The config to enable the features + +This property has the sub properties + +##### [boolean] text - To store the PLAIN text of the message in the IMAPSession. + +##### [boolean] html - To store the HTML of the message in the IMAPSession. + +##### [boolean] rfc822 - To store the rfc822 messages in the IMAPSession. + +##### [boolean] download_status - To enable the download status via the serial port. + +##### [boolean] recent_sort - To sort the message UID of the search result in descending order. + +##### [boolean] header_case_sesitive - To allow case sesitive in header parsing. + +```cpp +esp_mail_imap_enable_config_t enable; +``` + + + +#### [Properties] The config about downloads + +This property has the sub properties + +##### [boolean] text - To download the PLAIN text content of the message. + +##### [boolean] html - To download the HTML content of the message. + +##### [boolean] attachment - To download the attachments of the message. + +##### [boolean] inlineImg - To download the inline image of the message. + +##### [boolean] rfc822 - To download the rfc822 mesages in the message. + +##### [boolean] header - To download the message header. + +```cpp +esp_mail_imap_download_config_t download; +``` + + + +#### [Properties] The config about the storage and path to save the downloaded file. + +This property has the sub properties + +##### [const char*] saved_path - The path to save the downloaded file. + +##### [esp_mail_file_storage_type] type - The type of file storages enumeration e.g. + +esp_mail_file_storage_type_none = 0, + +esp_mail_file_storage_type_flash = 1, and + +esp_mail_file_storage_type_sd = 2 + +```cpp +esp_mail_imap_storage_config_t storage; +``` + + +#### [Properties] The config about firmware updates and downloads for ESP32, ESP8266 and Raspberry Pi Pico. + +This property has the sub properties + +##### [string] attach_filename - Update firmware using message attachments if one of its filename matches. + +##### [bool] save_to_file - Save firmware file option. + +```cpp +esp_mail_imap_firmware_config_t firmware_update; +``` + + + +## esp_mail_smtp_embed_message_body_t structured data + + +The following properties are available from the IMAP_Data data type. + +This data type is used for storing the IMAP transport and operating options to +control and store the operation result e.g. the messahe contents from search and fetch. + + + + +##### [Properties] Enable to send this message body as file + +```cpp +bool enable; +``` + + +##### [Properties] The name of embedded file + +```cpp +const char* enable; +``` + + +##### [Properties] The embedded type enumeration + +esp_mail_smtp_embed_message_type_attachment = 0 + +sp_mail_smtp_embed_message_type_inline = 1 + +```cpp +esp_mail_smtp_embed_message_type type; +``` + +## esp_mail_blob_message_content_t structured data + + +The following properties are available from the esp_mail_blob_message_content_t data type. + +This data type is used for storing the blob info of message body. + + + +##### [Properties] The array of content in flash memory. + +```cpp +const uint8_t * data; +``` + + +##### [Properties] The array size in bytes. + +```cpp +size_t size; +``` + + + + + +## esp_mail_file_message_content_t structured data + + +The following properties are available from the esp_mail_file_message_content_t data type. + +This data type is used for storing the file info of message body. + + +##### [Properties] The file path include its name. + +```cpp +const char *name; +``` + + +##### [Properties] The type of file storages. + +```cpp +esp_mail_file_storage_type type; +``` + + + + + +## IMAP_MSG_Item type data + + +The following properties are available from the IMAP_MSG_Item data type. + +This data type is used for message item info and its contents from search and fetch. + + + + +#### [Properties] The message number + +```cpp +int msgNo; +``` + + +#### [Properties] The message UID + +```cpp +int UID; +``` + + +#### [Properties] The message identifier + +```cpp +const char *ID; +``` + + + +#### [Properties] The language(s) for auto-responses + +```cpp +const char *acceptLang; +``` + + + +#### [Properties] The language of message content + +```cpp +const char *contentLang; +``` + + + +#### [Properties] The mailbox of message author + +```cpp +const char *from; +``` + + +#### [Properties] The charset of the mailbox of message author (deprecate) + +```cpp +const char *fromCharset; +``` + + +#### [Properties] The primary recipient mailbox + +```cpp +const char *to; +``` + + +#### [Properties] The charset of the primary recipient mailbox (deprecate) + +```cpp +const char *toCharset; +``` + + +#### [Properties] The Carbon-copy recipient mailboxes + +```cpp +const char *cc; +``` + + +#### [Properties] The charset of the Carbon-copy recipient mailbox header (deprecate) + +```cpp +const char *ccCharset; +``` + +#### [Properties] The message date and time + +```cpp +const char *date; +``` + +#### [Properties] The topic of message + +```cpp +const char *subject; +``` + +#### [Properties] The topic of message charset (deprecate) + +```cpp +const char *subjectCharset; +``` + +#### [Properties] The PLAIN text content of the message + +```cpp +esp_mail_plain_body_t text; +``` + +#### [Properties] The HTML content of the message + +```cpp +esp_mail_html_body_t html; +``` + +#### [Properties] The sender Email + +```cpp +const char *sender; +``` + + +#### [Properties] The charset of the sender Email (obsoleted) + +```cpp +const char *senderCharset; +``` + + +#### [Properties] The keywords or phrases, separated by commas + +```cpp +const char *keyword; +``` + +#### [Properties] The comments about message + +```cpp +const char *comments; +``` + + +#### [Properties] The return recipient of the message + +```cpp +const char *return_path; +``` + + +#### [Properties] The Email address to reply + +```cpp +const char *reply_to; +``` + + +#### [Properties] The field that contains the parent's message ID of the message to which this one is a reply + +```cpp +const char *in_reply_to; +``` + + +#### [Properties] The field that contains the parent's references (if any) and followed by the parent's message ID (if any) of the message to which this one is a reply + +```cpp +const char *references; +``` + + +#### [Properties] The Blind carbon-copy recipients + +```cpp +const char *bcc; +``` + +#### [Properties] The charset of the Blind carbon-copy recipient mailbox header (obsoleted) + +```cpp +const char *bccCharset; +``` + + +#### [Properties] The error description from fetching the message + +```cpp +const char *fetchError; +``` + + +#### [Properties] The info about the attachments in the message + +```cpp +std::vector attachments; +``` + +#### [Properties] The info about the rfc822 messages included in the message + +```cpp +std::vector rfc822; +``` + + + + +## IMAP_Response type data + +The following properties are available from the IMAP_Response data type. + +This data type obtains the response from sending custom IMAP commands. + + +#### [Properties] The status tag + +```cpp +MB_String tag; +``` + +#### [Properties] The status text + +```cpp +MB_String text; +``` + + +#### [Properties] The completion of response + +```cpp +bool completed; +``` + + + + + + +## MIME_Data_Stream_Info type data + +The following properties are available from the MIME_Data_Stream_Info data type. + +This data type obtains the IMAP multipart body or MIME stream data via the callback function. + + +#### [Properties] The message UID + +```cpp +uint32_t uid; +``` + +#### [Properties] The content type of the message part + +```cpp +const char *type; +``` + +#### [Properties] The content disposition of the message part + +```cpp +const char *disposition; +``` + + +#### [Properties] The content character set of the message part + +```cpp +const char *charSet; +``` + + +#### [Properties] The text content flowed format parameter of the message part + +```cpp +bool flowed; +``` + + +#### [Properties] The text content format DelSp parameter of the message part + +```cpp +bool delsp; +``` + + +#### [Properties] The content transfer encoding of the message part + +```cpp +const char *transfer_encoding; +``` + + +#### [Properties] The content ID of the inline attachment type message part + +```cpp +const char *cid; +``` + + +#### [Properties] The content description of the message part + +```cpp +const char *description; +``` + +#### [Properties] The file name of the attachment type message part + +```cpp +const char *filename; +``` + + +#### [Properties] The name of the attachment type message part + +```cpp +const char *name; +``` + + +#### [Properties] The creation date of the message part + +```cpp +const char *date; +``` + +#### [Properties] The size of the attachment (unencoded) type message part + +```cpp +size_t size; +``` + + +#### [Properties] The total octet of the message part + +```cpp +size_t octet_size; +``` + +#### [Properties] The current octet count of the message part that currently parses + +```cpp +int octet_count; +``` + +#### [Properties] The size of content (unencoded) of message part + +```cpp +size_t data_size; +``` + + +#### [Properties] The data buffer of message part that currently parses + +```cpp +void *data; +``` + + +#### [Properties] The flag that states the first chunk data of message part that currently parses + +```cpp +bool isFirstData; +``` + +#### [Properties] The flag that states the final chunk data of message part that currently parses + +```cpp +bool isLastData; +``` + + + + +## IMAP_Decoding_Info type data + +The following properties are available from the IMAP_Decoding_Info data type. + +This data type obtains the IMAP header and text (plain and html) strings to be decoded via the callback function based on its character set. + + +#### [Properties] The character set of the string to decode + +```cpp +const char *charset; +``` + +#### [Properties] The string to decode + +```cpp +const char *data; +``` + + +#### [Properties] The type of data that currently processed + +0 or IMAP_Decoding_Info::message_part_type_header + +1 or IMAP_Decoding_Info::message_part_type_text + +```cpp +message_part_type type; +``` + + + + + +## Search Criteria + +Search crieria is used for searching the mailbox for messages that match +the given searching criteria. + +Searching criteria consist of one or more search keys. When multiple keys are +specified, the result is the intersection (AND function) of all the messages +that match those keys. + +Example: + + **`DELETED FROM "SMITH" SINCE 1-Feb-1994`** refers +to all deleted messages from Smith that were placed in the mailbox since +February 1, 1994. + +A search key can also be a parenthesized list of one or more search keys +(e.g., for use with the OR and NOT keys). + +**`SINCE 10-Feb-2019`** will search all messages that received since 10 Feb 2019 + +**`UID SEARCH ALL`** will seach all message which will return the message UID +that can be use later for fetch one or more messages. + + +The following keywords can be used for the search criteria. + + +**ALL** - All messages in the mailbox; the default initial key for ANDing. + +**ANSWERED** - Messages with the \Answered flag set. + +**BCC** - Messages that contain the specified string in the envelope structure's BCC field. + +**BEFORE** - Messages whose internal date (disregarding time and timezone) is earlier than the specified date. + +**BODY** - Messages that contain the specified string in the body of the message. + +**CC** - Messages that contain the specified string in the envelope structure's CC field. + +**DELETED** - Messages with the \Deleted flag set. + +**DRAFT** - Messages with the \Draft flag set. + +**FLAGGED** - Messages with the \Flagged flag set. + +**FROM** - Messages that contain the specified string in the envelope structure's FROM field. + +**HEADER** - Messages that have a header with the specified field-name (as defined in [RFC-2822]) + +and that contains the specified string in the text of the header (what comes after the colon). + +If the string to search is zero-length, this matches all messages that have a header line with + +the specified field-name regardless of the contents. + +**KEYWORD** - Messages with the specified keyword flag set. + +**LARGER** - Messages with an (RFC-2822) size larger than the specified number of octets. + +**NEW** - Messages that have the \Recent flag set but not the \Seen flag. + +This is functionally equivalent to **"(RECENT UNSEEN)"**. + +**NOT** - Messages that do not match the specified search key. + +**OLD** - Messages that do not have the \Recent flag set. This is functionally equivalent to + +**"NOT RECENT"** (as opposed to **"NOT NEW"**). + +**ON** - Messages whose internal date (disregarding time and timezone) is within the specified date. + +**OR** - Messages that match either search key. + +**RECENT** - Messages that have the \Recent flag set. + +**SEEN** - Messages that have the \Seen flag set. + +**SENTBEFORE** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is earlier than the specified date. + +**SENTON** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within the specified date. + +**SENTSINCE** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within or later than the specified date. + +**SINCE** - Messages whose internal date (disregarding time and timezone) is within or later than the specified date. + +**SMALLER** - Messages with an (RFC-2822) size smaller than the specified number of octets. + +**SUBJECT** - Messages that contain the specified string in the envelope structure's SUBJECT field. + +**TEXT** - Messages that contain the specified string in the header or body of the message. + +**TO** - Messages that contain the specified string in the envelope structure's TO field. + +**UID** - Messages with unique identifiers corresponding to the specified unique identifier set. + +Sequence set ranges are permitted. + +**UNANSWERED** - Messages that do not have the \Answered flag set. + +**UNDELETED** - Messages that do not have the \Deleted flag set. + +**UNDRAFT** - Messages that do not have the \Draft flag set. + +**UNFLAGGED** - Messages that do not have the \Flagged flag set. + +**UNKEYWORD** - Messages that do not have the specified keyword flag set. + +**UNSEEN** - Messages that do not have the \Seen flag set. + + + + + + + + + +## MailClient.Time functions + + +The helper function to set and get the system time. + + + + + +#### Set the system time from the NTP server. + +param **`gmtOffset`** The GMT time offset in hour. + +param **`daylightOffset`** The Daylight time offset in hour. + +return **`boolean`** The status indicates the success of operation. + +This requires internet connection + +```cpp +bool setClock(float gmtOffset, float daylightOffset); +``` + + + + + +#### Get the timestamp from the year, month, date, hour, minute, and second provided. + +param **`year`** The year. + +param **`mon`** The months from 1 to 12. + +param **`date`** The dates. + +param **`hour`** The hours. + +param **`mins`** The minutes. + +param **`sec`** The seconds. + +return **`time_t`** The value of timestamp. + +```cpp +time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec); +``` + + + + +#### Get the timestamp from the time string. + +param **`gmt`** Return GMT time. + +return **`timestamp`** of time string. + +```cpp +time_t getTimestamp(const char* timeString, bool gmt = false); +``` + + + + + + +#### Get the current timestamp. + +return **`uint64_t`** The value of current timestamp. + +```cpp +uint64_t getCurrentTimestamp(); +``` + + + + + + +#### Get the current date time string that valid for Email + +return **`String`** The current date time string. + +```cpp +String getDateTimeString(); +``` + + + + + + +## License + +The MIT License (MIT) + +Copyright (c) 2023 K. Suwatchai (Mobizt) + + +Permission is hereby granted, free of charge, to any person returning a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/Custom_ESP_SSLClient_FS.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/Custom_ESP_SSLClient_FS.h new file mode 100644 index 000000000..1f28bdb0c --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/Custom_ESP_SSLClient_FS.h @@ -0,0 +1,23 @@ + +#ifndef CUSTOM_ESP_SSLCLIENT_FS_H +#define CUSTOM_ESP_SSLCLIENT_FS_H + +#include "../ESP_Mail_FS.h" + +#if defined(ESP_MAIL_DISABLE_SSL) +#undef USE_LIB_SSL_ENGINE +#undef USE_EMBED_SSL_ENGINE +#endif + +#if defined(ESP_MAIL_USE_PSRAM) +#if !defined(ESP_SSLCLIENT_USE_PSRAM) +#define ESP_SSLCLIENT_USE_PSRAM +#endif +#else +#undef ESP_SSLCLIENT_USE_PSRAM +#endif + +#undef ESP_SSLCLIENT_ENABLE_DEBUG +#undef ESP_SSLCLIENT_ENABLE_SSL_ERROR_STRING + +#endif diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient.h new file mode 100644 index 000000000..a77b08080 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient.h @@ -0,0 +1,79 @@ +/** + * + * The ESP SSL Client Class, ESP_SSLClient.h v2.1.6 + * + * Created August 27, 2023 + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ESP_SSLCLIENT_H +#define ESP_SSLCLIENT_H + +#include "ESP_SSLClient_FS.h" + +#ifndef SSLCLIENT_CONNECTION_UPGRADABLE +#define SSLCLIENT_CONNECTION_UPGRADABLE +#endif +#include "ESP_SSLClient_Const.h" +#if defined(USE_EMBED_SSL_ENGINE) || defined(USE_LIB_SSL_ENGINE) +#include "client/BSSL_TCP_Client.h" +class ESP_SSLClient : public BSSL_TCP_Client +{ +public: + ESP_SSLClient(){}; + ~ESP_SSLClient(){}; +}; + +class ESP_SSLClient2 : public BSSL_TCP_Client +{ +public: + ESP_SSLClient2(Client &client, bool enableSSL = true) : _base_client(client) + { + setClient(&_base_client, enableSSL); + }; + ~ESP_SSLClient2(){}; + +private: + Client &_base_client; +}; + +#else +class ESP_SSLClient +{ +public: + ESP_SSLClient(){}; + ~ESP_SSLClient(){}; +}; + +class ESP_SSLClient2 +{ +public: + ESP_SSLClient2(Client &client, bool enableSSL = true) : _base_client(client){}; + ~ESP_SSLClient2(){}; + +private: + Client &_base_client; +}; +#endif + +#endif diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient_Const.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient_Const.h new file mode 100644 index 000000000..290e702ba --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient_Const.h @@ -0,0 +1,138 @@ +#ifndef ESP_SSLCLIENT_CONST_H +#define ESP_SSLCLIENT_CONST_H + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wvla" + +#include "ESP_SSLClient_FS.h" + +#include +#include + +#if defined(__AVR__) +#undef USE_LIB_SSL_ENGINE +#undef USE_EMBED_SSL_ENGINE +#error "Not support AVR architecture" +#endif + +#define ESP_SSLCLIENT_VALID_TIMESTAMP 1690979919 + +#ifndef SSLCLIENT_CONNECTION_UPGRADABLE +#define SSLCLIENT_CONNECTION_UPGRADABLE +#endif + +#ifdef ESP_SSLCLIENT_ENABLE_DEBUG +#if !defined(ESP_SSLCLIENT_DEBUG_PORT) +#define ESP_SSLCLIENT_DEBUG_PORT Serial +#endif +#define ESP_SSLCLIENT_DEBUG_PRINT ESP_SSLCLIENT_DEBUG_PORT.print +#else +#define ESP_SSLCLIENT_DEBUG_PRINT(...) +#endif + +#if !defined(FPSTR) +#define FPSTR +#endif + +#if defined(USE_EMBED_SSL_ENGINE) || defined(USE_LIB_SSL_ENGINE) + +enum esp_ssl_client_debug_level +{ + esp_ssl_debug_none = 0, + esp_ssl_debug_error = 1, + esp_ssl_debug_warn = 2, + esp_ssl_debug_info = 3, + esp_ssl_debug_dump = 4 +}; + +enum esp_ssl_client_error_types +{ + esp_ssl_ok, + esp_ssl_connection_fail, + esp_ssl_write_error, + esp_ssl_read_error, + esp_ssl_out_of_memory, + esp_ssl_internal_error +}; + +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + +static void esp_ssl_debug_print_prefix(const char *func_name, int level) +{ + ESP_SSLCLIENT_DEBUG_PRINT(PSTR("> ")); + // print the debug level + switch (level) + { + case esp_ssl_debug_info: + ESP_SSLCLIENT_DEBUG_PRINT(PSTR("INFO.")); + break; + case esp_ssl_debug_warn: + ESP_SSLCLIENT_DEBUG_PRINT(PSTR("WARN.")); + break; + case esp_ssl_debug_error: + ESP_SSLCLIENT_DEBUG_PRINT(PSTR("ERROR.")); + break; + default: + break; + } + + // print the function name + ESP_SSLCLIENT_DEBUG_PRINT(PSTR("")); + ESP_SSLCLIENT_DEBUG_PRINT(func_name); + ESP_SSLCLIENT_DEBUG_PRINT(PSTR(": ")); +} + +static void esp_ssl_debug_print(PGM_P msg, int debug_level, int level, const char *func_name) +{ + if (debug_level >= level) + { + esp_ssl_debug_print_prefix(func_name, level); + ESP_SSLCLIENT_DEBUG_PRINT(msg); + ESP_SSLCLIENT_DEBUG_PRINT("\r\n"); + } +} + +#endif + +static uint8_t htoi(unsigned char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return 10 + c - 'A'; + else if (c >= 'a' && c <= 'f') + return 10 + c - 'a'; + else + return 255; +} + +// Helper function which aborts a TLS handshake by sending TLS +// ClientAbort and ClientClose messages. +static bool send_abort(Client *probe, bool supportsLen) +{ + // If we're still connected, send the appropriate notice that + // we're aborting the handshake per RFCs. + static const uint8_t clientAbort_P[] PROGMEM = { + 0x15 /*alert*/, 0x03, 0x03 /*TLS 1.2*/, 0x00, 0x02, + 1, 90 /* warning: user_cancelled */ + }; + static const uint8_t clientClose_P[] PROGMEM = { + 0x15 /*alert*/, 0x03, 0x03 /*TLS 1.2*/, 0x00, 0x02, + 1, 0 /* warning: close_notify */ + }; + if (probe->connected()) + { + uint8_t msg[sizeof(clientAbort_P)]; + memcpy_P(msg, clientAbort_P, sizeof(clientAbort_P)); + probe->write(msg, sizeof(clientAbort_P)); + memcpy_P(msg, clientClose_P, sizeof(clientClose_P)); + probe->write(msg, sizeof(clientClose_P)); + } + return supportsLen; +} + +const uint16_t _secure_ports[26] = {443 /* HTTPS */, 465 /* SMTP */, 563 /* NNTP */, 636 /* LDAPS */, 695 /* IEEE-MMS-SSL */, 832 /* NETCONF */, 853 /* DNS */, 989 /* FTPS */, 990 /* FTPS */, 992 /* Telnet */, 993 /* IMAP */, 995 /* POP3 */, 4116 /* Smartcard */, 4843 /* OPC */, 5061 /* SIP */, 5085 /* LLIP */, 5349 /* NAT */, 5671 /* AMQP */, 5986 /* WinRM-HTTPS */, 6513 /* NETCONF */, 6514 /* Syslog */, 6515 /* Elipse RPC */, 6619 /* OFTP */, 8243 /* Apache Synapse */, 8403 /* GxFWD */, 8883 /* MQTT */}; + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient_FS.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient_FS.h new file mode 100644 index 000000000..8c56a873c --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/ESP_SSLClient_FS.h @@ -0,0 +1,42 @@ +#ifndef ESP_SSLClient_FS_H +#define ESP_SSLClient_FS_H + +// #if (defined(ESP8266) || defined(ARDUINO_ARCH_RP2040)) && !defined(ARDUINO_NANO_RP2040_CONNECT) +// // for ESP8266 and Raspberry Pi Pico (RP2040) only except for Arduino Nano RP2040 Connect +// #define USE_EMBED_SSL_ENGINE +// #else +#define USE_LIB_SSL_ENGINE +// #endif + +#pragma once + +// for enable debugging +#define ESP_SSLCLIENT_ENABLE_DEBUG + +/** Call ssl_client.setDebugLevel(x) to set the debug + * esp_ssl_debug_none = 0 + * esp_ssl_debug_error = 1 + * esp_ssl_debug_warn = 2 + * esp_ssl_debug_info = 3 + * esp_ssl_debug_dump = 4 + */ + +// for debug port +#define ESP_SSLCLIENT_DEBUG_PORT Serial + +// for SSL Error String +#define ESP_SSLCLIENT_ENABLE_SSL_ERROR_STRING + +// for Filesystem support that required for CertStore +#define ESP_SSLCLIENT_USE_FILESYSTEM + +// For external SRAM (PSRAM) support +#define ESP_SSLCLIENT_USE_PSRAM + +#if defined __has_include +#if __has_include() +#include "Custom_ESP_SSLClient_FS.h" +#endif +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl.h new file mode 100644 index 000000000..cc1e52795 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_H__ +#define BR_BEARSSL_H__ + +#include +#include + +/** \mainpage BearSSL API + * + * # API Layout + * + * The functions and structures defined by the BearSSL API are located + * in various header files: + * + * | Header file | Elements | + * | :-------------- | :------------------------------------------------ | + * | bearssl_hash.h | Hash functions | + * | bearssl_hmac.h | HMAC | + * | bearssl_kdf.h | Key Derivation Functions | + * | bearssl_rand.h | Pseudorandom byte generators | + * | bearssl_prf.h | PRF implementations (for SSL/TLS) | + * | bearssl_block.h | Symmetric encryption | + * | bearssl_aead.h | AEAD algorithms (combined encryption + MAC) | + * | bearssl_rsa.h | RSA encryption and signatures | + * | bearssl_ec.h | Elliptic curves support (including ECDSA) | + * | bearssl_ssl.h | SSL/TLS engine interface | + * | bearssl_x509.h | X.509 certificate decoding and validation | + * | bearssl_pem.h | Base64/PEM decoding support functions | + * + * Applications using BearSSL are supposed to simply include `bearssl.h` + * as follows: + * + * #include + * + * The `bearssl.h` file itself includes all the other header files. It is + * possible to include specific header files, but it has no practical + * advantage for the application. The API is separated into separate + * header files only for documentation convenience. + * + * + * # Conventions + * + * ## MUST and SHALL + * + * In all descriptions, the usual "MUST", "SHALL", "MAY",... terminology + * is used. Failure to meet requirements expressed with a "MUST" or + * "SHALL" implies undefined behaviour, which means that segmentation + * faults, buffer overflows, and other similar adverse events, may occur. + * + * In general, BearSSL is not very forgiving of programming errors, and + * does not include much failsafes or error reporting when the problem + * does not arise from external transient conditions, and can be fixed + * only in the application code. This is done so in order to make the + * total code footprint lighter. + * + * + * ## `NULL` values + * + * Function parameters with a pointer type shall not be `NULL` unless + * explicitly authorised by the documentation. As an exception, when + * the pointer aims at a sequence of bytes and is accompanied with + * a length parameter, and the length is zero (meaning that there is + * no byte at all to retrieve), then the pointer may be `NULL` even if + * not explicitly allowed. + * + * + * ## Memory Allocation + * + * BearSSL does not perform dynamic memory allocation. This implies that + * for any functionality that requires a non-transient state, the caller + * is responsible for allocating the relevant context structure. Such + * allocation can be done in any appropriate area, including static data + * segments, the heap, and the stack, provided that proper alignment is + * respected. The header files define these context structures + * (including size and contents), so the C compiler should handle + * alignment automatically. + * + * Since there is no dynamic resource allocation, there is also nothing to + * release. When the calling code is done with a BearSSL feature, it + * may simple release the context structures it allocated itself, with + * no "close function" to call. If the context structures were allocated + * on the stack (as local variables), then even that release operation is + * implicit. + * + * + * ## Structure Contents + * + * Except when explicitly indicated, structure contents are opaque: they + * are included in the header files so that calling code may know the + * structure sizes and alignment requirements, but callers SHALL NOT + * access individual fields directly. For fields that are supposed to + * be read from or written to, the API defines accessor functions (the + * simplest of these accessor functions are defined as `static inline` + * functions, and the C compiler will optimise them away). + * + * + * # API Usage + * + * BearSSL usage for running a SSL/TLS client or server is described + * on the [BearSSL Web site](https://www.bearssl.org/api1.html). The + * BearSSL source archive also comes with sample code. + */ + +#include "bearssl_hash.h" +#include "bearssl_hmac.h" +#include "bearssl_kdf.h" +#include "bearssl_rand.h" +#include "bearssl_prf.h" +#include "bearssl_block.h" +#include "bearssl_aead.h" +#include "bearssl_rsa.h" +#include "bearssl_ec.h" +#include "bearssl_ssl.h" +#include "bearssl_x509.h" +#include "bearssl_pem.h" + +/** \brief Type for a configuration option. + * + * A "configuration option" is a value that is selected when the BearSSL + * library itself is compiled. Most options are boolean; their value is + * then either 1 (option is enabled) or 0 (option is disabled). Some + * values have other integer values. Option names correspond to macro + * names. Some of the options can be explicitly set in the internal + * `"config.h"` file. + */ +typedef struct { + /** \brief Configurable option name. */ + const char *name; + /** \brief Configurable option value. */ + long value; +} br_config_option; + +/** \brief Get configuration report. + * + * This function returns compiled configuration options, each as a + * 'long' value. Names match internal macro names, in particular those + * that can be set in the `"config.h"` inner file. For boolean options, + * the numerical value is 1 if enabled, 0 if disabled. For maximum + * key sizes, values are expressed in bits. + * + * The returned array is terminated by an entry whose `name` is `NULL`. + * + * \return the configuration report. + */ +const br_config_option *br_get_config(void); + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_aead.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_aead.h new file mode 100644 index 000000000..621de90e9 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_aead.h @@ -0,0 +1,1064 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_AEAD_H__ +#define BR_BEARSSL_AEAD_H__ + +#include +#include + +#include "bearssl_block.h" +#include "bearssl_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_aead.h + * + * # Authenticated Encryption with Additional Data + * + * This file documents the API for AEAD encryption. + * + * + * ## Procedural API + * + * An AEAD algorithm processes messages and provides confidentiality + * (encryption) and checked integrity (MAC). It uses the following + * parameters: + * + * - A symmetric key. Exact size depends on the AEAD algorithm. + * + * - A nonce (IV). Size depends on the AEAD algorithm; for most + * algorithms, it is crucial for security that any given nonce + * value is never used twice for the same key and distinct + * messages. + * + * - Data to encrypt and protect. + * + * - Additional authenticated data, which is covered by the MAC but + * otherwise left untouched (i.e. not encrypted). + * + * The AEAD algorithm encrypts the data, and produces an authentication + * tag. It is assumed that the encrypted data, the tag, the additional + * authenticated data and the nonce are sent to the receiver; the + * additional data and the nonce may be implicit (e.g. using elements of + * the underlying transport protocol, such as record sequence numbers). + * The receiver will recompute the tag value and compare it with the one + * received; if they match, then the data is correct, and can be + * decrypted and used; otherwise, at least one of the elements was + * altered in transit, normally leading to wholesale rejection of the + * complete message. + * + * For each AEAD algorithm, identified by a symbolic name (hereafter + * denoted as "`xxx`"), the following functions are defined: + * + * - `br_xxx_init()` + * + * Initialise the AEAD algorithm, on a provided context structure. + * Exact parameters depend on the algorithm, and may include + * pointers to extra implementations and context structures. The + * secret key is provided at this point, either directly or + * indirectly. + * + * - `br_xxx_reset()` + * + * Start a new AEAD computation. The nonce value is provided as + * parameter to this function. + * + * - `br_xxx_aad_inject()` + * + * Inject some additional authenticated data. Additional data may + * be provided in several chunks of arbitrary length. + * + * - `br_xxx_flip()` + * + * This function MUST be called after injecting all additional + * authenticated data, and before beginning to encrypt the plaintext + * (or decrypt the ciphertext). + * + * - `br_xxx_run()` + * + * Process some plaintext (to encrypt) or ciphertext (to decrypt). + * Encryption/decryption is done in place. Data may be provided in + * several chunks of arbitrary length. + * + * - `br_xxx_get_tag()` + * + * Compute the authentication tag. All message data (encrypted or + * decrypted) must have been injected at that point. Also, this + * call may modify internal context elements, so it may be called + * only once for a given AEAD computation. + * + * - `br_xxx_check_tag()` + * + * An alternative to `br_xxx_get_tag()`, meant to be used by the + * receiver: the authentication tag is internally recomputed, and + * compared with the one provided as parameter. + * + * This API makes the following assumptions on the AEAD algorithm: + * + * - Encryption does not expand the size of the ciphertext; there is + * no padding. This is true of most modern AEAD modes such as GCM. + * + * - The additional authenticated data must be processed first, + * before the encrypted/decrypted data. + * + * - Nonce, plaintext and additional authenticated data all consist + * in an integral number of bytes. There is no provision to use + * elements whose length in bits is not a multiple of 8. + * + * Each AEAD algorithm has its own requirements and limits on the sizes + * of additional data and plaintext. This API does not provide any + * way to report invalid usage; it is up to the caller to ensure that + * the provided key, nonce, and data elements all fit the algorithm's + * requirements. + * + * + * ## Object-Oriented API + * + * Each context structure begins with a field (called `vtable`) that + * points to an instance of a structure that references the relevant + * functions through pointers. Each such structure contains the + * following: + * + * - `reset` + * + * Pointer to the reset function, that allows starting a new + * computation. + * + * - `aad_inject` + * + * Pointer to the additional authenticated data injection function. + * + * - `flip` + * + * Pointer to the function that transitions from additional data + * to main message data processing. + * + * - `get_tag` + * + * Pointer to the function that computes and returns the tag. + * + * - `check_tag` + * + * Pointer to the function that computes and verifies the tag against + * a received value. + * + * Note that there is no OOP method for context initialisation: the + * various AEAD algorithms have different requirements that would not + * map well to a single initialisation API. + * + * The OOP API is not provided for CCM, due to its specific requirements + * (length of plaintext must be known in advance). + */ + +/** + * \brief Class type of an AEAD algorithm. + */ +typedef struct br_aead_class_ br_aead_class; +struct br_aead_class_ { + + /** + * \brief Size (in bytes) of authentication tags created by + * this AEAD algorithm. + */ + size_t tag_size; + + /** + * \brief Reset an AEAD context. + * + * This function resets an already initialised AEAD context for + * a new computation run. Implementations and keys are + * conserved. This function can be called at any time; it + * cancels any ongoing AEAD computation that uses the provided + * context structure. + + * The provided IV is a _nonce_. Each AEAD algorithm has its + * own requirements on IV size and contents; for most of them, + * it is crucial to security that each nonce value is used + * only once for a given secret key. + * + * \param cc AEAD context structure. + * \param iv AEAD nonce to use. + * \param len AEAD nonce length (in bytes). + */ + void (*reset)(const br_aead_class **cc, const void *iv, size_t len); + + /** + * \brief Inject additional authenticated data. + * + * The provided data is injected into a running AEAD + * computation. Additional data must be injected _before_ the + * call to `flip()`. Additional data can be injected in several + * chunks of arbitrary length. + * + * \param cc AEAD context structure. + * \param data pointer to additional authenticated data. + * \param len length of additional authenticated data (in bytes). + */ + void (*aad_inject)(const br_aead_class **cc, + const void *data, size_t len); + + /** + * \brief Finish injection of additional authenticated data. + * + * This function MUST be called before beginning the actual + * encryption or decryption (with `run()`), even if no + * additional authenticated data was injected. No additional + * authenticated data may be injected after this function call. + * + * \param cc AEAD context structure. + */ + void (*flip)(const br_aead_class **cc); + + /** + * \brief Encrypt or decrypt some data. + * + * Data encryption or decryption can be done after `flip()` has + * been called on the context. If `encrypt` is non-zero, then + * the provided data shall be plaintext, and it is encrypted in + * place. Otherwise, the data shall be ciphertext, and it is + * decrypted in place. + * + * Data may be provided in several chunks of arbitrary length. + * + * \param cc AEAD context structure. + * \param encrypt non-zero for encryption, zero for decryption. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ + void (*run)(const br_aead_class **cc, int encrypt, + void *data, size_t len); + + /** + * \brief Compute authentication tag. + * + * Compute the AEAD authentication tag. The tag length depends + * on the AEAD algorithm; it is written in the provided `tag` + * buffer. This call terminates the AEAD run: no data may be + * processed with that AEAD context afterwards, until `reset()` + * is called to initiate a new AEAD run. + * + * The tag value must normally be sent along with the encrypted + * data. When decrypting, the tag value must be recomputed and + * compared with the received tag: if the two tag values differ, + * then either the tag or the encrypted data was altered in + * transit. As an alternative to this function, the + * `check_tag()` function may be used to compute and check the + * tag value. + * + * Tag length depends on the AEAD algorithm. + * + * \param cc AEAD context structure. + * \param tag destination buffer for the tag. + */ + void (*get_tag)(const br_aead_class **cc, void *tag); + + /** + * \brief Compute and check authentication tag. + * + * This function is an alternative to `get_tag()`, and is + * normally used on the receiving end (i.e. when decrypting + * messages). The tag value is recomputed and compared with the + * provided tag value. If they match, 1 is returned; on + * mismatch, 0 is returned. A returned value of 0 means that the + * data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * Tag length depends on the AEAD algorithm. + * + * \param cc AEAD context structure. + * \param tag tag value to compare with. + * \return 1 on success (exact match of tag value), 0 otherwise. + */ + uint32_t (*check_tag)(const br_aead_class **cc, const void *tag); + + /** + * \brief Compute authentication tag (with truncation). + * + * This function is similar to `get_tag()`, except that the tag + * length is provided. Some AEAD algorithms allow several tag + * lengths, usually by truncating the normal tag. Shorter tags + * mechanically increase success probability of forgeries. + * The range of allowed tag lengths depends on the algorithm. + * + * \param cc AEAD context structure. + * \param tag destination buffer for the tag. + * \param len tag length (in bytes). + */ + void (*get_tag_trunc)(const br_aead_class **cc, void *tag, size_t len); + + /** + * \brief Compute and check authentication tag (with truncation). + * + * This function is similar to `check_tag()` except that it + * works over an explicit tag length. See `get_tag()` for a + * discussion of explicit tag lengths; the range of allowed tag + * lengths depends on the algorithm. + * + * \param cc AEAD context structure. + * \param tag tag value to compare with. + * \param len tag length (in bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ + uint32_t (*check_tag_trunc)(const br_aead_class **cc, + const void *tag, size_t len); +}; + +/** + * \brief Context structure for GCM. + * + * GCM is an AEAD mode that combines a block cipher in CTR mode with a + * MAC based on GHASH, to provide authenticated encryption: + * + * - Any block cipher with 16-byte blocks can be used with GCM. + * + * - The nonce can have any length, from 0 up to 2^64-1 bits; however, + * 96-bit nonces (12 bytes) are recommended (nonces with a length + * distinct from 12 bytes are internally hashed, which risks reusing + * nonce value with a small but not always negligible probability). + * + * - Additional authenticated data may have length up to 2^64-1 bits. + * + * - Message length may range up to 2^39-256 bits at most. + * + * - The authentication tag has length 16 bytes. + * + * The GCM initialisation function receives as parameter an + * _initialised_ block cipher implementation context, with the secret + * key already set. A pointer to that context will be kept within the + * GCM context structure. It is up to the caller to allocate and + * initialise that block cipher context. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_aead_class *vtable; + +#ifndef BR_DOXYGEN_IGNORE + const br_block_ctr_class **bctx; + br_ghash gh; + unsigned char h[16]; + unsigned char j0_1[12]; + unsigned char buf[16]; + unsigned char y[16]; + uint32_t j0_2, jc; + uint64_t count_aad, count_ctr; +#endif +} br_gcm_context; + +/** + * \brief Initialize a GCM context. + * + * A block cipher implementation, with its initialised context structure, + * is provided. The block cipher MUST use 16-byte blocks in CTR mode, + * and its secret key MUST have been already set in the provided context. + * A GHASH implementation must also be provided. The parameters are linked + * in the GCM context. + * + * After this function has been called, the `br_gcm_reset()` function must + * be called, to provide the IV for GCM computation. + * + * \param ctx GCM context structure. + * \param bctx block cipher context (already initialised with secret key). + * \param gh GHASH implementation. + */ +void br_gcm_init(br_gcm_context *ctx, + const br_block_ctr_class **bctx, br_ghash gh); + +/** + * \brief Reset a GCM context. + * + * This function resets an already initialised GCM context for a new + * computation run. Implementations and keys are conserved. This function + * can be called at any time; it cancels any ongoing GCM computation that + * uses the provided context structure. + * + * The provided IV is a _nonce_. It is critical to GCM security that IV + * values are not repeated for the same encryption key. IV can have + * arbitrary length (up to 2^64-1 bits), but the "normal" length is + * 96 bits (12 bytes). + * + * \param ctx GCM context structure. + * \param iv GCM nonce to use. + * \param len GCM nonce length (in bytes). + */ +void br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len); + +/** + * \brief Inject additional authenticated data into GCM. + * + * The provided data is injected into a running GCM computation. Additional + * data must be injected _before_ the call to `br_gcm_flip()`. + * Additional data can be injected in several chunks of arbitrary length; + * the maximum total size of additional authenticated data is 2^64-1 + * bits. + * + * \param ctx GCM context structure. + * \param data pointer to additional authenticated data. + * \param len length of additional authenticated data (in bytes). + */ +void br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len); + +/** + * \brief Finish injection of additional authenticated data into GCM. + * + * This function MUST be called before beginning the actual encryption + * or decryption (with `br_gcm_run()`), even if no additional authenticated + * data was injected. No additional authenticated data may be injected + * after this function call. + * + * \param ctx GCM context structure. + */ +void br_gcm_flip(br_gcm_context *ctx); + +/** + * \brief Encrypt or decrypt some data with GCM. + * + * Data encryption or decryption can be done after `br_gcm_flip()` + * has been called on the context. If `encrypt` is non-zero, then the + * provided data shall be plaintext, and it is encrypted in place. + * Otherwise, the data shall be ciphertext, and it is decrypted in place. + * + * Data may be provided in several chunks of arbitrary length. The maximum + * total length for data is 2^39-256 bits, i.e. about 65 gigabytes. + * + * \param ctx GCM context structure. + * \param encrypt non-zero for encryption, zero for decryption. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +void br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len); + +/** + * \brief Compute GCM authentication tag. + * + * Compute the GCM authentication tag. The tag is a 16-byte value which + * is written in the provided `tag` buffer. This call terminates the + * GCM run: no data may be processed with that GCM context afterwards, + * until `br_gcm_reset()` is called to initiate a new GCM run. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_gcm_check_tag()` function can be used to + * compute and check the tag value. + * + * \param ctx GCM context structure. + * \param tag destination buffer for the tag (16 bytes). + */ +void br_gcm_get_tag(br_gcm_context *ctx, void *tag); + +/** + * \brief Compute and check GCM authentication tag. + * + * This function is an alternative to `br_gcm_get_tag()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * \param ctx GCM context structure. + * \param tag tag value to compare with (16 bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_gcm_check_tag(br_gcm_context *ctx, const void *tag); + +/** + * \brief Compute GCM authentication tag (with truncation). + * + * This function is similar to `br_gcm_get_tag()`, except that it allows + * the tag to be truncated to a smaller length. The intended tag length + * is provided as `len` (in bytes); it MUST be no more than 16, but + * it may be smaller. Note that decreasing tag length mechanically makes + * forgeries easier; NIST SP 800-38D specifies that the tag length shall + * lie between 12 and 16 bytes (inclusive), but may be truncated down to + * 4 or 8 bytes, for specific applications that can tolerate it. It must + * also be noted that successful forgeries leak information on the + * authentication key, making subsequent forgeries easier. Therefore, + * tag truncation, and in particular truncation to sizes lower than 12 + * bytes, shall be envisioned only with great care. + * + * The tag is written in the provided `tag` buffer. This call terminates + * the GCM run: no data may be processed with that GCM context + * afterwards, until `br_gcm_reset()` is called to initiate a new GCM + * run. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_gcm_check_tag_trunc()` function can be used to + * compute and check the tag value. + * + * \param ctx GCM context structure. + * \param tag destination buffer for the tag. + * \param len tag length (16 bytes or less). + */ +void br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len); + +/** + * \brief Compute and check GCM authentication tag (with truncation). + * + * This function is an alternative to `br_gcm_get_tag_trunc()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * Tag length MUST be 16 bytes or less. The normal GCM tag length is 16 + * bytes. See `br_check_tag_trunc()` for some discussion on the potential + * perils of truncating authentication tags. + * + * \param ctx GCM context structure. + * \param tag tag value to compare with. + * \param len tag length (in bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_gcm_check_tag_trunc(br_gcm_context *ctx, + const void *tag, size_t len); + +/** + * \brief Class instance for GCM. + */ +extern const br_aead_class br_gcm_vtable; + +/** + * \brief Context structure for EAX. + * + * EAX is an AEAD mode that combines a block cipher in CTR mode with + * CBC-MAC using the same block cipher and the same key, to provide + * authenticated encryption: + * + * - Any block cipher with 16-byte blocks can be used with EAX + * (technically, other block sizes are defined as well, but this + * is not implemented by these functions; shorter blocks also + * imply numerous security issues). + * + * - The nonce can have any length, as long as nonce values are + * not reused (thus, if nonces are randomly selected, the nonce + * size should be such that reuse probability is negligible). + * + * - Additional authenticated data length is unlimited. + * + * - Message length is unlimited. + * + * - The authentication tag has length 16 bytes. + * + * The EAX initialisation function receives as parameter an + * _initialised_ block cipher implementation context, with the secret + * key already set. A pointer to that context will be kept within the + * EAX context structure. It is up to the caller to allocate and + * initialise that block cipher context. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_aead_class *vtable; + +#ifndef BR_DOXYGEN_IGNORE + const br_block_ctrcbc_class **bctx; + unsigned char L2[16]; + unsigned char L4[16]; + unsigned char nonce[16]; + unsigned char head[16]; + unsigned char ctr[16]; + unsigned char cbcmac[16]; + unsigned char buf[16]; + size_t ptr; +#endif +} br_eax_context; + +/** + * \brief EAX captured state. + * + * Some internal values computed by EAX may be captured at various + * points, and reused for another EAX run with the same secret key, + * for lower per-message overhead. Captured values do not depend on + * the nonce. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + unsigned char st[3][16]; +#endif +} br_eax_state; + +/** + * \brief Initialize an EAX context. + * + * A block cipher implementation, with its initialised context + * structure, is provided. The block cipher MUST use 16-byte blocks in + * CTR + CBC-MAC mode, and its secret key MUST have been already set in + * the provided context. The parameters are linked in the EAX context. + * + * After this function has been called, the `br_eax_reset()` function must + * be called, to provide the nonce for EAX computation. + * + * \param ctx EAX context structure. + * \param bctx block cipher context (already initialised with secret key). + */ +void br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx); + +/** + * \brief Capture pre-AAD state. + * + * This function precomputes key-dependent data, and stores it in the + * provided `st` structure. This structure should then be used with + * `br_eax_reset_pre_aad()`, or updated with `br_eax_get_aad_mac()` + * and then used with `br_eax_reset_post_aad()`. + * + * The EAX context structure is unmodified by this call. + * + * \param ctx EAX context structure. + * \param st recipient for captured state. + */ +void br_eax_capture(const br_eax_context *ctx, br_eax_state *st); + +/** + * \brief Reset an EAX context. + * + * This function resets an already initialised EAX context for a new + * computation run. Implementations and keys are conserved. This function + * can be called at any time; it cancels any ongoing EAX computation that + * uses the provided context structure. + * + * It is critical to EAX security that nonce values are not repeated for + * the same encryption key. Nonces can have arbitrary length. If nonces + * are randomly generated, then a nonce length of at least 128 bits (16 + * bytes) is recommended, to make nonce reuse probability sufficiently + * low. + * + * \param ctx EAX context structure. + * \param nonce EAX nonce to use. + * \param len EAX nonce length (in bytes). + */ +void br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len); + +/** + * \brief Reset an EAX context with a pre-AAD captured state. + * + * This function is an alternative to `br_eax_reset()`, that reuses a + * previously captured state structure for lower per-message overhead. + * The state should have been populated with `br_eax_capture_state()` + * but not updated with `br_eax_get_aad_mac()`. + * + * After this function is called, additional authenticated data MUST + * be injected. At least one byte of additional authenticated data + * MUST be provided with `br_eax_aad_inject()`; computation result will + * be incorrect if `br_eax_flip()` is called right away. + * + * After injection of the AAD and call to `br_eax_flip()`, at least + * one message byte must be provided. Empty messages are not supported + * with this reset mode. + * + * \param ctx EAX context structure. + * \param st pre-AAD captured state. + * \param nonce EAX nonce to use. + * \param len EAX nonce length (in bytes). + */ +void br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st, + const void *nonce, size_t len); + +/** + * \brief Reset an EAX context with a post-AAD captured state. + * + * This function is an alternative to `br_eax_reset()`, that reuses a + * previously captured state structure for lower per-message overhead. + * The state should have been populated with `br_eax_capture_state()` + * and then updated with `br_eax_get_aad_mac()`. + * + * After this function is called, message data MUST be injected. The + * `br_eax_flip()` function MUST NOT be called. At least one byte of + * message data MUST be provided with `br_eax_run()`; empty messages + * are not supported with this reset mode. + * + * \param ctx EAX context structure. + * \param st post-AAD captured state. + * \param nonce EAX nonce to use. + * \param len EAX nonce length (in bytes). + */ +void br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st, + const void *nonce, size_t len); + +/** + * \brief Inject additional authenticated data into EAX. + * + * The provided data is injected into a running EAX computation. Additional + * data must be injected _before_ the call to `br_eax_flip()`. + * Additional data can be injected in several chunks of arbitrary length; + * the total amount of additional authenticated data is unlimited. + * + * \param ctx EAX context structure. + * \param data pointer to additional authenticated data. + * \param len length of additional authenticated data (in bytes). + */ +void br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len); + +/** + * \brief Finish injection of additional authenticated data into EAX. + * + * This function MUST be called before beginning the actual encryption + * or decryption (with `br_eax_run()`), even if no additional authenticated + * data was injected. No additional authenticated data may be injected + * after this function call. + * + * \param ctx EAX context structure. + */ +void br_eax_flip(br_eax_context *ctx); + +/** + * \brief Obtain a copy of the MAC on additional authenticated data. + * + * This function may be called only after `br_eax_flip()`; it copies the + * AAD-specific MAC value into the provided state. The MAC value depends + * on the secret key and the additional data itself, but not on the + * nonce. The updated state `st` is meant to be used as parameter for a + * further `br_eax_reset_post_aad()` call. + * + * \param ctx EAX context structure. + * \param st captured state to update. + */ +static inline void +br_eax_get_aad_mac(const br_eax_context *ctx, br_eax_state *st) +{ + memcpy(st->st[1], ctx->head, sizeof ctx->head); +} + +/** + * \brief Encrypt or decrypt some data with EAX. + * + * Data encryption or decryption can be done after `br_eax_flip()` + * has been called on the context. If `encrypt` is non-zero, then the + * provided data shall be plaintext, and it is encrypted in place. + * Otherwise, the data shall be ciphertext, and it is decrypted in place. + * + * Data may be provided in several chunks of arbitrary length. + * + * \param ctx EAX context structure. + * \param encrypt non-zero for encryption, zero for decryption. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +void br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len); + +/** + * \brief Compute EAX authentication tag. + * + * Compute the EAX authentication tag. The tag is a 16-byte value which + * is written in the provided `tag` buffer. This call terminates the + * EAX run: no data may be processed with that EAX context afterwards, + * until `br_eax_reset()` is called to initiate a new EAX run. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_eax_check_tag()` function can be used to + * compute and check the tag value. + * + * \param ctx EAX context structure. + * \param tag destination buffer for the tag (16 bytes). + */ +void br_eax_get_tag(br_eax_context *ctx, void *tag); + +/** + * \brief Compute and check EAX authentication tag. + * + * This function is an alternative to `br_eax_get_tag()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * \param ctx EAX context structure. + * \param tag tag value to compare with (16 bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_eax_check_tag(br_eax_context *ctx, const void *tag); + +/** + * \brief Compute EAX authentication tag (with truncation). + * + * This function is similar to `br_eax_get_tag()`, except that it allows + * the tag to be truncated to a smaller length. The intended tag length + * is provided as `len` (in bytes); it MUST be no more than 16, but + * it may be smaller. Note that decreasing tag length mechanically makes + * forgeries easier; NIST SP 800-38D specifies that the tag length shall + * lie between 12 and 16 bytes (inclusive), but may be truncated down to + * 4 or 8 bytes, for specific applications that can tolerate it. It must + * also be noted that successful forgeries leak information on the + * authentication key, making subsequent forgeries easier. Therefore, + * tag truncation, and in particular truncation to sizes lower than 12 + * bytes, shall be envisioned only with great care. + * + * The tag is written in the provided `tag` buffer. This call terminates + * the EAX run: no data may be processed with that EAX context + * afterwards, until `br_eax_reset()` is called to initiate a new EAX + * run. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_eax_check_tag_trunc()` function can be used to + * compute and check the tag value. + * + * \param ctx EAX context structure. + * \param tag destination buffer for the tag. + * \param len tag length (16 bytes or less). + */ +void br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len); + +/** + * \brief Compute and check EAX authentication tag (with truncation). + * + * This function is an alternative to `br_eax_get_tag_trunc()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * Tag length MUST be 16 bytes or less. The normal EAX tag length is 16 + * bytes. See `br_check_tag_trunc()` for some discussion on the potential + * perils of truncating authentication tags. + * + * \param ctx EAX context structure. + * \param tag tag value to compare with. + * \param len tag length (in bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_eax_check_tag_trunc(br_eax_context *ctx, + const void *tag, size_t len); + +/** + * \brief Class instance for EAX. + */ +extern const br_aead_class br_eax_vtable; + +/** + * \brief Context structure for CCM. + * + * CCM is an AEAD mode that combines a block cipher in CTR mode with + * CBC-MAC using the same block cipher and the same key, to provide + * authenticated encryption: + * + * - Any block cipher with 16-byte blocks can be used with CCM + * (technically, other block sizes are defined as well, but this + * is not implemented by these functions; shorter blocks also + * imply numerous security issues). + * + * - The authentication tag length, and plaintext length, MUST be + * known when starting processing data. Plaintext and ciphertext + * can still be provided by chunks, but the total size must match + * the value provided upon initialisation. + * + * - The nonce length is constrained between 7 and 13 bytes (inclusive). + * Furthermore, the plaintext length, when encoded, must fit over + * 15-nonceLen bytes; thus, if the nonce has length 13 bytes, then + * the plaintext length cannot exceed 65535 bytes. + * + * - Additional authenticated data length is practically unlimited + * (formal limit is at 2^64 bytes). + * + * - The authentication tag has length 4 to 16 bytes (even values only). + * + * The CCM initialisation function receives as parameter an + * _initialised_ block cipher implementation context, with the secret + * key already set. A pointer to that context will be kept within the + * CCM context structure. It is up to the caller to allocate and + * initialise that block cipher context. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + const br_block_ctrcbc_class **bctx; + unsigned char ctr[16]; + unsigned char cbcmac[16]; + unsigned char tagmask[16]; + unsigned char buf[16]; + size_t ptr; + size_t tag_len; +#endif +} br_ccm_context; + +/** + * \brief Initialize a CCM context. + * + * A block cipher implementation, with its initialised context + * structure, is provided. The block cipher MUST use 16-byte blocks in + * CTR + CBC-MAC mode, and its secret key MUST have been already set in + * the provided context. The parameters are linked in the CCM context. + * + * After this function has been called, the `br_ccm_reset()` function must + * be called, to provide the nonce for CCM computation. + * + * \param ctx CCM context structure. + * \param bctx block cipher context (already initialised with secret key). + */ +void br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx); + +/** + * \brief Reset a CCM context. + * + * This function resets an already initialised CCM context for a new + * computation run. Implementations and keys are conserved. This function + * can be called at any time; it cancels any ongoing CCM computation that + * uses the provided context structure. + * + * The `aad_len` parameter contains the total length, in bytes, of the + * additional authenticated data. It may be zero. That length MUST be + * exact. + * + * The `data_len` parameter contains the total length, in bytes, of the + * data that will be injected (plaintext or ciphertext). That length MUST + * be exact. Moreover, that length MUST be less than 2^(8*(15-nonce_len)). + * + * The nonce length (`nonce_len`), in bytes, must be in the 7..13 range + * (inclusive). + * + * The tag length (`tag_len`), in bytes, must be in the 4..16 range, and + * be an even integer. Short tags mechanically allow for higher forgery + * probabilities; hence, tag sizes smaller than 12 bytes shall be used only + * with care. + * + * It is critical to CCM security that nonce values are not repeated for + * the same encryption key. Random generation of nonces is not generally + * recommended, due to the relatively small maximum nonce value. + * + * Returned value is 1 on success, 0 on error. An error is reported if + * the tag or nonce length is out of range, or if the + * plaintext/ciphertext length cannot be encoded with the specified + * nonce length. + * + * \param ctx CCM context structure. + * \param nonce CCM nonce to use. + * \param nonce_len CCM nonce length (in bytes, 7 to 13). + * \param aad_len additional authenticated data length (in bytes). + * \param data_len plaintext/ciphertext length (in bytes). + * \param tag_len tag length (in bytes). + * \return 1 on success, 0 on error. + */ +int br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len, + uint64_t aad_len, uint64_t data_len, size_t tag_len); + +/** + * \brief Inject additional authenticated data into CCM. + * + * The provided data is injected into a running CCM computation. Additional + * data must be injected _before_ the call to `br_ccm_flip()`. + * Additional data can be injected in several chunks of arbitrary length, + * but the total amount MUST exactly match the value which was provided + * to `br_ccm_reset()`. + * + * \param ctx CCM context structure. + * \param data pointer to additional authenticated data. + * \param len length of additional authenticated data (in bytes). + */ +void br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len); + +/** + * \brief Finish injection of additional authenticated data into CCM. + * + * This function MUST be called before beginning the actual encryption + * or decryption (with `br_ccm_run()`), even if no additional authenticated + * data was injected. No additional authenticated data may be injected + * after this function call. + * + * \param ctx CCM context structure. + */ +void br_ccm_flip(br_ccm_context *ctx); + +/** + * \brief Encrypt or decrypt some data with CCM. + * + * Data encryption or decryption can be done after `br_ccm_flip()` + * has been called on the context. If `encrypt` is non-zero, then the + * provided data shall be plaintext, and it is encrypted in place. + * Otherwise, the data shall be ciphertext, and it is decrypted in place. + * + * Data may be provided in several chunks of arbitrary length, provided + * that the total length exactly matches the length provided to the + * `br_ccm_reset()` call. + * + * \param ctx CCM context structure. + * \param encrypt non-zero for encryption, zero for decryption. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +void br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len); + +/** + * \brief Compute CCM authentication tag. + * + * Compute the CCM authentication tag. This call terminates the CCM + * run: all data must have been injected with `br_ccm_run()` (in zero, + * one or more successive calls). After this function has been called, + * no more data can br processed; a `br_ccm_reset()` call is required + * to start a new message. + * + * The tag length was provided upon context initialisation (last call + * to `br_ccm_reset()`); it is returned by this function. + * + * The tag value must normally be sent along with the encrypted data. + * When decrypting, the tag value must be recomputed and compared with + * the received tag: if the two tag values differ, then either the tag + * or the encrypted data was altered in transit. As an alternative to + * this function, the `br_ccm_check_tag()` function can be used to + * compute and check the tag value. + * + * \param ctx CCM context structure. + * \param tag destination buffer for the tag (up to 16 bytes). + * \return the tag length (in bytes). + */ +size_t br_ccm_get_tag(br_ccm_context *ctx, void *tag); + +/** + * \brief Compute and check CCM authentication tag. + * + * This function is an alternative to `br_ccm_get_tag()`, normally used + * on the receiving end (i.e. when decrypting value). The tag value is + * recomputed and compared with the provided tag value. If they match, 1 + * is returned; on mismatch, 0 is returned. A returned value of 0 means + * that the data or the tag was altered in transit, normally leading to + * wholesale rejection of the complete message. + * + * \param ctx CCM context structure. + * \param tag tag value to compare with (up to 16 bytes). + * \return 1 on success (exact match of tag value), 0 otherwise. + */ +uint32_t br_ccm_check_tag(br_ccm_context *ctx, const void *tag); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_block.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_block.h new file mode 100644 index 000000000..22a9434ee --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_block.h @@ -0,0 +1,2623 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_BLOCK_H__ +#define BR_BEARSSL_BLOCK_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_block.h + * + * # Block Ciphers and Symmetric Ciphers + * + * This file documents the API for block ciphers and other symmetric + * ciphers. + * + * + * ## Procedural API + * + * For a block cipher implementation, up to three separate sets of + * functions are provided, for CBC encryption, CBC decryption, and CTR + * encryption/decryption. Each set has its own context structure, + * initialised with the encryption key. + * + * For CBC encryption and decryption, the data to encrypt or decrypt is + * referenced as a sequence of blocks. The implementations assume that + * there is no partial block; no padding is applied or removed. The + * caller is responsible for handling any kind of padding. + * + * Function for CTR encryption are defined only for block ciphers with + * blocks of 16 bytes or more (i.e. AES, but not DES/3DES). + * + * Each implemented block cipher is identified by an "internal name" + * from which are derived the names of structures and functions that + * implement the cipher. For the block cipher of internal name "`xxx`", + * the following are defined: + * + * - `br_xxx_BLOCK_SIZE` + * + * A macro that evaluates to the block size (in bytes) of the + * cipher. For all implemented block ciphers, this value is a + * power of two. + * + * - `br_xxx_cbcenc_keys` + * + * Context structure that contains the subkeys resulting from the key + * expansion. These subkeys are appropriate for CBC encryption. The + * structure first field is called `vtable` and points to the + * appropriate OOP structure. + * + * - `br_xxx_cbcenc_init(br_xxx_cbcenc_keys *ctx, const void *key, size_t len)` + * + * Perform key expansion: subkeys for CBC encryption are computed and + * written in the provided context structure. The key length MUST be + * adequate for the implemented block cipher. This function also sets + * the `vtable` field. + * + * - `br_xxx_cbcenc_run(const br_xxx_cbcenc_keys *ctx, void *iv, void *data, size_t len)` + * + * Perform CBC encryption of `len` bytes, in place. The encrypted data + * replaces the cleartext. `len` MUST be a multiple of the block length + * (if it is not, the function may loop forever or overflow a buffer). + * The IV is provided with the `iv` pointer; it is also updated with + * a copy of the last encrypted block. + * + * - `br_xxx_cbcdec_keys` + * + * Context structure that contains the subkeys resulting from the key + * expansion. These subkeys are appropriate for CBC decryption. The + * structure first field is called `vtable` and points to the + * appropriate OOP structure. + * + * - `br_xxx_cbcdec_init(br_xxx_cbcenc_keys *ctx, const void *key, size_t len)` + * + * Perform key expansion: subkeys for CBC decryption are computed and + * written in the provided context structure. The key length MUST be + * adequate for the implemented block cipher. This function also sets + * the `vtable` field. + * + * - `br_xxx_cbcdec_run(const br_xxx_cbcdec_keys *ctx, void *iv, void *data, size_t num_blocks)` + * + * Perform CBC decryption of `len` bytes, in place. The decrypted data + * replaces the ciphertext. `len` MUST be a multiple of the block length + * (if it is not, the function may loop forever or overflow a buffer). + * The IV is provided with the `iv` pointer; it is also updated with + * a copy of the last _encrypted_ block. + * + * - `br_xxx_ctr_keys` + * + * Context structure that contains the subkeys resulting from the key + * expansion. These subkeys are appropriate for CTR encryption and + * decryption. The structure first field is called `vtable` and + * points to the appropriate OOP structure. + * + * - `br_xxx_ctr_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)` + * + * Perform key expansion: subkeys for CTR encryption and decryption + * are computed and written in the provided context structure. The + * key length MUST be adequate for the implemented block cipher. This + * function also sets the `vtable` field. + * + * - `br_xxx_ctr_run(const br_xxx_ctr_keys *ctx, const void *iv, uint32_t cc, void *data, size_t len)` (returns `uint32_t`) + * + * Perform CTR encryption/decryption of some data. Processing is done + * "in place" (the output data replaces the input data). This function + * implements the "standard incrementing function" from NIST SP800-38A, + * annex B: the IV length shall be 4 bytes less than the block size + * (i.e. 12 bytes for AES) and the counter is the 32-bit value starting + * with `cc`. The data length (`len`) is not necessarily a multiple of + * the block size. The new counter value is returned, which supports + * chunked processing, provided that each chunk length (except possibly + * the last one) is a multiple of the block size. + * + * - `br_xxx_ctrcbc_keys` + * + * Context structure that contains the subkeys resulting from the + * key expansion. These subkeys are appropriate for doing combined + * CTR encryption/decryption and CBC-MAC, as used in the CCM and EAX + * authenticated encryption modes. The structure first field is + * called `vtable` and points to the appropriate OOP structure. + * + * - `br_xxx_ctrcbc_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)` + * + * Perform key expansion: subkeys for combined CTR + * encryption/decryption and CBC-MAC are computed and written in the + * provided context structure. The key length MUST be adequate for + * the implemented block cipher. This function also sets the + * `vtable` field. + * + * - `br_xxx_ctrcbc_encrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)` + * + * Perform CTR encryption of some data, and CBC-MAC. Processing is + * done "in place" (the output data replaces the input data). This + * function applies CTR encryption on the data, using a full + * block-size counter (i.e. for 128-bit blocks, the counter is + * incremented as a 128-bit value). The 'ctr' array contains the + * initial value for the counter (used in the first block) and it is + * updated with the new value after data processing. The 'cbcmac' + * value shall point to a block-sized value which is used as IV for + * CBC-MAC, computed over the encrypted data (output of CTR + * encryption); the resulting CBC-MAC is written over 'cbcmac' on + * output. + * + * The data length MUST be a multiple of the block size. + * + * - `br_xxx_ctrcbc_decrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)` + * + * Perform CTR decryption of some data, and CBC-MAC. Processing is + * done "in place" (the output data replaces the input data). This + * function applies CTR decryption on the data, using a full + * block-size counter (i.e. for 128-bit blocks, the counter is + * incremented as a 128-bit value). The 'ctr' array contains the + * initial value for the counter (used in the first block) and it is + * updated with the new value after data processing. The 'cbcmac' + * value shall point to a block-sized value which is used as IV for + * CBC-MAC, computed over the encrypted data (input of CTR + * encryption); the resulting CBC-MAC is written over 'cbcmac' on + * output. + * + * The data length MUST be a multiple of the block size. + * + * - `br_xxx_ctrcbc_ctr(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *data, size_t len)` + * + * Perform CTR encryption or decryption of the provided data. The + * data is processed "in place" (the output data replaces the input + * data). A full block-sized counter is applied (i.e. for 128-bit + * blocks, the counter is incremented as a 128-bit value). The 'ctr' + * array contains the initial value for the counter (used in the + * first block), and it is updated with the new value after data + * processing. + * + * The data length MUST be a multiple of the block size. + * + * - `br_xxx_ctrcbc_mac(const br_xxx_ctrcbc_keys *ctx, void *cbcmac, const void *data, size_t len)` + * + * Compute CBC-MAC over the provided data. The IV for CBC-MAC is + * provided as 'cbcmac'; the output is written over the same array. + * The data itself is untouched. The data length MUST be a multiple + * of the block size. + * + * + * It shall be noted that the key expansion functions return `void`. If + * the provided key length is not allowed, then there will be no error + * reporting; implementations need not validate the key length, thus an + * invalid key length may result in undefined behaviour (e.g. buffer + * overflow). + * + * Subkey structures contain no interior pointer, and no external + * resources are allocated upon key expansion. They can thus be + * discarded without any explicit deallocation. + * + * + * ## Object-Oriented API + * + * Each context structure begins with a field (called `vtable`) that + * points to an instance of a structure that references the relevant + * functions through pointers. Each such structure contains the + * following: + * + * - `context_size` + * + * The size (in bytes) of the context structure for subkeys. + * + * - `block_size` + * + * The cipher block size (in bytes). + * + * - `log_block_size` + * + * The base-2 logarithm of cipher block size (e.g. 4 for blocks + * of 16 bytes). + * + * - `init` + * + * Pointer to the key expansion function. + * + * - `run` + * + * Pointer to the encryption/decryption function. + * + * For combined CTR/CBC-MAC encryption, the `vtable` has a slightly + * different structure: + * + * - `context_size` + * + * The size (in bytes) of the context structure for subkeys. + * + * - `block_size` + * + * The cipher block size (in bytes). + * + * - `log_block_size` + * + * The base-2 logarithm of cipher block size (e.g. 4 for blocks + * of 16 bytes). + * + * - `init` + * + * Pointer to the key expansion function. + * + * - `encrypt` + * + * Pointer to the CTR encryption + CBC-MAC function. + * + * - `decrypt` + * + * Pointer to the CTR decryption + CBC-MAC function. + * + * - `ctr` + * + * Pointer to the CTR encryption/decryption function. + * + * - `mac` + * + * Pointer to the CBC-MAC function. + * + * For block cipher "`xxx`", static, constant instances of these + * structures are defined, under the names: + * + * - `br_xxx_cbcenc_vtable` + * - `br_xxx_cbcdec_vtable` + * - `br_xxx_ctr_vtable` + * - `br_xxx_ctrcbc_vtable` + * + * + * ## Implemented Block Ciphers + * + * Provided implementations are: + * + * | Name | Function | Block Size (bytes) | Key lengths (bytes) | + * | :-------- | :------- | :----------------: | :-----------------: | + * | aes_big | AES | 16 | 16, 24 and 32 | + * | aes_small | AES | 16 | 16, 24 and 32 | + * | aes_ct | AES | 16 | 16, 24 and 32 | + * | aes_ct64 | AES | 16 | 16, 24 and 32 | + * | aes_x86ni | AES | 16 | 16, 24 and 32 | + * | aes_pwr8 | AES | 16 | 16, 24 and 32 | + * | des_ct | DES/3DES | 8 | 8, 16 and 24 | + * | des_tab | DES/3DES | 8 | 8, 16 and 24 | + * + * **Note:** DES/3DES nominally uses keys of 64, 128 and 192 bits (i.e. 8, + * 16 and 24 bytes), but some of the bits are ignored by the algorithm, so + * the _effective_ key lengths, from a security point of view, are 56, + * 112 and 168 bits, respectively. + * + * `aes_big` is a "classical" AES implementation, using tables. It + * is fast but not constant-time, since it makes data-dependent array + * accesses. + * + * `aes_small` is an AES implementation optimized for code size. It + * is substantially slower than `aes_big`; it is not constant-time + * either. + * + * `aes_ct` is a constant-time implementation of AES; its code is about + * as big as that of `aes_big`, while its performance is comparable to + * that of `aes_small`. However, it is constant-time. This + * implementation should thus be considered to be the "default" AES in + * BearSSL, to be used unless the operational context guarantees that a + * non-constant-time implementation is safe, or an architecture-specific + * constant-time implementation can be used (e.g. using dedicated + * hardware opcodes). + * + * `aes_ct64` is another constant-time implementation of AES. It is + * similar to `aes_ct` but uses 64-bit values. On 32-bit machines, + * `aes_ct64` is not faster than `aes_ct`, often a bit slower, and has + * a larger footprint; however, on 64-bit architectures, `aes_ct64` + * is typically twice faster than `aes_ct` for modes that allow parallel + * operations (i.e. CTR, and CBC decryption, but not CBC encryption). + * + * `aes_x86ni` exists only on x86 architectures (32-bit and 64-bit). It + * uses the AES-NI opcodes when available. + * + * `aes_pwr8` exists only on PowerPC / POWER architectures (32-bit and + * 64-bit, both little-endian and big-endian). It uses the AES opcodes + * present in POWER8 and later. + * + * `des_tab` is a classic, table-based implementation of DES/3DES. It + * is not constant-time. + * + * `des_ct` is an constant-time implementation of DES/3DES. It is + * substantially slower than `des_tab`. + * + * ## ChaCha20 and Poly1305 + * + * ChaCha20 is a stream cipher. Poly1305 is a MAC algorithm. They + * are described in [RFC 7539](https://tools.ietf.org/html/rfc7539). + * + * Two function pointer types are defined: + * + * - `br_chacha20_run` describes a function that implements ChaCha20 + * only. + * + * - `br_poly1305_run` describes an implementation of Poly1305, + * in the AEAD combination with ChaCha20 specified in RFC 7539 + * (the ChaCha20 implementation is provided as a function pointer). + * + * `chacha20_ct` is a straightforward implementation of ChaCha20 in + * plain C; it is constant-time, small, and reasonably fast. + * + * `chacha20_sse2` leverages SSE2 opcodes (on x86 architectures that + * support these opcodes). It is faster than `chacha20_ct`. + * + * `poly1305_ctmul` is an implementation of the ChaCha20+Poly1305 AEAD + * construction, where the Poly1305 part is performed with mixed 32-bit + * multiplications (operands are 32-bit, result is 64-bit). + * + * `poly1305_ctmul32` implements ChaCha20+Poly1305 using pure 32-bit + * multiplications (32-bit operands, 32-bit result). It is slower than + * `poly1305_ctmul`, except on some specific architectures such as + * the ARM Cortex M0+. + * + * `poly1305_ctmulq` implements ChaCha20+Poly1305 with mixed 64-bit + * multiplications (operands are 64-bit, result is 128-bit) on 64-bit + * platforms that support such operations. + * + * `poly1305_i15` implements ChaCha20+Poly1305 with the generic "i15" + * big integer implementation. It is meant mostly for testing purposes, + * although it can help with saving a few hundred bytes of code footprint + * on systems where code size is scarce. + */ + +/** + * \brief Class type for CBC encryption implementations. + * + * A `br_block_cbcenc_class` instance points to the functions implementing + * a specific block cipher, when used in CBC mode for encrypting data. + */ +typedef struct br_block_cbcenc_class_ br_block_cbcenc_class; +struct br_block_cbcenc_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate + * for containing subkeys. + */ + size_t context_size; + + /** + * \brief Size of individual blocks (in bytes). + */ + unsigned block_size; + + /** + * \brief Base-2 logarithm of the size of individual blocks, + * expressed in bytes. + */ + unsigned log_block_size; + + /** + * \brief Initialisation function. + * + * This function sets the `vtable` field in the context structure. + * The key length MUST be one of the key lengths supported by + * the implementation. + * + * \param ctx context structure to initialise. + * \param key secret key. + * \param key_len key length (in bytes). + */ + void (*init)(const br_block_cbcenc_class **ctx, + const void *key, size_t key_len); + + /** + * \brief Run the CBC encryption. + * + * The `iv` parameter points to the IV for this run; it is + * updated with a copy of the last encrypted block. The data + * is encrypted "in place"; its length (`len`) MUST be a + * multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param iv IV for CBC encryption (updated). + * \param data data to encrypt. + * \param len data length (in bytes, multiple of block size). + */ + void (*run)(const br_block_cbcenc_class *const *ctx, + void *iv, void *data, size_t len); +}; + +/** + * \brief Class type for CBC decryption implementations. + * + * A `br_block_cbcdec_class` instance points to the functions implementing + * a specific block cipher, when used in CBC mode for decrypting data. + */ +typedef struct br_block_cbcdec_class_ br_block_cbcdec_class; +struct br_block_cbcdec_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate + * for containing subkeys. + */ + size_t context_size; + + /** + * \brief Size of individual blocks (in bytes). + */ + unsigned block_size; + + /** + * \brief Base-2 logarithm of the size of individual blocks, + * expressed in bytes. + */ + unsigned log_block_size; + + /** + * \brief Initialisation function. + * + * This function sets the `vtable` field in the context structure. + * The key length MUST be one of the key lengths supported by + * the implementation. + * + * \param ctx context structure to initialise. + * \param key secret key. + * \param key_len key length (in bytes). + */ + void (*init)(const br_block_cbcdec_class **ctx, + const void *key, size_t key_len); + + /** + * \brief Run the CBC decryption. + * + * The `iv` parameter points to the IV for this run; it is + * updated with a copy of the last encrypted block. The data + * is decrypted "in place"; its length (`len`) MUST be a + * multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param iv IV for CBC decryption (updated). + * \param data data to decrypt. + * \param len data length (in bytes, multiple of block size). + */ + void (*run)(const br_block_cbcdec_class *const *ctx, + void *iv, void *data, size_t len); +}; + +/** + * \brief Class type for CTR encryption/decryption implementations. + * + * A `br_block_ctr_class` instance points to the functions implementing + * a specific block cipher, when used in CTR mode for encrypting or + * decrypting data. + */ +typedef struct br_block_ctr_class_ br_block_ctr_class; +struct br_block_ctr_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate + * for containing subkeys. + */ + size_t context_size; + + /** + * \brief Size of individual blocks (in bytes). + */ + unsigned block_size; + + /** + * \brief Base-2 logarithm of the size of individual blocks, + * expressed in bytes. + */ + unsigned log_block_size; + + /** + * \brief Initialisation function. + * + * This function sets the `vtable` field in the context structure. + * The key length MUST be one of the key lengths supported by + * the implementation. + * + * \param ctx context structure to initialise. + * \param key secret key. + * \param key_len key length (in bytes). + */ + void (*init)(const br_block_ctr_class **ctx, + const void *key, size_t key_len); + + /** + * \brief Run the CTR encryption or decryption. + * + * The `iv` parameter points to the IV for this run; its + * length is exactly 4 bytes less than the block size (e.g. + * 12 bytes for AES/CTR). The IV is combined with a 32-bit + * block counter to produce the block value which is processed + * with the block cipher. + * + * The data to encrypt or decrypt is updated "in place". Its + * length (`len` bytes) is not required to be a multiple of + * the block size; if the final block is partial, then the + * corresponding key stream bits are dropped. + * + * The resulting counter value is returned. + * + * \param ctx context structure (already initialised). + * \param iv IV for CTR encryption/decryption. + * \param cc initial value for the block counter. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \return the new block counter value. + */ + uint32_t (*run)(const br_block_ctr_class *const *ctx, + const void *iv, uint32_t cc, void *data, size_t len); +}; + +/** + * \brief Class type for combined CTR and CBC-MAC implementations. + * + * A `br_block_ctrcbc_class` instance points to the functions implementing + * a specific block cipher, when used in CTR mode for encrypting or + * decrypting data, along with CBC-MAC. + */ +typedef struct br_block_ctrcbc_class_ br_block_ctrcbc_class; +struct br_block_ctrcbc_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate + * for containing subkeys. + */ + size_t context_size; + + /** + * \brief Size of individual blocks (in bytes). + */ + unsigned block_size; + + /** + * \brief Base-2 logarithm of the size of individual blocks, + * expressed in bytes. + */ + unsigned log_block_size; + + /** + * \brief Initialisation function. + * + * This function sets the `vtable` field in the context structure. + * The key length MUST be one of the key lengths supported by + * the implementation. + * + * \param ctx context structure to initialise. + * \param key secret key. + * \param key_len key length (in bytes). + */ + void (*init)(const br_block_ctrcbc_class **ctx, + const void *key, size_t key_len); + + /** + * \brief Run the CTR encryption + CBC-MAC. + * + * The `ctr` parameter points to the counter; its length shall + * be equal to the block size. It is updated by this function + * as encryption proceeds. + * + * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC + * is computed over the encrypted data (output of CTR + * encryption). Its length shall be equal to the block size. The + * computed CBC-MAC value is written over the `cbcmac` array. + * + * The data to encrypt is updated "in place". Its length (`len` + * bytes) MUST be a multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param ctr counter for CTR encryption (initial and final). + * \param cbcmac IV and output buffer for CBC-MAC. + * \param data data to encrypt. + * \param len data length (in bytes). + */ + void (*encrypt)(const br_block_ctrcbc_class *const *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + + /** + * \brief Run the CTR decryption + CBC-MAC. + * + * The `ctr` parameter points to the counter; its length shall + * be equal to the block size. It is updated by this function + * as decryption proceeds. + * + * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC + * is computed over the encrypted data (i.e. before CTR + * decryption). Its length shall be equal to the block size. The + * computed CBC-MAC value is written over the `cbcmac` array. + * + * The data to decrypt is updated "in place". Its length (`len` + * bytes) MUST be a multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param ctr counter for CTR encryption (initial and final). + * \param cbcmac IV and output buffer for CBC-MAC. + * \param data data to decrypt. + * \param len data length (in bytes). + */ + void (*decrypt)(const br_block_ctrcbc_class *const *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + + /** + * \brief Run the CTR encryption/decryption only. + * + * The `ctr` parameter points to the counter; its length shall + * be equal to the block size. It is updated by this function + * as decryption proceeds. + * + * The data to decrypt is updated "in place". Its length (`len` + * bytes) MUST be a multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param ctr counter for CTR encryption (initial and final). + * \param data data to decrypt. + * \param len data length (in bytes). + */ + void (*ctr)(const br_block_ctrcbc_class *const *ctx, + void *ctr, void *data, size_t len); + + /** + * \brief Run the CBC-MAC only. + * + * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC + * is computed over the encrypted data (i.e. before CTR + * decryption). Its length shall be equal to the block size. The + * computed CBC-MAC value is written over the `cbcmac` array. + * + * The data is unmodified. Its length (`len` bytes) MUST be a + * multiple of the block size. + * + * \param ctx context structure (already initialised). + * \param cbcmac IV and output buffer for CBC-MAC. + * \param data data to decrypt. + * \param len data length (in bytes). + */ + void (*mac)(const br_block_ctrcbc_class *const *ctx, + void *cbcmac, const void *data, size_t len); +}; + +/* + * Traditional, table-based AES implementation. It is fast, but uses + * internal tables (in particular a 1 kB table for encryption, another + * 1 kB table for decryption, and a 256-byte table for key schedule), + * and it is not constant-time. In contexts where cache-timing attacks + * apply, this implementation may leak the secret key. + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_big_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_big` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_big_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_big` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_big_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_big` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_big_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_big` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_big_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_big` implementation). + */ +extern const br_block_cbcenc_class br_aes_big_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_big` implementation). + */ +extern const br_block_cbcdec_class br_aes_big_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_big` implementation). + */ +extern const br_block_ctr_class br_aes_big_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_big` implementation). + */ +extern const br_block_ctrcbc_class br_aes_big_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_big` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_big_cbcenc_init(br_aes_big_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_big` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_big` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_big` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_big_ctrcbc_init(br_aes_big_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_big_cbcenc_run(const br_aes_big_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to encrypt or decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_big_ctr_run(const br_aes_big_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_big_ctrcbc_encrypt(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_big_ctrcbc_decrypt(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_big_ctrcbc_ctr(const br_aes_big_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_big` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_big_ctrcbc_mac(const br_aes_big_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/* + * AES implementation optimized for size. It is slower than the + * traditional table-based AES implementation, but requires much less + * code. It still uses data-dependent table accesses (albeit within a + * much smaller 256-byte table), which makes it conceptually vulnerable + * to cache-timing attacks. + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_small_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_small` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_small_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_small` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_small_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_small` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_small_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_small` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_small_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_small` implementation). + */ +extern const br_block_cbcenc_class br_aes_small_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_small` implementation). + */ +extern const br_block_cbcdec_class br_aes_small_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_small` implementation). + */ +extern const br_block_ctr_class br_aes_small_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_small` implementation). + */ +extern const br_block_ctrcbc_class br_aes_small_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_small` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_small_cbcenc_init(br_aes_small_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_small` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_small` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_small` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_small_ctrcbc_init(br_aes_small_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_small_cbcenc_run(const br_aes_small_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_small_ctr_run(const br_aes_small_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_small_ctrcbc_encrypt(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_small_ctrcbc_decrypt(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_small_ctrcbc_ctr(const br_aes_small_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_small` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_small_ctrcbc_mac(const br_aes_small_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/* + * Constant-time AES implementation. Its size is similar to that of + * 'aes_big', and its performance is similar to that of 'aes_small' (faster + * decryption, slower encryption). However, it is constant-time, i.e. + * immune to cache-timing and similar attacks. + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_ct_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_ct` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_ct_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_ct` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_ct_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_ct_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[60]; + unsigned num_rounds; +#endif +} br_aes_ct_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_ct` implementation). + */ +extern const br_block_cbcenc_class br_aes_ct_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_ct` implementation). + */ +extern const br_block_cbcdec_class br_aes_ct_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_ct` implementation). + */ +extern const br_block_ctr_class br_aes_ct_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_ct` implementation). + */ +extern const br_block_ctrcbc_class br_aes_ct_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct_cbcenc_init(br_aes_ct_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct_ctrcbc_init(br_aes_ct_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_ct_cbcenc_run(const br_aes_ct_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_ct_ctr_run(const br_aes_ct_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct_ctrcbc_encrypt(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct_ctrcbc_decrypt(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct_ctrcbc_ctr(const br_aes_ct_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_ct` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct_ctrcbc_mac(const br_aes_ct_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/* + * 64-bit constant-time AES implementation. It is similar to 'aes_ct' + * but uses 64-bit registers, making it about twice faster than 'aes_ct' + * on 64-bit platforms, while remaining constant-time and with a similar + * code size. (The doubling in performance is only for CBC decryption + * and CTR mode; CBC encryption is non-parallel and cannot benefit from + * the larger registers.) + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_ct64_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_ct64` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t skey[30]; + unsigned num_rounds; +#endif +} br_aes_ct64_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_ct64` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t skey[30]; + unsigned num_rounds; +#endif +} br_aes_ct64_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t skey[30]; + unsigned num_rounds; +#endif +} br_aes_ct64_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t skey[30]; + unsigned num_rounds; +#endif +} br_aes_ct64_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_ct64` implementation). + */ +extern const br_block_cbcenc_class br_aes_ct64_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_ct64` implementation). + */ +extern const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_ct64` implementation). + */ +extern const br_block_ctr_class br_aes_ct64_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_ct64` implementation). + */ +extern const br_block_ctrcbc_class br_aes_ct64_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_ct64` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct64_cbcenc_init(br_aes_ct64_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_ct64` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_ct64` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_ct64` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_ct64_ctrcbc_init(br_aes_ct64_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_ct64_cbcenc_run(const br_aes_ct64_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_ct64_ctr_run(const br_aes_ct64_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct64_ctrcbc_encrypt(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct64_ctrcbc_decrypt(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct64_ctrcbc_ctr(const br_aes_ct64_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_ct64` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_ct64_ctrcbc_mac(const br_aes_ct64_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/* + * AES implementation using AES-NI opcodes (x86 platform). + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_x86ni_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_x86ni` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_x86ni_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_x86ni` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_x86ni_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_x86ni_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_x86ni_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_x86ni` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_x86ni_cbcenc_get_vtable()`. + */ +extern const br_block_cbcenc_class br_aes_x86ni_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_x86ni` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_x86ni_cbcdec_get_vtable()`. + */ +extern const br_block_cbcdec_class br_aes_x86ni_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_x86ni` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_x86ni_ctr_get_vtable()`. + */ +extern const br_block_ctr_class br_aes_x86ni_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_x86ni` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_x86ni_ctrcbc_get_vtable()`. + */ +extern const br_block_ctrcbc_class br_aes_x86ni_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_x86ni` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_x86ni_cbcenc_init(br_aes_x86ni_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_x86ni` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_x86ni_cbcdec_init(br_aes_x86ni_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_x86ni` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_x86ni_ctr_init(br_aes_x86ni_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_x86ni` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_x86ni_ctrcbc_init(br_aes_x86ni_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_x86ni_cbcenc_run(const br_aes_x86ni_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_x86ni_ctr_run(const br_aes_x86ni_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_x86ni_ctrcbc_encrypt(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_x86ni_ctrcbc_decrypt(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_x86ni_ctrcbc_ctr(const br_aes_x86ni_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_x86ni` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_x86ni_ctrcbc_mac(const br_aes_x86ni_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/** + * \brief Obtain the `aes_x86ni` AES-CBC (encryption) implementation, if + * available. + * + * This function returns a pointer to `br_aes_x86ni_cbcenc_vtable`, if + * that implementation was compiled in the library _and_ the x86 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_x86ni` AES-CBC (encryption) implementation, or `NULL`. + */ +const br_block_cbcenc_class *br_aes_x86ni_cbcenc_get_vtable(void); + +/** + * \brief Obtain the `aes_x86ni` AES-CBC (decryption) implementation, if + * available. + * + * This function returns a pointer to `br_aes_x86ni_cbcdec_vtable`, if + * that implementation was compiled in the library _and_ the x86 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_x86ni` AES-CBC (decryption) implementation, or `NULL`. + */ +const br_block_cbcdec_class *br_aes_x86ni_cbcdec_get_vtable(void); + +/** + * \brief Obtain the `aes_x86ni` AES-CTR implementation, if available. + * + * This function returns a pointer to `br_aes_x86ni_ctr_vtable`, if + * that implementation was compiled in the library _and_ the x86 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_x86ni` AES-CTR implementation, or `NULL`. + */ +const br_block_ctr_class *br_aes_x86ni_ctr_get_vtable(void); + +/** + * \brief Obtain the `aes_x86ni` AES-CTR + CBC-MAC implementation, if + * available. + * + * This function returns a pointer to `br_aes_x86ni_ctrcbc_vtable`, if + * that implementation was compiled in the library _and_ the x86 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_x86ni` AES-CTR implementation, or `NULL`. + */ +const br_block_ctrcbc_class *br_aes_x86ni_ctrcbc_get_vtable(void); + +/* + * AES implementation using POWER8 opcodes. + */ + +/** \brief AES block size (16 bytes). */ +#define br_aes_pwr8_BLOCK_SIZE 16 + +/** + * \brief Context for AES subkeys (`aes_pwr8` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_pwr8_cbcenc_keys; + +/** + * \brief Context for AES subkeys (`aes_pwr8` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_pwr8_cbcdec_keys; + +/** + * \brief Context for AES subkeys (`aes_pwr8` implementation, CTR encryption + * and decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctr_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_pwr8_ctr_keys; + +/** + * \brief Context for AES subkeys (`aes_pwr8` implementation, CTR encryption + * and decryption + CBC-MAC). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_ctrcbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + union { + unsigned char skni[16 * 15]; + } skey; + unsigned num_rounds; +#endif +} br_aes_pwr8_ctrcbc_keys; + +/** + * \brief Class instance for AES CBC encryption (`aes_pwr8` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_pwr8_cbcenc_get_vtable()`. + */ +extern const br_block_cbcenc_class br_aes_pwr8_cbcenc_vtable; + +/** + * \brief Class instance for AES CBC decryption (`aes_pwr8` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_pwr8_cbcdec_get_vtable()`. + */ +extern const br_block_cbcdec_class br_aes_pwr8_cbcdec_vtable; + +/** + * \brief Class instance for AES CTR encryption and decryption + * (`aes_pwr8` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_pwr8_ctr_get_vtable()`. + */ +extern const br_block_ctr_class br_aes_pwr8_ctr_vtable; + +/** + * \brief Class instance for AES CTR encryption/decryption + CBC-MAC + * (`aes_pwr8` implementation). + * + * Since this implementation might be omitted from the library, or the + * AES opcode unavailable on the current CPU, a pointer to this class + * instance should be obtained through `br_aes_pwr8_ctrcbc_get_vtable()`. + */ +extern const br_block_ctrcbc_class br_aes_pwr8_ctrcbc_vtable; + +/** + * \brief Context initialisation (key schedule) for AES CBC encryption + * (`aes_pwr8` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_pwr8_cbcenc_init(br_aes_pwr8_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CBC decryption + * (`aes_pwr8` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_pwr8_cbcdec_init(br_aes_pwr8_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR encryption + * and decryption (`aes_pwr8` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_pwr8_ctr_init(br_aes_pwr8_ctr_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC + * (`aes_pwr8` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_aes_pwr8_ctrcbc_init(br_aes_pwr8_ctrcbc_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_pwr8_cbcenc_run(const br_aes_pwr8_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 16). + */ +void br_aes_pwr8_cbcdec_run(const br_aes_pwr8_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CTR encryption and decryption with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (constant, 12 bytes). + * \param cc initial block counter value. + * \param data data to decrypt (updated). + * \param len data length (in bytes). + * \return new block counter value. + */ +uint32_t br_aes_pwr8_ctr_run(const br_aes_pwr8_ctr_keys *ctx, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief CTR encryption + CBC-MAC with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_pwr8_ctrcbc_encrypt(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR decryption + CBC-MAC with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_pwr8_ctrcbc_decrypt(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *cbcmac, void *data, size_t len); + +/** + * \brief CTR encryption/decryption with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param ctr counter for CTR (16 bytes, updated). + * \param data data to MAC (updated). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_pwr8_ctrcbc_ctr(const br_aes_pwr8_ctrcbc_keys *ctx, + void *ctr, void *data, size_t len); + +/** + * \brief CBC-MAC with AES (`aes_pwr8` implementation). + * + * \param ctx context (already initialised). + * \param cbcmac IV for CBC-MAC (updated). + * \param data data to MAC (unmodified). + * \param len data length (in bytes, MUST be a multiple of 16). + */ +void br_aes_pwr8_ctrcbc_mac(const br_aes_pwr8_ctrcbc_keys *ctx, + void *cbcmac, const void *data, size_t len); + +/** + * \brief Obtain the `aes_pwr8` AES-CBC (encryption) implementation, if + * available. + * + * This function returns a pointer to `br_aes_pwr8_cbcenc_vtable`, if + * that implementation was compiled in the library _and_ the POWER8 + * crypto opcodes are available on the currently running CPU. If either + * of these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_pwr8` AES-CBC (encryption) implementation, or `NULL`. + */ +const br_block_cbcenc_class *br_aes_pwr8_cbcenc_get_vtable(void); + +/** + * \brief Obtain the `aes_pwr8` AES-CBC (decryption) implementation, if + * available. + * + * This function returns a pointer to `br_aes_pwr8_cbcdec_vtable`, if + * that implementation was compiled in the library _and_ the POWER8 + * crypto opcodes are available on the currently running CPU. If either + * of these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_pwr8` AES-CBC (decryption) implementation, or `NULL`. + */ +const br_block_cbcdec_class *br_aes_pwr8_cbcdec_get_vtable(void); + +/** + * \brief Obtain the `aes_pwr8` AES-CTR implementation, if available. + * + * This function returns a pointer to `br_aes_pwr8_ctr_vtable`, if that + * implementation was compiled in the library _and_ the POWER8 crypto + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_pwr8` AES-CTR implementation, or `NULL`. + */ +const br_block_ctr_class *br_aes_pwr8_ctr_get_vtable(void); + +/** + * \brief Obtain the `aes_pwr8` AES-CTR + CBC-MAC implementation, if + * available. + * + * This function returns a pointer to `br_aes_pwr8_ctrcbc_vtable`, if + * that implementation was compiled in the library _and_ the POWER8 AES + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `NULL`. + * + * \return the `aes_pwr8` AES-CTR implementation, or `NULL`. + */ +const br_block_ctrcbc_class *br_aes_pwr8_ctrcbc_get_vtable(void); + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CBC encryption) for all AES implementations. + */ +typedef union { + const br_block_cbcenc_class *vtable; + br_aes_big_cbcenc_keys c_big; + br_aes_small_cbcenc_keys c_small; + br_aes_ct_cbcenc_keys c_ct; + br_aes_ct64_cbcenc_keys c_ct64; + br_aes_x86ni_cbcenc_keys c_x86ni; + br_aes_pwr8_cbcenc_keys c_pwr8; +} br_aes_gen_cbcenc_keys; + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CBC decryption) for all AES implementations. + */ +typedef union { + const br_block_cbcdec_class *vtable; + br_aes_big_cbcdec_keys c_big; + br_aes_small_cbcdec_keys c_small; + br_aes_ct_cbcdec_keys c_ct; + br_aes_ct64_cbcdec_keys c_ct64; + br_aes_x86ni_cbcdec_keys c_x86ni; + br_aes_pwr8_cbcdec_keys c_pwr8; +} br_aes_gen_cbcdec_keys; + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CTR encryption and decryption) for all AES implementations. + */ +typedef union { + const br_block_ctr_class *vtable; + br_aes_big_ctr_keys c_big; + br_aes_small_ctr_keys c_small; + br_aes_ct_ctr_keys c_ct; + br_aes_ct64_ctr_keys c_ct64; + br_aes_x86ni_ctr_keys c_x86ni; + br_aes_pwr8_ctr_keys c_pwr8; +} br_aes_gen_ctr_keys; + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CTR encryption/decryption + CBC-MAC) for all AES implementations. + */ +typedef union { + const br_block_ctrcbc_class *vtable; + br_aes_big_ctrcbc_keys c_big; + br_aes_small_ctrcbc_keys c_small; + br_aes_ct_ctrcbc_keys c_ct; + br_aes_ct64_ctrcbc_keys c_ct64; + br_aes_x86ni_ctrcbc_keys c_x86ni; + br_aes_pwr8_ctrcbc_keys c_pwr8; +} br_aes_gen_ctrcbc_keys; + +/* + * Traditional, table-based implementation for DES/3DES. Since tables are + * used, cache-timing attacks are conceptually possible. + */ + +/** \brief DES/3DES block size (8 bytes). */ +#define br_des_tab_BLOCK_SIZE 8 + +/** + * \brief Context for DES subkeys (`des_tab` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[96]; + unsigned num_rounds; +#endif +} br_des_tab_cbcenc_keys; + +/** + * \brief Context for DES subkeys (`des_tab` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[96]; + unsigned num_rounds; +#endif +} br_des_tab_cbcdec_keys; + +/** + * \brief Class instance for DES CBC encryption (`des_tab` implementation). + */ +extern const br_block_cbcenc_class br_des_tab_cbcenc_vtable; + +/** + * \brief Class instance for DES CBC decryption (`des_tab` implementation). + */ +extern const br_block_cbcdec_class br_des_tab_cbcdec_vtable; + +/** + * \brief Context initialisation (key schedule) for DES CBC encryption + * (`des_tab` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for DES CBC decryption + * (`des_tab` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with DES (`des_tab` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 8). + */ +void br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with DES (`des_tab` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 8). + */ +void br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/* + * Constant-time implementation for DES/3DES. It is substantially slower + * (by a factor of about 4x), but also immune to cache-timing attacks. + */ + +/** \brief DES/3DES block size (8 bytes). */ +#define br_des_ct_BLOCK_SIZE 8 + +/** + * \brief Context for DES subkeys (`des_ct` implementation, CBC encryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcenc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[96]; + unsigned num_rounds; +#endif +} br_des_ct_cbcenc_keys; + +/** + * \brief Context for DES subkeys (`des_ct` implementation, CBC decryption). + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** \brief Pointer to vtable for this context. */ + const br_block_cbcdec_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint32_t skey[96]; + unsigned num_rounds; +#endif +} br_des_ct_cbcdec_keys; + +/** + * \brief Class instance for DES CBC encryption (`des_ct` implementation). + */ +extern const br_block_cbcenc_class br_des_ct_cbcenc_vtable; + +/** + * \brief Class instance for DES CBC decryption (`des_ct` implementation). + */ +extern const br_block_cbcdec_class br_des_ct_cbcdec_vtable; + +/** + * \brief Context initialisation (key schedule) for DES CBC encryption + * (`des_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx, + const void *key, size_t len); + +/** + * \brief Context initialisation (key schedule) for DES CBC decryption + * (`des_ct` implementation). + * + * \param ctx context to initialise. + * \param key secret key. + * \param len secret key length (in bytes). + */ +void br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx, + const void *key, size_t len); + +/** + * \brief CBC encryption with DES (`des_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to encrypt (updated). + * \param len data length (in bytes, MUST be multiple of 8). + */ +void br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx, void *iv, + void *data, size_t len); + +/** + * \brief CBC decryption with DES (`des_ct` implementation). + * + * \param ctx context (already initialised). + * \param iv IV (updated). + * \param data data to decrypt (updated). + * \param len data length (in bytes, MUST be multiple of 8). + */ +void br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx, void *iv, + void *data, size_t len); + +/* + * These structures are large enough to accommodate subkeys for all + * DES/3DES implementations. + */ + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CBC encryption) for all DES implementations. + */ +typedef union { + const br_block_cbcenc_class *vtable; + br_des_tab_cbcenc_keys tab; + br_des_ct_cbcenc_keys ct; +} br_des_gen_cbcenc_keys; + +/** + * \brief Aggregate structure large enough to be used as context for + * subkeys (CBC decryption) for all DES implementations. + */ +typedef union { + const br_block_cbcdec_class *vtable; + br_des_tab_cbcdec_keys c_tab; + br_des_ct_cbcdec_keys c_ct; +} br_des_gen_cbcdec_keys; + +/** + * \brief Type for a ChaCha20 implementation. + * + * An implementation follows the description in RFC 7539: + * + * - Key is 256 bits (`key` points to exactly 32 bytes). + * + * - IV is 96 bits (`iv` points to exactly 12 bytes). + * + * - Block counter is over 32 bits and starts at value `cc`; the + * resulting value is returned. + * + * Data (pointed to by `data`, of length `len`) is encrypted/decrypted + * in place. If `len` is not a multiple of 64, then the excess bytes from + * the last block processing are dropped (therefore, "chunked" processing + * works only as long as each non-final chunk has a length multiple of 64). + * + * \param key secret key (32 bytes). + * \param iv IV (12 bytes). + * \param cc initial counter value. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +typedef uint32_t (*br_chacha20_run)(const void *key, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief ChaCha20 implementation (straightforward C code, constant-time). + * + * \see br_chacha20_run + * + * \param key secret key (32 bytes). + * \param iv IV (12 bytes). + * \param cc initial counter value. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +uint32_t br_chacha20_ct_run(const void *key, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief ChaCha20 implementation (SSE2 code, constant-time). + * + * This implementation is available only on x86 platforms, depending on + * compiler support. Moreover, in 32-bit mode, it might not actually run, + * if the underlying hardware does not implement the SSE2 opcode (in + * 64-bit mode, SSE2 is part of the ABI, so if the code could be compiled + * at all, then it can run). Use `br_chacha20_sse2_get()` to safely obtain + * a pointer to that function. + * + * \see br_chacha20_run + * + * \param key secret key (32 bytes). + * \param iv IV (12 bytes). + * \param cc initial counter value. + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + */ +uint32_t br_chacha20_sse2_run(const void *key, + const void *iv, uint32_t cc, void *data, size_t len); + +/** + * \brief Obtain the `sse2` ChaCha20 implementation, if available. + * + * This function returns a pointer to `br_chacha20_sse2_run`, if + * that implementation was compiled in the library _and_ the SSE2 + * opcodes are available on the currently running CPU. If either of + * these conditions is not met, then this function returns `0`. + * + * \return the `sse2` ChaCha20 implementation, or `0`. + */ +br_chacha20_run br_chacha20_sse2_get(void); + +/** + * \brief Type for a ChaCha20+Poly1305 AEAD implementation. + * + * The provided data is encrypted or decrypted with ChaCha20. The + * authentication tag is computed on the concatenation of the + * additional data and the ciphertext, with the padding and lengths + * as described in RFC 7539 (section 2.8). + * + * After decryption, the caller is responsible for checking that the + * computed tag matches the expected value. + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +typedef void (*br_poly1305_run)(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief ChaCha20+Poly1305 AEAD implementation (mixed 32-bit multiplications). + * + * \see br_poly1305_run + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +void br_poly1305_ctmul_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief ChaCha20+Poly1305 AEAD implementation (pure 32-bit multiplications). + * + * \see br_poly1305_run + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +void br_poly1305_ctmul32_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief ChaCha20+Poly1305 AEAD implementation (i15). + * + * This implementation relies on the generic big integer code "i15" + * (which uses pure 32-bit multiplications). As such, it may save a + * little code footprint in a context where "i15" is already included + * (e.g. for elliptic curves or for RSA); however, it is also + * substantially slower than the ctmul and ctmul32 implementations. + * + * \see br_poly1305_run + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +void br_poly1305_i15_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief ChaCha20+Poly1305 AEAD implementation (ctmulq). + * + * This implementation uses 64-bit multiplications (result over 128 bits). + * It is available only on platforms that offer such a primitive (in + * practice, 64-bit architectures). Use `br_poly1305_ctmulq_get()` to + * dynamically obtain a pointer to that function, or 0 if not supported. + * + * \see br_poly1305_run + * + * \param key secret key (32 bytes). + * \param iv nonce (12 bytes). + * \param data data to encrypt or decrypt. + * \param len data length (in bytes). + * \param aad additional authenticated data. + * \param aad_len length of additional authenticated data (in bytes). + * \param tag output buffer for the authentication tag. + * \param ichacha implementation of ChaCha20. + * \param encrypt non-zero for encryption, zero for decryption. + */ +void br_poly1305_ctmulq_run(const void *key, const void *iv, + void *data, size_t len, const void *aad, size_t aad_len, + void *tag, br_chacha20_run ichacha, int encrypt); + +/** + * \brief Get the ChaCha20+Poly1305 "ctmulq" implementation, if available. + * + * This function returns a pointer to the `br_poly1305_ctmulq_run()` + * function if supported on the current platform; otherwise, it returns 0. + * + * \return the ctmulq ChaCha20+Poly1305 implementation, or 0. + */ +br_poly1305_run br_poly1305_ctmulq_get(void); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_ec.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_ec.h new file mode 100644 index 000000000..ad07476e7 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_ec.h @@ -0,0 +1,983 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_EC_H__ +#define BR_BEARSSL_EC_H__ + +#include +#include + +#include "bearssl_rand.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_ec.h + * + * # Elliptic Curves + * + * This file documents the EC implementations provided with BearSSL, and + * ECDSA. + * + * ## Elliptic Curve API + * + * Only "named curves" are supported. Each EC implementation supports + * one or several named curves, identified by symbolic identifiers. + * These identifiers are small integers, that correspond to the values + * registered by the + * [IANA](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8). + * + * Since all currently defined elliptic curve identifiers are in the 0..31 + * range, it is convenient to encode support of some curves in a 32-bit + * word, such that bit x corresponds to curve of identifier x. + * + * An EC implementation is incarnated by a `br_ec_impl` instance, that + * offers the following fields: + * + * - `supported_curves` + * + * A 32-bit word that documents the identifiers of the curves supported + * by this implementation. + * + * - `generator()` + * + * Callback method that returns a pointer to the conventional generator + * point for that curve. + * + * - `order()` + * + * Callback method that returns a pointer to the subgroup order for + * that curve. That value uses unsigned big-endian encoding. + * + * - `xoff()` + * + * Callback method that returns the offset and length of the X + * coordinate in an encoded point. + * + * - `mul()` + * + * Multiply a curve point with an integer. + * + * - `mulgen()` + * + * Multiply the curve generator with an integer. This may be faster + * than the generic `mul()`. + * + * - `muladd()` + * + * Multiply two curve points by two integers, and return the sum of + * the two products. + * + * All curve points are represented in uncompressed format. The `mul()` + * and `muladd()` methods take care to validate that the provided points + * are really part of the relevant curve subgroup. + * + * For all point multiplication functions, the following holds: + * + * - Functions validate that the provided points are valid members + * of the relevant curve subgroup. An error is reported if that is + * not the case. + * + * - Processing is constant-time, even if the point operands are not + * valid. This holds for both the source and resulting points, and + * the multipliers (integers). Only the byte length of the provided + * multiplier arrays (not their actual value length in bits) may + * leak through timing-based side channels. + * + * - The multipliers (integers) MUST be lower than the subgroup order. + * If this property is not met, then the result is indeterminate, + * but an error value is not necessarily returned. + * + * + * ## ECDSA + * + * ECDSA signatures have two standard formats, called "raw" and "asn1". + * Internally, such a signature is a pair of modular integers `(r,s)`. + * The "raw" format is the concatenation of the unsigned big-endian + * encodings of these two integers, possibly left-padded with zeros so + * that they have the same encoded length. The "asn1" format is the + * DER encoding of an ASN.1 structure that contains the two integer + * values: + * + * ECDSASignature ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * In general, in all of X.509 and SSL/TLS, the "asn1" format is used. + * BearSSL offers ECDSA implementations for both formats; conversion + * functions between the two formats are also provided. Conversion of a + * "raw" format signature into "asn1" may enlarge a signature by no more + * than 9 bytes for all supported curves; conversely, conversion of an + * "asn1" signature to "raw" may expand the signature but the "raw" + * length will never be more than twice the length of the "asn1" length + * (and usually it will be shorter). + * + * Note that for a given signature, the "raw" format is not fully + * deterministic, in that it does not enforce a minimal common length. + */ + +/* + * Standard curve ID. These ID are equal to the assigned numerical + * identifiers assigned to these curves for TLS: + * http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 + */ + +/** \brief Identifier for named curve sect163k1. */ +#define BR_EC_sect163k1 1 + +/** \brief Identifier for named curve sect163r1. */ +#define BR_EC_sect163r1 2 + +/** \brief Identifier for named curve sect163r2. */ +#define BR_EC_sect163r2 3 + +/** \brief Identifier for named curve sect193r1. */ +#define BR_EC_sect193r1 4 + +/** \brief Identifier for named curve sect193r2. */ +#define BR_EC_sect193r2 5 + +/** \brief Identifier for named curve sect233k1. */ +#define BR_EC_sect233k1 6 + +/** \brief Identifier for named curve sect233r1. */ +#define BR_EC_sect233r1 7 + +/** \brief Identifier for named curve sect239k1. */ +#define BR_EC_sect239k1 8 + +/** \brief Identifier for named curve sect283k1. */ +#define BR_EC_sect283k1 9 + +/** \brief Identifier for named curve sect283r1. */ +#define BR_EC_sect283r1 10 + +/** \brief Identifier for named curve sect409k1. */ +#define BR_EC_sect409k1 11 + +/** \brief Identifier for named curve sect409r1. */ +#define BR_EC_sect409r1 12 + +/** \brief Identifier for named curve sect571k1. */ +#define BR_EC_sect571k1 13 + +/** \brief Identifier for named curve sect571r1. */ +#define BR_EC_sect571r1 14 + +/** \brief Identifier for named curve secp160k1. */ +#define BR_EC_secp160k1 15 + +/** \brief Identifier for named curve secp160r1. */ +#define BR_EC_secp160r1 16 + +/** \brief Identifier for named curve secp160r2. */ +#define BR_EC_secp160r2 17 + +/** \brief Identifier for named curve secp192k1. */ +#define BR_EC_secp192k1 18 + +/** \brief Identifier for named curve secp192r1. */ +#define BR_EC_secp192r1 19 + +/** \brief Identifier for named curve secp224k1. */ +#define BR_EC_secp224k1 20 + +/** \brief Identifier for named curve secp224r1. */ +#define BR_EC_secp224r1 21 + +/** \brief Identifier for named curve secp256k1. */ +#define BR_EC_secp256k1 22 + +/** \brief Identifier for named curve secp256r1. */ +#define BR_EC_secp256r1 23 + +/** \brief Identifier for named curve secp384r1. */ +#define BR_EC_secp384r1 24 + +/** \brief Identifier for named curve secp521r1. */ +#define BR_EC_secp521r1 25 + +/** \brief Identifier for named curve brainpoolP256r1. */ +#define BR_EC_brainpoolP256r1 26 + +/** \brief Identifier for named curve brainpoolP384r1. */ +#define BR_EC_brainpoolP384r1 27 + +/** \brief Identifier for named curve brainpoolP512r1. */ +#define BR_EC_brainpoolP512r1 28 + +/** \brief Identifier for named curve Curve25519. */ +#define BR_EC_curve25519 29 + +/** \brief Identifier for named curve Curve448. */ +#define BR_EC_curve448 30 + +/** + * \brief Structure for an EC public key. + */ +typedef struct { + /** \brief Identifier for the curve used by this key. */ + int curve; + /** \brief Public curve point (uncompressed format). */ + unsigned char *q; + /** \brief Length of public curve point (in bytes). */ + size_t qlen; +} br_ec_public_key; + +/** + * \brief Structure for an EC private key. + * + * The private key is an integer modulo the curve subgroup order. The + * encoding below tolerates extra leading zeros. In general, it is + * recommended that the private key has the same length as the curve + * subgroup order. + */ +typedef struct { + /** \brief Identifier for the curve used by this key. */ + int curve; + /** \brief Private key (integer, unsigned big-endian encoding). */ + unsigned char *x; + /** \brief Private key length (in bytes). */ + size_t xlen; +} br_ec_private_key; + +/** + * \brief Type for an EC implementation. + */ +typedef struct { + /** + * \brief Supported curves. + * + * This word is a bitfield: bit `x` is set if the curve of ID `x` + * is supported. E.g. an implementation supporting both NIST P-256 + * (secp256r1, ID 23) and NIST P-384 (secp384r1, ID 24) will have + * value `0x01800000` in this field. + */ + uint32_t supported_curves; + + /** + * \brief Get the conventional generator. + * + * This function returns the conventional generator (encoded + * curve point) for the specified curve. This function MUST NOT + * be called if the curve is not supported. + * + * \param curve curve identifier. + * \param len receiver for the encoded generator length (in bytes). + * \return the encoded generator. + */ + const unsigned char *(*generator)(int curve, size_t *len); + + /** + * \brief Get the subgroup order. + * + * This function returns the order of the subgroup generated by + * the conventional generator, for the specified curve. Unsigned + * big-endian encoding is used. This function MUST NOT be called + * if the curve is not supported. + * + * \param curve curve identifier. + * \param len receiver for the encoded order length (in bytes). + * \return the encoded order. + */ + const unsigned char *(*order)(int curve, size_t *len); + + /** + * \brief Get the offset and length for the X coordinate. + * + * This function returns the offset and length (in bytes) of + * the X coordinate in an encoded non-zero point. + * + * \param curve curve identifier. + * \param len receiver for the X coordinate length (in bytes). + * \return the offset for the X coordinate (in bytes). + */ + size_t (*xoff)(int curve, size_t *len); + + /** + * \brief Multiply a curve point by an integer. + * + * The source point is provided in array `G` (of size `Glen` bytes); + * the multiplication result is written over it. The multiplier + * `x` (of size `xlen` bytes) uses unsigned big-endian encoding. + * + * Rules: + * + * - The specified curve MUST be supported. + * + * - The source point must be a valid point on the relevant curve + * subgroup (and not the "point at infinity" either). If this is + * not the case, then this function returns an error (0). + * + * - The multiplier integer MUST be non-zero and less than the + * curve subgroup order. If this property does not hold, then + * the result is indeterminate and an error code is not + * guaranteed. + * + * Returned value is 1 on success, 0 on error. On error, the + * contents of `G` are indeterminate. + * + * \param G point to multiply. + * \param Glen length of the encoded point (in bytes). + * \param x multiplier (unsigned big-endian). + * \param xlen multiplier length (in bytes). + * \param curve curve identifier. + * \return 1 on success, 0 on error. + */ + uint32_t (*mul)(unsigned char *G, size_t Glen, + const unsigned char *x, size_t xlen, int curve); + + /** + * \brief Multiply the generator by an integer. + * + * The multiplier MUST be non-zero and less than the curve + * subgroup order. Results are indeterminate if this property + * does not hold. + * + * \param R output buffer for the point. + * \param x multiplier (unsigned big-endian). + * \param xlen multiplier length (in bytes). + * \param curve curve identifier. + * \return encoded result point length (in bytes). + */ + size_t (*mulgen)(unsigned char *R, + const unsigned char *x, size_t xlen, int curve); + + /** + * \brief Multiply two points by two integers and add the + * results. + * + * The point `x*A + y*B` is computed and written back in the `A` + * array. + * + * Rules: + * + * - The specified curve MUST be supported. + * + * - The source points (`A` and `B`) must be valid points on + * the relevant curve subgroup (and not the "point at + * infinity" either). If this is not the case, then this + * function returns an error (0). + * + * - If the `B` pointer is `NULL`, then the conventional + * subgroup generator is used. With some implementations, + * this may be faster than providing a pointer to the + * generator. + * + * - The multiplier integers (`x` and `y`) MUST be non-zero + * and less than the curve subgroup order. If either integer + * is zero, then an error is reported, but if one of them is + * not lower than the subgroup order, then the result is + * indeterminate and an error code is not guaranteed. + * + * - If the final result is the point at infinity, then an + * error is returned. + * + * Returned value is 1 on success, 0 on error. On error, the + * contents of `A` are indeterminate. + * + * \param A first point to multiply. + * \param B second point to multiply (`NULL` for the generator). + * \param len common length of the encoded points (in bytes). + * \param x multiplier for `A` (unsigned big-endian). + * \param xlen length of multiplier for `A` (in bytes). + * \param y multiplier for `A` (unsigned big-endian). + * \param ylen length of multiplier for `A` (in bytes). + * \param curve curve identifier. + * \return 1 on success, 0 on error. + */ + uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len, + const unsigned char *x, size_t xlen, + const unsigned char *y, size_t ylen, int curve); +} br_ec_impl; + +/** + * \brief EC implementation "i31". + * + * This implementation internally uses generic code for modular integers, + * with a representation as sequences of 31-bit words. It supports secp256r1, + * secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521). + */ +extern const br_ec_impl br_ec_prime_i31; + +/** + * \brief EC implementation "i15". + * + * This implementation internally uses generic code for modular integers, + * with a representation as sequences of 15-bit words. It supports secp256r1, + * secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521). + */ +extern const br_ec_impl br_ec_prime_i15; + +/** + * \brief EC implementation "m15" for P-256. + * + * This implementation uses specialised code for curve secp256r1 (also + * known as NIST P-256), with optional Karatsuba decomposition, and fast + * modular reduction thanks to the field modulus special format. Only + * 32-bit multiplications are used (with 32-bit results, not 64-bit). + */ +extern const br_ec_impl br_ec_p256_m15; + +/** + * \brief EC implementation "m31" for P-256. + * + * This implementation uses specialised code for curve secp256r1 (also + * known as NIST P-256), relying on multiplications of 31-bit values + * (MUL31). + */ +extern const br_ec_impl br_ec_p256_m31; + +/** + * \brief EC implementation "m62" (specialised code) for P-256. + * + * This implementation uses custom code relying on multiplication of + * integers up to 64 bits, with a 128-bit result. This implementation is + * defined only on platforms that offer the 64x64->128 multiplication + * support; use `br_ec_p256_m62_get()` to dynamically obtain a pointer + * to that implementation. + */ +extern const br_ec_impl br_ec_p256_m62; + +/** + * \brief Get the "m62" implementation of P-256, if available. + * + * \return the implementation, or 0. + */ +const br_ec_impl *br_ec_p256_m62_get(void); + +/** + * \brief EC implementation "m64" (specialised code) for P-256. + * + * This implementation uses custom code relying on multiplication of + * integers up to 64 bits, with a 128-bit result. This implementation is + * defined only on platforms that offer the 64x64->128 multiplication + * support; use `br_ec_p256_m64_get()` to dynamically obtain a pointer + * to that implementation. + */ +extern const br_ec_impl br_ec_p256_m64; + +/** + * \brief Get the "m64" implementation of P-256, if available. + * + * \return the implementation, or 0. + */ +const br_ec_impl *br_ec_p256_m64_get(void); + +/** + * \brief EC implementation "i15" (generic code) for Curve25519. + * + * This implementation uses the generic code for modular integers (with + * 15-bit words) to support Curve25519. Due to the specificities of the + * curve definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_i15; + +/** + * \brief EC implementation "i31" (generic code) for Curve25519. + * + * This implementation uses the generic code for modular integers (with + * 31-bit words) to support Curve25519. Due to the specificities of the + * curve definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_i31; + +/** + * \brief EC implementation "m15" (specialised code) for Curve25519. + * + * This implementation uses custom code relying on multiplication of + * integers up to 15 bits. Due to the specificities of the curve + * definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_m15; + +/** + * \brief EC implementation "m31" (specialised code) for Curve25519. + * + * This implementation uses custom code relying on multiplication of + * integers up to 31 bits. Due to the specificities of the curve + * definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_m31; + +/** + * \brief EC implementation "m62" (specialised code) for Curve25519. + * + * This implementation uses custom code relying on multiplication of + * integers up to 62 bits, with a 124-bit result. This implementation is + * defined only on platforms that offer the 64x64->128 multiplication + * support; use `br_ec_c25519_m62_get()` to dynamically obtain a pointer + * to that implementation. Due to the specificities of the curve + * definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_m62; + +/** + * \brief Get the "m62" implementation of Curve25519, if available. + * + * \return the implementation, or 0. + */ +const br_ec_impl *br_ec_c25519_m62_get(void); + +/** + * \brief EC implementation "m64" (specialised code) for Curve25519. + * + * This implementation uses custom code relying on multiplication of + * integers up to 64 bits, with a 128-bit result. This implementation is + * defined only on platforms that offer the 64x64->128 multiplication + * support; use `br_ec_c25519_m64_get()` to dynamically obtain a pointer + * to that implementation. Due to the specificities of the curve + * definition, the following applies: + * + * - `muladd()` is not implemented (the function returns 0 systematically). + * - `order()` returns 2^255-1, since the point multiplication algorithm + * accepts any 32-bit integer as input (it clears the top bit and low + * three bits systematically). + */ +extern const br_ec_impl br_ec_c25519_m64; + +/** + * \brief Get the "m64" implementation of Curve25519, if available. + * + * \return the implementation, or 0. + */ +const br_ec_impl *br_ec_c25519_m64_get(void); + +/** + * \brief Aggregate EC implementation "m15". + * + * This implementation is a wrapper for: + * + * - `br_ec_c25519_m15` for Curve25519 + * - `br_ec_p256_m15` for NIST P-256 + * - `br_ec_prime_i15` for other curves (NIST P-384 and NIST-P512) + */ +extern const br_ec_impl br_ec_all_m15; + +/** + * \brief Aggregate EC implementation "m31". + * + * This implementation is a wrapper for: + * + * - `br_ec_c25519_m31` for Curve25519 + * - `br_ec_p256_m31` for NIST P-256 + * - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512) + */ +extern const br_ec_impl br_ec_all_m31; + +/** + * \brief Aggregate EC implementation "m31". + * + * This implementation is a wrapper for: + * + * - `br_ec_p256_m31` for NIST P-256 + * - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512) + */ +extern const br_ec_impl br_ec_prime_fast_256; + +/** + * \brief Get the "default" EC implementation for the current system. + * + * This returns a pointer to the preferred implementation on the + * current system. + * + * \return the default EC implementation. + */ +const br_ec_impl *br_ec_get_default(void); + +/** + * \brief Convert a signature from "raw" to "asn1". + * + * Conversion is done "in place" and the new length is returned. + * Conversion may enlarge the signature, but by no more than 9 bytes at + * most. On error, 0 is returned (error conditions include an odd raw + * signature length, or an oversized integer). + * + * \param sig signature to convert. + * \param sig_len signature length (in bytes). + * \return the new signature length, or 0 on error. + */ +size_t br_ecdsa_raw_to_asn1(void *sig, size_t sig_len); + +/** + * \brief Convert a signature from "asn1" to "raw". + * + * Conversion is done "in place" and the new length is returned. + * Conversion may enlarge the signature, but the new signature length + * will be less than twice the source length at most. On error, 0 is + * returned (error conditions include an invalid ASN.1 structure or an + * oversized integer). + * + * \param sig signature to convert. + * \param sig_len signature length (in bytes). + * \return the new signature length, or 0 on error. + */ +size_t br_ecdsa_asn1_to_raw(void *sig, size_t sig_len); + +/** + * \brief Type for an ECDSA signer function. + * + * A pointer to the EC implementation is provided. The hash value is + * assumed to have the length inferred from the designated hash function + * class. + * + * Signature is written in the buffer pointed to by `sig`, and the length + * (in bytes) is returned. On error, nothing is written in the buffer, + * and 0 is returned. This function returns 0 if the specified curve is + * not supported by the provided EC implementation. + * + * The signature format is either "raw" or "asn1", depending on the + * implementation; maximum length is predictable from the implemented + * curve: + * + * | curve | raw | asn1 | + * | :--------- | --: | ---: | + * | NIST P-256 | 64 | 72 | + * | NIST P-384 | 96 | 104 | + * | NIST P-521 | 132 | 139 | + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +typedef size_t (*br_ecdsa_sign)(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief Type for an ECDSA signature verification function. + * + * A pointer to the EC implementation is provided. The hashed value, + * computed over the purportedly signed data, is also provided with + * its length. + * + * The signature format is either "raw" or "asn1", depending on the + * implementation. + * + * Returned value is 1 on success (valid signature), 0 on error. This + * function returns 0 if the specified curve is not supported by the + * provided EC implementation. + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_ecdsa_vrfy)(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief ECDSA signature generator, "i31" implementation, "asn1" format. + * + * \see br_ecdsa_sign() + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +size_t br_ecdsa_i31_sign_asn1(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief ECDSA signature generator, "i31" implementation, "raw" format. + * + * \see br_ecdsa_sign() + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +size_t br_ecdsa_i31_sign_raw(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief ECDSA signature verifier, "i31" implementation, "asn1" format. + * + * \see br_ecdsa_vrfy() + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +uint32_t br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief ECDSA signature verifier, "i31" implementation, "raw" format. + * + * \see br_ecdsa_vrfy() + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +uint32_t br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief ECDSA signature generator, "i15" implementation, "asn1" format. + * + * \see br_ecdsa_sign() + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +size_t br_ecdsa_i15_sign_asn1(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief ECDSA signature generator, "i15" implementation, "raw" format. + * + * \see br_ecdsa_sign() + * + * \param impl EC implementation to use. + * \param hf hash function used to process the data. + * \param hash_value signed data (hashed). + * \param sk EC private key. + * \param sig destination buffer. + * \return the signature length (in bytes), or 0 on error. + */ +size_t br_ecdsa_i15_sign_raw(const br_ec_impl *impl, + const br_hash_class *hf, const void *hash_value, + const br_ec_private_key *sk, void *sig); + +/** + * \brief ECDSA signature verifier, "i15" implementation, "asn1" format. + * + * \see br_ecdsa_vrfy() + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +uint32_t br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief ECDSA signature verifier, "i15" implementation, "raw" format. + * + * \see br_ecdsa_vrfy() + * + * \param impl EC implementation to use. + * \param hash signed data (hashed). + * \param hash_len hash value length (in bytes). + * \param pk EC public key. + * \param sig signature. + * \param sig_len signature length (in bytes). + * \return 1 on success, 0 on error. + */ +uint32_t br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl, + const void *hash, size_t hash_len, + const br_ec_public_key *pk, const void *sig, size_t sig_len); + +/** + * \brief Get "default" ECDSA implementation (signer, asn1 format). + * + * This returns the preferred implementation of ECDSA signature generation + * ("asn1" output format) on the current system. + * + * \return the default implementation. + */ +br_ecdsa_sign br_ecdsa_sign_asn1_get_default(void); + +/** + * \brief Get "default" ECDSA implementation (signer, raw format). + * + * This returns the preferred implementation of ECDSA signature generation + * ("raw" output format) on the current system. + * + * \return the default implementation. + */ +br_ecdsa_sign br_ecdsa_sign_raw_get_default(void); + +/** + * \brief Get "default" ECDSA implementation (verifier, asn1 format). + * + * This returns the preferred implementation of ECDSA signature verification + * ("asn1" output format) on the current system. + * + * \return the default implementation. + */ +br_ecdsa_vrfy br_ecdsa_vrfy_asn1_get_default(void); + +/** + * \brief Get "default" ECDSA implementation (verifier, raw format). + * + * This returns the preferred implementation of ECDSA signature verification + * ("raw" output format) on the current system. + * + * \return the default implementation. + */ +br_ecdsa_vrfy br_ecdsa_vrfy_raw_get_default(void); + +/** + * \brief Maximum size for EC private key element buffer. + * + * This is the largest number of bytes that `br_ec_keygen()` may need or + * ever return. + */ +#define BR_EC_KBUF_PRIV_MAX_SIZE 72 + +/** + * \brief Maximum size for EC public key element buffer. + * + * This is the largest number of bytes that `br_ec_compute_public()` may + * need or ever return. + */ +#define BR_EC_KBUF_PUB_MAX_SIZE 145 + +/** + * \brief Generate a new EC private key. + * + * If the specified `curve` is not supported by the elliptic curve + * implementation (`impl`), then this function returns zero. + * + * The `sk` structure fields are set to the new private key data. In + * particular, `sk.x` is made to point to the provided key buffer (`kbuf`), + * in which the actual private key data is written. That buffer is assumed + * to be large enough. The `BR_EC_KBUF_PRIV_MAX_SIZE` defines the maximum + * size for all supported curves. + * + * The number of bytes used in `kbuf` is returned. If `kbuf` is `NULL`, then + * the private key is not actually generated, and `sk` may also be `NULL`; + * the minimum length for `kbuf` is still computed and returned. + * + * If `sk` is `NULL` but `kbuf` is not `NULL`, then the private key is + * still generated and stored in `kbuf`. + * + * \param rng_ctx source PRNG context (already initialized). + * \param impl the elliptic curve implementation. + * \param sk the private key structure to fill, or `NULL`. + * \param kbuf the key element buffer, or `NULL`. + * \param curve the curve identifier. + * \return the key data length (in bytes), or zero. + */ +size_t br_ec_keygen(const br_prng_class **rng_ctx, + const br_ec_impl *impl, br_ec_private_key *sk, + void *kbuf, int curve); + +/** + * \brief Compute EC public key from EC private key. + * + * This function uses the provided elliptic curve implementation (`impl`) + * to compute the public key corresponding to the private key held in `sk`. + * The public key point is written into `kbuf`, which is then linked from + * the `*pk` structure. The size of the public key point, i.e. the number + * of bytes used in `kbuf`, is returned. + * + * If `kbuf` is `NULL`, then the public key point is NOT computed, and + * the public key structure `*pk` is unmodified (`pk` may be `NULL` in + * that case). The size of the public key point is still returned. + * + * If `pk` is `NULL` but `kbuf` is not `NULL`, then the public key + * point is computed and stored in `kbuf`, and its size is returned. + * + * If the curve used by the private key is not supported by the curve + * implementation, then this function returns zero. + * + * The private key MUST be valid. An off-range private key value is not + * necessarily detected, and leads to unpredictable results. + * + * \param impl the elliptic curve implementation. + * \param pk the public key structure to fill (or `NULL`). + * \param kbuf the public key point buffer (or `NULL`). + * \param sk the source private key. + * \return the public key point length (in bytes), or zero. + */ +size_t br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk, + void *kbuf, const br_ec_private_key *sk); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_hash.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_hash.h new file mode 100644 index 000000000..8d5a2a8ee --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_hash.h @@ -0,0 +1,1352 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_HASH_H__ +#define BR_BEARSSL_HASH_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_hash.h + * + * # Hash Functions + * + * This file documents the API for hash functions. + * + * + * ## Procedural API + * + * For each implemented hash function, of name "`xxx`", the following + * elements are defined: + * + * - `br_xxx_vtable` + * + * An externally defined instance of `br_hash_class`. + * + * - `br_xxx_SIZE` + * + * A macro that evaluates to the output size (in bytes) of the + * hash function. + * + * - `br_xxx_ID` + * + * A macro that evaluates to a symbolic identifier for the hash + * function. Such identifiers are used with HMAC and signature + * algorithm implementations. + * + * NOTE: for the "standard" hash functions defined in [the TLS + * standard](https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1), + * the symbolic identifiers match the constants used in TLS, i.e. + * 1 to 6 for MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512, + * respectively. + * + * - `br_xxx_context` + * + * Context for an ongoing computation. It is allocated by the + * caller, and a pointer to it is passed to all functions. A + * context contains no interior pointer, so it can be moved around + * and cloned (with a simple `memcpy()` or equivalent) in order to + * capture the function state at some point. Computations that use + * distinct context structures are independent of each other. The + * first field of `br_xxx_context` is always a pointer to the + * `br_xxx_vtable` structure; `br_xxx_init()` sets that pointer. + * + * - `br_xxx_init(br_xxx_context *ctx)` + * + * Initialise the provided context. Previous contents of the structure + * are ignored. This calls resets the context to the start of a new + * hash computation; it also sets the first field of the context + * structure (called `vtable`) to a pointer to the statically + * allocated constant `br_xxx_vtable` structure. + * + * - `br_xxx_update(br_xxx_context *ctx, const void *data, size_t len)` + * + * Add some more bytes to the hash computation represented by the + * provided context. + * + * - `br_xxx_out(const br_xxx_context *ctx, void *out)` + * + * Complete the hash computation and write the result in the provided + * buffer. The output buffer MUST be large enough to accommodate the + * result. The context is NOT modified by this operation, so this + * function can be used to get a "partial hash" while still keeping + * the possibility of adding more bytes to the input. + * + * - `br_xxx_state(const br_xxx_context *ctx, void *out)` + * + * Get a copy of the "current state" for the computation so far. For + * MD functions (MD5, SHA-1, SHA-2 family), this is the running state + * resulting from the processing of the last complete input block. + * Returned value is the current input length (in bytes). + * + * - `br_xxx_set_state(br_xxx_context *ctx, const void *stb, uint64_t count)` + * + * Set the internal state to the provided values. The 'stb' and + * 'count' values shall match that which was obtained from + * `br_xxx_state()`. This restores the hash state only if the state + * values were at an appropriate block boundary. This does NOT set + * the `vtable` pointer in the context. + * + * Context structures can be discarded without any explicit deallocation. + * Hash function implementations are purely software and don't reserve + * any resources outside of the context structure itself. + * + * + * ## Object-Oriented API + * + * For each hash function that follows the procedural API described + * above, an object-oriented API is also provided. In that API, function + * pointers from the vtable (`br_xxx_vtable`) are used. The vtable + * incarnates object-oriented programming. An introduction on the OOP + * concept used here can be read on the BearSSL Web site:
+ *    [https://www.bearssl.org/oop.html](https://www.bearssl.org/oop.html) + * + * The vtable offers functions called `init()`, `update()`, `out()`, + * `set()` and `set_state()`, which are in fact the functions from + * the procedural API. That vtable also contains two informative fields: + * + * - `context_size` + * + * The size of the context structure (`br_xxx_context`), in bytes. + * This can be used by generic implementations to perform dynamic + * context allocation. + * + * - `desc` + * + * A "descriptor" field that encodes some information on the hash + * function: symbolic identifier, output size, state size, + * internal block size, details on the padding. + * + * Users of this object-oriented API (in particular generic HMAC + * implementations) may make the following assumptions: + * + * - Hash output size is no more than 64 bytes. + * - Hash internal state size is no more than 64 bytes. + * - Internal block size is a power of two, no less than 16 and no more + * than 256. + * + * + * ## Implemented Hash Functions + * + * Implemented hash functions are: + * + * | Function | Name | Output length | State length | + * | :-------- | :------ | :-----------: | :----------: | + * | MD5 | md5 | 16 | 16 | + * | SHA-1 | sha1 | 20 | 20 | + * | SHA-224 | sha224 | 28 | 32 | + * | SHA-256 | sha256 | 32 | 32 | + * | SHA-384 | sha384 | 48 | 64 | + * | SHA-512 | sha512 | 64 | 64 | + * | MD5+SHA-1 | md5sha1 | 36 | 36 | + * + * (MD5+SHA-1 is the concatenation of MD5 and SHA-1 computed over the + * same input; in the implementation, the internal data buffer is + * shared, thus making it more memory-efficient than separate MD5 and + * SHA-1. It can be useful in implementing SSL 3.0, TLS 1.0 and TLS + * 1.1.) + * + * + * ## Multi-Hasher + * + * An aggregate hasher is provided, that can compute several standard + * hash functions in parallel. It uses `br_multihash_context` and a + * procedural API. It is configured with the implementations (the vtables) + * that it should use; it will then compute all these hash functions in + * parallel, on the same input. It is meant to be used in cases when the + * hash of an object will be used, but the exact hash function is not + * known yet (typically, streamed processing on X.509 certificates). + * + * Only the standard hash functions (MD5, SHA-1, SHA-224, SHA-256, SHA-384 + * and SHA-512) are supported by the multi-hasher. + * + * + * ## GHASH + * + * GHASH is not a generic hash function; it is a _universal_ hash function, + * which, as the name does not say, means that it CANNOT be used in most + * places where a hash function is needed. GHASH is used within the GCM + * encryption mode, to provide the checked integrity functionality. + * + * A GHASH implementation is basically a function that uses the type defined + * in this file under the name `br_ghash`: + * + * typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len); + * + * The `y` pointer refers to a 16-byte value which is used as input, and + * receives the output of the GHASH invocation. `h` is a 16-byte secret + * value (that serves as key). `data` and `len` define the input data. + * + * Three GHASH implementations are provided, all constant-time, based on + * the use of integer multiplications with appropriate masking to cancel + * carry propagation. + */ + +/** + * \brief Class type for hash function implementations. + * + * A `br_hash_class` instance references the methods implementing a hash + * function. Constant instances of this structure are defined for each + * implemented hash function. Such instances are also called "vtables". + * + * Vtables are used to support object-oriented programming, as + * described on [the BearSSL Web site](https://www.bearssl.org/oop.html). + */ +typedef struct br_hash_class_ br_hash_class; +struct br_hash_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate for + * computing this hash function. + */ + size_t context_size; + + /** + * \brief Descriptor word that contains information about the hash + * function. + * + * For each word `xxx` described below, use `BR_HASHDESC_xxx_OFF` + * and `BR_HASHDESC_xxx_MASK` to access the specific value, as + * follows: + * + * (hf->desc >> BR_HASHDESC_xxx_OFF) & BR_HASHDESC_xxx_MASK + * + * The defined elements are: + * + * - `ID`: the symbolic identifier for the function, as defined + * in [TLS](https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1) + * (MD5 = 1, SHA-1 = 2,...). + * + * - `OUT`: hash output size, in bytes. + * + * - `STATE`: internal running state size, in bytes. + * + * - `LBLEN`: base-2 logarithm for the internal block size, as + * defined for HMAC processing (this is 6 for MD5, SHA-1, SHA-224 + * and SHA-256, since these functions use 64-byte blocks; for + * SHA-384 and SHA-512, this is 7, corresponding to their + * 128-byte blocks). + * + * The descriptor may contain a few other flags. + */ + uint32_t desc; + + /** + * \brief Initialisation method. + * + * This method takes as parameter a pointer to a context area, + * that it initialises. The first field of the context is set + * to this vtable; other elements are initialised for a new hash + * computation. + * + * \param ctx pointer to (the first field of) the context. + */ + void (*init)(const br_hash_class **ctx); + + /** + * \brief Data injection method. + * + * The `len` bytes starting at address `data` are injected into + * the running hash computation incarnated by the specified + * context. The context is updated accordingly. It is allowed + * to have `len == 0`, in which case `data` is ignored (and could + * be `NULL`), and nothing happens. + * on the input data. + * + * \param ctx pointer to (the first field of) the context. + * \param data pointer to the first data byte to inject. + * \param len number of bytes to inject. + */ + void (*update)(const br_hash_class **ctx, const void *data, size_t len); + + /** + * \brief Produce hash output. + * + * The hash output corresponding to all data bytes injected in the + * context since the last `init()` call is computed, and written + * in the buffer pointed to by `dst`. The hash output size depends + * on the implemented hash function (e.g. 16 bytes for MD5). + * The context is _not_ modified by this call, so further bytes + * may be afterwards injected to continue the current computation. + * + * \param ctx pointer to (the first field of) the context. + * \param dst destination buffer for the hash output. + */ + void (*out)(const br_hash_class *const *ctx, void *dst); + + /** + * \brief Get running state. + * + * This method saves the current running state into the `dst` + * buffer. What constitutes the "running state" depends on the + * hash function; for Merkle-Damgård hash functions (like + * MD5 or SHA-1), this is the output obtained after processing + * each block. The number of bytes injected so far is returned. + * The context is not modified by this call. + * + * \param ctx pointer to (the first field of) the context. + * \param dst destination buffer for the state. + * \return the injected total byte length. + */ + uint64_t (*state)(const br_hash_class *const *ctx, void *dst); + + /** + * \brief Set running state. + * + * This methods replaces the running state for the function. + * + * \param ctx pointer to (the first field of) the context. + * \param stb source buffer for the state. + * \param count injected total byte length. + */ + void (*set_state)(const br_hash_class **ctx, + const void *stb, uint64_t count); +}; + +#ifndef BR_DOXYGEN_IGNORE +#define BR_HASHDESC_ID(id) ((uint32_t)(id) << BR_HASHDESC_ID_OFF) +#define BR_HASHDESC_ID_OFF 0 +#define BR_HASHDESC_ID_MASK 0xFF + +#define BR_HASHDESC_OUT(size) ((uint32_t)(size) << BR_HASHDESC_OUT_OFF) +#define BR_HASHDESC_OUT_OFF 8 +#define BR_HASHDESC_OUT_MASK 0x7F + +#define BR_HASHDESC_STATE(size) ((uint32_t)(size) << BR_HASHDESC_STATE_OFF) +#define BR_HASHDESC_STATE_OFF 15 +#define BR_HASHDESC_STATE_MASK 0xFF + +#define BR_HASHDESC_LBLEN(ls) ((uint32_t)(ls) << BR_HASHDESC_LBLEN_OFF) +#define BR_HASHDESC_LBLEN_OFF 23 +#define BR_HASHDESC_LBLEN_MASK 0x0F + +#define BR_HASHDESC_MD_PADDING ((uint32_t)1 << 28) +#define BR_HASHDESC_MD_PADDING_128 ((uint32_t)1 << 29) +#define BR_HASHDESC_MD_PADDING_BE ((uint32_t)1 << 30) +#endif + +/* + * Specific hash functions. + * + * Rules for contexts: + * -- No interior pointer. + * -- No pointer to external dynamically allocated resources. + * -- First field is called 'vtable' and is a pointer to a + * const-qualified br_hash_class instance (pointer is set by init()). + * -- SHA-224 and SHA-256 contexts are identical. + * -- SHA-384 and SHA-512 contexts are identical. + * + * Thus, contexts can be moved and cloned to capture the hash function + * current state; and there is no need for any explicit "release" function. + */ + +/** + * \brief Symbolic identifier for MD5. + */ +#define br_md5_ID 1 + +/** + * \brief MD5 output size (in bytes). + */ +#define br_md5_SIZE 16 + +/** + * \brief Constant vtable for MD5. + */ +extern const br_hash_class br_md5_vtable; + +/** + * \brief MD5 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[64]; + uint64_t count; + uint32_t val[4]; +#endif +} br_md5_context; + +/** + * \brief MD5 context initialisation. + * + * This function initialises or resets a context for a new MD5 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_md5_init(br_md5_context *ctx); + +/** + * \brief Inject some data bytes in a running MD5 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_md5_update(br_md5_context *ctx, const void *data, size_t len); + +/** + * \brief Compute MD5 output. + * + * The MD5 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_md5_out(const br_md5_context *ctx, void *out); + +/** + * \brief Save MD5 running state. + * + * The running state for MD5 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_md5_state(const br_md5_context *ctx, void *out); + +/** + * \brief Restore MD5 running state. + * + * The running state for MD5 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_md5_set_state(br_md5_context *ctx, const void *stb, uint64_t count); + +/** + * \brief Symbolic identifier for SHA-1. + */ +#define br_sha1_ID 2 + +/** + * \brief SHA-1 output size (in bytes). + */ +#define br_sha1_SIZE 20 + +/** + * \brief Constant vtable for SHA-1. + */ +extern const br_hash_class br_sha1_vtable; + +/** + * \brief SHA-1 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[64]; + uint64_t count; + uint32_t val[5]; +#endif +} br_sha1_context; + +/** + * \brief SHA-1 context initialisation. + * + * This function initialises or resets a context for a new SHA-1 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha1_init(br_sha1_context *ctx); + +/** + * \brief Inject some data bytes in a running SHA-1 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha1_update(br_sha1_context *ctx, const void *data, size_t len); + +/** + * \brief Compute SHA-1 output. + * + * The SHA-1 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha1_out(const br_sha1_context *ctx, void *out); + +/** + * \brief Save SHA-1 running state. + * + * The running state for SHA-1 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha1_state(const br_sha1_context *ctx, void *out); + +/** + * \brief Restore SHA-1 running state. + * + * The running state for SHA-1 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha1_set_state(br_sha1_context *ctx, const void *stb, uint64_t count); + +/** + * \brief Symbolic identifier for SHA-224. + */ +#define br_sha224_ID 3 + +/** + * \brief SHA-224 output size (in bytes). + */ +#define br_sha224_SIZE 28 + +/** + * \brief Constant vtable for SHA-224. + */ +extern const br_hash_class br_sha224_vtable; + +/** + * \brief SHA-224 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[64]; + uint64_t count; + uint32_t val[8]; +#endif +} br_sha224_context; + +/** + * \brief SHA-224 context initialisation. + * + * This function initialises or resets a context for a new SHA-224 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha224_init(br_sha224_context *ctx); + +/** + * \brief Inject some data bytes in a running SHA-224 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha224_update(br_sha224_context *ctx, const void *data, size_t len); + +/** + * \brief Compute SHA-224 output. + * + * The SHA-224 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha224_out(const br_sha224_context *ctx, void *out); + +/** + * \brief Save SHA-224 running state. + * + * The running state for SHA-224 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha224_state(const br_sha224_context *ctx, void *out); + +/** + * \brief Restore SHA-224 running state. + * + * The running state for SHA-224 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha224_set_state(br_sha224_context *ctx, + const void *stb, uint64_t count); + +/** + * \brief Symbolic identifier for SHA-256. + */ +#define br_sha256_ID 4 + +/** + * \brief SHA-256 output size (in bytes). + */ +#define br_sha256_SIZE 32 + +/** + * \brief Constant vtable for SHA-256. + */ +extern const br_hash_class br_sha256_vtable; + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief SHA-256 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +} br_sha256_context; +#else +typedef br_sha224_context br_sha256_context; +#endif + +/** + * \brief SHA-256 context initialisation. + * + * This function initialises or resets a context for a new SHA-256 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha256_init(br_sha256_context *ctx); + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Inject some data bytes in a running SHA-256 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha256_update(br_sha256_context *ctx, const void *data, size_t len); +#else +#define br_sha256_update br_sha224_update +#endif + +/** + * \brief Compute SHA-256 output. + * + * The SHA-256 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha256_out(const br_sha256_context *ctx, void *out); + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Save SHA-256 running state. + * + * The running state for SHA-256 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha256_state(const br_sha256_context *ctx, void *out); +#else +#define br_sha256_state br_sha224_state +#endif + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Restore SHA-256 running state. + * + * The running state for SHA-256 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha256_set_state(br_sha256_context *ctx, + const void *stb, uint64_t count); +#else +#define br_sha256_set_state br_sha224_set_state +#endif + +/** + * \brief Symbolic identifier for SHA-384. + */ +#define br_sha384_ID 5 + +/** + * \brief SHA-384 output size (in bytes). + */ +#define br_sha384_SIZE 48 + +/** + * \brief Constant vtable for SHA-384. + */ +extern const br_hash_class br_sha384_vtable; + +/** + * \brief SHA-384 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[128]; + uint64_t count; + uint64_t val[8]; +#endif +} br_sha384_context; + +/** + * \brief SHA-384 context initialisation. + * + * This function initialises or resets a context for a new SHA-384 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha384_init(br_sha384_context *ctx); + +/** + * \brief Inject some data bytes in a running SHA-384 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha384_update(br_sha384_context *ctx, const void *data, size_t len); + +/** + * \brief Compute SHA-384 output. + * + * The SHA-384 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha384_out(const br_sha384_context *ctx, void *out); + +/** + * \brief Save SHA-384 running state. + * + * The running state for SHA-384 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha384_state(const br_sha384_context *ctx, void *out); + +/** + * \brief Restore SHA-384 running state. + * + * The running state for SHA-384 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha384_set_state(br_sha384_context *ctx, + const void *stb, uint64_t count); + +/** + * \brief Symbolic identifier for SHA-512. + */ +#define br_sha512_ID 6 + +/** + * \brief SHA-512 output size (in bytes). + */ +#define br_sha512_SIZE 64 + +/** + * \brief Constant vtable for SHA-512. + */ +extern const br_hash_class br_sha512_vtable; + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief SHA-512 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +} br_sha512_context; +#else +typedef br_sha384_context br_sha512_context; +#endif + +/** + * \brief SHA-512 context initialisation. + * + * This function initialises or resets a context for a new SHA-512 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_sha512_init(br_sha512_context *ctx); + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Inject some data bytes in a running SHA-512 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_sha512_update(br_sha512_context *ctx, const void *data, size_t len); +#else +#define br_sha512_update br_sha384_update +#endif + +/** + * \brief Compute SHA-512 output. + * + * The SHA-512 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_sha512_out(const br_sha512_context *ctx, void *out); + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Save SHA-512 running state. + * + * The running state for SHA-512 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_sha512_state(const br_sha512_context *ctx, void *out); +#else +#define br_sha512_state br_sha384_state +#endif + +#ifdef BR_DOXYGEN_IGNORE +/** + * \brief Restore SHA-512 running state. + * + * The running state for SHA-512 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_sha512_set_state(br_sha512_context *ctx, + const void *stb, uint64_t count); +#else +#define br_sha512_set_state br_sha384_set_state +#endif + +/* + * "md5sha1" is a special hash function that computes both MD5 and SHA-1 + * on the same input, and produces a 36-byte output (MD5 and SHA-1 + * concatenation, in that order). State size is also 36 bytes. + */ + +/** + * \brief Symbolic identifier for MD5+SHA-1. + * + * MD5+SHA-1 is the concatenation of MD5 and SHA-1, computed over the + * same input. It is not one of the functions identified in TLS, so + * we give it a symbolic identifier of value 0. + */ +#define br_md5sha1_ID 0 + +/** + * \brief MD5+SHA-1 output size (in bytes). + */ +#define br_md5sha1_SIZE 36 + +/** + * \brief Constant vtable for MD5+SHA-1. + */ +extern const br_hash_class br_md5sha1_vtable; + +/** + * \brief MD5+SHA-1 context. + * + * First field is a pointer to the vtable; it is set by the initialisation + * function. Other fields are not supposed to be accessed by user code. + */ +typedef struct { + /** + * \brief Pointer to vtable for this context. + */ + const br_hash_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[64]; + uint64_t count; + uint32_t val_md5[4]; + uint32_t val_sha1[5]; +#endif +} br_md5sha1_context; + +/** + * \brief MD5+SHA-1 context initialisation. + * + * This function initialises or resets a context for a new SHA-512 + * computation. It also sets the vtable pointer. + * + * \param ctx pointer to the context structure. + */ +void br_md5sha1_init(br_md5sha1_context *ctx); + +/** + * \brief Inject some data bytes in a running MD5+SHA-1 computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_md5sha1_update(br_md5sha1_context *ctx, const void *data, size_t len); + +/** + * \brief Compute MD5+SHA-1 output. + * + * The MD5+SHA-1 output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `out`. The context + * itself is not modified, so extra bytes may be injected afterwards + * to continue that computation. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the hash output. + */ +void br_md5sha1_out(const br_md5sha1_context *ctx, void *out); + +/** + * \brief Save MD5+SHA-1 running state. + * + * The running state for MD5+SHA-1 (output of the last internal block + * processing) is written in the buffer pointed to by `out`. The + * number of bytes injected since the last initialisation or reset + * call is returned. The context is not modified. + * + * \param ctx pointer to the context structure. + * \param out destination buffer for the running state. + * \return the injected total byte length. + */ +uint64_t br_md5sha1_state(const br_md5sha1_context *ctx, void *out); + +/** + * \brief Restore MD5+SHA-1 running state. + * + * The running state for MD5+SHA-1 is set to the provided values. + * + * \param ctx pointer to the context structure. + * \param stb source buffer for the running state. + * \param count the injected total byte length. + */ +void br_md5sha1_set_state(br_md5sha1_context *ctx, + const void *stb, uint64_t count); + +/** + * \brief Aggregate context for configurable hash function support. + * + * The `br_hash_compat_context` type is a type which is large enough to + * serve as context for all standard hash functions defined above. + */ +typedef union { + const br_hash_class *vtable; + br_md5_context md5; + br_sha1_context sha1; + br_sha224_context sha224; + br_sha256_context sha256; + br_sha384_context sha384; + br_sha512_context sha512; + br_md5sha1_context md5sha1; +} br_hash_compat_context; + +/* + * The multi-hasher is a construct that handles hashing of the same input + * data with several hash functions, with a single shared input buffer. + * It can handle MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 + * simultaneously, though which functions are activated depends on + * the set implementation pointers. + */ + +/** + * \brief Multi-hasher context structure. + * + * The multi-hasher runs up to six hash functions in the standard TLS list + * (MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512) in parallel, over + * the same input. + * + * The multi-hasher does _not_ follow the OOP structure with a vtable. + * Instead, it is configured with the vtables of the hash functions it + * should run. Structure fields are not supposed to be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + unsigned char buf[128]; + uint64_t count; + uint32_t val_32[25]; + uint64_t val_64[16]; + const br_hash_class *impl[6]; +#endif +} br_multihash_context; + +/** + * \brief Clear a multi-hasher context. + * + * This should always be called once on a given context, _before_ setting + * the implementation pointers. + * + * \param ctx the multi-hasher context. + */ +void br_multihash_zero(br_multihash_context *ctx); + +/** + * \brief Set a hash function implementation. + * + * Implementations shall be set _after_ clearing the context (with + * `br_multihash_zero()`) but _before_ initialising the computation + * (with `br_multihash_init()`). The hash function implementation + * MUST be one of the standard hash functions (MD5, SHA-1, SHA-224, + * SHA-256, SHA-384 or SHA-512); it may also be `NULL` to remove + * an implementation from the multi-hasher. + * + * \param ctx the multi-hasher context. + * \param id the hash function symbolic identifier. + * \param impl the hash function vtable, or `NULL`. + */ +static inline void +br_multihash_setimpl(br_multihash_context *ctx, + int id, const br_hash_class *impl) +{ + /* + * This code relies on hash functions ID being values 1 to 6, + * in the MD5 to SHA-512 order. + */ + ctx->impl[id - 1] = impl; +} + +/** + * \brief Get a hash function implementation. + * + * This function returns the currently configured vtable for a given + * hash function (by symbolic ID). If no such function was configured in + * the provided multi-hasher context, then this function returns `NULL`. + * + * \param ctx the multi-hasher context. + * \param id the hash function symbolic identifier. + * \return the hash function vtable, or `NULL`. + */ +static inline const br_hash_class * +br_multihash_getimpl(const br_multihash_context *ctx, int id) +{ + return ctx->impl[id - 1]; +} + +/** + * \brief Reset a multi-hasher context. + * + * This function prepares the context for a new hashing computation, + * for all implementations configured at that point. + * + * \param ctx the multi-hasher context. + */ +void br_multihash_init(br_multihash_context *ctx); + +/** + * \brief Inject some data bytes in a running multi-hashing computation. + * + * The provided context is updated with some data bytes. If the number + * of bytes (`len`) is zero, then the data pointer (`data`) is ignored + * and may be `NULL`, and this function does nothing. + * + * \param ctx pointer to the context structure. + * \param data pointer to the injected data. + * \param len injected data length (in bytes). + */ +void br_multihash_update(br_multihash_context *ctx, + const void *data, size_t len); + +/** + * \brief Compute a hash output from a multi-hasher. + * + * The hash output for the concatenation of all bytes injected in the + * provided context since the last initialisation or reset call, is + * computed and written in the buffer pointed to by `dst`. The hash + * function to use is identified by `id` and must be one of the standard + * hash functions. If that hash function was indeed configured in the + * multi-hasher context, the corresponding hash value is written in + * `dst` and its length (in bytes) is returned. If the hash function + * was _not_ configured, then nothing is written in `dst` and 0 is + * returned. + * + * The context itself is not modified, so extra bytes may be injected + * afterwards to continue the hash computations. + * + * \param ctx pointer to the context structure. + * \param id the hash function symbolic identifier. + * \param dst destination buffer for the hash output. + * \return the hash output length (in bytes), or 0. + */ +size_t br_multihash_out(const br_multihash_context *ctx, int id, void *dst); + +/** + * \brief Type for a GHASH implementation. + * + * GHASH is a sort of keyed hash meant to be used to implement GCM in + * combination with a block cipher (with 16-byte blocks). + * + * The `y` array has length 16 bytes and is used for input and output; in + * a complete GHASH run, it starts with an all-zero value. `h` is a 16-byte + * value that serves as key (it is derived from the encryption key in GCM, + * using the block cipher). The data length (`len`) is expressed in bytes. + * The `y` array is updated. + * + * If the data length is not a multiple of 16, then the data is implicitly + * padded with zeros up to the next multiple of 16. Thus, when using GHASH + * in GCM, this method may be called twice, for the associated data and + * for the ciphertext, respectively; the zero-padding implements exactly + * the GCM rules. + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len); + +/** + * \brief GHASH implementation using multiplications (mixed 32-bit). + * + * This implementation uses multiplications of 32-bit values, with a + * 64-bit result. It is constant-time (if multiplications are + * constant-time). + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_ctmul(void *y, const void *h, const void *data, size_t len); + +/** + * \brief GHASH implementation using multiplications (strict 32-bit). + * + * This implementation uses multiplications of 32-bit values, with a + * 32-bit result. It is usually somewhat slower than `br_ghash_ctmul()`, + * but it is expected to be faster on architectures for which the + * 32-bit multiplication opcode does not yield the upper 32 bits of the + * product. It is constant-time (if multiplications are constant-time). + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len); + +/** + * \brief GHASH implementation using multiplications (64-bit). + * + * This implementation uses multiplications of 64-bit values, with a + * 64-bit result. It is constant-time (if multiplications are + * constant-time). It is substantially faster than `br_ghash_ctmul()` + * and `br_ghash_ctmul32()` on most 64-bit architectures. + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len); + +/** + * \brief GHASH implementation using the `pclmulqdq` opcode (part of the + * AES-NI instructions). + * + * This implementation is available only on x86 platforms where the + * compiler supports the relevant intrinsic functions. Even if the + * compiler supports these functions, the local CPU might not support + * the `pclmulqdq` opcode, meaning that a call will fail with an + * illegal instruction exception. To safely obtain a pointer to this + * function when supported (or 0 otherwise), use `br_ghash_pclmul_get()`. + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_pclmul(void *y, const void *h, const void *data, size_t len); + +/** + * \brief Obtain the `pclmul` GHASH implementation, if available. + * + * If the `pclmul` implementation was compiled in the library (depending + * on the compiler abilities) _and_ the local CPU appears to support the + * opcode, then this function will return a pointer to the + * `br_ghash_pclmul()` function. Otherwise, it will return `0`. + * + * \return the `pclmul` GHASH implementation, or `0`. + */ +br_ghash br_ghash_pclmul_get(void); + +/** + * \brief GHASH implementation using the POWER8 opcodes. + * + * This implementation is available only on POWER8 platforms (and later). + * To safely obtain a pointer to this function when supported (or 0 + * otherwise), use `br_ghash_pwr8_get()`. + * + * \param y the array to update. + * \param h the GHASH key. + * \param data the input data (may be `NULL` if `len` is zero). + * \param len the input data length (in bytes). + */ +void br_ghash_pwr8(void *y, const void *h, const void *data, size_t len); + +/** + * \brief Obtain the `pwr8` GHASH implementation, if available. + * + * If the `pwr8` implementation was compiled in the library (depending + * on the compiler abilities) _and_ the local CPU appears to support the + * opcode, then this function will return a pointer to the + * `br_ghash_pwr8()` function. Otherwise, it will return `0`. + * + * \return the `pwr8` GHASH implementation, or `0`. + */ +br_ghash br_ghash_pwr8_get(void); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_hmac.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_hmac.h new file mode 100644 index 000000000..70e9dd11e --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_hmac.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_HMAC_H__ +#define BR_BEARSSL_HMAC_H__ + +#include +#include + +#include "bearssl_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_hmac.h + * + * # HMAC + * + * HMAC is initialized with a key and an underlying hash function; it + * then fills a "key context". That context contains the processed + * key. + * + * With the key context, a HMAC context can be initialized to process + * the input bytes and obtain the MAC output. The key context is not + * modified during that process, and can be reused. + * + * IMPORTANT: HMAC shall be used only with functions that have the + * following properties: + * + * - hash output size does not exceed 64 bytes; + * - hash internal state size does not exceed 64 bytes; + * - internal block length is a power of 2 between 16 and 256 bytes. + */ + +/** + * \brief HMAC key context. + * + * The HMAC key context is initialised with a hash function implementation + * and a secret key. Contents are opaque (callers should not access them + * directly). The caller is responsible for allocating the context where + * appropriate. Context initialisation and usage incurs no dynamic + * allocation, so there is no release function. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + const br_hash_class *dig_vtable; + unsigned char ksi[64], kso[64]; +#endif +} br_hmac_key_context; + +/** + * \brief HMAC key context initialisation. + * + * Initialise the key context with the provided key, using the hash function + * identified by `digest_vtable`. This supports arbitrary key lengths. + * + * \param kc HMAC key context to initialise. + * \param digest_vtable pointer to the hash function implementation vtable. + * \param key pointer to the HMAC secret key. + * \param key_len HMAC secret key length (in bytes). + */ +void br_hmac_key_init(br_hmac_key_context *kc, + const br_hash_class *digest_vtable, const void *key, size_t key_len); + +/* + * \brief Get the underlying hash function. + * + * This function returns a pointer to the implementation vtable of the + * hash function used for this HMAC key context. + * + * \param kc HMAC key context. + * \return the hash function implementation. + */ +static inline const br_hash_class *br_hmac_key_get_digest( + const br_hmac_key_context *kc) +{ + return kc->dig_vtable; +} + +/** + * \brief HMAC computation context. + * + * The HMAC computation context maintains the state for a single HMAC + * computation. It is modified as input bytes are injected. The context + * is caller-allocated and has no release function since it does not + * dynamically allocate external resources. Its contents are opaque. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + br_hash_compat_context dig; + unsigned char kso[64]; + size_t out_len; +#endif +} br_hmac_context; + +/** + * \brief HMAC computation initialisation. + * + * Initialise a HMAC context with a key context. The key context is + * unmodified. Relevant data from the key context is immediately copied; + * the key context can thus be independently reused, modified or released + * without impacting this HMAC computation. + * + * An explicit output length can be specified; the actual output length + * will be the minimum of that value and the natural HMAC output length. + * If `out_len` is 0, then the natural HMAC output length is selected. The + * "natural output length" is the output length of the underlying hash + * function. + * + * \param ctx HMAC context to initialise. + * \param kc HMAC key context (already initialised with the key). + * \param out_len HMAC output length (0 to select "natural length"). + */ +void br_hmac_init(br_hmac_context *ctx, + const br_hmac_key_context *kc, size_t out_len); + +/** + * \brief Get the HMAC output size. + * + * The HMAC output size is the number of bytes that will actually be + * produced with `br_hmac_out()` with the provided context. This function + * MUST NOT be called on a non-initialised HMAC computation context. + * The returned value is the minimum of the HMAC natural length (output + * size of the underlying hash function) and the `out_len` parameter which + * was used with the last `br_hmac_init()` call on that context (if the + * initialisation `out_len` parameter was 0, then this function will + * return the HMAC natural length). + * + * \param ctx the (already initialised) HMAC computation context. + * \return the HMAC actual output size. + */ +static inline size_t +br_hmac_size(br_hmac_context *ctx) +{ + return ctx->out_len; +} + +/* + * \brief Get the underlying hash function. + * + * This function returns a pointer to the implementation vtable of the + * hash function used for this HMAC context. + * + * \param hc HMAC context. + * \return the hash function implementation. + */ +static inline const br_hash_class *br_hmac_get_digest( + const br_hmac_context *hc) +{ + return hc->dig.vtable; +} + +/** + * \brief Inject some bytes in HMAC. + * + * The provided `len` bytes are injected as extra input in the HMAC + * computation incarnated by the `ctx` HMAC context. It is acceptable + * that `len` is zero, in which case `data` is ignored (and may be + * `NULL`) and this function does nothing. + */ +void br_hmac_update(br_hmac_context *ctx, const void *data, size_t len); + +/** + * \brief Compute the HMAC output. + * + * The destination buffer MUST be large enough to accommodate the result; + * its length is at most the "natural length" of HMAC (i.e. the output + * length of the underlying hash function). The context is NOT modified; + * further bytes may be processed. Thus, "partial HMAC" values can be + * efficiently obtained. + * + * Returned value is the output length (in bytes). + * + * \param ctx HMAC computation context. + * \param out destination buffer for the HMAC output. + * \return the produced value length (in bytes). + */ +size_t br_hmac_out(const br_hmac_context *ctx, void *out); + +/** + * \brief Constant-time HMAC computation. + * + * This function compute the HMAC output in constant time. Some extra + * input bytes are processed, then the output is computed. The extra + * input consists in the `len` bytes pointed to by `data`. The `len` + * parameter must lie between `min_len` and `max_len` (inclusive); + * `max_len` bytes are actually read from `data`. Computing time (and + * memory access pattern) will not depend upon the data byte contents or + * the value of `len`. + * + * The output is written in the `out` buffer, that MUST be large enough + * to receive it. + * + * The difference `max_len - min_len` MUST be less than 230 + * (i.e. about one gigabyte). + * + * This function computes the output properly only if the underlying + * hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256, + * SHA-384 or SHA-512). + * + * The provided context is NOT modified. + * + * \param ctx the (already initialised) HMAC computation context. + * \param data the extra input bytes. + * \param len the extra input length (in bytes). + * \param min_len minimum extra input length (in bytes). + * \param max_len maximum extra input length (in bytes). + * \param out destination buffer for the HMAC output. + * \return the produced value length (in bytes). + */ +size_t br_hmac_outCT(const br_hmac_context *ctx, + const void *data, size_t len, size_t min_len, size_t max_len, + void *out); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_kdf.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_kdf.h new file mode 100644 index 000000000..f0968320f --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_kdf.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2018 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_KDF_H__ +#define BR_BEARSSL_KDF_H__ + +#include +#include + +#include "bearssl_hash.h" +#include "bearssl_hmac.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_kdf.h + * + * # Key Derivation Functions + * + * KDF are functions that takes a variable length input, and provide a + * variable length output, meant to be used to derive subkeys from a + * master key. + * + * ## HKDF + * + * HKDF is a KDF defined by [RFC 5869](https://tools.ietf.org/html/rfc5869). + * It is based on HMAC, itself using an underlying hash function. Any + * hash function can be used, as long as it is compatible with the rules + * for the HMAC implementation (i.e. output size is 64 bytes or less, hash + * internal state size is 64 bytes or less, and the internal block length is + * a power of 2 between 16 and 256 bytes). HKDF has two phases: + * + * - HKDF-Extract: the input data in ingested, along with a "salt" value. + * + * - HKDF-Expand: the output is produced, from the result of processing + * the input and salt, and using an extra non-secret parameter called + * "info". + * + * The "salt" and "info" strings are non-secret and can be empty. Their role + * is normally to bind the input and output, respectively, to conventional + * identifiers that qualifu them within the used protocol or application. + * + * The implementation defined in this file uses the following functions: + * + * - `br_hkdf_init()`: initialize an HKDF context, with a hash function, + * and the salt. This starts the HKDF-Extract process. + * + * - `br_hkdf_inject()`: inject more input bytes. This function may be + * called repeatedly if the input data is provided by chunks. + * + * - `br_hkdf_flip()`: end the HKDF-Extract process, and start the + * HKDF-Expand process. + * + * - `br_hkdf_produce()`: get the next bytes of output. This function + * may be called several times to obtain the full output by chunks. + * For correct HKDF processing, the same "info" string must be + * provided for each call. + * + * Note that the HKDF total output size (the number of bytes that + * HKDF-Expand is willing to produce) is limited: if the hash output size + * is _n_ bytes, then the maximum output size is _255*n_. + * + * ## SHAKE + * + * SHAKE is defined in + * [FIPS 202](https://csrc.nist.gov/publications/detail/fips/202/final) + * under two versions: SHAKE128 and SHAKE256, offering an alleged + * "security level" of 128 and 256 bits, respectively (SHAKE128 is + * about 20 to 25% faster than SHAKE256). SHAKE internally relies on + * the Keccak family of sponge functions, not on any externally provided + * hash function. Contrary to HKDF, SHAKE does not have a concept of + * either a "salt" or an "info" string. The API consists in four + * functions: + * + * - `br_shake_init()`: initialize a SHAKE context for a given + * security level. + * + * - `br_shake_inject()`: inject more input bytes. This function may be + * called repeatedly if the input data is provided by chunks. + * + * - `br_shake_flip()`: end the data injection process, and start the + * data production process. + * + * - `br_shake_produce()`: get the next bytes of output. This function + * may be called several times to obtain the full output by chunks. + */ + +/** + * \brief HKDF context. + * + * The HKDF context is initialized with a hash function implementation + * and a salt value. Contents are opaque (callers should not access them + * directly). The caller is responsible for allocating the context where + * appropriate. Context initialisation and usage incurs no dynamic + * allocation, so there is no release function. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + union { + br_hmac_context hmac_ctx; + br_hmac_key_context prk_ctx; + } u; + unsigned char buf[64]; + size_t ptr; + size_t dig_len; + unsigned chunk_num; +#endif +} br_hkdf_context; + +/** + * \brief HKDF context initialization. + * + * The underlying hash function and salt value are provided. Arbitrary + * salt lengths can be used. + * + * HKDF makes a difference between a salt of length zero, and an + * absent salt (the latter being equivalent to a salt consisting of + * bytes of value zero, of the same length as the hash function output). + * If `salt_len` is zero, then this function assumes that the salt is + * present but of length zero. To specify an _absent_ salt, use + * `BR_HKDF_NO_SALT` as `salt` parameter (`salt_len` is then ignored). + * + * \param hc HKDF context to initialise. + * \param digest_vtable pointer to the hash function implementation vtable. + * \param salt HKDF-Extract salt. + * \param salt_len HKDF-Extract salt length (in bytes). + */ +void br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable, + const void *salt, size_t salt_len); + +/** + * \brief The special "absent salt" value for HKDF. + */ +#define BR_HKDF_NO_SALT (&br_hkdf_no_salt) + +#ifndef BR_DOXYGEN_IGNORE +extern const unsigned char br_hkdf_no_salt; +#endif + +/** + * \brief HKDF input injection (HKDF-Extract). + * + * This function injects some more input bytes ("key material") into + * HKDF. This function may be called several times, after `br_hkdf_init()` + * but before `br_hkdf_flip()`. + * + * \param hc HKDF context. + * \param ikm extra input bytes. + * \param ikm_len number of extra input bytes. + */ +void br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len); + +/** + * \brief HKDF switch to the HKDF-Expand phase. + * + * This call terminates the HKDF-Extract process (input injection), and + * starts the HKDF-Expand process (output production). + * + * \param hc HKDF context. + */ +void br_hkdf_flip(br_hkdf_context *hc); + +/** + * \brief HKDF output production (HKDF-Expand). + * + * Produce more output bytes from the current state. This function may be + * called several times, but only after `br_hkdf_flip()`. + * + * Returned value is the number of actually produced bytes. The total + * output length is limited to 255 times the output length of the + * underlying hash function. + * + * \param hc HKDF context. + * \param info application specific information string. + * \param info_len application specific information string length (in bytes). + * \param out destination buffer for the HKDF output. + * \param out_len the length of the requested output (in bytes). + * \return the produced output length (in bytes). + */ +size_t br_hkdf_produce(br_hkdf_context *hc, + const void *info, size_t info_len, void *out, size_t out_len); + +/** + * \brief SHAKE context. + * + * The HKDF context is initialized with a "security level". The internal + * notion is called "capacity"; the capacity is twice the security level + * (for instance, SHAKE128 has capacity 256). + * + * The caller is responsible for allocating the context where + * appropriate. Context initialisation and usage incurs no dynamic + * allocation, so there is no release function. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + unsigned char dbuf[200]; + size_t dptr; + size_t rate; + uint64_t A[25]; +#endif +} br_shake_context; + +/** + * \brief SHAKE context initialization. + * + * The context is initialized for the provided "security level". + * Internally, this sets the "capacity" to twice the security level; + * thus, for SHAKE128, the `security_level` parameter should be 128, + * which corresponds to a 256-bit capacity. + * + * Allowed security levels are all multiples of 32, from 32 to 768, + * inclusive. Larger security levels imply lower performance; levels + * beyond 256 bits don't make much sense. Standard levels are 128 + * and 256 bits (for SHAKE128 and SHAKE256, respectively). + * + * \param sc SHAKE context to initialise. + * \param security_level security level (in bits). + */ +void br_shake_init(br_shake_context *sc, int security_level); + +/** + * \brief SHAKE input injection. + * + * This function injects some more input bytes ("key material") into + * SHAKE. This function may be called several times, after `br_shake_init()` + * but before `br_shake_flip()`. + * + * \param sc SHAKE context. + * \param data extra input bytes. + * \param len number of extra input bytes. + */ +void br_shake_inject(br_shake_context *sc, const void *data, size_t len); + +/** + * \brief SHAKE switch to production phase. + * + * This call terminates the input injection process, and starts the + * output production process. + * + * \param sc SHAKE context. + */ +void br_shake_flip(br_shake_context *hc); + +/** + * \brief SHAKE output production. + * + * Produce more output bytes from the current state. This function may be + * called several times, but only after `br_shake_flip()`. + * + * There is no practical limit to the number of bytes that may be produced. + * + * \param sc SHAKE context. + * \param out destination buffer for the SHAKE output. + * \param len the length of the requested output (in bytes). + */ +void br_shake_produce(br_shake_context *sc, void *out, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_pem.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_pem.h new file mode 100644 index 000000000..13b3b4b39 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_pem.h @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_PEM_H__ +#define BR_BEARSSL_PEM_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_pem.h + * + * # PEM Support + * + * PEM is a traditional encoding layer use to store binary objects (in + * particular X.509 certificates, and private keys) in text files. While + * the acronym comes from an old, defunct standard ("Privacy Enhanced + * Mail"), the format has been reused, with some variations, by many + * systems, and is a _de facto_ standard, even though it is not, actually, + * specified in all clarity anywhere. + * + * ## Format Details + * + * BearSSL contains a generic, streamed PEM decoder, which handles the + * following format: + * + * - The input source (a sequence of bytes) is assumed to be the + * encoding of a text file in an ASCII-compatible charset. This + * includes ISO-8859-1, Windows-1252, and UTF-8 encodings. Each + * line ends on a newline character (U+000A LINE FEED). The + * U+000D CARRIAGE RETURN characters are ignored, so the code + * accepts both Windows-style and Unix-style line endings. + * + * - Each object begins with a banner that occurs at the start of + * a line; the first banner characters are "`-----BEGIN `" (five + * dashes, the word "BEGIN", and a space). The banner matching is + * not case-sensitive. + * + * - The _object name_ consists in the characters that follow the + * banner start sequence, up to the end of the line, but without + * trailing dashes (in "normal" PEM, there are five trailing + * dashes, but this implementation is not picky about these dashes). + * The BearSSL decoder normalises the name characters to uppercase + * (for ASCII letters only) and accepts names up to 127 characters. + * + * - The object ends with a banner that again occurs at the start of + * a line, and starts with "`-----END `" (again case-insensitive). + * + * - Between that start and end banner, only Base64 data shall occur. + * Base64 converts each sequence of three bytes into four + * characters; the four characters are ASCII letters, digits, "`+`" + * or "`-`" signs, and one or two "`=`" signs may occur in the last + * quartet. Whitespace is ignored (whitespace is any ASCII character + * of code 32 or less, so control characters are whitespace) and + * lines may have arbitrary length; the only restriction is that the + * four characters of a quartet must appear on the same line (no + * line break inside a quartet). + * + * - A single file may contain more than one PEM object. Bytes that + * occur between objects are ignored. + * + * + * ## PEM Decoder API + * + * The PEM decoder offers a state-machine API. The caller allocates a + * decoder context, then injects source bytes. Source bytes are pushed + * with `br_pem_decoder_push()`. The decoder stops accepting bytes when + * it reaches an "event", which is either the start of an object, the + * end of an object, or a decoding error within an object. + * + * The `br_pem_decoder_event()` function is used to obtain the current + * event; it also clears it, thus allowing the decoder to accept more + * bytes. When a object start event is raised, the decoder context + * offers the found object name (normalised to ASCII uppercase). + * + * When an object is reached, the caller must set an appropriate callback + * function, which will receive (by chunks) the decoded object data. + * + * Since the decoder context makes no dynamic allocation, it requires + * no explicit deallocation. + */ + +/** + * \brief PEM decoder context. + * + * Contents are opaque (they should not be accessed directly). + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + const unsigned char *hbuf; + size_t hlen; + + void (*dest)(void *dest_ctx, const void *src, size_t len); + void *dest_ctx; + + unsigned char event; + char name[128]; + unsigned char buf[255]; + size_t ptr; +#endif +} br_pem_decoder_context; + +/** + * \brief Initialise a PEM decoder structure. + * + * \param ctx decoder context to initialise. + */ +void br_pem_decoder_init(br_pem_decoder_context *ctx); + +/** + * \brief Push some bytes into the decoder. + * + * Returned value is the number of bytes actually consumed; this may be + * less than the number of provided bytes if an event is raised. When an + * event is raised, it must be read (with `br_pem_decoder_event()`); + * until the event is read, this function will return 0. + * + * \param ctx decoder context. + * \param data new data bytes. + * \param len number of new data bytes. + * \return the number of bytes actually received (may be less than `len`). + */ +size_t br_pem_decoder_push(br_pem_decoder_context *ctx, + const void *data, size_t len); + +/** + * \brief Set the receiver for decoded data. + * + * When an object is entered, the provided function (with opaque context + * pointer) will be called repeatedly with successive chunks of decoded + * data for that object. If `dest` is set to 0, then decoded data is + * simply ignored. The receiver can be set at any time, but, in practice, + * it should be called immediately after receiving a "start of object" + * event. + * + * \param ctx decoder context. + * \param dest callback for receiving decoded data. + * \param dest_ctx opaque context pointer for the `dest` callback. + */ +static inline void +br_pem_decoder_setdest(br_pem_decoder_context *ctx, + void (*dest)(void *dest_ctx, const void *src, size_t len), + void *dest_ctx) +{ + ctx->dest = dest; + ctx->dest_ctx = dest_ctx; +} + +/** + * \brief Get the last event. + * + * If an event was raised, then this function returns the event value, and + * also clears it, thereby allowing the decoder to proceed. If no event + * was raised since the last call to `br_pem_decoder_event()`, then this + * function returns 0. + * + * \param ctx decoder context. + * \return the raised event, or 0. + */ +int br_pem_decoder_event(br_pem_decoder_context *ctx); + +/** + * \brief Event: start of object. + * + * This event is raised when the start of a new object has been detected. + * The object name (normalised to uppercase) can be accessed with + * `br_pem_decoder_name()`. + */ +#define BR_PEM_BEGIN_OBJ 1 + +/** + * \brief Event: end of object. + * + * This event is raised when the end of the current object is reached + * (normally, i.e. with no decoding error). + */ +#define BR_PEM_END_OBJ 2 + +/** + * \brief Event: decoding error. + * + * This event is raised when decoding fails within an object. + * This formally closes the current object and brings the decoder back + * to the "out of any object" state. The offending line in the source + * is consumed. + */ +#define BR_PEM_ERROR 3 + +/** + * \brief Get the name of the encountered object. + * + * The encountered object name is defined only when the "start of object" + * event is raised. That name is normalised to uppercase (for ASCII letters + * only) and does not include trailing dashes. + * + * \param ctx decoder context. + * \return the current object name. + */ +static inline const char * +br_pem_decoder_name(br_pem_decoder_context *ctx) +{ + return ctx->name; +} + +/** + * \brief Encode an object in PEM. + * + * This function encodes the provided binary object (`data`, of length `len` + * bytes) into PEM. The `banner` text will be included in the header and + * footer (e.g. use `"CERTIFICATE"` to get a `"BEGIN CERTIFICATE"` header). + * + * The length (in characters) of the PEM output is returned; that length + * does NOT include the terminating zero, that this function nevertheless + * adds. If using the returned value for allocation purposes, the allocated + * buffer size MUST be at least one byte larger than the returned size. + * + * If `dest` is `NULL`, then the encoding does not happen; however, the + * length of the encoded object is still computed and returned. + * + * The `data` pointer may be `NULL` only if `len` is zero (when encoding + * an object of length zero, which is not very useful), or when `dest` + * is `NULL` (in that case, source data bytes are ignored). + * + * Some `flags` can be specified to alter the encoding behaviour: + * + * - If `BR_PEM_LINE64` is set, then line-breaking will occur after + * every 64 characters of output, instead of the default of 76. + * + * - If `BR_PEM_CRLF` is set, then end-of-line sequence will use + * CR+LF instead of a single LF. + * + * The `data` and `dest` buffers may overlap, in which case the source + * binary data is destroyed in the process. Note that the PEM-encoded output + * is always larger than the source binary. + * + * \param dest the destination buffer (or `NULL`). + * \param data the source buffer (can be `NULL` in some cases). + * \param len the source length (in bytes). + * \param banner the PEM banner expression. + * \param flags the behavioural flags. + * \return the PEM object length (in characters), EXCLUDING the final zero. + */ +size_t br_pem_encode(void *dest, const void *data, size_t len, + const char *banner, unsigned flags); + +/** + * \brief PEM encoding flag: split lines at 64 characters. + */ +#define BR_PEM_LINE64 0x0001 + +/** + * \brief PEM encoding flag: use CR+LF line endings. + */ +#define BR_PEM_CRLF 0x0002 + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_prf.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_prf.h new file mode 100644 index 000000000..f611bf937 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_prf.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_PRF_H__ +#define BR_BEARSSL_PRF_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_prf.h + * + * # The TLS PRF + * + * The "PRF" is the pseudorandom function used internally during the + * SSL/TLS handshake, notably to expand negotiated shared secrets into + * the symmetric encryption keys that will be used to process the + * application data. + * + * TLS 1.0 and 1.1 define a PRF that is based on both MD5 and SHA-1. This + * is implemented by the `br_tls10_prf()` function. + * + * TLS 1.2 redefines the PRF, using an explicit hash function. The + * `br_tls12_sha256_prf()` and `br_tls12_sha384_prf()` functions apply that + * PRF with, respectively, SHA-256 and SHA-384. Most standard cipher suites + * rely on the SHA-256 based PRF, but some use SHA-384. + * + * The PRF always uses as input three parameters: a "secret" (some + * bytes), a "label" (ASCII string), and a "seed" (again some bytes). An + * arbitrary output length can be produced. The "seed" is provided as an + * arbitrary number of binary chunks, that gets internally concatenated. + */ + +/** + * \brief Type for a seed chunk. + * + * Each chunk may have an arbitrary length, and may be empty (no byte at + * all). If the chunk length is zero, then the pointer to the chunk data + * may be `NULL`. + */ +typedef struct { + /** + * \brief Pointer to the chunk data. + */ + const void *data; + + /** + * \brief Chunk length (in bytes). + */ + size_t len; +} br_tls_prf_seed_chunk; + +/** + * \brief PRF implementation for TLS 1.0 and 1.1. + * + * This PRF is the one specified by TLS 1.0 and 1.1. It internally uses + * MD5 and SHA-1. + * + * \param dst destination buffer. + * \param len output length (in bytes). + * \param secret secret value (key) for this computation. + * \param secret_len length of "secret" (in bytes). + * \param label PRF label (zero-terminated ASCII string). + * \param seed_num number of seed chunks. + * \param seed seed chnks for this computation (usually non-secret). + */ +void br_tls10_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +/** + * \brief PRF implementation for TLS 1.2, with SHA-256. + * + * This PRF is the one specified by TLS 1.2, when the underlying hash + * function is SHA-256. + * + * \param dst destination buffer. + * \param len output length (in bytes). + * \param secret secret value (key) for this computation. + * \param secret_len length of "secret" (in bytes). + * \param label PRF label (zero-terminated ASCII string). + * \param seed_num number of seed chunks. + * \param seed seed chnks for this computation (usually non-secret). + */ +void br_tls12_sha256_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +/** + * \brief PRF implementation for TLS 1.2, with SHA-384. + * + * This PRF is the one specified by TLS 1.2, when the underlying hash + * function is SHA-384. + * + * \param dst destination buffer. + * \param len output length (in bytes). + * \param secret secret value (key) for this computation. + * \param secret_len length of "secret" (in bytes). + * \param label PRF label (zero-terminated ASCII string). + * \param seed_num number of seed chunks. + * \param seed seed chnks for this computation (usually non-secret). + */ +void br_tls12_sha384_prf(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +/** + * brief A convenient type name for a PRF implementation. + * + * \param dst destination buffer. + * \param len output length (in bytes). + * \param secret secret value (key) for this computation. + * \param secret_len length of "secret" (in bytes). + * \param label PRF label (zero-terminated ASCII string). + * \param seed_num number of seed chunks. + * \param seed seed chnks for this computation (usually non-secret). + */ +typedef void (*br_tls_prf_impl)(void *dst, size_t len, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_rand.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_rand.h new file mode 100644 index 000000000..82c590b51 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_rand.h @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_RAND_H__ +#define BR_BEARSSL_RAND_H__ + +#include +#include + +#include "bearssl_block.h" +#include "bearssl_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_rand.h + * + * # Pseudo-Random Generators + * + * A PRNG is a state-based engine that outputs pseudo-random bytes on + * demand. It is initialized with an initial seed, and additional seed + * bytes can be added afterwards. Bytes produced depend on the seeds and + * also on the exact sequence of calls (including sizes requested for + * each call). + * + * + * ## Procedural and OOP API + * + * For the PRNG of name "`xxx`", two API are provided. The _procedural_ + * API defined a context structure `br_xxx_context` and three functions: + * + * - `br_xxx_init()` + * + * Initialise the context with an initial seed. + * + * - `br_xxx_generate()` + * + * Produce some pseudo-random bytes. + * + * - `br_xxx_update()` + * + * Inject some additional seed. + * + * The initialisation function sets the first context field (`vtable`) + * to a pointer to the vtable that supports the OOP API. The OOP API + * provides access to the same functions through function pointers, + * named `init()`, `generate()` and `update()`. + * + * Note that the context initialisation method may accept additional + * parameters, provided as a 'const void *' pointer at API level. These + * additional parameters depend on the implemented PRNG. + * + * + * ## HMAC_DRBG + * + * HMAC_DRBG is defined in [NIST SP 800-90A Revision + * 1](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf). + * It uses HMAC repeatedly, over some configurable underlying hash + * function. In BearSSL, it is implemented under the "`hmac_drbg`" name. + * The "extra parameters" pointer for context initialisation should be + * set to a pointer to the vtable for the underlying hash function (e.g. + * pointer to `br_sha256_vtable` to use HMAC_DRBG with SHA-256). + * + * According to the NIST standard, each request shall produce up to + * 219 bits (i.e. 64 kB of data); moreover, the context shall + * be reseeded at least once every 248 requests. This + * implementation does not maintain the reseed counter (the threshold is + * too high to be reached in practice) and does not object to producing + * more than 64 kB in a single request; thus, the code cannot fail, + * which corresponds to the fact that the API has no room for error + * codes. However, this implies that requesting more than 64 kB in one + * `generate()` request, or making more than 248 requests + * without reseeding, is formally out of NIST specification. There is + * no currently known security penalty for exceeding the NIST limits, + * and, in any case, HMAC_DRBG usage in implementing SSL/TLS always + * stays much below these thresholds. + * + * + * ## AESCTR_DRBG + * + * AESCTR_DRBG is a custom PRNG based on AES-128 in CTR mode. This is + * meant to be used only in situations where you are desperate for + * speed, and have an hardware-optimized AES/CTR implementation. Whether + * this will yield perceptible improvements depends on what you use the + * pseudorandom bytes for, and how many you want; for instance, RSA key + * pair generation uses a substantial amount of randomness, and using + * AESCTR_DRBG instead of HMAC_DRBG yields a 15 to 20% increase in key + * generation speed on a recent x86 CPU (Intel Core i7-6567U at 3.30 GHz). + * + * Internally, it uses CTR mode with successive counter values, starting + * at zero (counter value expressed over 128 bits, big-endian convention). + * The counter is not allowed to reach 32768; thus, every 32768*16 bytes + * at most, the `update()` function is run (on an empty seed, if none is + * provided). The `update()` function computes the new AES-128 key by + * applying a custom hash function to the concatenation of a state-dependent + * word (encryption of an all-one block with the current key) and the new + * seed. The custom hash function uses Hirose's construction over AES-256; + * see the comments in `aesctr_drbg.c` for details. + * + * This DRBG does not follow an existing standard, and thus should be + * considered as inadequate for production use until it has been properly + * analysed. + */ + +/** + * \brief Class type for PRNG implementations. + * + * A `br_prng_class` instance references the methods implementing a PRNG. + * Constant instances of this structure are defined for each implemented + * PRNG. Such instances are also called "vtables". + */ +typedef struct br_prng_class_ br_prng_class; +struct br_prng_class_ { + /** + * \brief Size (in bytes) of the context structure appropriate for + * running this PRNG. + */ + size_t context_size; + + /** + * \brief Initialisation method. + * + * The context to initialise is provided as a pointer to its + * first field (the vtable pointer); this function sets that + * first field to a pointer to the vtable. + * + * The extra parameters depend on the implementation; each + * implementation defines what kind of extra parameters it + * expects (if any). + * + * Requirements on the initial seed depend on the implemented + * PRNG. + * + * \param ctx PRNG context to initialise. + * \param params extra parameters for the PRNG. + * \param seed initial seed. + * \param seed_len initial seed length (in bytes). + */ + void (*init)(const br_prng_class **ctx, const void *params, + const void *seed, size_t seed_len); + + /** + * \brief Random bytes generation. + * + * This method produces `len` pseudorandom bytes, in the `out` + * buffer. The context is updated accordingly. + * + * \param ctx PRNG context. + * \param out output buffer. + * \param len number of pseudorandom bytes to produce. + */ + void (*generate)(const br_prng_class **ctx, void *out, size_t len); + + /** + * \brief Inject additional seed bytes. + * + * The provided seed bytes are added into the PRNG internal + * entropy pool. + * + * \param ctx PRNG context. + * \param seed additional seed. + * \param seed_len additional seed length (in bytes). + */ + void (*update)(const br_prng_class **ctx, + const void *seed, size_t seed_len); +}; + +/** + * \brief Context for HMAC_DRBG. + * + * The context contents are opaque, except the first field, which + * supports OOP. + */ +typedef struct { + /** + * \brief Pointer to the vtable. + * + * This field is set with the initialisation method/function. + */ + const br_prng_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char K[64]; + unsigned char V[64]; + const br_hash_class *digest_class; +#endif +} br_hmac_drbg_context; + +/** + * \brief Statically allocated, constant vtable for HMAC_DRBG. + */ +extern const br_prng_class br_hmac_drbg_vtable; + +/** + * \brief HMAC_DRBG initialisation. + * + * The context to initialise is provided as a pointer to its first field + * (the vtable pointer); this function sets that first field to a + * pointer to the vtable. + * + * The `seed` value is what is called, in NIST terminology, the + * concatenation of the "seed", "nonce" and "personalization string", in + * that order. + * + * The `digest_class` parameter defines the underlying hash function. + * Formally, the NIST standard specifies that the hash function shall + * be only SHA-1 or one of the SHA-2 functions. This implementation also + * works with any other implemented hash function (such as MD5), but + * this is non-standard and therefore not recommended. + * + * \param ctx HMAC_DRBG context to initialise. + * \param digest_class vtable for the underlying hash function. + * \param seed initial seed. + * \param seed_len initial seed length (in bytes). + */ +void br_hmac_drbg_init(br_hmac_drbg_context *ctx, + const br_hash_class *digest_class, const void *seed, size_t seed_len); + +/** + * \brief Random bytes generation with HMAC_DRBG. + * + * This method produces `len` pseudorandom bytes, in the `out` + * buffer. The context is updated accordingly. Formally, requesting + * more than 65536 bytes in one request falls out of specification + * limits (but it won't fail). + * + * \param ctx HMAC_DRBG context. + * \param out output buffer. + * \param len number of pseudorandom bytes to produce. + */ +void br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len); + +/** + * \brief Inject additional seed bytes in HMAC_DRBG. + * + * The provided seed bytes are added into the HMAC_DRBG internal + * entropy pool. The process does not _replace_ existing entropy, + * thus pushing non-random bytes (i.e. bytes which are known to the + * attackers) does not degrade the overall quality of generated bytes. + * + * \param ctx HMAC_DRBG context. + * \param seed additional seed. + * \param seed_len additional seed length (in bytes). + */ +void br_hmac_drbg_update(br_hmac_drbg_context *ctx, + const void *seed, size_t seed_len); + +/** + * \brief Get the hash function implementation used by a given instance of + * HMAC_DRBG. + * + * This calls MUST NOT be performed on a context which was not + * previously initialised. + * + * \param ctx HMAC_DRBG context. + * \return the hash function vtable. + */ +static inline const br_hash_class * +br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx) +{ + return ctx->digest_class; +} + +/** + * \brief Type for a provider of entropy seeds. + * + * A "seeder" is a function that is able to obtain random values from + * some source and inject them as entropy seed in a PRNG. A seeder + * shall guarantee that the total entropy of the injected seed is large + * enough to seed a PRNG for purposes of cryptographic key generation + * (i.e. at least 128 bits). + * + * A seeder may report a failure to obtain adequate entropy. Seeders + * shall endeavour to fix themselves transient errors by trying again; + * thus, callers may consider reported errors as permanent. + * + * \param ctx PRNG context to seed. + * \return 1 on success, 0 on error. + */ +typedef int (*br_prng_seeder)(const br_prng_class **ctx); + +/** + * \brief Get a seeder backed by the operating system or hardware. + * + * Get a seeder that feeds on RNG facilities provided by the current + * operating system or hardware. If no such facility is known, then 0 + * is returned. + * + * If `name` is not `NULL`, then `*name` is set to a symbolic string + * that identifies the seeder implementation. If no seeder is returned + * and `name` is not `NULL`, then `*name` is set to a pointer to the + * constant string `"none"`. + * + * \param name receiver for seeder name, or `NULL`. + * \return the system seeder, if available, or 0. + */ +br_prng_seeder br_prng_seeder_system(const char **name); + +/** + * \brief Context for AESCTR_DRBG. + * + * The context contents are opaque, except the first field, which + * supports OOP. + */ +typedef struct { + /** + * \brief Pointer to the vtable. + * + * This field is set with the initialisation method/function. + */ + const br_prng_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + br_aes_gen_ctr_keys sk; + uint32_t cc; +#endif +} br_aesctr_drbg_context; + +/** + * \brief Statically allocated, constant vtable for AESCTR_DRBG. + */ +extern const br_prng_class br_aesctr_drbg_vtable; + +/** + * \brief AESCTR_DRBG initialisation. + * + * The context to initialise is provided as a pointer to its first field + * (the vtable pointer); this function sets that first field to a + * pointer to the vtable. + * + * The internal AES key is first set to the all-zero key; then, the + * `br_aesctr_drbg_update()` function is called with the provided `seed`. + * The call is performed even if the seed length (`seed_len`) is zero. + * + * The `aesctr` parameter defines the underlying AES/CTR implementation. + * + * \param ctx AESCTR_DRBG context to initialise. + * \param aesctr vtable for the AES/CTR implementation. + * \param seed initial seed (can be `NULL` if `seed_len` is zero). + * \param seed_len initial seed length (in bytes). + */ +void br_aesctr_drbg_init(br_aesctr_drbg_context *ctx, + const br_block_ctr_class *aesctr, const void *seed, size_t seed_len); + +/** + * \brief Random bytes generation with AESCTR_DRBG. + * + * This method produces `len` pseudorandom bytes, in the `out` + * buffer. The context is updated accordingly. + * + * \param ctx AESCTR_DRBG context. + * \param out output buffer. + * \param len number of pseudorandom bytes to produce. + */ +void br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx, + void *out, size_t len); + +/** + * \brief Inject additional seed bytes in AESCTR_DRBG. + * + * The provided seed bytes are added into the AESCTR_DRBG internal + * entropy pool. The process does not _replace_ existing entropy, + * thus pushing non-random bytes (i.e. bytes which are known to the + * attackers) does not degrade the overall quality of generated bytes. + * + * \param ctx AESCTR_DRBG context. + * \param seed additional seed. + * \param seed_len additional seed length (in bytes). + */ +void br_aesctr_drbg_update(br_aesctr_drbg_context *ctx, + const void *seed, size_t seed_len); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_rsa.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_rsa.h new file mode 100644 index 000000000..18e953bb1 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_rsa.h @@ -0,0 +1,1660 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_RSA_H__ +#define BR_BEARSSL_RSA_H__ + +#include +#include + +#include "bearssl_hash.h" +#include "bearssl_rand.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_rsa.h + * + * # RSA + * + * This file documents the RSA implementations provided with BearSSL. + * Note that the SSL engine accesses these implementations through a + * configurable API, so it is possible to, for instance, run a SSL + * server which uses a RSA engine which is not based on this code. + * + * ## Key Elements + * + * RSA public and private keys consist in lists of big integers. All + * such integers are represented with big-endian unsigned notation: + * first byte is the most significant, and the value is positive (so + * there is no dedicated "sign bit"). Public and private key structures + * thus contain, for each such integer, a pointer to the first value byte + * (`unsigned char *`), and a length (`size_t`) which is the number of + * relevant bytes. As a general rule, minimal-length encoding is not + * enforced: values may have extra leading bytes of value 0. + * + * RSA public keys consist in two integers: + * + * - the modulus (`n`); + * - the public exponent (`e`). + * + * RSA private keys, as defined in + * [PKCS#1](https://tools.ietf.org/html/rfc3447), contain eight integers: + * + * - the modulus (`n`); + * - the public exponent (`e`); + * - the private exponent (`d`); + * - the first prime factor (`p`); + * - the second prime factor (`q`); + * - the first reduced exponent (`dp`, which is `d` modulo `p-1`); + * - the second reduced exponent (`dq`, which is `d` modulo `q-1`); + * - the CRT coefficient (`iq`, the inverse of `q` modulo `p`). + * + * However, the implementations defined in BearSSL use only five of + * these integers: `p`, `q`, `dp`, `dq` and `iq`. + * + * ## Security Features and Limitations + * + * The implementations contained in BearSSL have the following limitations + * and features: + * + * - They are constant-time. This means that the execution time and + * memory access pattern may depend on the _lengths_ of the private + * key components, but not on their value, nor on the value of + * the operand. Note that this property is not achieved through + * random masking, but "true" constant-time code. + * + * - They support only private keys with two prime factors. RSA private + * keys with three or more prime factors are nominally supported, but + * rarely used; they may offer faster operations, at the expense of + * more code and potentially a reduction in security if there are + * "too many" prime factors. + * + * - The public exponent may have arbitrary length. Of course, it is + * a good idea to keep public exponents small, so that public key + * operations are fast; but, contrary to some widely deployed + * implementations, BearSSL has no problem with public exponents + * longer than 32 bits. + * + * - The two prime factors of the modulus need not have the same length + * (but severely imbalanced factor lengths might reduce security). + * Similarly, there is no requirement that the first factor (`p`) + * be greater than the second factor (`q`). + * + * - Prime factors and modulus must be smaller than a compile-time limit. + * This is made necessary by the use of fixed-size stack buffers, and + * the limit has been adjusted to keep stack usage under 2 kB for the + * RSA operations. Currently, the maximum modulus size is 4096 bits, + * and the maximum prime factor size is 2080 bits. + * + * - The RSA functions themselves do not enforce lower size limits, + * except that which is absolutely necessary for the operation to + * mathematically make sense (e.g. a PKCS#1 v1.5 signature with + * SHA-1 requires a modulus of at least 361 bits). It is up to users + * of this code to enforce size limitations when appropriate (e.g. + * the X.509 validation engine, by default, rejects RSA keys of + * less than 1017 bits). + * + * - Within the size constraints expressed above, arbitrary bit lengths + * are supported. There is no requirement that prime factors or + * modulus have a size multiple of 8 or 16. + * + * - When verifying PKCS#1 v1.5 signatures, both variants of the hash + * function identifying header (with and without the ASN.1 NULL) are + * supported. When producing such signatures, the variant with the + * ASN.1 NULL is used. + * + * ## Implementations + * + * Three RSA implementations are included: + * + * - The **i32** implementation internally represents big integers + * as arrays of 32-bit integers. It is perfunctory and portable, + * but not very efficient. + * + * - The **i31** implementation uses 32-bit integers, each containing + * 31 bits worth of integer data. The i31 implementation is somewhat + * faster than the i32 implementation (the reduced integer size makes + * carry propagation easier) for a similar code footprint, but uses + * very slightly larger stack buffers (about 4% bigger). + * + * - The **i62** implementation is similar to the i31 implementation, + * except that it internally leverages the 64x64->128 multiplication + * opcode. This implementation is available only on architectures + * where such an opcode exists. It is much faster than i31. + * + * - The **i15** implementation uses 16-bit integers, each containing + * 15 bits worth of integer data. Multiplication results fit on + * 32 bits, so this won't use the "widening" multiplication routine + * on ARM Cortex M0/M0+, for much better performance and constant-time + * execution. + */ + +/** + * \brief RSA public key. + * + * The structure references the modulus and the public exponent. Both + * integers use unsigned big-endian representation; extra leading bytes + * of value 0 are allowed. + */ +typedef struct { + /** \brief Modulus. */ + unsigned char *n; + /** \brief Modulus length (in bytes). */ + size_t nlen; + /** \brief Public exponent. */ + unsigned char *e; + /** \brief Public exponent length (in bytes). */ + size_t elen; +} br_rsa_public_key; + +/** + * \brief RSA private key. + * + * The structure references the private factors, reduced private + * exponents, and CRT coefficient. It also contains the bit length of + * the modulus. The big integers use unsigned big-endian representation; + * extra leading bytes of value 0 are allowed. However, the modulus bit + * length (`n_bitlen`) MUST be exact. + */ +typedef struct { + /** \brief Modulus bit length (in bits, exact value). */ + uint32_t n_bitlen; + /** \brief First prime factor. */ + unsigned char *p; + /** \brief First prime factor length (in bytes). */ + size_t plen; + /** \brief Second prime factor. */ + unsigned char *q; + /** \brief Second prime factor length (in bytes). */ + size_t qlen; + /** \brief First reduced private exponent. */ + unsigned char *dp; + /** \brief First reduced private exponent length (in bytes). */ + size_t dplen; + /** \brief Second reduced private exponent. */ + unsigned char *dq; + /** \brief Second reduced private exponent length (in bytes). */ + size_t dqlen; + /** \brief CRT coefficient. */ + unsigned char *iq; + /** \brief CRT coefficient length (in bytes). */ + size_t iqlen; +} br_rsa_private_key; + +/** + * \brief Type for a RSA public key engine. + * + * The public key engine performs the modular exponentiation of the + * provided value with the public exponent. The value is modified in + * place. + * + * The value length (`xlen`) is verified to have _exactly_ the same + * length as the modulus (actual modulus length, without extra leading + * zeros in the modulus representation in memory). If the length does + * not match, then this function returns 0 and `x[]` is unmodified. + * + * It `xlen` is correct, then `x[]` is modified. Returned value is 1 + * on success, 0 on error. Error conditions include an oversized `x[]` + * (the array has the same length as the modulus, but the numerical value + * is not lower than the modulus) and an invalid modulus (e.g. an even + * integer). If an error is reported, then the new contents of `x[]` are + * unspecified. + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_public)(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief Type for a RSA signature verification engine (PKCS#1 v1.5). + * + * Parameters are: + * + * - The signature itself. The provided array is NOT modified. + * + * - The encoded OID for the hash function. The provided array must begin + * with a single byte that contains the length of the OID value (in + * bytes), followed by exactly that many bytes. This parameter may + * also be `NULL`, in which case the raw hash value should be used + * with the PKCS#1 v1.5 "type 1" padding (as used in SSL/TLS up + * to TLS-1.1, with a 36-byte hash value). + * + * - The hash output length, in bytes. + * + * - The public key. + * + * - An output buffer for the hash value. The caller must still compare + * it with the hash of the data over which the signature is computed. + * + * **Constraints:** + * + * - Hash length MUST be no more than 64 bytes. + * + * - OID value length MUST be no more than 32 bytes (i.e. `hash_oid[0]` + * must have a value in the 0..32 range, inclusive). + * + * This function verifies that the signature length (`xlen`) matches the + * modulus length (this function returns 0 on mismatch). If the modulus + * size exceeds the maximum supported RSA size, then the function also + * returns 0. + * + * Returned value is 1 on success, 0 on error. + * + * Implementations of this type need not be constant-time. + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_pkcs1_vrfy)(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief Type for a RSA signature verification engine (PSS). + * + * Parameters are: + * + * - The signature itself. The provided array is NOT modified. + * + * - The hash function which was used to hash the message. + * + * - The hash function to use with MGF1 within the PSS padding. This + * is not necessarily the same hash function as the one which was + * used to hash the signed message. + * + * - The hashed message (as an array of bytes). + * + * - The PSS salt length (in bytes). + * + * - The public key. + * + * **Constraints:** + * + * - Hash message length MUST be no more than 64 bytes. + * + * Note that, contrary to PKCS#1 v1.5 signature, the hash value of the + * signed data cannot be extracted from the signature; it must be + * provided to the verification function. + * + * This function verifies that the signature length (`xlen`) matches the + * modulus length (this function returns 0 on mismatch). If the modulus + * size exceeds the maximum supported RSA size, then the function also + * returns 0. + * + * Returned value is 1 on success, 0 on error. + * + * Implementations of this type need not be constant-time. + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_pss_vrfy)(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + +/** + * \brief Type for a RSA encryption engine (OAEP). + * + * Parameters are: + * + * - A source of random bytes. The source must be already initialized. + * + * - A hash function, used internally with the mask generation function + * (MGF1). + * + * - A label. The `label` pointer may be `NULL` if `label_len` is zero + * (an empty label, which is the default in PKCS#1 v2.2). + * + * - The public key. + * + * - The destination buffer. Its maximum length (in bytes) is provided; + * if that length is lower than the public key length, then an error + * is reported. + * + * - The source message. + * + * The encrypted message output has exactly the same length as the modulus + * (mathematical length, in bytes, not counting extra leading zeros in the + * modulus representation in the public key). + * + * The source message (`src`, length `src_len`) may overlap with the + * destination buffer (`dst`, length `dst_max_len`). + * + * This function returns the actual encrypted message length, in bytes; + * on error, zero is returned. An error is reported if the output buffer + * is not large enough, or the public is invalid, or the public key + * modulus exceeds the maximum supported RSA size. + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +typedef size_t (*br_rsa_oaep_encrypt)( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief Type for a RSA private key engine. + * + * The `x[]` buffer is modified in place, and its length is inferred from + * the modulus length (`x[]` is assumed to have a length of + * `(sk->n_bitlen+7)/8` bytes). + * + * Returned value is 1 on success, 0 on error. + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_private)(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief Type for a RSA signature generation engine (PKCS#1 v1.5). + * + * Parameters are: + * + * - The encoded OID for the hash function. The provided array must begin + * with a single byte that contains the length of the OID value (in + * bytes), followed by exactly that many bytes. This parameter may + * also be `NULL`, in which case the raw hash value should be used + * with the PKCS#1 v1.5 "type 1" padding (as used in SSL/TLS up + * to TLS-1.1, with a 36-byte hash value). + * + * - The hash value computes over the data to sign (its length is + * expressed in bytes). + * + * - The RSA private key. + * + * - The output buffer, that receives the signature. + * + * Returned value is 1 on success, 0 on error. Error conditions include + * a too small modulus for the provided hash OID and value, or some + * invalid key parameters. The signature length is exactly + * `(sk->n_bitlen+7)/8` bytes. + * + * This function is expected to be constant-time with regards to the + * private key bytes (lengths of the modulus and the individual factors + * may leak, though) and to the hashed data. + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_pkcs1_sign)(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief Type for a RSA signature generation engine (PSS). + * + * Parameters are: + * + * - An initialized PRNG for salt generation. If the salt length is + * zero (`salt_len` parameter), then the PRNG is optional (this is + * not the typical case, as the security proof of RSA/PSS is + * tighter when a non-empty salt is used). + * + * - The hash function which was used to hash the message. + * + * - The hash function to use with MGF1 within the PSS padding. This + * is not necessarily the same function as the one used to hash the + * message. + * + * - The hashed message. + * + * - The salt length, in bytes. + * + * - The RSA private key. + * + * - The output buffer, that receives the signature. + * + * Returned value is 1 on success, 0 on error. Error conditions include + * a too small modulus for the provided hash and salt lengths, or some + * invalid key parameters. The signature length is exactly + * `(sk->n_bitlen+7)/8` bytes. + * + * This function is expected to be constant-time with regards to the + * private key bytes (lengths of the modulus and the individual factors + * may leak, though) and to the hashed data. + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_pss_sign)(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief Encoded OID for SHA-1 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA1 \ + ((const unsigned char *)"\x05\x2B\x0E\x03\x02\x1A") + +/** + * \brief Encoded OID for SHA-224 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA224 \ + ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04") + +/** + * \brief Encoded OID for SHA-256 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA256 \ + ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01") + +/** + * \brief Encoded OID for SHA-384 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA384 \ + ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02") + +/** + * \brief Encoded OID for SHA-512 (in RSA PKCS#1 signatures). + */ +#define BR_HASH_OID_SHA512 \ + ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03") + +/** + * \brief Type for a RSA decryption engine (OAEP). + * + * Parameters are: + * + * - A hash function, used internally with the mask generation function + * (MGF1). + * + * - A label. The `label` pointer may be `NULL` if `label_len` is zero + * (an empty label, which is the default in PKCS#1 v2.2). + * + * - The private key. + * + * - The source and destination buffer. The buffer initially contains + * the encrypted message; the buffer contents are altered, and the + * decrypted message is written at the start of that buffer + * (decrypted message is always shorter than the encrypted message). + * + * If decryption fails in any way, then `*len` is unmodified, and the + * function returns 0. Otherwise, `*len` is set to the decrypted message + * length, and 1 is returned. The implementation is responsible for + * checking that the input message length matches the key modulus length, + * and that the padding is correct. + * + * Implementations MUST use constant-time check of the validity of the + * OAEP padding, at least until the leading byte and hash value have + * been checked. Whether overall decryption worked, and the length of + * the decrypted message, may leak. + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +typedef uint32_t (*br_rsa_oaep_decrypt)( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/* + * RSA "i32" engine. Integers are internally represented as arrays of + * 32-bit integers, and the core multiplication primitive is the + * 32x32->64 multiplication. + */ + +/** + * \brief RSA public key engine "i32". + * + * \see br_rsa_public + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief RSA signature verification engine "i32" (PKCS#1 v1.5 signatures). + * + * \see br_rsa_pkcs1_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief RSA signature verification engine "i32" (PSS signatures). + * + * \see br_rsa_pss_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + +/** + * \brief RSA private key engine "i32". + * + * \see br_rsa_private + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_private(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief RSA signature generation engine "i32" (PKCS#1 v1.5 signatures). + * + * \see br_rsa_pkcs1_sign + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief RSA signature generation engine "i32" (PSS signatures). + * + * \see br_rsa_pss_sign + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + +/* + * RSA "i31" engine. Similar to i32, but only 31 bits are used per 32-bit + * word. This uses slightly more stack space (about 4% more) and code + * space, but it quite faster. + */ + +/** + * \brief RSA public key engine "i31". + * + * \see br_rsa_public + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief RSA signature verification engine "i31" (PKCS#1 v1.5 signatures). + * + * \see br_rsa_pkcs1_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief RSA signature verification engine "i31" (PSS signatures). + * + * \see br_rsa_pss_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + +/** + * \brief RSA private key engine "i31". + * + * \see br_rsa_private + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_private(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief RSA signature generation engine "i31" (PKCS#1 v1.5 signatures). + * + * \see br_rsa_pkcs1_sign + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief RSA signature generation engine "i31" (PSS signatures). + * + * \see br_rsa_pss_sign + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + +/* + * RSA "i62" engine. Similar to i31, but internal multiplication use + * 64x64->128 multiplications. This is available only on architecture + * that offer such an opcode. + */ + +/** + * \brief RSA public key engine "i62". + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_public_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_public + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief RSA signature verification engine "i62" (PKCS#1 v1.5 signatures). + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_pkcs1_vrfy_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_pkcs1_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief RSA signature verification engine "i62" (PSS signatures). + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_pss_vrfy_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_pss_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + +/** + * \brief RSA private key engine "i62". + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_private_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_private + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_private(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief RSA signature generation engine "i62" (PKCS#1 v1.5 signatures). + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_pkcs1_sign_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_pkcs1_sign + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief RSA signature generation engine "i62" (PSS signatures). + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_pss_sign_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_pss_sign + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief Get the RSA "i62" implementation (public key operations), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_public br_rsa_i62_public_get(void); + +/** + * \brief Get the RSA "i62" implementation (PKCS#1 v1.5 signature verification), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_pkcs1_vrfy br_rsa_i62_pkcs1_vrfy_get(void); + +/** + * \brief Get the RSA "i62" implementation (PSS signature verification), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_pss_vrfy br_rsa_i62_pss_vrfy_get(void); + +/** + * \brief Get the RSA "i62" implementation (private key operations), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_private br_rsa_i62_private_get(void); + +/** + * \brief Get the RSA "i62" implementation (PKCS#1 v1.5 signature generation), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_pkcs1_sign br_rsa_i62_pkcs1_sign_get(void); + +/** + * \brief Get the RSA "i62" implementation (PSS signature generation), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_pss_sign br_rsa_i62_pss_sign_get(void); + +/** + * \brief Get the RSA "i62" implementation (OAEP encryption), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_oaep_encrypt br_rsa_i62_oaep_encrypt_get(void); + +/** + * \brief Get the RSA "i62" implementation (OAEP decryption), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_oaep_decrypt br_rsa_i62_oaep_decrypt_get(void); + +/* + * RSA "i15" engine. Integers are represented as 15-bit integers, so + * the code uses only 32-bit multiplication (no 64-bit result), which + * is vastly faster (and constant-time) on the ARM Cortex M0/M0+. + */ + +/** + * \brief RSA public key engine "i15". + * + * \see br_rsa_public + * + * \param x operand to exponentiate. + * \param xlen length of the operand (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_public(unsigned char *x, size_t xlen, + const br_rsa_public_key *pk); + +/** + * \brief RSA signature verification engine "i15" (PKCS#1 v1.5 signatures). + * + * \see br_rsa_pkcs1_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash_len expected hash value length (in bytes). + * \param pk RSA public key. + * \param hash_out output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_pkcs1_vrfy(const unsigned char *x, size_t xlen, + const unsigned char *hash_oid, size_t hash_len, + const br_rsa_public_key *pk, unsigned char *hash_out); + +/** + * \brief RSA signature verification engine "i15" (PSS signatures). + * + * \see br_rsa_pss_vrfy + * + * \param x signature buffer. + * \param xlen signature length (in bytes). + * \param hf_data hash function applied on the message. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hash value of the signed message. + * \param salt_len PSS salt length (in bytes). + * \param pk RSA public key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_pss_vrfy(const unsigned char *x, size_t xlen, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const void *hash, size_t salt_len, const br_rsa_public_key *pk); + +/** + * \brief RSA private key engine "i15". + * + * \see br_rsa_private + * + * \param x operand to exponentiate. + * \param sk RSA private key. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_private(unsigned char *x, + const br_rsa_private_key *sk); + +/** + * \brief RSA signature generation engine "i15" (PKCS#1 v1.5 signatures). + * + * \see br_rsa_pkcs1_sign + * + * \param hash_oid encoded hash algorithm OID (or `NULL`). + * \param hash hash value. + * \param hash_len hash value length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the hash value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief RSA signature generation engine "i15" (PSS signatures). + * + * \see br_rsa_pss_sign + * + * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero). + * \param hf_data hash function used to hash the signed data. + * \param hf_mgf1 hash function to use with MGF1. + * \param hash hashed message. + * \param salt_len salt length (in bytes). + * \param sk RSA private key. + * \param x output buffer for the signature value. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_pss_sign(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash_value, size_t salt_len, + const br_rsa_private_key *sk, unsigned char *x); + +/** + * \brief Get "default" RSA implementation (public-key operations). + * + * This returns the preferred implementation of RSA (public-key operations) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_public br_rsa_public_get_default(void); + +/** + * \brief Get "default" RSA implementation (private-key operations). + * + * This returns the preferred implementation of RSA (private-key operations) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_private br_rsa_private_get_default(void); + +/** + * \brief Get "default" RSA implementation (PKCS#1 v1.5 signature verification). + * + * This returns the preferred implementation of RSA (signature verification) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_pkcs1_vrfy br_rsa_pkcs1_vrfy_get_default(void); + +/** + * \brief Get "default" RSA implementation (PSS signature verification). + * + * This returns the preferred implementation of RSA (signature verification) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_pss_vrfy br_rsa_pss_vrfy_get_default(void); + +/** + * \brief Get "default" RSA implementation (PKCS#1 v1.5 signature generation). + * + * This returns the preferred implementation of RSA (signature generation) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_pkcs1_sign br_rsa_pkcs1_sign_get_default(void); + +/** + * \brief Get "default" RSA implementation (PSS signature generation). + * + * This returns the preferred implementation of RSA (signature generation) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_pss_sign br_rsa_pss_sign_get_default(void); + +/** + * \brief Get "default" RSA implementation (OAEP encryption). + * + * This returns the preferred implementation of RSA (OAEP encryption) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_oaep_encrypt br_rsa_oaep_encrypt_get_default(void); + +/** + * \brief Get "default" RSA implementation (OAEP decryption). + * + * This returns the preferred implementation of RSA (OAEP decryption) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_oaep_decrypt br_rsa_oaep_decrypt_get_default(void); + +/** + * \brief RSA decryption helper, for SSL/TLS. + * + * This function performs the RSA decryption for a RSA-based key exchange + * in a SSL/TLS server. The provided RSA engine is used. The `data` + * parameter points to the value to decrypt, of length `len` bytes. On + * success, the 48-byte pre-master secret is copied into `data`, starting + * at the first byte of that buffer; on error, the contents of `data` + * become indeterminate. + * + * This function first checks that the provided value length (`len`) is + * not lower than 59 bytes, and matches the RSA modulus length; if neither + * of this property is met, then this function returns 0 and the buffer + * is unmodified. + * + * Otherwise, decryption and then padding verification are performed, both + * in constant-time. A decryption error, or a bad padding, or an + * incorrect decrypted value length are reported with a returned value of + * 0; on success, 1 is returned. The caller (SSL server engine) is supposed + * to proceed with a random pre-master secret in case of error. + * + * \param core RSA private key engine. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len length (in bytes) of the data to decrypt. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_ssl_decrypt(br_rsa_private core, const br_rsa_private_key *sk, + unsigned char *data, size_t len); + +/** + * \brief RSA encryption (OAEP) with the "i15" engine. + * + * \see br_rsa_oaep_encrypt + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +size_t br_rsa_i15_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief RSA decryption (OAEP) with the "i15" engine. + * + * \see br_rsa_oaep_decrypt + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i15_oaep_decrypt( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/** + * \brief RSA encryption (OAEP) with the "i31" engine. + * + * \see br_rsa_oaep_encrypt + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +size_t br_rsa_i31_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief RSA decryption (OAEP) with the "i31" engine. + * + * \see br_rsa_oaep_decrypt + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i31_oaep_decrypt( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/** + * \brief RSA encryption (OAEP) with the "i32" engine. + * + * \see br_rsa_oaep_encrypt + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +size_t br_rsa_i32_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief RSA decryption (OAEP) with the "i32" engine. + * + * \see br_rsa_oaep_decrypt + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i32_oaep_decrypt( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/** + * \brief RSA encryption (OAEP) with the "i62" engine. + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_oaep_encrypt_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_oaep_encrypt + * + * \param rnd source of random bytes. + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param pk RSA public key. + * \param dst destination buffer. + * \param dst_max_len destination buffer length (maximum encrypted data size). + * \param src message to encrypt. + * \param src_len source message length (in bytes). + * \return encrypted message length (in bytes), or 0 on error. + */ +size_t br_rsa_i62_oaep_encrypt( + const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, + const br_rsa_public_key *pk, + void *dst, size_t dst_max_len, + const void *src, size_t src_len); + +/** + * \brief RSA decryption (OAEP) with the "i62" engine. + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_oaep_decrypt_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_oaep_decrypt + * + * \param dig hash function to use with MGF1. + * \param label label value (may be `NULL` if `label_len` is zero). + * \param label_len label length, in bytes. + * \param sk RSA private key. + * \param data input/output buffer. + * \param len encrypted/decrypted message length. + * \return 1 on success, 0 on error. + */ +uint32_t br_rsa_i62_oaep_decrypt( + const br_hash_class *dig, const void *label, size_t label_len, + const br_rsa_private_key *sk, void *data, size_t *len); + +/** + * \brief Get buffer size to hold RSA private key elements. + * + * This macro returns the length (in bytes) of the buffer needed to + * receive the elements of a RSA private key, as generated by one of + * the `br_rsa_*_keygen()` functions. If the provided size is a constant + * expression, then the whole macro evaluates to a constant expression. + * + * \param size target key size (modulus size, in bits) + * \return the length of the private key buffer, in bytes. + */ +#define BR_RSA_KBUF_PRIV_SIZE(size) (5 * (((size) + 15) >> 4)) + +/** + * \brief Get buffer size to hold RSA public key elements. + * + * This macro returns the length (in bytes) of the buffer needed to + * receive the elements of a RSA public key, as generated by one of + * the `br_rsa_*_keygen()` functions. If the provided size is a constant + * expression, then the whole macro evaluates to a constant expression. + * + * \param size target key size (modulus size, in bits) + * \return the length of the public key buffer, in bytes. + */ +#define BR_RSA_KBUF_PUB_SIZE(size) (4 + (((size) + 7) >> 3)) + +/** + * \brief Type for RSA key pair generator implementation. + * + * This function generates a new RSA key pair whose modulus has bit + * length `size` bits. The private key elements are written in the + * `kbuf_priv` buffer, and pointer values and length fields to these + * elements are populated in the provided private key structure `sk`. + * Similarly, the public key elements are written in `kbuf_pub`, with + * pointers and lengths set in `pk`. + * + * If `pk` is `NULL`, then `kbuf_pub` may be `NULL`, and only the + * private key is set. + * + * If `pubexp` is not zero, then its value will be used as public + * exponent. Valid RSA public exponent values are odd integers + * greater than 1. If `pubexp` is zero, then the public exponent will + * have value 3. + * + * The provided PRNG (`rng_ctx`) must have already been initialized + * and seeded. + * + * Returned value is 1 on success, 0 on error. An error is reported + * if the requested range is outside of the supported key sizes, or + * if an invalid non-zero public exponent value is provided. Supported + * range starts at 512 bits, and up to an implementation-defined + * maximum (by default 4096 bits). Note that key sizes up to 768 bits + * have been broken in practice, and sizes lower than 2048 bits are + * usually considered to be weak and should not be used. + * + * \param rng_ctx source PRNG context (already initialized) + * \param sk RSA private key structure (destination) + * \param kbuf_priv buffer for private key elements + * \param pk RSA public key structure (destination), or `NULL` + * \param kbuf_pub buffer for public key elements, or `NULL` + * \param size target RSA modulus size (in bits) + * \param pubexp public exponent to use, or zero + * \return 1 on success, 0 on error (invalid parameters) + */ +typedef uint32_t (*br_rsa_keygen)( + const br_prng_class **rng_ctx, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp); + +/** + * \brief RSA key pair generation with the "i15" engine. + * + * \see br_rsa_keygen + * + * \param rng_ctx source PRNG context (already initialized) + * \param sk RSA private key structure (destination) + * \param kbuf_priv buffer for private key elements + * \param pk RSA public key structure (destination), or `NULL` + * \param kbuf_pub buffer for public key elements, or `NULL` + * \param size target RSA modulus size (in bits) + * \param pubexp public exponent to use, or zero + * \return 1 on success, 0 on error (invalid parameters) + */ +uint32_t br_rsa_i15_keygen( + const br_prng_class **rng_ctx, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp); + +/** + * \brief RSA key pair generation with the "i31" engine. + * + * \see br_rsa_keygen + * + * \param rng_ctx source PRNG context (already initialized) + * \param sk RSA private key structure (destination) + * \param kbuf_priv buffer for private key elements + * \param pk RSA public key structure (destination), or `NULL` + * \param kbuf_pub buffer for public key elements, or `NULL` + * \param size target RSA modulus size (in bits) + * \param pubexp public exponent to use, or zero + * \return 1 on success, 0 on error (invalid parameters) + */ +uint32_t br_rsa_i31_keygen( + const br_prng_class **rng_ctx, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp); + +/** + * \brief RSA key pair generation with the "i62" engine. + * + * This function is defined only on architecture that offer a 64x64->128 + * opcode. Use `br_rsa_i62_keygen_get()` to dynamically obtain a pointer + * to that function. + * + * \see br_rsa_keygen + * + * \param rng_ctx source PRNG context (already initialized) + * \param sk RSA private key structure (destination) + * \param kbuf_priv buffer for private key elements + * \param pk RSA public key structure (destination), or `NULL` + * \param kbuf_pub buffer for public key elements, or `NULL` + * \param size target RSA modulus size (in bits) + * \param pubexp public exponent to use, or zero + * \return 1 on success, 0 on error (invalid parameters) + */ +uint32_t br_rsa_i62_keygen( + const br_prng_class **rng_ctx, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp); + +/** + * \brief Get the RSA "i62" implementation (key pair generation), + * if available. + * + * \return the implementation, or 0. + */ +br_rsa_keygen br_rsa_i62_keygen_get(void); + +/** + * \brief Get "default" RSA implementation (key pair generation). + * + * This returns the preferred implementation of RSA (key pair generation) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_keygen br_rsa_keygen_get_default(void); + +/** + * \brief Type for a modulus computing function. + * + * Such a function computes the public modulus from the private key. The + * encoded modulus (unsigned big-endian) is written on `n`, and the size + * (in bytes) is returned. If `n` is `NULL`, then the size is returned but + * the modulus itself is not computed. + * + * If the key size exceeds an internal limit, 0 is returned. + * + * \param n destination buffer (or `NULL`). + * \param sk RSA private key. + * \return the modulus length (in bytes), or 0. + */ +typedef size_t (*br_rsa_compute_modulus)(void *n, const br_rsa_private_key *sk); + +/** + * \brief Recompute RSA modulus ("i15" engine). + * + * \see br_rsa_compute_modulus + * + * \param n destination buffer (or `NULL`). + * \param sk RSA private key. + * \return the modulus length (in bytes), or 0. + */ +size_t br_rsa_i15_compute_modulus(void *n, const br_rsa_private_key *sk); + +/** + * \brief Recompute RSA modulus ("i31" engine). + * + * \see br_rsa_compute_modulus + * + * \param n destination buffer (or `NULL`). + * \param sk RSA private key. + * \return the modulus length (in bytes), or 0. + */ +size_t br_rsa_i31_compute_modulus(void *n, const br_rsa_private_key *sk); + +/** + * \brief Get "default" RSA implementation (recompute modulus). + * + * This returns the preferred implementation of RSA (recompute modulus) + * on the current system. + * + * \return the default implementation. + */ +br_rsa_compute_modulus br_rsa_compute_modulus_get_default(void); + +/** + * \brief Type for a public exponent computing function. + * + * Such a function recomputes the public exponent from the private key. + * 0 is returned if any of the following occurs: + * + * - Either `p` or `q` is not equal to 3 modulo 4. + * + * - The public exponent does not fit on 32 bits. + * + * - An internal limit is exceeded. + * + * - The private key is invalid in some way. + * + * For all private keys produced by the key generator functions + * (`br_rsa_keygen` type), this function succeeds and returns the true + * public exponent. The public exponent is always an odd integer greater + * than 1. + * + * \return the public exponent, or 0. + */ +typedef uint32_t (*br_rsa_compute_pubexp)(const br_rsa_private_key *sk); + +/** + * \brief Recompute RSA public exponent ("i15" engine). + * + * \see br_rsa_compute_pubexp + * + * \return the public exponent, or 0. + */ +uint32_t br_rsa_i15_compute_pubexp(const br_rsa_private_key *sk); + +/** + * \brief Recompute RSA public exponent ("i31" engine). + * + * \see br_rsa_compute_pubexp + * + * \return the public exponent, or 0. + */ +uint32_t br_rsa_i31_compute_pubexp(const br_rsa_private_key *sk); + +/** + * \brief Get "default" RSA implementation (recompute public exponent). + * + * This returns the preferred implementation of RSA (recompute public + * exponent) on the current system. + * + * \return the default implementation. + */ +br_rsa_compute_pubexp br_rsa_compute_pubexp_get_default(void); + +/** + * \brief Type for a private exponent computing function. + * + * An RSA private key (`br_rsa_private_key`) contains two reduced + * private exponents, which are sufficient to perform private key + * operations. However, standard encoding formats for RSA private keys + * require also a copy of the complete private exponent (non-reduced), + * which this function recomputes. + * + * This function suceeds if all the following conditions hold: + * + * - Both private factors `p` and `q` are equal to 3 modulo 4. + * + * - The provided public exponent `pubexp` is correct, and, in particular, + * is odd, relatively prime to `p-1` and `q-1`, and greater than 1. + * + * - No internal storage limit is exceeded. + * + * For all private keys produced by the key generator functions + * (`br_rsa_keygen` type), this function succeeds. Note that the API + * restricts the public exponent to a maximum size of 32 bits. + * + * The encoded private exponent is written in `d` (unsigned big-endian + * convention), and the length (in bytes) is returned. If `d` is `NULL`, + * then the exponent is not written anywhere, but the length is still + * returned. On error, 0 is returned. + * + * Not all error conditions are detected when `d` is `NULL`; therefore, the + * returned value shall be checked also when actually producing the value. + * + * \param d destination buffer (or `NULL`). + * \param sk RSA private key. + * \param pubexp the public exponent. + * \return the private exponent length (in bytes), or 0. + */ +typedef size_t (*br_rsa_compute_privexp)(void *d, + const br_rsa_private_key *sk, uint32_t pubexp); + +/** + * \brief Recompute RSA private exponent ("i15" engine). + * + * \see br_rsa_compute_privexp + * + * \param d destination buffer (or `NULL`). + * \param sk RSA private key. + * \param pubexp the public exponent. + * \return the private exponent length (in bytes), or 0. + */ +size_t br_rsa_i15_compute_privexp(void *d, + const br_rsa_private_key *sk, uint32_t pubexp); + +/** + * \brief Recompute RSA private exponent ("i31" engine). + * + * \see br_rsa_compute_privexp + * + * \param d destination buffer (or `NULL`). + * \param sk RSA private key. + * \param pubexp the public exponent. + * \return the private exponent length (in bytes), or 0. + */ +size_t br_rsa_i31_compute_privexp(void *d, + const br_rsa_private_key *sk, uint32_t pubexp); + +/** + * \brief Get "default" RSA implementation (recompute private exponent). + * + * This returns the preferred implementation of RSA (recompute private + * exponent) on the current system. + * + * \return the default implementation. + */ +br_rsa_compute_privexp br_rsa_compute_privexp_get_default(void); + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_ssl.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_ssl.h new file mode 100644 index 000000000..8ad2d69c5 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_ssl.h @@ -0,0 +1,4331 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_SSL_H__ +#define BR_BEARSSL_SSL_H__ + +#include +#include + +#include "bearssl_block.h" +#include "bearssl_hash.h" +#include "bearssl_hmac.h" +#include "bearssl_prf.h" +#include "bearssl_rand.h" +#include "bearssl_x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file bearssl_ssl.h + * + * # SSL + * + * For an overview of the SSL/TLS API, see [the BearSSL Web + * site](https://www.bearssl.org/api1.html). + * + * The `BR_TLS_*` constants correspond to the standard cipher suites and + * their values in the [IANA + * registry](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4). + * + * The `BR_ALERT_*` constants are for standard TLS alert messages. When + * a fatal alert message is sent of received, then the SSL engine context + * status is set to the sum of that alert value (an integer in the 0..255 + * range) and a fixed offset (`BR_ERR_SEND_FATAL_ALERT` for a sent alert, + * `BR_ERR_RECV_FATAL_ALERT` for a received alert). + */ + +/** \brief Optimal input buffer size. */ +#define BR_SSL_BUFSIZE_INPUT (16384 + 325) + +/** \brief Optimal output buffer size. */ +#define BR_SSL_BUFSIZE_OUTPUT (16384 + 85) + +/** \brief Optimal buffer size for monodirectional engine + (shared input/output buffer). */ +#define BR_SSL_BUFSIZE_MONO BR_SSL_BUFSIZE_INPUT + +/** \brief Optimal buffer size for bidirectional engine + (single buffer split into two separate input/output buffers). */ +#define BR_SSL_BUFSIZE_BIDI (BR_SSL_BUFSIZE_INPUT + BR_SSL_BUFSIZE_OUTPUT) + +/* + * Constants for known SSL/TLS protocol versions (SSL 3.0, TLS 1.0, TLS 1.1 + * and TLS 1.2). Note that though there is a constant for SSL 3.0, that + * protocol version is not actually supported. + */ + +/** \brief Protocol version: SSL 3.0 (unsupported). */ +#define BR_SSL30 0x0300 +/** \brief Protocol version: TLS 1.0. */ +#define BR_TLS10 0x0301 +/** \brief Protocol version: TLS 1.1. */ +#define BR_TLS11 0x0302 +/** \brief Protocol version: TLS 1.2. */ +#define BR_TLS12 0x0303 + +/* + * Error constants. They are used to report the reason why a context has + * been marked as failed. + * + * Implementation note: SSL-level error codes should be in the 1..31 + * range. The 32..63 range is for certificate decoding and validation + * errors. Received fatal alerts imply an error code in the 256..511 range. + */ + +/** \brief SSL status: no error so far (0). */ +#define BR_ERR_OK 0 + +/** \brief SSL status: caller-provided parameter is incorrect. */ +#define BR_ERR_BAD_PARAM 1 + +/** \brief SSL status: operation requested by the caller cannot be applied + with the current context state (e.g. reading data while outgoing data + is waiting to be sent). */ +#define BR_ERR_BAD_STATE 2 + +/** \brief SSL status: incoming protocol or record version is unsupported. */ +#define BR_ERR_UNSUPPORTED_VERSION 3 + +/** \brief SSL status: incoming record version does not match the expected + version. */ +#define BR_ERR_BAD_VERSION 4 + +/** \brief SSL status: incoming record length is invalid. */ +#define BR_ERR_BAD_LENGTH 5 + +/** \brief SSL status: incoming record is too large to be processed, or + buffer is too small for the handshake message to send. */ +#define BR_ERR_TOO_LARGE 6 + +/** \brief SSL status: decryption found an invalid padding, or the record + MAC is not correct. */ +#define BR_ERR_BAD_MAC 7 + +/** \brief SSL status: no initial entropy was provided, and none can be + obtained from the OS. */ +#define BR_ERR_NO_RANDOM 8 + +/** \brief SSL status: incoming record type is unknown. */ +#define BR_ERR_UNKNOWN_TYPE 9 + +/** \brief SSL status: incoming record or message has wrong type with + regards to the current engine state. */ +#define BR_ERR_UNEXPECTED 10 + +/** \brief SSL status: ChangeCipherSpec message from the peer has invalid + contents. */ +#define BR_ERR_BAD_CCS 12 + +/** \brief SSL status: alert message from the peer has invalid contents + (odd length). */ +#define BR_ERR_BAD_ALERT 13 + +/** \brief SSL status: incoming handshake message decoding failed. */ +#define BR_ERR_BAD_HANDSHAKE 14 + +/** \brief SSL status: ServerHello contains a session ID which is larger + than 32 bytes. */ +#define BR_ERR_OVERSIZED_ID 15 + +/** \brief SSL status: server wants to use a cipher suite that we did + not claim to support. This is also reported if we tried to advertise + a cipher suite that we do not support. */ +#define BR_ERR_BAD_CIPHER_SUITE 16 + +/** \brief SSL status: server wants to use a compression that we did not + claim to support. */ +#define BR_ERR_BAD_COMPRESSION 17 + +/** \brief SSL status: server's max fragment length does not match + client's. */ +#define BR_ERR_BAD_FRAGLEN 18 + +/** \brief SSL status: secure renegotiation failed. */ +#define BR_ERR_BAD_SECRENEG 19 + +/** \brief SSL status: server sent an extension type that we did not + announce, or used the same extension type several times in a single + ServerHello. */ +#define BR_ERR_EXTRA_EXTENSION 20 + +/** \brief SSL status: invalid Server Name Indication contents (when + used by the server, this extension shall be empty). */ +#define BR_ERR_BAD_SNI 21 + +/** \brief SSL status: invalid ServerHelloDone from the server (length + is not 0). */ +#define BR_ERR_BAD_HELLO_DONE 22 + +/** \brief SSL status: internal limit exceeded (e.g. server's public key + is too large). */ +#define BR_ERR_LIMIT_EXCEEDED 23 + +/** \brief SSL status: Finished message from peer does not match the + expected value. */ +#define BR_ERR_BAD_FINISHED 24 + +/** \brief SSL status: session resumption attempt with distinct version + or cipher suite. */ +#define BR_ERR_RESUME_MISMATCH 25 + +/** \brief SSL status: unsupported or invalid algorithm (ECDHE curve, + signature algorithm, hash function). */ +#define BR_ERR_INVALID_ALGORITHM 26 + +/** \brief SSL status: invalid signature (on ServerKeyExchange from + server, or in CertificateVerify from client). */ +#define BR_ERR_BAD_SIGNATURE 27 + +/** \brief SSL status: peer's public key does not have the proper type + or is not allowed for requested operation. */ +#define BR_ERR_WRONG_KEY_USAGE 28 + +/** \brief SSL status: client did not send a certificate upon request, + or the client certificate could not be validated. */ +#define BR_ERR_NO_CLIENT_AUTH 29 + +/** \brief SSL status: I/O error or premature close on underlying + transport stream. This error code is set only by the simplified + I/O API ("br_sslio_*"). */ +#define BR_ERR_IO 31 + +/** \brief SSL status: base value for a received fatal alert. + + When a fatal alert is received from the peer, the alert value + is added to this constant. */ +#define BR_ERR_RECV_FATAL_ALERT 256 + +/** \brief SSL status: base value for a sent fatal alert. + + When a fatal alert is sent to the peer, the alert value is added + to this constant. */ +#define BR_ERR_SEND_FATAL_ALERT 512 + +/* ===================================================================== */ + +/** + * \brief Decryption engine for SSL. + * + * When processing incoming records, the SSL engine will use a decryption + * engine that uses a specific context structure, and has a set of + * methods (a vtable) that follows this template. + * + * The decryption engine is responsible for applying decryption, verifying + * MAC, and keeping track of the record sequence number. + */ +typedef struct br_sslrec_in_class_ br_sslrec_in_class; +struct br_sslrec_in_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Test validity of the incoming record length. + * + * This function returns 1 if the announced length for an + * incoming record is valid, 0 otherwise, + * + * \param ctx decryption engine context. + * \param record_len incoming record length. + * \return 1 of a valid length, 0 otherwise. + */ + int (*check_length)(const br_sslrec_in_class *const *ctx, + size_t record_len); + + /** + * \brief Decrypt the incoming record. + * + * This function may assume that the record length is valid + * (it has been previously tested with `check_length()`). + * Decryption is done in place; `*len` is updated with the + * cleartext length, and the address of the first plaintext + * byte is returned. If the record is correct but empty, then + * `*len` is set to 0 and a non-`NULL` pointer is returned. + * + * On decryption/MAC error, `NULL` is returned. + * + * \param ctx decryption engine context. + * \param record_type record type (23 for application data, etc). + * \param version record version. + * \param payload address of encrypted payload. + * \param len pointer to payload length (updated). + * \return pointer to plaintext, or `NULL` on error. + */ + unsigned char *(*decrypt)(const br_sslrec_in_class **ctx, + int record_type, unsigned version, + void *payload, size_t *len); +}; + +/** + * \brief Encryption engine for SSL. + * + * When building outgoing records, the SSL engine will use an encryption + * engine that uses a specific context structure, and has a set of + * methods (a vtable) that follows this template. + * + * The encryption engine is responsible for applying encryption and MAC, + * and keeping track of the record sequence number. + */ +typedef struct br_sslrec_out_class_ br_sslrec_out_class; +struct br_sslrec_out_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Compute maximum plaintext sizes and offsets. + * + * When this function is called, the `*start` and `*end` + * values contain offsets designating the free area in the + * outgoing buffer for plaintext data; that free area is + * preceded by a 5-byte space which will receive the record + * header. + * + * The `max_plaintext()` function is responsible for adjusting + * both `*start` and `*end` to make room for any record-specific + * header, MAC, padding, and possible split. + * + * \param ctx encryption engine context. + * \param start pointer to start of plaintext offset (updated). + * \param end pointer to start of plaintext offset (updated). + */ + void (*max_plaintext)(const br_sslrec_out_class *const *ctx, + size_t *start, size_t *end); + + /** + * \brief Perform record encryption. + * + * This function encrypts the record. The plaintext address and + * length are provided. Returned value is the start of the + * encrypted record (or sequence of records, if a split was + * performed), _including_ the 5-byte header, and `*len` is + * adjusted to the total size of the record(s), there again + * including the header(s). + * + * \param ctx decryption engine context. + * \param record_type record type (23 for application data, etc). + * \param version record version. + * \param plaintext address of plaintext. + * \param len pointer to plaintext length (updated). + * \return pointer to start of built record. + */ + unsigned char *(*encrypt)(const br_sslrec_out_class **ctx, + int record_type, unsigned version, + void *plaintext, size_t *len); +}; + +/** + * \brief Context for a no-encryption engine. + * + * The no-encryption engine processes outgoing records during the initial + * handshake, before encryption is applied. + */ +typedef struct { + /** \brief No-encryption engine vtable. */ + const br_sslrec_out_class *vtable; +} br_sslrec_out_clear_context; + +/** \brief Static, constant vtable for the no-encryption engine. */ +extern const br_sslrec_out_class br_sslrec_out_clear_vtable; + +/* ===================================================================== */ + +/** + * \brief Record decryption engine class, for CBC mode. + * + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for CBC processing: block cipher implementation, block cipher key, + * HMAC parameters (hash function, key, MAC length), and IV. If the + * IV is `NULL`, then a per-record IV will be used (TLS 1.1+). + */ +typedef struct br_sslrec_in_cbc_class_ br_sslrec_in_cbc_class; +struct br_sslrec_in_cbc_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CBC decryption). + * \param bc_key block cipher key. + * \param bc_key_len block cipher key length (in bytes). + * \param dig_impl hash function for HMAC. + * \param mac_key HMAC key. + * \param mac_key_len HMAC key length (in bytes). + * \param mac_out_len HMAC output length (in bytes). + * \param iv initial IV (or `NULL`). + */ + void (*init)(const br_sslrec_in_cbc_class **ctx, + const br_block_cbcdec_class *bc_impl, + const void *bc_key, size_t bc_key_len, + const br_hash_class *dig_impl, + const void *mac_key, size_t mac_key_len, size_t mac_out_len, + const void *iv); +}; + +/** + * \brief Record encryption engine class, for CBC mode. + * + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for CBC processing: block cipher implementation, block cipher key, + * HMAC parameters (hash function, key, MAC length), and IV. If the + * IV is `NULL`, then a per-record IV will be used (TLS 1.1+). + */ +typedef struct br_sslrec_out_cbc_class_ br_sslrec_out_cbc_class; +struct br_sslrec_out_cbc_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CBC encryption). + * \param bc_key block cipher key. + * \param bc_key_len block cipher key length (in bytes). + * \param dig_impl hash function for HMAC. + * \param mac_key HMAC key. + * \param mac_key_len HMAC key length (in bytes). + * \param mac_out_len HMAC output length (in bytes). + * \param iv initial IV (or `NULL`). + */ + void (*init)(const br_sslrec_out_cbc_class **ctx, + const br_block_cbcenc_class *bc_impl, + const void *bc_key, size_t bc_key_len, + const br_hash_class *dig_impl, + const void *mac_key, size_t mac_key_len, size_t mac_out_len, + const void *iv); +}; + +/** + * \brief Context structure for decrypting incoming records with + * CBC + HMAC. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_sslrec_in_cbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + union { + const br_block_cbcdec_class *vtable; + br_aes_gen_cbcdec_keys aes; + br_des_gen_cbcdec_keys des; + } bc; + br_hmac_key_context mac; + size_t mac_len; + unsigned char iv[16]; + int explicit_IV; +#endif +} br_sslrec_in_cbc_context; + +/** + * \brief Static, constant vtable for record decryption with CBC. + */ +extern const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable; + +/** + * \brief Context structure for encrypting outgoing records with + * CBC + HMAC. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_sslrec_out_cbc_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + union { + const br_block_cbcenc_class *vtable; + br_aes_gen_cbcenc_keys aes; + br_des_gen_cbcenc_keys des; + } bc; + br_hmac_key_context mac; + size_t mac_len; + unsigned char iv[16]; + int explicit_IV; +#endif +} br_sslrec_out_cbc_context; + +/** + * \brief Static, constant vtable for record encryption with CBC. + */ +extern const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable; + +/* ===================================================================== */ + +/** + * \brief Record decryption engine class, for GCM mode. + * + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for GCM processing: block cipher implementation, block cipher key, + * GHASH implementation, and 4-byte IV. + */ +typedef struct br_sslrec_in_gcm_class_ br_sslrec_in_gcm_class; +struct br_sslrec_in_gcm_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param gh_impl GHASH implementation. + * \param iv static IV (4 bytes). + */ + void (*init)(const br_sslrec_in_gcm_class **ctx, + const br_block_ctr_class *bc_impl, + const void *key, size_t key_len, + br_ghash gh_impl, + const void *iv); +}; + +/** + * \brief Record encryption engine class, for GCM mode. + * + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for GCM processing: block cipher implementation, block cipher key, + * GHASH implementation, and 4-byte IV. + */ +typedef struct br_sslrec_out_gcm_class_ br_sslrec_out_gcm_class; +struct br_sslrec_out_gcm_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param gh_impl GHASH implementation. + * \param iv static IV (4 bytes). + */ + void (*init)(const br_sslrec_out_gcm_class **ctx, + const br_block_ctr_class *bc_impl, + const void *key, size_t key_len, + br_ghash gh_impl, + const void *iv); +}; + +/** + * \brief Context structure for processing records with GCM. + * + * The same context structure is used for encrypting and decrypting. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + union { + const void *gen; + const br_sslrec_in_gcm_class *in; + const br_sslrec_out_gcm_class *out; + } vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + union { + const br_block_ctr_class *vtable; + br_aes_gen_ctr_keys aes; + } bc; + br_ghash gh; + unsigned char iv[4]; + unsigned char h[16]; +#endif +} br_sslrec_gcm_context; + +/** + * \brief Static, constant vtable for record decryption with GCM. + */ +extern const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable; + +/** + * \brief Static, constant vtable for record encryption with GCM. + */ +extern const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable; + +/* ===================================================================== */ + +/** + * \brief Record decryption engine class, for ChaCha20+Poly1305. + * + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for ChaCha20+Poly1305 processing: ChaCha20 implementation, + * Poly1305 implementation, key, and 12-byte IV. + */ +typedef struct br_sslrec_in_chapol_class_ br_sslrec_in_chapol_class; +struct br_sslrec_in_chapol_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param ichacha ChaCha20 implementation. + * \param ipoly Poly1305 implementation. + * \param key secret key (32 bytes). + * \param iv static IV (12 bytes). + */ + void (*init)(const br_sslrec_in_chapol_class **ctx, + br_chacha20_run ichacha, + br_poly1305_run ipoly, + const void *key, const void *iv); +}; + +/** + * \brief Record encryption engine class, for ChaCha20+Poly1305. + * + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for ChaCha20+Poly1305 processing: ChaCha20 implementation, + * Poly1305 implementation, key, and 12-byte IV. + */ +typedef struct br_sslrec_out_chapol_class_ br_sslrec_out_chapol_class; +struct br_sslrec_out_chapol_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param ichacha ChaCha20 implementation. + * \param ipoly Poly1305 implementation. + * \param key secret key (32 bytes). + * \param iv static IV (12 bytes). + */ + void (*init)(const br_sslrec_out_chapol_class **ctx, + br_chacha20_run ichacha, + br_poly1305_run ipoly, + const void *key, const void *iv); +}; + +/** + * \brief Context structure for processing records with ChaCha20+Poly1305. + * + * The same context structure is used for encrypting and decrypting. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + union { + const void *gen; + const br_sslrec_in_chapol_class *in; + const br_sslrec_out_chapol_class *out; + } vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + unsigned char key[32]; + unsigned char iv[12]; + br_chacha20_run ichacha; + br_poly1305_run ipoly; +#endif +} br_sslrec_chapol_context; + +/** + * \brief Static, constant vtable for record decryption with ChaCha20+Poly1305. + */ +extern const br_sslrec_in_chapol_class br_sslrec_in_chapol_vtable; + +/** + * \brief Static, constant vtable for record encryption with ChaCha20+Poly1305. + */ +extern const br_sslrec_out_chapol_class br_sslrec_out_chapol_vtable; + +/* ===================================================================== */ + +/** + * \brief Record decryption engine class, for CCM mode. + * + * This class type extends the decryption engine class with an + * initialisation method that receives the parameters needed + * for CCM processing: block cipher implementation, block cipher key, + * and 4-byte IV. + */ +typedef struct br_sslrec_in_ccm_class_ br_sslrec_in_ccm_class; +struct br_sslrec_in_ccm_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_in_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR+CBC). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param iv static IV (4 bytes). + * \param tag_len tag length (in bytes) + */ + void (*init)(const br_sslrec_in_ccm_class **ctx, + const br_block_ctrcbc_class *bc_impl, + const void *key, size_t key_len, + const void *iv, size_t tag_len); +}; + +/** + * \brief Record encryption engine class, for CCM mode. + * + * This class type extends the encryption engine class with an + * initialisation method that receives the parameters needed + * for CCM processing: block cipher implementation, block cipher key, + * and 4-byte IV. + */ +typedef struct br_sslrec_out_ccm_class_ br_sslrec_out_ccm_class; +struct br_sslrec_out_ccm_class_ { + /** + * \brief Superclass, as first vtable field. + */ + br_sslrec_out_class inner; + + /** + * \brief Engine initialisation method. + * + * This method sets the vtable field in the context. + * + * \param ctx context to initialise. + * \param bc_impl block cipher implementation (CTR+CBC). + * \param key block cipher key. + * \param key_len block cipher key length (in bytes). + * \param iv static IV (4 bytes). + * \param tag_len tag length (in bytes) + */ + void (*init)(const br_sslrec_out_ccm_class **ctx, + const br_block_ctrcbc_class *bc_impl, + const void *key, size_t key_len, + const void *iv, size_t tag_len); +}; + +/** + * \brief Context structure for processing records with CCM. + * + * The same context structure is used for encrypting and decrypting. + * + * The first field points to the vtable. The other fields are opaque + * and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + union { + const void *gen; + const br_sslrec_in_ccm_class *in; + const br_sslrec_out_ccm_class *out; + } vtable; +#ifndef BR_DOXYGEN_IGNORE + uint64_t seq; + union { + const br_block_ctrcbc_class *vtable; + br_aes_gen_ctrcbc_keys aes; + } bc; + unsigned char iv[4]; + size_t tag_len; +#endif +} br_sslrec_ccm_context; + +/** + * \brief Static, constant vtable for record decryption with CCM. + */ +extern const br_sslrec_in_ccm_class br_sslrec_in_ccm_vtable; + +/** + * \brief Static, constant vtable for record encryption with CCM. + */ +extern const br_sslrec_out_ccm_class br_sslrec_out_ccm_vtable; + +/* ===================================================================== */ + +/** + * \brief Type for session parameters, to be saved for session resumption. + */ +typedef struct { + /** \brief Session ID buffer. */ + unsigned char session_id[32]; + /** \brief Session ID length (in bytes, at most 32). */ + unsigned char session_id_len; + /** \brief Protocol version. */ + uint16_t version; + /** \brief Cipher suite. */ + uint16_t cipher_suite; + /** \brief Master secret. */ + unsigned char master_secret[48]; +} br_ssl_session_parameters; + +#ifndef BR_DOXYGEN_IGNORE +/* + * Maximum number of cipher suites supported by a client or server. + */ +#define BR_MAX_CIPHER_SUITES 48 +#endif + +/** + * \brief Context structure for SSL engine. + * + * This strucuture is common to the client and server; both the client + * context (`br_ssl_client_context`) and the server context + * (`br_ssl_server_context`) include a `br_ssl_engine_context` as their + * first field. + * + * The engine context manages records, including alerts, closures, and + * transitions to new encryption/MAC algorithms. Processing of handshake + * records is delegated to externally provided code. This structure + * should not be used directly. + * + * Structure contents are opaque and shall not be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + /* + * The error code. When non-zero, then the state is "failed" and + * no I/O may occur until reset. + */ + int err; + + /* + * Configured I/O buffers. They are either disjoint, or identical. + */ + unsigned char *ibuf, *obuf; + size_t ibuf_len, obuf_len; + + /* + * Maximum fragment length applies to outgoing records; incoming + * records can be processed as long as they fit in the input + * buffer. It is guaranteed that incoming records at least as big + * as max_frag_len can be processed. + */ + uint16_t max_frag_len; + unsigned char log_max_frag_len; + unsigned char max_frag_len_negotiated; + unsigned char peer_log_max_frag_len; + + /* + * Buffering management registers. + */ + size_t ixa, ixb, ixc; + size_t oxa, oxb, oxc; + unsigned char iomode; + unsigned char incrypt; + + /* + * Shutdown flag: when set to non-zero, incoming record bytes + * will not be accepted anymore. This is used after a close_notify + * has been received: afterwards, the engine no longer claims that + * it could receive bytes from the transport medium. + */ + unsigned char shutdown_recv; + + /* + * 'record_type_in' is set to the incoming record type when the + * record header has been received. + * 'record_type_out' is used to make the next outgoing record + * header when it is ready to go. + */ + unsigned char record_type_in, record_type_out; + + /* + * When a record is received, its version is extracted: + * -- if 'version_in' is 0, then it is set to the received version; + * -- otherwise, if the received version is not identical to + * the 'version_in' contents, then a failure is reported. + * + * This implements the SSL requirement that all records shall + * use the negotiated protocol version, once decided (in the + * ServerHello). It is up to the handshake handler to adjust this + * field when necessary. + */ + uint16_t version_in; + + /* + * 'version_out' is used when the next outgoing record is ready + * to go. + */ + uint16_t version_out; + + /* + * Record handler contexts. + */ + union { + const br_sslrec_in_class *vtable; + br_sslrec_in_cbc_context cbc; + br_sslrec_gcm_context gcm; + br_sslrec_chapol_context chapol; + br_sslrec_ccm_context ccm; + } in; + union { + const br_sslrec_out_class *vtable; + br_sslrec_out_clear_context clear; + br_sslrec_out_cbc_context cbc; + br_sslrec_gcm_context gcm; + br_sslrec_chapol_context chapol; + br_sslrec_ccm_context ccm; + } out; + + /* + * The "application data" flag. Value: + * 0 handshake is in process, no application data acceptable + * 1 application data can be sent and received + * 2 closing, no application data can be sent, but some + * can still be received (and discarded) + */ + unsigned char application_data; + + /* + * Context RNG. + * + * rng_init_done is initially 0. It is set to 1 when the + * basic structure of the RNG is set, and 2 when some + * entropy has been pushed in. The value 2 marks the RNG + * as "properly seeded". + * + * rng_os_rand_done is initially 0. It is set to 1 when + * some seeding from the OS or hardware has been attempted. + */ + br_hmac_drbg_context rng; + int rng_init_done; + int rng_os_rand_done; + + /* + * Supported minimum and maximum versions, and cipher suites. + */ + uint16_t version_min; + uint16_t version_max; + uint16_t suites_buf[BR_MAX_CIPHER_SUITES]; + unsigned char suites_num; + + /* + * For clients, the server name to send as a SNI extension. For + * servers, the name received in the SNI extension (if any). + */ + char server_name[256]; + + /* + * "Security parameters". These are filled by the handshake + * handler, and used when switching encryption state. + */ + unsigned char client_random[32]; + unsigned char server_random[32]; + br_ssl_session_parameters session; + + /* + * ECDHE elements: curve and point from the peer. The server also + * uses that buffer for the point to send to the client. + */ + unsigned char ecdhe_curve; + unsigned char ecdhe_point[133]; + unsigned char ecdhe_point_len; + + /* + * Secure renegotiation (RFC 5746): 'reneg' can be: + * 0 first handshake (server support is not known) + * 1 peer does not support secure renegotiation + * 2 peer supports secure renegotiation + * + * The saved_finished buffer contains the client and the + * server "Finished" values from the last handshake, in + * that order (12 bytes each). + */ + unsigned char reneg; + unsigned char saved_finished[24]; + + /* + * Behavioural flags. + */ + uint32_t flags; + + /* + * Context variables for the handshake processor. The 'pad' must + * be large enough to accommodate an RSA-encrypted pre-master + * secret, or an RSA signature; since we want to support up to + * RSA-4096, this means at least 512 bytes. (Other pad usages + * require its length to be at least 256.) + */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + unsigned char pad[512]; + unsigned char *hbuf_in, *hbuf_out, *saved_hbuf_out; + size_t hlen_in, hlen_out; + void (*hsrun)(void *ctx); + + /* + * The 'action' value communicates OOB information between the + * engine and the handshake processor. + * + * From the engine: + * 0 invocation triggered by I/O + * 1 invocation triggered by explicit close + * 2 invocation triggered by explicit renegotiation + */ + unsigned char action; + + /* + * State for alert messages. Value is either 0, or the value of + * the alert level byte (level is either 1 for warning, or 2 for + * fatal; we convert all other values to 'fatal'). + */ + unsigned char alert; + + /* + * Closure flags. This flag is set when a close_notify has been + * received from the peer. + */ + unsigned char close_received; + + /* + * Multi-hasher for the handshake messages. The handshake handler + * is responsible for resetting it when appropriate. + */ + br_multihash_context mhash; + + /* + * Pointer to the X.509 engine. The engine is supposed to be + * already initialized. It is used to validate the peer's + * certificate. + */ + const br_x509_class **x509ctx; + + /* + * Certificate chain to send. This is used by both client and + * server, when they send their respective Certificate messages. + * If chain_len is 0, then chain may be NULL. + */ + const br_x509_certificate *chain; + size_t chain_len; + const unsigned char *cert_cur; + size_t cert_len; + + /* + * List of supported protocol names (ALPN extension). If unset, + * (number of names is 0), then: + * - the client sends no ALPN extension; + * - the server ignores any incoming ALPN extension. + * + * Otherwise: + * - the client sends an ALPN extension with all the names; + * - the server selects the first protocol in its list that + * the client also supports, or fails (fatal alert 120) + * if the client sends an ALPN extension and there is no + * match. + * + * The 'selected_protocol' field contains 1+n if the matching + * name has index n in the list (the value is 0 if no match was + * performed, e.g. the peer did not send an ALPN extension). + */ + const char **protocol_names; + uint16_t protocol_names_num; + uint16_t selected_protocol; + + /* + * Pointers to implementations; left to NULL for unsupported + * functions. For the raw hash functions, implementations are + * referenced from the multihasher (mhash field). + */ + br_tls_prf_impl prf10; + br_tls_prf_impl prf_sha256; + br_tls_prf_impl prf_sha384; + const br_block_cbcenc_class *iaes_cbcenc; + const br_block_cbcdec_class *iaes_cbcdec; + const br_block_ctr_class *iaes_ctr; + const br_block_ctrcbc_class *iaes_ctrcbc; + const br_block_cbcenc_class *ides_cbcenc; + const br_block_cbcdec_class *ides_cbcdec; + br_ghash ighash; + br_chacha20_run ichacha; + br_poly1305_run ipoly; + const br_sslrec_in_cbc_class *icbc_in; + const br_sslrec_out_cbc_class *icbc_out; + const br_sslrec_in_gcm_class *igcm_in; + const br_sslrec_out_gcm_class *igcm_out; + const br_sslrec_in_chapol_class *ichapol_in; + const br_sslrec_out_chapol_class *ichapol_out; + const br_sslrec_in_ccm_class *iccm_in; + const br_sslrec_out_ccm_class *iccm_out; + const br_ec_impl *iec; + br_rsa_pkcs1_vrfy irsavrfy; + br_ecdsa_vrfy iecdsa; +#endif +} br_ssl_engine_context; + +/** + * \brief Get currently defined engine behavioural flags. + * + * \param cc SSL engine context. + * \return the flags. + */ +static inline uint32_t +br_ssl_engine_get_flags(br_ssl_engine_context *cc) +{ + return cc->flags; +} + +/** + * \brief Set all engine behavioural flags. + * + * \param cc SSL engine context. + * \param flags new value for all flags. + */ +static inline void +br_ssl_engine_set_all_flags(br_ssl_engine_context *cc, uint32_t flags) +{ + cc->flags = flags; +} + +/** + * \brief Set some engine behavioural flags. + * + * The flags set in the `flags` parameter are set in the context; other + * flags are untouched. + * + * \param cc SSL engine context. + * \param flags additional set flags. + */ +static inline void +br_ssl_engine_add_flags(br_ssl_engine_context *cc, uint32_t flags) +{ + cc->flags |= flags; +} + +/** + * \brief Clear some engine behavioural flags. + * + * The flags set in the `flags` parameter are cleared from the context; other + * flags are untouched. + * + * \param cc SSL engine context. + * \param flags flags to remove. + */ +static inline void +br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags) +{ + cc->flags &= ~flags; +} + +/** + * \brief Behavioural flag: enforce server preferences. + * + * If this flag is set, then the server will enforce its own cipher suite + * preference order; otherwise, it follows the client preferences. + */ +#define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0) + +/** + * \brief Behavioural flag: disable renegotiation. + * + * If this flag is set, then renegotiations are rejected unconditionally: + * they won't be honoured if asked for programmatically, and requests from + * the peer are rejected. + */ +#define BR_OPT_NO_RENEGOTIATION ((uint32_t)1 << 1) + +/** + * \brief Behavioural flag: tolerate lack of client authentication. + * + * If this flag is set in a server and the server requests a client + * certificate, but the authentication fails (the client does not send + * a certificate, or the client's certificate chain cannot be validated), + * then the connection keeps on. Without this flag, a failed client + * authentication terminates the connection. + * + * Notes: + * + * - If the client's certificate can be validated and its public key is + * supported, then a wrong signature value terminates the connection + * regardless of that flag. + * + * - If using full-static ECDH, then a failure to validate the client's + * certificate prevents the handshake from succeeding. + */ +#define BR_OPT_TOLERATE_NO_CLIENT_AUTH ((uint32_t)1 << 2) + +/** + * \brief Behavioural flag: fail on application protocol mismatch. + * + * The ALPN extension ([RFC 7301](https://tools.ietf.org/html/rfc7301)) + * allows the client to send a list of application protocol names, and + * the server to select one. A mismatch is one of the following occurrences: + * + * - On the client: the client sends a list of names, the server + * responds with a protocol name which is _not_ part of the list of + * names sent by the client. + * + * - On the server: the client sends a list of names, and the server + * is also configured with a list of names, but there is no common + * protocol name between the two lists. + * + * Normal behaviour in case of mismatch is to report no matching name + * (`br_ssl_engine_get_selected_protocol()` returns `NULL`) and carry on. + * If the flag is set, then a mismatch implies a protocol failure (if + * the mismatch is detected by the server, it will send a fatal alert). + * + * Note: even with this flag, `br_ssl_engine_get_selected_protocol()` + * may still return `NULL` if the client or the server does not send an + * ALPN extension at all. + */ +#define BR_OPT_FAIL_ON_ALPN_MISMATCH ((uint32_t)1 << 3) + +/** + * \brief Set the minimum and maximum supported protocol versions. + * + * The two provided versions MUST be supported by the implementation + * (i.e. TLS 1.0, 1.1 and 1.2), and `version_max` MUST NOT be lower + * than `version_min`. + * + * \param cc SSL engine context. + * \param version_min minimum supported TLS version. + * \param version_max maximum supported TLS version. + */ +static inline void +br_ssl_engine_set_versions(br_ssl_engine_context *cc, + unsigned version_min, unsigned version_max) +{ + cc->version_min = (uint16_t)version_min; + cc->version_max = (uint16_t)version_max; +} + +/** + * \brief Set the list of cipher suites advertised by this context. + * + * The provided array is copied into the context. It is the caller + * responsibility to ensure that all provided suites will be supported + * by the context. The engine context has enough room to receive _all_ + * suites supported by the implementation. The provided array MUST NOT + * contain duplicates. + * + * If the engine is for a client, the "signaling" pseudo-cipher suite + * `TLS_FALLBACK_SCSV` can be added at the end of the list, if the + * calling application is performing a voluntary downgrade (voluntary + * downgrades are not recommended, but if such a downgrade is done, then + * adding the fallback pseudo-suite is a good idea). + * + * \param cc SSL engine context. + * \param suites cipher suites. + * \param suites_num number of cipher suites. + */ +void br_ssl_engine_set_suites(br_ssl_engine_context *cc, + const uint16_t *suites, size_t suites_num); + +/** + * \brief Set the X.509 engine. + * + * The caller shall ensure that the X.509 engine is properly initialised. + * + * \param cc SSL engine context. + * \param x509ctx X.509 certificate validation context. + */ +static inline void +br_ssl_engine_set_x509(br_ssl_engine_context *cc, const br_x509_class **x509ctx) +{ + cc->x509ctx = x509ctx; +} + +/** + * \brief Set the supported protocol names. + * + * Protocol names are part of the ALPN extension ([RFC + * 7301](https://tools.ietf.org/html/rfc7301)). Each protocol name is a + * character string, containing no more than 255 characters (256 with the + * terminating zero). When names are set, then: + * + * - The client will send an ALPN extension, containing the names. If + * the server responds with an ALPN extension, the client will verify + * that the response contains one of its name, and report that name + * through `br_ssl_engine_get_selected_protocol()`. + * + * - The server will parse incoming ALPN extension (from clients), and + * try to find a common protocol; if none is found, the connection + * is aborted with a fatal alert. On match, a response ALPN extension + * is sent, and name is reported through + * `br_ssl_engine_get_selected_protocol()`. + * + * The provided array is linked in, and must remain valid while the + * connection is live. + * + * Names MUST NOT be empty. Names MUST NOT be longer than 255 characters + * (excluding the terminating 0). + * + * \param ctx SSL engine context. + * \param names list of protocol names (zero-terminated). + * \param num number of protocol names (MUST be 1 or more). + */ +static inline void +br_ssl_engine_set_protocol_names(br_ssl_engine_context *ctx, + const char **names, size_t num) +{ + ctx->protocol_names = names; + ctx->protocol_names_num = (uint16_t)num; +} + +/** + * \brief Get the selected protocol. + * + * If this context was initialised with a non-empty list of protocol + * names, and both client and server sent ALPN extensions during the + * handshake, and a common name was found, then that name is returned. + * Otherwise, `NULL` is returned. + * + * The returned pointer is one of the pointers provided to the context + * with `br_ssl_engine_set_protocol_names()`. + * + * \return the selected protocol, or `NULL`. + */ +static inline const char * +br_ssl_engine_get_selected_protocol(br_ssl_engine_context *ctx) +{ + unsigned k; + + k = ctx->selected_protocol; + return (k == 0 || k == 0xFFFF) ? NULL : ctx->protocol_names[k - 1]; +} + +/** + * \brief Set a hash function implementation (by ID). + * + * Hash functions set with this call will be used for SSL/TLS specific + * usages, not X.509 certificate validation. Only "standard" hash functions + * may be set (MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512). If `impl` + * is `NULL`, then the hash function support is removed, not added. + * + * \param ctx SSL engine context. + * \param id hash function identifier. + * \param impl hash function implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_hash(br_ssl_engine_context *ctx, + int id, const br_hash_class *impl) +{ + br_multihash_setimpl(&ctx->mhash, id, impl); +} + +/** + * \brief Get a hash function implementation (by ID). + * + * This function retrieves a hash function implementation which was + * set with `br_ssl_engine_set_hash()`. + * + * \param ctx SSL engine context. + * \param id hash function identifier. + * \return the hash function implementation (or `NULL`). + */ +static inline const br_hash_class * +br_ssl_engine_get_hash(br_ssl_engine_context *ctx, int id) +{ + return br_multihash_getimpl(&ctx->mhash, id); +} + +/** + * \brief Set the PRF implementation (for TLS 1.0 and 1.1). + * + * This function sets (or removes, if `impl` is `NULL`) the implementation + * for the PRF used in TLS 1.0 and 1.1. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_prf10(br_ssl_engine_context *cc, br_tls_prf_impl impl) +{ + cc->prf10 = impl; +} + +/** + * \brief Set the PRF implementation with SHA-256 (for TLS 1.2). + * + * This function sets (or removes, if `impl` is `NULL`) the implementation + * for the SHA-256 variant of the PRF used in TLS 1.2. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_prf_sha256(br_ssl_engine_context *cc, br_tls_prf_impl impl) +{ + cc->prf_sha256 = impl; +} + +/** + * \brief Set the PRF implementation with SHA-384 (for TLS 1.2). + * + * This function sets (or removes, if `impl` is `NULL`) the implementation + * for the SHA-384 variant of the PRF used in TLS 1.2. + * + * \param cc SSL engine context. + * \param impl PRF implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_prf_sha384(br_ssl_engine_context *cc, br_tls_prf_impl impl) +{ + cc->prf_sha384 = impl; +} + +/** + * \brief Set the AES/CBC implementations. + * + * \param cc SSL engine context. + * \param impl_enc AES/CBC encryption implementation (or `NULL`). + * \param impl_dec AES/CBC decryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_aes_cbc(br_ssl_engine_context *cc, + const br_block_cbcenc_class *impl_enc, + const br_block_cbcdec_class *impl_dec) +{ + cc->iaes_cbcenc = impl_enc; + cc->iaes_cbcdec = impl_dec; +} + +/** + * \brief Set the "default" AES/CBC implementations. + * + * This function configures in the engine the AES implementations that + * should provide best runtime performance on the local system, while + * still being safe (in particular, constant-time). It also sets the + * handlers for CBC records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_aes_cbc(br_ssl_engine_context *cc); + +/** + * \brief Set the AES/CTR implementation. + * + * \param cc SSL engine context. + * \param impl AES/CTR encryption/decryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_aes_ctr(br_ssl_engine_context *cc, + const br_block_ctr_class *impl) +{ + cc->iaes_ctr = impl; +} + +/** + * \brief Set the "default" implementations for AES/GCM (AES/CTR + GHASH). + * + * This function configures in the engine the AES/CTR and GHASH + * implementation that should provide best runtime performance on the local + * system, while still being safe (in particular, constant-time). It also + * sets the handlers for GCM records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_aes_gcm(br_ssl_engine_context *cc); + +/** + * \brief Set the DES/CBC implementations. + * + * \param cc SSL engine context. + * \param impl_enc DES/CBC encryption implementation (or `NULL`). + * \param impl_dec DES/CBC decryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_des_cbc(br_ssl_engine_context *cc, + const br_block_cbcenc_class *impl_enc, + const br_block_cbcdec_class *impl_dec) +{ + cc->ides_cbcenc = impl_enc; + cc->ides_cbcdec = impl_dec; +} + +/** + * \brief Set the "default" DES/CBC implementations. + * + * This function configures in the engine the DES implementations that + * should provide best runtime performance on the local system, while + * still being safe (in particular, constant-time). It also sets the + * handlers for CBC records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_des_cbc(br_ssl_engine_context *cc); + +/** + * \brief Set the GHASH implementation (used in GCM mode). + * + * \param cc SSL engine context. + * \param impl GHASH implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_ghash(br_ssl_engine_context *cc, br_ghash impl) +{ + cc->ighash = impl; +} + +/** + * \brief Set the ChaCha20 implementation. + * + * \param cc SSL engine context. + * \param ichacha ChaCha20 implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_chacha20(br_ssl_engine_context *cc, + br_chacha20_run ichacha) +{ + cc->ichacha = ichacha; +} + +/** + * \brief Set the Poly1305 implementation. + * + * \param cc SSL engine context. + * \param ipoly Poly1305 implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_poly1305(br_ssl_engine_context *cc, + br_poly1305_run ipoly) +{ + cc->ipoly = ipoly; +} + +/** + * \brief Set the "default" ChaCha20 and Poly1305 implementations. + * + * This function configures in the engine the ChaCha20 and Poly1305 + * implementations that should provide best runtime performance on the + * local system, while still being safe (in particular, constant-time). + * It also sets the handlers for ChaCha20+Poly1305 records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_chapol(br_ssl_engine_context *cc); + +/** + * \brief Set the AES/CTR+CBC implementation. + * + * \param cc SSL engine context. + * \param impl AES/CTR+CBC encryption/decryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_aes_ctrcbc(br_ssl_engine_context *cc, + const br_block_ctrcbc_class *impl) +{ + cc->iaes_ctrcbc = impl; +} + +/** + * \brief Set the "default" implementations for AES/CCM. + * + * This function configures in the engine the AES/CTR+CBC + * implementation that should provide best runtime performance on the local + * system, while still being safe (in particular, constant-time). It also + * sets the handlers for CCM records. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_aes_ccm(br_ssl_engine_context *cc); + +/** + * \brief Set the record encryption and decryption engines for CBC + HMAC. + * + * \param cc SSL engine context. + * \param impl_in record CBC decryption implementation (or `NULL`). + * \param impl_out record CBC encryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_cbc(br_ssl_engine_context *cc, + const br_sslrec_in_cbc_class *impl_in, + const br_sslrec_out_cbc_class *impl_out) +{ + cc->icbc_in = impl_in; + cc->icbc_out = impl_out; +} + +/** + * \brief Set the record encryption and decryption engines for GCM. + * + * \param cc SSL engine context. + * \param impl_in record GCM decryption implementation (or `NULL`). + * \param impl_out record GCM encryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_gcm(br_ssl_engine_context *cc, + const br_sslrec_in_gcm_class *impl_in, + const br_sslrec_out_gcm_class *impl_out) +{ + cc->igcm_in = impl_in; + cc->igcm_out = impl_out; +} + +/** + * \brief Set the record encryption and decryption engines for CCM. + * + * \param cc SSL engine context. + * \param impl_in record CCM decryption implementation (or `NULL`). + * \param impl_out record CCM encryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_ccm(br_ssl_engine_context *cc, + const br_sslrec_in_ccm_class *impl_in, + const br_sslrec_out_ccm_class *impl_out) +{ + cc->iccm_in = impl_in; + cc->iccm_out = impl_out; +} + +/** + * \brief Set the record encryption and decryption engines for + * ChaCha20+Poly1305. + * + * \param cc SSL engine context. + * \param impl_in record ChaCha20 decryption implementation (or `NULL`). + * \param impl_out record ChaCha20 encryption implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_chapol(br_ssl_engine_context *cc, + const br_sslrec_in_chapol_class *impl_in, + const br_sslrec_out_chapol_class *impl_out) +{ + cc->ichapol_in = impl_in; + cc->ichapol_out = impl_out; +} + +/** + * \brief Set the EC implementation. + * + * The elliptic curve implementation will be used for ECDH and ECDHE + * cipher suites, and for ECDSA support. + * + * \param cc SSL engine context. + * \param iec EC implementation (or `NULL`). + */ +static inline void +br_ssl_engine_set_ec(br_ssl_engine_context *cc, const br_ec_impl *iec) +{ + cc->iec = iec; +} + +/** + * \brief Set the "default" EC implementation. + * + * This function sets the elliptic curve implementation for ECDH and + * ECDHE cipher suites, and for ECDSA support. It selects the fastest + * implementation on the current system. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_ec(br_ssl_engine_context *cc); + +/** + * \brief Get the EC implementation configured in the provided engine. + * + * \param cc SSL engine context. + * \return the EC implementation. + */ +static inline const br_ec_impl * +br_ssl_engine_get_ec(br_ssl_engine_context *cc) +{ + return cc->iec; +} + +/** + * \brief Set the RSA signature verification implementation. + * + * On the client, this is used to verify the server's signature on its + * ServerKeyExchange message (for ECDHE_RSA cipher suites). On the server, + * this is used to verify the client's CertificateVerify message (if a + * client certificate is requested, and that certificate contains a RSA key). + * + * \param cc SSL engine context. + * \param irsavrfy RSA signature verification implementation. + */ +static inline void +br_ssl_engine_set_rsavrfy(br_ssl_engine_context *cc, br_rsa_pkcs1_vrfy irsavrfy) +{ + cc->irsavrfy = irsavrfy; +} + +/** + * \brief Set the "default" RSA implementation (signature verification). + * + * This function sets the RSA implementation (signature verification) + * to the fastest implementation available on the current platform. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_rsavrfy(br_ssl_engine_context *cc); + +/** + * \brief Get the RSA implementation (signature verification) configured + * in the provided engine. + * + * \param cc SSL engine context. + * \return the RSA signature verification implementation. + */ +static inline br_rsa_pkcs1_vrfy +br_ssl_engine_get_rsavrfy(br_ssl_engine_context *cc) +{ + return cc->irsavrfy; +} + +/* + * \brief Set the ECDSA implementation (signature verification). + * + * On the client, this is used to verify the server's signature on its + * ServerKeyExchange message (for ECDHE_ECDSA cipher suites). On the server, + * this is used to verify the client's CertificateVerify message (if a + * client certificate is requested, that certificate contains an EC key, + * and full-static ECDH is not used). + * + * The ECDSA implementation will use the EC core implementation configured + * in the engine context. + * + * \param cc client context. + * \param iecdsa ECDSA verification implementation. + */ +static inline void +br_ssl_engine_set_ecdsa(br_ssl_engine_context *cc, br_ecdsa_vrfy iecdsa) +{ + cc->iecdsa = iecdsa; +} + +/** + * \brief Set the "default" ECDSA implementation (signature verification). + * + * This function sets the ECDSA implementation (signature verification) + * to the fastest implementation available on the current platform. This + * call also sets the elliptic curve implementation itself, there again + * to the fastest EC implementation available. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_set_default_ecdsa(br_ssl_engine_context *cc); + +/** + * \brief Get the ECDSA implementation (signature verification) configured + * in the provided engine. + * + * \param cc SSL engine context. + * \return the ECDSA signature verification implementation. + */ +static inline br_ecdsa_vrfy +br_ssl_engine_get_ecdsa(br_ssl_engine_context *cc) +{ + return cc->iecdsa; +} + +/** + * \brief Set the I/O buffer for the SSL engine. + * + * Once this call has been made, `br_ssl_client_reset()` or + * `br_ssl_server_reset()` MUST be called before using the context. + * + * The provided buffer will be used as long as the engine context is + * used. The caller is responsible for keeping it available. + * + * If `bidi` is 0, then the engine will operate in half-duplex mode + * (it won't be able to send data while there is unprocessed incoming + * data in the buffer, and it won't be able to receive data while there + * is unsent data in the buffer). The optimal buffer size in half-duplex + * mode is `BR_SSL_BUFSIZE_MONO`; if the buffer is larger, then extra + * bytes are ignored. If the buffer is smaller, then this limits the + * capacity of the engine to support all allowed record sizes. + * + * If `bidi` is 1, then the engine will split the buffer into two + * parts, for separate handling of outgoing and incoming data. This + * enables full-duplex processing, but requires more RAM. The optimal + * buffer size in full-duplex mode is `BR_SSL_BUFSIZE_BIDI`; if the + * buffer is larger, then extra bytes are ignored. If the buffer is + * smaller, then the split will favour the incoming part, so that + * interoperability is maximised. + * + * \param cc SSL engine context + * \param iobuf I/O buffer. + * \param iobuf_len I/O buffer length (in bytes). + * \param bidi non-zero for full-duplex mode. + */ +void br_ssl_engine_set_buffer(br_ssl_engine_context *cc, + void *iobuf, size_t iobuf_len, int bidi); + +/** + * \brief Set the I/O buffers for the SSL engine. + * + * Once this call has been made, `br_ssl_client_reset()` or + * `br_ssl_server_reset()` MUST be called before using the context. + * + * This function is similar to `br_ssl_engine_set_buffer()`, except + * that it enforces full-duplex mode, and the two I/O buffers are + * provided as separate chunks. + * + * The macros `BR_SSL_BUFSIZE_INPUT` and `BR_SSL_BUFSIZE_OUTPUT` + * evaluate to the optimal (maximum) sizes for the input and output + * buffer, respectively. + * + * \param cc SSL engine context + * \param ibuf input buffer. + * \param ibuf_len input buffer length (in bytes). + * \param obuf output buffer. + * \param obuf_len output buffer length (in bytes). + */ +void br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *cc, + void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len); + +/** + * \brief Determine if MFLN negotiation was successful + * + * \param cc SSL engine context. + */ +static inline uint8_t +br_ssl_engine_get_mfln_negotiated(br_ssl_engine_context *cc) +{ + return cc->max_frag_len_negotiated; +} + +/** + * \brief Inject some "initial entropy" in the context. + * + * This entropy will be added to what can be obtained from the + * underlying operating system, if that OS is supported. + * + * This function may be called several times; all injected entropy chunks + * are cumulatively mixed. + * + * If entropy gathering from the OS is supported and compiled in, then this + * step is optional. Otherwise, it is mandatory to inject randomness, and + * the caller MUST take care to push (as one or several successive calls) + * enough entropy to achieve cryptographic resistance (at least 80 bits, + * preferably 128 or more). The engine will report an error if no entropy + * was provided and none can be obtained from the OS. + * + * Take care that this function cannot assess the cryptographic quality of + * the provided bytes. + * + * In all generality, "entropy" must here be considered to mean "that + * which the attacker cannot predict". If your OS/architecture does not + * have a suitable source of randomness, then you can make do with the + * combination of a large enough secret value (possibly a copy of an + * asymmetric private key that you also store on the system) AND a + * non-repeating value (e.g. current time, provided that the local clock + * cannot be reset or altered by the attacker). + * + * \param cc SSL engine context. + * \param data extra entropy to inject. + * \param len length of the extra data (in bytes). + */ +void br_ssl_engine_inject_entropy(br_ssl_engine_context *cc, + const void *data, size_t len); + +/** + * \brief Get the "server name" in this engine. + * + * For clients, this is the name provided with `br_ssl_client_reset()`; + * for servers, this is the name received from the client as part of the + * ClientHello message. If there is no such name (e.g. the client did + * not send an SNI extension) then the returned string is empty + * (returned pointer points to a byte of value 0). + * + * The returned pointer refers to a buffer inside the context, which may + * be overwritten as part of normal SSL activity (even within the same + * connection, if a renegotiation occurs). + * + * \param cc SSL engine context. + * \return the server name (possibly empty). + */ +static inline const char * +br_ssl_engine_get_server_name(const br_ssl_engine_context *cc) +{ + return cc->server_name; +} + +/** + * \brief Get the protocol version. + * + * This function returns the protocol version that is used by the + * engine. That value is set after sending (for a server) or receiving + * (for a client) the ServerHello message. + * + * \param cc SSL engine context. + * \return the protocol version. + */ +static inline unsigned +br_ssl_engine_get_version(const br_ssl_engine_context *cc) +{ + return cc->session.version; +} + +/** + * \brief Get a copy of the session parameters. + * + * The session parameters are filled during the handshake, so this + * function shall not be called before completion of the handshake. + * The initial handshake is completed when the context first allows + * application data to be injected. + * + * This function copies the current session parameters into the provided + * structure. Beware that the session parameters include the master + * secret, which is sensitive data, to handle with great care. + * + * \param cc SSL engine context. + * \param pp destination structure for the session parameters. + */ +static inline void +br_ssl_engine_get_session_parameters(const br_ssl_engine_context *cc, + br_ssl_session_parameters *pp) +{ + memcpy(pp, &cc->session, sizeof *pp); +} + +/** + * \brief Set the session parameters to the provided values. + * + * This function is meant to be used in the client, before doing a new + * handshake; a session resumption will be attempted with these + * parameters. In the server, this function has no effect. + * + * \param cc SSL engine context. + * \param pp source structure for the session parameters. + */ +static inline void +br_ssl_engine_set_session_parameters(br_ssl_engine_context *cc, + const br_ssl_session_parameters *pp) +{ + memcpy(&cc->session, pp, sizeof *pp); +} + +/** + * \brief Get identifier for the curve used for key exchange. + * + * If the cipher suite uses ECDHE, then this function returns the + * identifier for the curve used for transient parameters. This is + * defined during the course of the handshake, when the ServerKeyExchange + * is sent (on the server) or received (on the client). If the + * cipher suite does not use ECDHE (e.g. static ECDH, or RSA key + * exchange), then this value is indeterminate. + * + * @param cc SSL engine context. + * @return the ECDHE curve identifier. + */ +static inline int +br_ssl_engine_get_ecdhe_curve(br_ssl_engine_context *cc) +{ + return cc->ecdhe_curve; +} + +/** + * \brief Get the current engine state. + * + * An SSL engine (client or server) has, at any time, a state which is + * the combination of zero, one or more of these flags: + * + * - `BR_SSL_CLOSED` + * + * Engine is finished, no more I/O (until next reset). + * + * - `BR_SSL_SENDREC` + * + * Engine has some bytes to send to the peer. + * + * - `BR_SSL_RECVREC` + * + * Engine expects some bytes from the peer. + * + * - `BR_SSL_SENDAPP` + * + * Engine may receive application data to send (or flush). + * + * - `BR_SSL_RECVAPP` + * + * Engine has obtained some application data from the peer, + * that should be read by the caller. + * + * If no flag at all is set (state value is 0), then the engine is not + * fully initialised yet. + * + * The `BR_SSL_CLOSED` flag is exclusive; when it is set, no other flag + * is set. To distinguish between a normal closure and an error, use + * `br_ssl_engine_last_error()`. + * + * Generally speaking, `BR_SSL_SENDREC` and `BR_SSL_SENDAPP` are mutually + * exclusive: the input buffer, at any point, either accumulates + * plaintext data, or contains an assembled record that is being sent. + * Similarly, `BR_SSL_RECVREC` and `BR_SSL_RECVAPP` are mutually exclusive. + * This may change in a future library version. + * + * \param cc SSL engine context. + * \return the current engine state. + */ +unsigned br_ssl_engine_current_state(const br_ssl_engine_context *cc); + +/** \brief SSL engine state: closed or failed. */ +#define BR_SSL_CLOSED 0x0001 +/** \brief SSL engine state: record data is ready to be sent to the peer. */ +#define BR_SSL_SENDREC 0x0002 +/** \brief SSL engine state: engine may receive records from the peer. */ +#define BR_SSL_RECVREC 0x0004 +/** \brief SSL engine state: engine may accept application data to send. */ +#define BR_SSL_SENDAPP 0x0008 +/** \brief SSL engine state: engine has received application data. */ +#define BR_SSL_RECVAPP 0x0010 + +/** + * \brief Get the engine error indicator. + * + * The error indicator is `BR_ERR_OK` (0) if no error was encountered + * since the last call to `br_ssl_client_reset()` or + * `br_ssl_server_reset()`. Other status values are "sticky": they + * remain set, and prevent all I/O activity, until cleared. Only the + * reset calls clear the error indicator. + * + * \param cc SSL engine context. + * \return 0, or a non-zero error code. + */ +static inline int +br_ssl_engine_last_error(const br_ssl_engine_context *cc) +{ + return cc->err; +} + +/* + * There are four I/O operations, each identified by a symbolic name: + * + * sendapp inject application data in the engine + * recvapp retrieving application data from the engine + * sendrec sending records on the transport medium + * recvrec receiving records from the transport medium + * + * Terminology works thus: in a layered model where the SSL engine sits + * between the application and the network, "send" designates operations + * where bytes flow from application to network, and "recv" for the + * reverse operation. Application data (the plaintext that is to be + * conveyed through SSL) is "app", while encrypted records are "rec". + * Note that from the SSL engine point of view, "sendapp" and "recvrec" + * designate bytes that enter the engine ("inject" operation), while + * "recvapp" and "sendrec" designate bytes that exit the engine + * ("extract" operation). + * + * For the operation 'xxx', two functions are defined: + * + * br_ssl_engine_xxx_buf + * Returns a pointer and length to the buffer to use for that + * operation. '*len' is set to the number of bytes that may be read + * from the buffer (extract operation) or written to the buffer + * (inject operation). If no byte may be exchanged for that operation + * at that point, then '*len' is set to zero, and NULL is returned. + * The engine state is unmodified by this call. + * + * br_ssl_engine_xxx_ack + * Informs the engine that 'len' bytes have been read from the buffer + * (extract operation) or written to the buffer (inject operation). + * The 'len' value MUST NOT be zero. The 'len' value MUST NOT exceed + * that which was obtained from a preceding br_ssl_engine_xxx_buf() + * call. + */ + +/** + * \brief Get buffer for application data to send. + * + * If the engine is ready to accept application data to send to the + * peer, then this call returns a pointer to the buffer where such + * data shall be written, and its length is written in `*len`. + * Otherwise, `*len` is set to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the application data output buffer length, or 0. + * \return the application data output buffer, or `NULL`. + */ +unsigned char *br_ssl_engine_sendapp_buf( + const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Inform the engine of some new application data. + * + * After writing `len` bytes in the buffer returned by + * `br_ssl_engine_sendapp_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_sendapp_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes pushed (not zero). + */ +void br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len); + +/** + * \brief Get buffer for received application data. + * + * If the engine has received application data from the peer, then this + * call returns a pointer to the buffer from where such data shall be + * read, and its length is written in `*len`. Otherwise, `*len` is set + * to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the application data input buffer length, or 0. + * \return the application data input buffer, or `NULL`. + */ +unsigned char *br_ssl_engine_recvapp_buf( + const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Acknowledge some received application data. + * + * After reading `len` bytes from the buffer returned by + * `br_ssl_engine_recvapp_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_recvapp_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes read (not zero). + */ +void br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len); + +/** + * \brief Get buffer for record data to send. + * + * If the engine has prepared some records to send to the peer, then this + * call returns a pointer to the buffer from where such data shall be + * read, and its length is written in `*len`. Otherwise, `*len` is set + * to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the record data output buffer length, or 0. + * \return the record data output buffer, or `NULL`. + */ +unsigned char *br_ssl_engine_sendrec_buf( + const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Acknowledge some sent record data. + * + * After reading `len` bytes from the buffer returned by + * `br_ssl_engine_sendrec_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_sendrec_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes read (not zero). + */ +void br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len); + +/** + * \brief Get buffer for incoming records. + * + * If the engine is ready to accept records from the peer, then this + * call returns a pointer to the buffer where such data shall be + * written, and its length is written in `*len`. Otherwise, `*len` is + * set to 0 and `NULL` is returned. + * + * \param cc SSL engine context. + * \param len receives the record data input buffer length, or 0. + * \return the record data input buffer, or `NULL`. + */ +unsigned char *br_ssl_engine_recvrec_buf( + const br_ssl_engine_context *cc, size_t *len); + +/** + * \brief Inform the engine of some new record data. + * + * After writing `len` bytes in the buffer returned by + * `br_ssl_engine_recvrec_buf()`, the application shall call this + * function to trigger any relevant processing. The `len` parameter + * MUST NOT be 0, and MUST NOT exceed the value obtained in the + * `br_ssl_engine_recvrec_buf()` call. + * + * \param cc SSL engine context. + * \param len number of bytes pushed (not zero). + */ +void br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len); + +/** + * \brief Flush buffered application data. + * + * If some application data has been buffered in the engine, then wrap + * it into a record and mark it for sending. If no application data has + * been buffered but the engine would be ready to accept some, AND the + * `force` parameter is non-zero, then an empty record is assembled and + * marked for sending. In all other cases, this function does nothing. + * + * Empty records are technically legal, but not all existing SSL/TLS + * implementations support them. Empty records can be useful as a + * transparent "keep-alive" mechanism to maintain some low-level + * network activity. + * + * \param cc SSL engine context. + * \param force non-zero to force sending an empty record. + */ +void br_ssl_engine_flush(br_ssl_engine_context *cc, int force); + +/** + * \brief Initiate a closure. + * + * If, at that point, the context is open and in ready state, then a + * `close_notify` alert is assembled and marked for sending; this + * triggers the closure protocol. Otherwise, no such alert is assembled. + * + * \param cc SSL engine context. + */ +void br_ssl_engine_close(br_ssl_engine_context *cc); + +/** + * \brief Initiate a renegotiation. + * + * If the engine is failed or closed, or if the peer is known not to + * support secure renegotiation (RFC 5746), or if renegotiations have + * been disabled with the `BR_OPT_NO_RENEGOTIATION` flag, or if there + * is buffered incoming application data, then this function returns 0 + * and nothing else happens. + * + * Otherwise, this function returns 1, and a renegotiation attempt is + * triggered (if a handshake is already ongoing at that point, then + * no new handshake is triggered). + * + * \param cc SSL engine context. + * \return 1 on success, 0 on error. + */ +int br_ssl_engine_renegotiate(br_ssl_engine_context *cc); + +/** + * \brief Export key material from a connected SSL engine (RFC 5705). + * + * This calls compute a secret key of arbitrary length from the master + * secret of a connected SSL engine. If the provided context is not + * currently in "application data" state (initial handshake is not + * finished, another handshake is ongoing, or the connection failed or + * was closed), then this function returns 0. Otherwise, a secret key of + * length `len` bytes is computed and written in the buffer pointed to + * by `dst`, and 1 is returned. + * + * The computed key follows the specification described in RFC 5705. + * That RFC includes two key computations, with and without a "context + * value". If `context` is `NULL`, then the variant without context is + * used; otherwise, the `context_len` bytes located at the address + * pointed to by `context` are used in the computation. Note that it + * is possible to have a "with context" key with a context length of + * zero bytes, by setting `context` to a non-`NULL` value but + * `context_len` to 0. + * + * When context bytes are used, the context length MUST NOT exceed + * 65535 bytes. + * + * \param cc SSL engine context. + * \param dst destination buffer for exported key. + * \param len exported key length (in bytes). + * \param label disambiguation label. + * \param context context value (or `NULL`). + * \param context_len context length (in bytes). + * \return 1 on success, 0 on error. + */ +int br_ssl_key_export(br_ssl_engine_context *cc, + void *dst, size_t len, const char *label, + const void *context, size_t context_len); + +/* + * Pre-declaration for the SSL client context. + */ +typedef struct br_ssl_client_context_ br_ssl_client_context; + +/** + * \brief Type for the client certificate, if requested by the server. + */ +typedef struct { + /** + * \brief Authentication type. + * + * This is either `BR_AUTH_RSA` (RSA signature), `BR_AUTH_ECDSA` + * (ECDSA signature), or `BR_AUTH_ECDH` (static ECDH key exchange). + */ + int auth_type; + + /** + * \brief Hash function for computing the CertificateVerify. + * + * This is the symbolic identifier for the hash function that + * will be used to produce the hash of handshake messages, to + * be signed into the CertificateVerify. For full static ECDH + * (client and server certificates are both EC in the same + * curve, and static ECDH is used), this value is set to -1. + * + * Take care that with TLS 1.0 and 1.1, that value MUST match + * the protocol requirements: value must be 0 (MD5+SHA-1) for + * a RSA signature, or 2 (SHA-1) for an ECDSA signature. Only + * TLS 1.2 allows for other hash functions. + */ + int hash_id; + + /** + * \brief Certificate chain to send to the server. + * + * This is an array of `br_x509_certificate` objects, each + * normally containing a DER-encoded certificate. The client + * code does not try to decode these elements. If there is no + * chain to send to the server, then this pointer shall be + * set to `NULL`. + */ + const br_x509_certificate *chain; + + /** + * \brief Certificate chain length (number of certificates). + * + * If there is no chain to send to the server, then this value + * shall be set to 0. + */ + size_t chain_len; + +} br_ssl_client_certificate; + +/* + * Note: the constants below for signatures match the TLS constants. + */ + +/** \brief Client authentication type: static ECDH. */ +#define BR_AUTH_ECDH 0 +/** \brief Client authentication type: RSA signature. */ +#define BR_AUTH_RSA 1 +/** \brief Client authentication type: ECDSA signature. */ +#define BR_AUTH_ECDSA 3 + +/** + * \brief Class type for a certificate handler (client side). + * + * A certificate handler selects a client certificate chain to send to + * the server, upon explicit request from that server. It receives + * the list of trust anchor DN from the server, and supported types + * of certificates and signatures, and returns the chain to use. It + * is also invoked to perform the corresponding private key operation + * (a signature, or an ECDH computation). + * + * The SSL client engine will first push the trust anchor DN with + * `start_name_list()`, `start_name()`, `append_name()`, `end_name()` + * and `end_name_list()`. Then it will call `choose()`, to select the + * actual chain (and signature/hash algorithms). Finally, it will call + * either `do_sign()` or `do_keyx()`, depending on the algorithm choices. + */ +typedef struct br_ssl_client_certificate_class_ br_ssl_client_certificate_class; +struct br_ssl_client_certificate_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Begin reception of a list of trust anchor names. This + * is called while parsing the incoming CertificateRequest. + * + * \param pctx certificate handler context. + */ + void (*start_name_list)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief Begin reception of a new trust anchor name. + * + * The total encoded name length is provided; it is less than + * 65535 bytes. + * + * \param pctx certificate handler context. + * \param len encoded name length (in bytes). + */ + void (*start_name)(const br_ssl_client_certificate_class **pctx, + size_t len); + + /** + * \brief Receive some more bytes for the current trust anchor name. + * + * The provided reference (`data`) points to a transient buffer + * they may be reused as soon as this function returns. The chunk + * length (`len`) is never zero. + * + * \param pctx certificate handler context. + * \param data anchor name chunk. + * \param len anchor name chunk length (in bytes). + */ + void (*append_name)(const br_ssl_client_certificate_class **pctx, + const unsigned char *data, size_t len); + + /** + * \brief End current trust anchor name. + * + * This function is called when all the encoded anchor name data + * has been provided. + * + * \param pctx certificate handler context. + */ + void (*end_name)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief End list of trust anchor names. + * + * This function is called when all the anchor names in the + * CertificateRequest message have been obtained. + * + * \param pctx certificate handler context. + */ + void (*end_name_list)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief Select client certificate and algorithms. + * + * This callback function shall fill the provided `choices` + * structure with the selected algorithms and certificate chain. + * The `hash_id`, `chain` and `chain_len` fields must be set. If + * the client cannot or does not wish to send a certificate, + * then it shall set `chain` to `NULL` and `chain_len` to 0. + * + * The `auth_types` parameter describes the authentication types, + * signature algorithms and hash functions that are supported by + * both the client context and the server, and compatible with + * the current protocol version. This is a bit field with the + * following contents: + * + * - If RSA signatures with hash function x are supported, then + * bit x is set. + * + * - If ECDSA signatures with hash function x are supported, + * then bit 8+x is set. + * + * - If static ECDH is supported, with a RSA-signed certificate, + * then bit 16 is set. + * + * - If static ECDH is supported, with an ECDSA-signed certificate, + * then bit 17 is set. + * + * Notes: + * + * - When using TLS 1.0 or 1.1, the hash function for RSA + * signatures is always the special MD5+SHA-1 (id 0), and the + * hash function for ECDSA signatures is always SHA-1 (id 2). + * + * - When using TLS 1.2, the list of hash functions is trimmed + * down to include only hash functions that the client context + * can support. The actual server list can be obtained with + * `br_ssl_client_get_server_hashes()`; that list may be used + * to select the certificate chain to send to the server. + * + * \param pctx certificate handler context. + * \param cc SSL client context. + * \param auth_types supported authentication types and algorithms. + * \param choices destination structure for the policy choices. + */ + void (*choose)(const br_ssl_client_certificate_class **pctx, + const br_ssl_client_context *cc, uint32_t auth_types, + br_ssl_client_certificate *choices); + + /** + * \brief Perform key exchange (client part). + * + * This callback is invoked in case of a full static ECDH key + * exchange: + * + * - the cipher suite uses `ECDH_RSA` or `ECDH_ECDSA`; + * + * - the server requests a client certificate; + * + * - the client has, and sends, a client certificate that + * uses an EC key in the same curve as the server's key, + * and chooses static ECDH (the `hash_id` field in the choice + * structure was set to -1). + * + * In that situation, this callback is invoked to compute the + * client-side ECDH: the provided `data` (of length `*len` bytes) + * is the server's public key point (as decoded from its + * certificate), and the client shall multiply that point with + * its own private key, and write back the X coordinate of the + * resulting point in the same buffer, starting at offset 0. + * The `*len` value shall be modified to designate the actual + * length of the X coordinate. + * + * The callback must uphold the following: + * + * - If the input array does not have the proper length for + * an encoded curve point, then an error (0) shall be reported. + * + * - If the input array has the proper length, then processing + * MUST be constant-time, even if the data is not a valid + * encoded point. + * + * - This callback MUST check that the input point is valid. + * + * Returned value is 1 on success, 0 on error. + * + * \param pctx certificate handler context. + * \param data server public key point. + * \param len public key point length / X coordinate length. + * \return 1 on success, 0 on error. + */ + uint32_t (*do_keyx)(const br_ssl_client_certificate_class **pctx, + unsigned char *data, size_t *len); + + /** + * \brief Perform a signature (client authentication). + * + * This callback is invoked when a client certificate was sent, + * and static ECDH is not used. It shall compute a signature, + * using the client's private key, over the provided hash value + * (which is the hash of all previous handshake messages). + * + * On input, the hash value to sign is in `data`, of size + * `hv_len`; the involved hash function is identified by + * `hash_id`. The signature shall be computed and written + * back into `data`; the total size of that buffer is `len` + * bytes. + * + * This callback shall verify that the signature length does not + * exceed `len` bytes, and abstain from writing the signature if + * it does not fit. + * + * For RSA signatures, the `hash_id` may be 0, in which case + * this is the special header-less signature specified in TLS 1.0 + * and 1.1, with a 36-byte hash value. Otherwise, normal PKCS#1 + * v1.5 signatures shall be computed. + * + * For ECDSA signatures, the signature value shall use the ASN.1 + * based encoding. + * + * Returned value is the signature length (in bytes), or 0 on error. + * + * \param pctx certificate handler context. + * \param hash_id hash function identifier. + * \param hv_len hash value length (in bytes). + * \param data input/output buffer (hash value, then signature). + * \param len total buffer length (in bytes). + * \return signature length (in bytes) on success, or 0 on error. + */ + size_t (*do_sign)(const br_ssl_client_certificate_class **pctx, + int hash_id, size_t hv_len, unsigned char *data, size_t len); +}; + +/** + * \brief A single-chain RSA client certificate handler. + * + * This handler uses a single certificate chain, with a RSA + * signature. The list of trust anchor DN is ignored. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_client_certificate_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_rsa_private_key *sk; + br_rsa_pkcs1_sign irsasign; +#endif +} br_ssl_client_certificate_rsa_context; + +/** + * \brief A single-chain EC client certificate handler. + * + * This handler uses a single certificate chain, with a RSA + * signature. The list of trust anchor DN is ignored. + * + * This handler may support both static ECDH, and ECDSA signatures + * (either usage may be selectively disabled). + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_client_certificate_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_ec_private_key *sk; + unsigned allowed_usages; + unsigned issuer_key_type; + const br_multihash_context *mhash; + const br_ec_impl *iec; + br_ecdsa_sign iecdsa; +#endif +} br_ssl_client_certificate_ec_context; + +/** + * \brief Context structure for a SSL client. + * + * The first field (called `eng`) is the SSL engine; all functions that + * work on a `br_ssl_engine_context` structure shall take as parameter + * a pointer to that field. The other structure fields are opaque and + * must not be accessed directly. + */ +struct br_ssl_client_context_ { + /** + * \brief The encapsulated engine context. + */ + br_ssl_engine_context eng; + +#ifndef BR_DOXYGEN_IGNORE + /* + * Minimum ClientHello length; padding with an extension (RFC + * 7685) is added if necessary to match at least that length. + * Such padding is nominally unnecessary, but it has been used + * to work around some server implementation bugs. + */ + uint16_t min_clienthello_len; + + /* + * Bit field for algoithms (hash + signature) supported by the + * server when requesting a client certificate. + */ + uint32_t hashes; + + /* + * Server's public key curve. + */ + int server_curve; + + /* + * Context for certificate handler. + */ + const br_ssl_client_certificate_class **client_auth_vtable; + + /* + * Client authentication type. + */ + unsigned char auth_type; + + /* + * Hash function to use for the client signature. This is 0xFF + * if static ECDH is used. + */ + unsigned char hash_id; + + /* + * For the core certificate handlers, thus avoiding (in most + * cases) the need for an externally provided policy context. + */ + union { + const br_ssl_client_certificate_class *vtable; + br_ssl_client_certificate_rsa_context single_rsa; + br_ssl_client_certificate_ec_context single_ec; + } client_auth; + + /* + * Implementations. + */ + br_rsa_public irsapub; +#endif +}; + +/** + * \brief Get the hash functions and signature algorithms supported by + * the server. + * + * This value is a bit field: + * + * - If RSA (PKCS#1 v1.5) is supported with hash function of ID `x`, + * then bit `x` is set (hash function ID is 0 for the special MD5+SHA-1, + * or 2 to 6 for the SHA family). + * + * - If ECDSA is supported with hash function of ID `x`, then bit `8+x` + * is set. + * + * - Newer algorithms are symbolic 16-bit identifiers that do not + * represent signature algorithm and hash function separately. If + * the TLS-level identifier is `0x0800+x` for a `x` in the 0..15 + * range, then bit `16+x` is set. + * + * "New algorithms" are currently defined only in draft documents, so + * this support is subject to possible change. Right now (early 2017), + * this maps ed25519 (EdDSA on Curve25519) to bit 23, and ed448 (EdDSA + * on Curve448) to bit 24. If the identifiers on the wire change in + * future document, then the decoding mechanism in BearSSL will be + * amended to keep mapping ed25519 and ed448 on bits 23 and 24, + * respectively. Mapping of other new algorithms (e.g. RSA/PSS) is not + * guaranteed yet. + * + * \param cc client context. + * \return the server-supported hash functions and signature algorithms. + */ +static inline uint32_t +br_ssl_client_get_server_hashes(const br_ssl_client_context *cc) +{ + return cc->hashes; +} + +/** + * \brief Get the server key curve. + * + * This function returns the ID for the curve used by the server's public + * key. This is set when the server's certificate chain is processed; + * this value is 0 if the server's key is not an EC key. + * + * \return the server's public key curve ID, or 0. + */ +static inline int +br_ssl_client_get_server_curve(const br_ssl_client_context *cc) +{ + return cc->server_curve; +} + +/* + * Each br_ssl_client_init_xxx() function sets the list of supported + * cipher suites and used implementations, as specified by the profile + * name 'xxx'. Defined profile names are: + * + * full all supported versions and suites; constant-time implementations + * TODO: add other profiles + */ + +/** + * \brief SSL client profile: full. + * + * This function initialises the provided SSL client context with + * all supported algorithms and cipher suites. It also initialises + * a companion X.509 validation engine with all supported algorithms, + * and the provided trust anchors; the X.509 engine will be used by + * the client context to validate the server's certificate. + * + * \param cc client context to initialise. + * \param xc X.509 validation context to initialise. + * \param trust_anchors trust anchors to use. + * \param trust_anchors_num number of trust anchors. + */ +void br_ssl_client_init_full(br_ssl_client_context *cc, + br_x509_minimal_context *xc, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); + +/** + * \brief SSL client profile: TLS1.2 minus weak ciphers + * + * This function initialises the provided SSL client context with + * most (see brief) supported algorithms and cipher suites. It also initialises + * a companion X.509 validation engine with most supported algorithms, + * and the provided trust anchors; the X.509 engine will be used by + * the client context to validate the server's certificate. + * + * \param cc client context to initialise. + * \param xc X.509 validation context to initialise. + * \param trust_anchors trust anchors to use. + * \param trust_anchors_num number of trust anchors. + */ +void br_client_init_TLS12_only(br_ssl_client_context *cc, + br_x509_minimal_context *xc, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); + +/** + * \brief Clear the complete contents of a SSL client context. + * + * Everything is cleared, including the reference to the configured buffer, + * implementations, cipher suites and state. This is a preparatory step + * to assembling a custom profile. + * + * \param cc client context to clear. + */ +void br_ssl_client_zero(br_ssl_client_context *cc); + +/** + * \brief Set an externally provided client certificate handler context. + * + * The handler's methods are invoked when the server requests a client + * certificate. + * + * \param cc client context. + * \param pctx certificate handler context (pointer to its vtable field). + */ +static inline void +br_ssl_client_set_client_certificate(br_ssl_client_context *cc, + const br_ssl_client_certificate_class **pctx) +{ + cc->client_auth_vtable = pctx; +} + +/** + * \brief Set the RSA public-key operations implementation. + * + * This will be used to encrypt the pre-master secret with the server's + * RSA public key (RSA-encryption cipher suites only). + * + * \param cc client context. + * \param irsapub RSA public-key encryption implementation. + */ +static inline void +br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub) +{ + cc->irsapub = irsapub; +} + +/** + * \brief Set the "default" RSA implementation for public-key operations. + * + * This sets the RSA implementation in the client context (for encrypting + * the pre-master secret, in `TLS_RSA_*` cipher suites) to the fastest + * available on the current platform. + * + * \param cc client context. + */ +void br_ssl_client_set_default_rsapub(br_ssl_client_context *cc); + +/** + * \brief Set the minimum ClientHello length (RFC 7685 padding). + * + * If this value is set and the ClientHello would be shorter, then + * the Pad ClientHello extension will be added with enough padding bytes + * to reach the target size. Because of the extension header, the resulting + * size will sometimes be slightly more than `len` bytes if the target + * size cannot be exactly met. + * + * The target length relates to the _contents_ of the ClientHello, not + * counting its 4-byte header. For instance, if `len` is set to 512, + * then the padding will bring the ClientHello size to 516 bytes with its + * header, and 521 bytes when counting the 5-byte record header. + * + * \param cc client context. + * \param len minimum ClientHello length (in bytes). + */ +static inline void +br_ssl_client_set_min_clienthello_len(br_ssl_client_context *cc, uint16_t len) +{ + cc->min_clienthello_len = len; +} + +/** + * \brief Prepare or reset a client context for a new connection. + * + * The `server_name` parameter is used to fill the SNI extension; the + * X.509 "minimal" engine will also match that name against the server + * names included in the server's certificate. If the parameter is + * `NULL` then no SNI extension will be sent, and the X.509 "minimal" + * engine (if used for server certificate validation) will not check + * presence of any specific name in the received certificate. + * + * Therefore, setting the `server_name` to `NULL` shall be reserved + * to cases where alternate or additional methods are used to ascertain + * that the right server public key is used (e.g. a "known key" model). + * + * If `resume_session` is non-zero and the context was previously used + * then the session parameters may be reused (depending on whether the + * server previously sent a non-empty session ID, and accepts the session + * resumption). The session parameters for session resumption can also + * be set explicitly with `br_ssl_engine_set_session_parameters()`. + * + * On failure, the context is marked as failed, and this function + * returns 0. A possible failure condition is when no initial entropy + * was injected, and none could be obtained from the OS (either OS + * randomness gathering is not supported, or it failed). + * + * \param cc client context. + * \param server_name target server name, or `NULL`. + * \param resume_session non-zero to try session resumption. + * \return 0 on failure, 1 on success. + */ +int br_ssl_client_reset(br_ssl_client_context *cc, + const char *server_name, int resume_session); + +/** + * \brief Forget any session in the context. + * + * This means that the next handshake that uses this context will + * necessarily be a full handshake (this applies both to new connections + * and to renegotiations). + * + * \param cc client context. + */ +static inline void +br_ssl_client_forget_session(br_ssl_client_context *cc) +{ + cc->eng.session.session_id_len = 0; +} + +/** + * \brief Set client certificate chain and key (single RSA case). + * + * This function sets a client certificate chain, that the client will + * send to the server whenever a client certificate is requested. This + * certificate uses an RSA public key; the corresponding private key is + * invoked for authentication. Trust anchor names sent by the server are + * ignored. + * + * The provided chain and private key are linked in the client context; + * they must remain valid as long as they may be used, i.e. normally + * for the duration of the connection, since they might be invoked + * again upon renegotiations. + * + * \param cc SSL client context. + * \param chain client certificate chain (SSL order: EE comes first). + * \param chain_len client chain length (number of certificates). + * \param sk client private key. + * \param irsasign RSA signature implementation (PKCS#1 v1.5). + */ +void br_ssl_client_set_single_rsa(br_ssl_client_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign); + +/* + * \brief Set the client certificate chain and key (single EC case). + * + * This function sets a client certificate chain, that the client will + * send to the server whenever a client certificate is requested. This + * certificate uses an EC public key; the corresponding private key is + * invoked for authentication. Trust anchor names sent by the server are + * ignored. + * + * The provided chain and private key are linked in the client context; + * they must remain valid as long as they may be used, i.e. normally + * for the duration of the connection, since they might be invoked + * again upon renegotiations. + * + * The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`. The `BR_KEYTYPE_KEYX` + * value allows full static ECDH, while the `BR_KEYTYPE_SIGN` value + * allows ECDSA signatures. If ECDSA signatures are used, then an ECDSA + * signature implementation must be provided; otherwise, the `iecdsa` + * parameter may be 0. + * + * The `cert_issuer_key_type` value is either `BR_KEYTYPE_RSA` or + * `BR_KEYTYPE_EC`; it is the type of the public key used the the CA + * that issued (signed) the client certificate. That value is used with + * full static ECDH: support of the certificate by the server depends + * on how the certificate was signed. (Note: when using TLS 1.2, this + * parameter is ignored; but its value matters for TLS 1.0 and 1.1.) + * + * \param cc server context. + * \param chain server certificate chain to send. + * \param chain_len chain length (number of certificates). + * \param sk server private key (EC). + * \param allowed_usages allowed private key usages. + * \param cert_issuer_key_type issuing CA's key type. + * \param iec EC core implementation. + * \param iecdsa ECDSA signature implementation ("asn1" format). + */ +void br_ssl_client_set_single_ec(br_ssl_client_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk, unsigned allowed_usages, + unsigned cert_issuer_key_type, + const br_ec_impl *iec, br_ecdsa_sign iecdsa); + +/** + * \brief Type for a "translated cipher suite", as an array of two + * 16-bit integers. + * + * The first element is the cipher suite identifier (as used on the wire). + * The second element is the concatenation of four 4-bit elements which + * characterise the cipher suite contents. In most to least significant + * order, these 4-bit elements are: + * + * - Bits 12 to 15: key exchange + server key type + * + * | val | symbolic constant | suite type | details | + * | :-- | :----------------------- | :---------- | :----------------------------------------------- | + * | 0 | `BR_SSLKEYX_RSA` | RSA | RSA key exchange, key is RSA (encryption) | + * | 1 | `BR_SSLKEYX_ECDHE_RSA` | ECDHE_RSA | ECDHE key exchange, key is RSA (signature) | + * | 2 | `BR_SSLKEYX_ECDHE_ECDSA` | ECDHE_ECDSA | ECDHE key exchange, key is EC (signature) | + * | 3 | `BR_SSLKEYX_ECDH_RSA` | ECDH_RSA | Key is EC (key exchange), cert signed with RSA | + * | 4 | `BR_SSLKEYX_ECDH_ECDSA` | ECDH_ECDSA | Key is EC (key exchange), cert signed with ECDSA | + * + * - Bits 8 to 11: symmetric encryption algorithm + * + * | val | symbolic constant | symmetric encryption | key strength (bits) | + * | :-- | :--------------------- | :------------------- | :------------------ | + * | 0 | `BR_SSLENC_3DES_CBC` | 3DES/CBC | 168 | + * | 1 | `BR_SSLENC_AES128_CBC` | AES-128/CBC | 128 | + * | 2 | `BR_SSLENC_AES256_CBC` | AES-256/CBC | 256 | + * | 3 | `BR_SSLENC_AES128_GCM` | AES-128/GCM | 128 | + * | 4 | `BR_SSLENC_AES256_GCM` | AES-256/GCM | 256 | + * | 5 | `BR_SSLENC_CHACHA20` | ChaCha20/Poly1305 | 256 | + * + * - Bits 4 to 7: MAC algorithm + * + * | val | symbolic constant | MAC type | details | + * | :-- | :----------------- | :----------- | :------------------------------------ | + * | 0 | `BR_SSLMAC_AEAD` | AEAD | No dedicated MAC (encryption is AEAD) | + * | 2 | `BR_SSLMAC_SHA1` | HMAC/SHA-1 | Value matches `br_sha1_ID` | + * | 4 | `BR_SSLMAC_SHA256` | HMAC/SHA-256 | Value matches `br_sha256_ID` | + * | 5 | `BR_SSLMAC_SHA384` | HMAC/SHA-384 | Value matches `br_sha384_ID` | + * + * - Bits 0 to 3: hash function for PRF when used with TLS-1.2 + * + * | val | symbolic constant | hash function | details | + * | :-- | :----------------- | :------------ | :----------------------------------- | + * | 4 | `BR_SSLPRF_SHA256` | SHA-256 | Value matches `br_sha256_ID` | + * | 5 | `BR_SSLPRF_SHA384` | SHA-384 | Value matches `br_sha384_ID` | + * + * For instance, cipher suite `TLS_RSA_WITH_AES_128_GCM_SHA256` has + * standard identifier 0x009C, and is translated to 0x0304, for, in + * that order: RSA key exchange (0), AES-128/GCM (3), AEAD integrity (0), + * SHA-256 in the TLS PRF (4). + */ +typedef uint16_t br_suite_translated[2]; + +#ifndef BR_DOXYGEN_IGNORE +/* + * Constants are already documented in the br_suite_translated type. + */ + +#define BR_SSLKEYX_RSA 0 +#define BR_SSLKEYX_ECDHE_RSA 1 +#define BR_SSLKEYX_ECDHE_ECDSA 2 +#define BR_SSLKEYX_ECDH_RSA 3 +#define BR_SSLKEYX_ECDH_ECDSA 4 + +#define BR_SSLENC_3DES_CBC 0 +#define BR_SSLENC_AES128_CBC 1 +#define BR_SSLENC_AES256_CBC 2 +#define BR_SSLENC_AES128_GCM 3 +#define BR_SSLENC_AES256_GCM 4 +#define BR_SSLENC_CHACHA20 5 + +#define BR_SSLMAC_AEAD 0 +#define BR_SSLMAC_SHA1 br_sha1_ID +#define BR_SSLMAC_SHA256 br_sha256_ID +#define BR_SSLMAC_SHA384 br_sha384_ID + +#define BR_SSLPRF_SHA256 br_sha256_ID +#define BR_SSLPRF_SHA384 br_sha384_ID + +#endif + +/* + * Pre-declaration for the SSL server context. + */ +typedef struct br_ssl_server_context_ br_ssl_server_context; + +/** + * \brief Type for the server policy choices, taken after analysis of + * the client message (ClientHello). + */ +typedef struct { + /** + * \brief Cipher suite to use with that client. + */ + uint16_t cipher_suite; + + /** + * \brief Hash function or algorithm for signing the ServerKeyExchange. + * + * This parameter is ignored for `TLS_RSA_*` and `TLS_ECDH_*` + * cipher suites; it is used only for `TLS_ECDHE_*` suites, in + * which the server _signs_ the ephemeral EC Diffie-Hellman + * parameters sent to the client. + * + * This identifier must be one of the following values: + * + * - `0xFF00 + id`, where `id` is a hash function identifier + * (0 for MD5+SHA-1, or 2 to 6 for one of the SHA functions); + * + * - a full 16-bit identifier, lower than `0xFF00`. + * + * If the first option is used, then the SSL engine will + * compute the hash of the data that is to be signed, with the + * designated hash function. The `do_sign()` method will be + * invoked with that hash value provided in the the `data` + * buffer. + * + * If the second option is used, then the SSL engine will NOT + * compute a hash on the data; instead, it will provide the + * to-be-signed data itself in `data`, i.e. the concatenation of + * the client random, server random, and encoded ECDH + * parameters. Furthermore, with TLS-1.2 and later, the 16-bit + * identifier will be used "as is" in the protocol, in the + * SignatureAndHashAlgorithm; for instance, `0x0401` stands for + * RSA PKCS#1 v1.5 signature (the `01`) with SHA-256 as hash + * function (the `04`). + * + * Take care that with TLS 1.0 and 1.1, the hash function is + * constrainted by the protocol: RSA signature must use + * MD5+SHA-1 (so use `0xFF00`), while ECDSA must use SHA-1 + * (`0xFF02`). Since TLS 1.0 and 1.1 don't include a + * SignatureAndHashAlgorithm field in their ServerKeyExchange + * messages, any value below `0xFF00` will be usable to send the + * raw ServerKeyExchange data to the `do_sign()` callback, but + * that callback must still follow the protocol requirements + * when generating the signature. + */ + unsigned algo_id; + + /** + * \brief Certificate chain to send to the client. + * + * This is an array of `br_x509_certificate` objects, each + * normally containing a DER-encoded certificate. The server + * code does not try to decode these elements. + */ + const br_x509_certificate *chain; + + /** + * \brief Certificate chain length (number of certificates). + */ + size_t chain_len; + +} br_ssl_server_choices; + +/** + * \brief Class type for a policy handler (server side). + * + * A policy handler selects the policy parameters for a connection + * (cipher suite and other algorithms, and certificate chain to send to + * the client); it also performs the server-side computations involving + * its permanent private key. + * + * The SSL server engine will invoke first `choose()`, once the + * ClientHello message has been received, then either `do_keyx()` + * `do_sign()`, depending on the cipher suite. + */ +typedef struct br_ssl_server_policy_class_ br_ssl_server_policy_class; +struct br_ssl_server_policy_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Select algorithms and certificates for this connection. + * + * This callback function shall fill the provided `choices` + * structure with the policy choices for this connection. This + * entails selecting the cipher suite, hash function for signing + * the ServerKeyExchange (applicable only to ECDHE cipher suites), + * and certificate chain to send. + * + * The callback receives a pointer to the server context that + * contains the relevant data. In particular, the functions + * `br_ssl_server_get_client_suites()`, + * `br_ssl_server_get_client_hashes()` and + * `br_ssl_server_get_client_curves()` can be used to obtain + * the cipher suites, hash functions and elliptic curves + * supported by both the client and server, respectively. The + * `br_ssl_engine_get_version()` and `br_ssl_engine_get_server_name()` + * functions yield the protocol version and requested server name + * (SNI), respectively. + * + * This function may modify its context structure (`pctx`) in + * arbitrary ways to keep track of its own choices. + * + * This function shall return 1 if appropriate policy choices + * could be made, or 0 if this connection cannot be pursued. + * + * \param pctx policy context. + * \param cc SSL server context. + * \param choices destination structure for the policy choices. + * \return 1 on success, 0 on error. + */ + int (*choose)(const br_ssl_server_policy_class **pctx, + const br_ssl_server_context *cc, + br_ssl_server_choices *choices); + + /** + * \brief Perform key exchange (server part). + * + * This callback is invoked to perform the server-side cryptographic + * operation for a key exchange that is not ECDHE. This callback + * uses the private key. + * + * **For RSA key exchange**, the provided `data` (of length `*len` + * bytes) shall be decrypted with the server's private key, and + * the 48-byte premaster secret copied back to the first 48 bytes + * of `data`. + * + * - The caller makes sure that `*len` is at least 59 bytes. + * + * - This callback MUST check that the provided length matches + * that of the key modulus; it shall report an error otherwise. + * + * - If the length matches that of the RSA key modulus, then + * processing MUST be constant-time, even if decryption fails, + * or the padding is incorrect, or the plaintext message length + * is not exactly 48 bytes. + * + * - This callback needs not check the two first bytes of the + * obtained pre-master secret (the caller will do that). + * + * - If an error is reported (0), then what the callback put + * in the first 48 bytes of `data` is unimportant (the caller + * will use random bytes instead). + * + * **For ECDH key exchange**, the provided `data` (of length `*len` + * bytes) is the elliptic curve point from the client. The + * callback shall multiply it with its private key, and store + * the resulting X coordinate in `data`, starting at offset 0, + * and set `*len` to the length of the X coordinate. + * + * - If the input array does not have the proper length for + * an encoded curve point, then an error (0) shall be reported. + * + * - If the input array has the proper length, then processing + * MUST be constant-time, even if the data is not a valid + * encoded point. + * + * - This callback MUST check that the input point is valid. + * + * Returned value is 1 on success, 0 on error. + * + * \param pctx policy context. + * \param data key exchange data from the client. + * \param len key exchange data length (in bytes). + * \return 1 on success, 0 on error. + */ + uint32_t (*do_keyx)(const br_ssl_server_policy_class **pctx, + unsigned char *data, size_t *len); + + /** + * \brief Perform a signature (for a ServerKeyExchange message). + * + * This callback function is invoked for ECDHE cipher suites. On + * input, the hash value or message to sign is in `data`, of + * size `hv_len`; the involved hash function or algorithm is + * identified by `algo_id`. The signature shall be computed and + * written back into `data`; the total size of that buffer is + * `len` bytes. + * + * This callback shall verify that the signature length does not + * exceed `len` bytes, and abstain from writing the signature if + * it does not fit. + * + * The `algo_id` value matches that which was written in the + * `choices` structures by the `choose()` callback. This will be + * one of the following: + * + * - `0xFF00 + id` for a hash function identifier `id`. In + * that case, the `data` buffer contains a hash value + * already computed over the data that is to be signed, + * of length `hv_len`. The `id` may be 0 to designate the + * special MD5+SHA-1 concatenation (old-style RSA signing). + * + * - Another value, lower than `0xFF00`. The `data` buffer + * then contains the raw, non-hashed data to be signed + * (concatenation of the client and server randoms and + * ECDH parameters). The callback is responsible to apply + * any relevant hashing as part of the signing process. + * + * Returned value is the signature length (in bytes), or 0 on error. + * + * \param pctx policy context. + * \param algo_id hash function / algorithm identifier. + * \param data input/output buffer (message/hash, then signature). + * \param hv_len hash value or message length (in bytes). + * \param len total buffer length (in bytes). + * \return signature length (in bytes) on success, or 0 on error. + */ + size_t (*do_sign)(const br_ssl_server_policy_class **pctx, + unsigned algo_id, + unsigned char *data, size_t hv_len, size_t len); +}; + +/** + * \brief A single-chain RSA policy handler. + * + * This policy context uses a single certificate chain, and a RSA + * private key. The context can be restricted to only signatures or + * only key exchange. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_server_policy_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_rsa_private_key *sk; + unsigned allowed_usages; + br_rsa_private irsacore; + br_rsa_pkcs1_sign irsasign; +#endif +} br_ssl_server_policy_rsa_context; + +/** + * \brief A single-chain EC policy handler. + * + * This policy context uses a single certificate chain, and an EC + * private key. The context can be restricted to only signatures or + * only key exchange. + * + * Due to how TLS is defined, this context must be made aware whether + * the server certificate was itself signed with RSA or ECDSA. The code + * does not try to decode the certificate to obtain that information. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_server_policy_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_ec_private_key *sk; + unsigned allowed_usages; + unsigned cert_issuer_key_type; + const br_multihash_context *mhash; + const br_ec_impl *iec; + br_ecdsa_sign iecdsa; +#endif +} br_ssl_server_policy_ec_context; + +/** + * \brief Class type for a session parameter cache. + * + * Session parameters are saved in the cache with `save()`, and + * retrieved with `load()`. The cache implementation can apply any + * storage and eviction strategy that it sees fit. The SSL server + * context that performs the request is provided, so that its + * functionalities may be used by the implementation (e.g. hash + * functions or random number generation). + */ +typedef struct br_ssl_session_cache_class_ br_ssl_session_cache_class; +struct br_ssl_session_cache_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Record a session. + * + * This callback should record the provided session parameters. + * The `params` structure is transient, so its contents shall + * be copied into the cache. The session ID has been randomly + * generated and always has length exactly 32 bytes. + * + * \param ctx session cache context. + * \param server_ctx SSL server context. + * \param params session parameters to save. + */ + void (*save)(const br_ssl_session_cache_class **ctx, + br_ssl_server_context *server_ctx, + const br_ssl_session_parameters *params); + + /** + * \brief Lookup a session in the cache. + * + * The session ID to lookup is in `params` and always has length + * exactly 32 bytes. If the session parameters are found in the + * cache, then the parameters shall be copied into the `params` + * structure. Returned value is 1 on successful lookup, 0 + * otherwise. + * + * \param ctx session cache context. + * \param server_ctx SSL server context. + * \param params destination for session parameters. + * \return 1 if found, 0 otherwise. + */ + int (*load)(const br_ssl_session_cache_class **ctx, + br_ssl_server_context *server_ctx, + br_ssl_session_parameters *params); +}; + +/** + * \brief Context for a basic cache system. + * + * The system stores session parameters in a buffer provided at + * initialisation time. Each entry uses exactly 100 bytes, and + * buffer sizes up to 4294967295 bytes are supported. + * + * Entries are evicted with a LRU (Least Recently Used) policy. A + * search tree is maintained to keep lookups fast even with large + * caches. + * + * Apart from the first field (vtable pointer), the structure + * contents are opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_session_cache_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + unsigned char *store; + size_t store_len, store_ptr; + unsigned char index_key[32]; + const br_hash_class *hash; + int init_done; + uint32_t head, tail, root; +#endif +} br_ssl_session_cache_lru; + +/** + * \brief Initialise a LRU session cache with the provided storage space. + * + * The provided storage space must remain valid as long as the cache + * is used. Arbitrary lengths are supported, up to 4294967295 bytes; + * each entry uses up exactly 100 bytes. + * + * \param cc session cache context. + * \param store storage space for cached entries. + * \param store_len storage space length (in bytes). + */ +void br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc, + unsigned char *store, size_t store_len); + +/** + * \brief Forget an entry in an LRU session cache. + * + * The session cache context must have been initialised. The entry + * with the provided session ID (of exactly 32 bytes) is looked for + * in the cache; if located, it is disabled. + * + * \param cc session cache context. + * \param id session ID to forget. + */ +void br_ssl_session_cache_lru_forget( + br_ssl_session_cache_lru *cc, const unsigned char *id); + +/** + * \brief Context structure for a SSL server. + * + * The first field (called `eng`) is the SSL engine; all functions that + * work on a `br_ssl_engine_context` structure shall take as parameter + * a pointer to that field. The other structure fields are opaque and + * must not be accessed directly. + */ +struct br_ssl_server_context_ { + /** + * \brief The encapsulated engine context. + */ + br_ssl_engine_context eng; + +#ifndef BR_DOXYGEN_IGNORE + /* + * Maximum version from the client. + */ + uint16_t client_max_version; + + /* + * Session cache. + */ + const br_ssl_session_cache_class **cache_vtable; + + /* + * Translated cipher suites supported by the client. The list + * is trimmed to include only the cipher suites that the + * server also supports; they are in the same order as in the + * client message. + */ + br_suite_translated client_suites[BR_MAX_CIPHER_SUITES]; + unsigned char client_suites_num; + + /* + * Hash functions supported by the client, with ECDSA and RSA + * (bit mask). For hash function with id 'x', set bit index is + * x for RSA, x+8 for ECDSA. For newer algorithms, with ID + * 0x08**, bit 16+k is set for algorithm 0x0800+k. + */ + uint32_t hashes; + + /* + * Curves supported by the client (bit mask, for named curves). + */ + uint32_t curves; + + /* + * Context for chain handler. + */ + const br_ssl_server_policy_class **policy_vtable; + uint16_t sign_hash_id; + + /* + * For the core handlers, thus avoiding (in most cases) the + * need for an externally provided policy context. + */ + union { + const br_ssl_server_policy_class *vtable; + br_ssl_server_policy_rsa_context single_rsa; + br_ssl_server_policy_ec_context single_ec; + } chain_handler; + + /* + * Buffer for the ECDHE private key. + */ + unsigned char ecdhe_key[70]; + size_t ecdhe_key_len; + + /* + * Trust anchor names for client authentication. "ta_names" and + * "tas" cannot be both non-NULL. + */ + const br_x500_name *ta_names; + const br_x509_trust_anchor *tas; + size_t num_tas; + size_t cur_dn_index; + const unsigned char *cur_dn; + size_t cur_dn_len; + + /* + * Buffer for the hash value computed over all handshake messages + * prior to CertificateVerify, and identifier for the hash function. + */ + unsigned char hash_CV[64]; + size_t hash_CV_len; + int hash_CV_id; + + /* + * Server-specific implementations. + * (none for now) + */ +#endif +}; + +/* + * Each br_ssl_server_init_xxx() function sets the list of supported + * cipher suites and used implementations, as specified by the profile + * name 'xxx'. Defined profile names are: + * + * full_rsa all supported algorithm, server key type is RSA + * full_ec all supported algorithm, server key type is EC + * TODO: add other profiles + * + * Naming scheme for "minimal" profiles: min123 + * + * -- character 1: key exchange + * r = RSA + * e = ECDHE_RSA + * f = ECDHE_ECDSA + * u = ECDH_RSA + * v = ECDH_ECDSA + * -- character 2: version / PRF + * 0 = TLS 1.0 / 1.1 with MD5+SHA-1 + * 2 = TLS 1.2 with SHA-256 + * 3 = TLS 1.2 with SHA-384 + * -- character 3: encryption + * a = AES/CBC + * d = 3DES/CBC + * g = AES/GCM + * c = ChaCha20+Poly1305 + */ + +/** + * \brief SSL server profile: full_rsa. + * + * This function initialises the provided SSL server context with + * all supported algorithms and cipher suites that rely on a RSA + * key pair. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ +void br_ssl_server_init_full_rsa(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: full_ec. + * + * This function initialises the provided SSL server context with + * all supported algorithms and cipher suites that rely on an EC + * key pair. + * + * The key type of the CA that issued the server's certificate must + * be provided, since it matters for ECDH cipher suites (ECDH_RSA + * suites require a RSA-powered CA). The key type is either + * `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len chain length (number of certificates). + * \param cert_issuer_key_type certificate issuer's key type. + * \param sk EC private key. + */ +void br_ssl_server_init_full_ec(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + unsigned cert_issuer_key_type, const br_ec_private_key *sk); + +/** + * \brief SSL server profile: minr2g. + * + * This profile uses only TLS_RSA_WITH_AES_128_GCM_SHA256. Server key is + * RSA, and RSA key exchange is used (not forward secure, but uses little + * CPU in the client). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ +void br_ssl_server_init_minr2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: mine2g. + * + * This profile uses only TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. Server key + * is RSA, and ECDHE key exchange is used. This suite provides forward + * security, with a higher CPU expense on the client, and a somewhat + * larger code footprint (compared to "minr2g"). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ +void br_ssl_server_init_mine2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: minf2g. + * + * This profile uses only TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDHE key exchange is used. This suite provides + * forward security, with a higher CPU expense on the client and server + * (by a factor of about 3 to 4), and a somewhat larger code footprint + * (compared to "minu2g" and "minv2g"). + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ +void br_ssl_server_init_minf2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk); + +/** + * \brief SSL server profile: minu2g. + * + * This profile uses only TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDH key exchange is used; the issuing CA used + * a RSA key. + * + * The "minu2g" and "minv2g" profiles do not provide forward secrecy, + * but are the lightest on the server (for CPU usage), and are rather + * inexpensive on the client as well. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ +void br_ssl_server_init_minu2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk); + +/** + * \brief SSL server profile: minv2g. + * + * This profile uses only TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256. + * Server key is EC, and ECDH key exchange is used; the issuing CA used + * an EC key. + * + * The "minu2g" and "minv2g" profiles do not provide forward secrecy, + * but are the lightest on the server (for CPU usage), and are rather + * inexpensive on the client as well. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ +void br_ssl_server_init_minv2g(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk); + +/** + * \brief SSL server profile: mine2c. + * + * This profile uses only TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256. + * Server key is RSA, and ECDHE key exchange is used. This suite + * provides forward security. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk RSA private key. + */ +void br_ssl_server_init_mine2c(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk); + +/** + * \brief SSL server profile: minf2c. + * + * This profile uses only TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256. + * Server key is EC, and ECDHE key exchange is used. This suite provides + * forward security. + * + * \param cc server context to initialise. + * \param chain server certificate chain. + * \param chain_len certificate chain length (number of certificate). + * \param sk EC private key. + */ +void br_ssl_server_init_minf2c(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk); + +/** + * \brief Get the supported client suites. + * + * This function shall be called only after the ClientHello has been + * processed, typically from the policy engine. The returned array + * contains the cipher suites that are supported by both the client + * and the server; these suites are in client preference order, unless + * the `BR_OPT_ENFORCE_SERVER_PREFERENCES` flag was set, in which case + * they are in server preference order. + * + * The suites are _translated_, which means that each suite is given + * as two 16-bit integers: the standard suite identifier, and its + * translated version, broken down into its individual components, + * as explained with the `br_suite_translated` type. + * + * The returned array is allocated in the context and will be rewritten + * by each handshake. + * + * \param cc server context. + * \param num receives the array size (number of suites). + * \return the translated common cipher suites, in preference order. + */ +static inline const br_suite_translated * +br_ssl_server_get_client_suites(const br_ssl_server_context *cc, size_t *num) +{ + *num = cc->client_suites_num; + return cc->client_suites; +} + +/** + * \brief Get the hash functions and signature algorithms supported by + * the client. + * + * This value is a bit field: + * + * - If RSA (PKCS#1 v1.5) is supported with hash function of ID `x`, + * then bit `x` is set (hash function ID is 0 for the special MD5+SHA-1, + * or 2 to 6 for the SHA family). + * + * - If ECDSA is supported with hash function of ID `x`, then bit `8+x` + * is set. + * + * - Newer algorithms are symbolic 16-bit identifiers that do not + * represent signature algorithm and hash function separately. If + * the TLS-level identifier is `0x0800+x` for a `x` in the 0..15 + * range, then bit `16+x` is set. + * + * "New algorithms" are currently defined only in draft documents, so + * this support is subject to possible change. Right now (early 2017), + * this maps ed25519 (EdDSA on Curve25519) to bit 23, and ed448 (EdDSA + * on Curve448) to bit 24. If the identifiers on the wire change in + * future document, then the decoding mechanism in BearSSL will be + * amended to keep mapping ed25519 and ed448 on bits 23 and 24, + * respectively. Mapping of other new algorithms (e.g. RSA/PSS) is not + * guaranteed yet. + * + * \param cc server context. + * \return the client-supported hash functions and signature algorithms. + */ +static inline uint32_t +br_ssl_server_get_client_hashes(const br_ssl_server_context *cc) +{ + return cc->hashes; +} + +/** + * \brief Get the elliptic curves supported by the client. + * + * This is a bit field (bit x is set if curve of ID x is supported). + * + * \param cc server context. + * \return the client-supported elliptic curves. + */ +static inline uint32_t +br_ssl_server_get_client_curves(const br_ssl_server_context *cc) +{ + return cc->curves; +} + +/** + * \brief Clear the complete contents of a SSL server context. + * + * Everything is cleared, including the reference to the configured buffer, + * implementations, cipher suites and state. This is a preparatory step + * to assembling a custom profile. + * + * \param cc server context to clear. + */ +void br_ssl_server_zero(br_ssl_server_context *cc); + +/** + * \brief Set an externally provided policy context. + * + * The policy context's methods are invoked to decide the cipher suite + * and certificate chain, and to perform operations involving the server's + * private key. + * + * \param cc server context. + * \param pctx policy context (pointer to its vtable field). + */ +static inline void +br_ssl_server_set_policy(br_ssl_server_context *cc, + const br_ssl_server_policy_class **pctx) +{ + cc->policy_vtable = pctx; +} + +/** + * \brief Set the server certificate chain and key (single RSA case). + * + * This function uses a policy context included in the server context. + * It configures use of a single server certificate chain with a RSA + * private key. The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`; this enables or disables + * the corresponding cipher suites (i.e. `TLS_RSA_*` use the RSA key for + * key exchange, while `TLS_ECDHE_RSA_*` use the RSA key for signatures). + * + * \param cc server context. + * \param chain server certificate chain to send to the client. + * \param chain_len chain length (number of certificates). + * \param sk server private key (RSA). + * \param allowed_usages allowed private key usages. + * \param irsacore RSA core implementation. + * \param irsasign RSA signature implementation (PKCS#1 v1.5). + */ +void br_ssl_server_set_single_rsa(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk, unsigned allowed_usages, + br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign); + +/** + * \brief Set the server certificate chain and key (single EC case). + * + * This function uses a policy context included in the server context. + * It configures use of a single server certificate chain with an EC + * private key. The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`; this enables or disables + * the corresponding cipher suites (i.e. `TLS_ECDH_*` use the EC key for + * key exchange, while `TLS_ECDHE_ECDSA_*` use the EC key for signatures). + * + * In order to support `TLS_ECDH_*` cipher suites (non-ephemeral ECDH), + * the algorithm type of the key used by the issuing CA to sign the + * server's certificate must be provided, as `cert_issuer_key_type` + * parameter (this value is either `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`). + * + * \param cc server context. + * \param chain server certificate chain to send. + * \param chain_len chain length (number of certificates). + * \param sk server private key (EC). + * \param allowed_usages allowed private key usages. + * \param cert_issuer_key_type issuing CA's key type. + * \param iec EC core implementation. + * \param iecdsa ECDSA signature implementation ("asn1" format). + */ +void br_ssl_server_set_single_ec(br_ssl_server_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk, unsigned allowed_usages, + unsigned cert_issuer_key_type, + const br_ec_impl *iec, br_ecdsa_sign iecdsa); + +/** + * \brief Activate client certificate authentication. + * + * The trust anchor encoded X.500 names (DN) to send to the client are + * provided. A client certificate will be requested and validated through + * the X.509 validator configured in the SSL engine. If `num` is 0, then + * client certificate authentication is disabled. + * + * If the client does not send a certificate, or on validation failure, + * the handshake aborts. Unauthenticated clients can be tolerated by + * setting the `BR_OPT_TOLERATE_NO_CLIENT_AUTH` flag. + * + * The provided array is linked in, not copied, so that pointer must + * remain valid as long as anchor names may be used. + * + * \param cc server context. + * \param ta_names encoded trust anchor names. + * \param num number of encoded trust anchor names. + */ +static inline void +br_ssl_server_set_trust_anchor_names(br_ssl_server_context *cc, + const br_x500_name *ta_names, size_t num) +{ + cc->ta_names = ta_names; + cc->tas = NULL; + cc->num_tas = num; +} + +/** + * \brief Activate client certificate authentication. + * + * This is a variant for `br_ssl_server_set_trust_anchor_names()`: the + * trust anchor names are provided not as an array of stand-alone names + * (`br_x500_name` structures), but as an array of trust anchors + * (`br_x509_trust_anchor` structures). The server engine itself will + * only use the `dn` field of each trust anchor. This is meant to allow + * defining a single array of trust anchors, to be used here and in the + * X.509 validation engine itself. + * + * The provided array is linked in, not copied, so that pointer must + * remain valid as long as anchor names may be used. + * + * \param cc server context. + * \param tas trust anchors (only names are used). + * \param num number of trust anchors. + */ +static inline void +br_ssl_server_set_trust_anchor_names_alt(br_ssl_server_context *cc, + const br_x509_trust_anchor *tas, size_t num) +{ + cc->ta_names = NULL; + cc->tas = tas; + cc->num_tas = num; +} + +/** + * \brief Configure the cache for session parameters. + * + * The cache context is provided as a pointer to its first field (vtable + * pointer). + * + * \param cc server context. + * \param vtable session cache context. + */ +static inline void +br_ssl_server_set_cache(br_ssl_server_context *cc, + const br_ssl_session_cache_class **vtable) +{ + cc->cache_vtable = vtable; +} + +/** + * \brief Prepare or reset a server context for handling an incoming client. + * + * \param cc server context. + * \return 1 on success, 0 on error. + */ +int br_ssl_server_reset(br_ssl_server_context *cc); + +/* ===================================================================== */ + +/* + * Context for the simplified I/O context. The transport medium is accessed + * through the low_read() and low_write() callback functions, each with + * its own opaque context pointer. + * + * low_read() read some bytes, at most 'len' bytes, into data[]. The + * returned value is the number of read bytes, or -1 on error. + * The 'len' parameter is guaranteed never to exceed 20000, + * so the length always fits in an 'int' on all platforms. + * + * low_write() write up to 'len' bytes, to be read from data[]. The + * returned value is the number of written bytes, or -1 on + * error. The 'len' parameter is guaranteed never to exceed + * 20000, so the length always fits in an 'int' on all + * parameters. + * + * A socket closure (if the transport medium is a socket) should be reported + * as an error (-1). The callbacks shall endeavour to block until at least + * one byte can be read or written; a callback returning 0 at times is + * acceptable, but this normally leads to the callback being immediately + * called again, so the callback should at least always try to block for + * some time if no I/O can take place. + * + * The SSL engine naturally applies some buffering, so the callbacks need + * not apply buffers of their own. + */ +/** + * \brief Context structure for the simplified SSL I/O wrapper. + * + * This structure is initialised with `br_sslio_init()`. Its contents + * are opaque and shall not be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + br_ssl_engine_context *engine; + int (*low_read)(void *read_context, + unsigned char *data, size_t len); + void *read_context; + int (*low_write)(void *write_context, + const unsigned char *data, size_t len); + void *write_context; +#endif +} br_sslio_context; + +/** + * \brief Initialise a simplified I/O wrapper context. + * + * The simplified I/O wrapper offers a simpler read/write API for a SSL + * engine (client or server), using the provided callback functions for + * reading data from, or writing data to, the transport medium. + * + * The callback functions have the following semantics: + * + * - Each callback receives an opaque context value (of type `void *`) + * that the callback may use arbitrarily (or possibly ignore). + * + * - `low_read()` reads at least one byte, at most `len` bytes, from + * the transport medium. Read bytes shall be written in `data`. + * + * - `low_write()` writes at least one byte, at most `len` bytes, unto + * the transport medium. The bytes to write are read from `data`. + * + * - The `len` parameter is never zero, and is always lower than 20000. + * + * - The number of processed bytes (read or written) is returned. Since + * that number is less than 20000, it always fits on an `int`. + * + * - On error, the callbacks return -1. Reaching end-of-stream is an + * error. Errors are permanent: the SSL connection is terminated. + * + * - Callbacks SHOULD NOT return 0. This is tolerated, as long as + * callbacks endeavour to block for some non-negligible amount of + * time until at least one byte can be sent or received (if a + * callback returns 0, then the wrapper invokes it again + * immediately). + * + * - Callbacks MAY return as soon as at least one byte is processed; + * they MAY also insist on reading or writing _all_ requested bytes. + * Since SSL is a self-terminated protocol (each record has a length + * header), this does not change semantics. + * + * - Callbacks need not apply any buffering (for performance) since SSL + * itself uses buffers. + * + * \param ctx wrapper context to initialise. + * \param engine SSL engine to wrap. + * \param low_read callback for reading data from the transport. + * \param read_context context pointer for `low_read()`. + * \param low_write callback for writing data on the transport. + * \param write_context context pointer for `low_write()`. + */ +void br_sslio_init(br_sslio_context *ctx, + br_ssl_engine_context *engine, + int (*low_read)(void *read_context, + unsigned char *data, size_t len), + void *read_context, + int (*low_write)(void *write_context, + const unsigned char *data, size_t len), + void *write_context); + +/** + * \brief Read some application data from a SSL connection. + * + * If `len` is zero, then this function returns 0 immediately. In + * all other cases, it never returns 0. + * + * This call returns only when at least one byte has been obtained. + * Returned value is the number of bytes read, or -1 on error. The + * number of bytes always fits on an 'int' (data from a single SSL/TLS + * record is returned). + * + * On error or SSL closure, this function returns -1. The caller should + * inspect the error status on the SSL engine to distinguish between + * normal closure and error. + * + * \param cc SSL wrapper context. + * \param dst destination buffer for application data. + * \param len maximum number of bytes to obtain. + * \return number of bytes obtained, or -1 on error. + */ +int br_sslio_read(br_sslio_context *cc, void *dst, size_t len); + +/** + * \brief Read application data from a SSL connection. + * + * This calls returns only when _all_ requested `len` bytes are read, + * or an error is reached. Returned value is 0 on success, -1 on error. + * A normal (verified) SSL closure before that many bytes are obtained + * is reported as an error by this function. + * + * \param cc SSL wrapper context. + * \param dst destination buffer for application data. + * \param len number of bytes to obtain. + * \return 0 on success, or -1 on error. + */ +int br_sslio_read_all(br_sslio_context *cc, void *dst, size_t len); + +/** + * \brief Write some application data unto a SSL connection. + * + * If `len` is zero, then this function returns 0 immediately. In + * all other cases, it never returns 0. + * + * This call returns only when at least one byte has been written. + * Returned value is the number of bytes written, or -1 on error. The + * number of bytes always fits on an 'int' (less than 20000). + * + * On error or SSL closure, this function returns -1. The caller should + * inspect the error status on the SSL engine to distinguish between + * normal closure and error. + * + * **Important:** SSL is buffered; a "written" byte is a byte that was + * injected into the wrapped SSL engine, but this does not necessarily mean + * that it has been scheduled for sending. Use `br_sslio_flush()` to + * ensure that all pending data has been sent to the transport medium. + * + * \param cc SSL wrapper context. + * \param src source buffer for application data. + * \param len maximum number of bytes to write. + * \return number of bytes written, or -1 on error. + */ +int br_sslio_write(br_sslio_context *cc, const void *src, size_t len); + +/** + * \brief Write application data unto a SSL connection. + * + * This calls returns only when _all_ requested `len` bytes have been + * written, or an error is reached. Returned value is 0 on success, -1 + * on error. A normal (verified) SSL closure before that many bytes are + * written is reported as an error by this function. + * + * **Important:** SSL is buffered; a "written" byte is a byte that was + * injected into the wrapped SSL engine, but this does not necessarily mean + * that it has been scheduled for sending. Use `br_sslio_flush()` to + * ensure that all pending data has been sent to the transport medium. + * + * \param cc SSL wrapper context. + * \param src source buffer for application data. + * \param len number of bytes to write. + * \return 0 on success, or -1 on error. + */ +int br_sslio_write_all(br_sslio_context *cc, const void *src, size_t len); + +/** + * \brief Flush pending data. + * + * This call makes sure that any buffered application data in the + * provided context (including the wrapped SSL engine) has been sent + * to the transport medium (i.e. accepted by the `low_write()` callback + * method). If there is no such pending data, then this function does + * nothing (and returns a success, i.e. 0). + * + * If the underlying transport medium has its own buffers, then it is + * up to the caller to ensure the corresponding flushing. + * + * Returned value is 0 on success, -1 on error. + * + * \param cc SSL wrapper context. + * \return 0 on success, or -1 on error. + */ +int br_sslio_flush(br_sslio_context *cc); + +/** + * \brief Close the SSL connection. + * + * This call runs the SSL closure protocol (sending a `close_notify`, + * receiving the response `close_notify`). When it returns, the SSL + * connection is finished. It is still up to the caller to manage the + * possible transport-level termination, if applicable (alternatively, + * the underlying transport stream may be reused for non-SSL messages). + * + * Returned value is 0 on success, -1 on error. A failure by the peer + * to process the complete closure protocol (i.e. sending back the + * `close_notify`) is an error. + * + * \param cc SSL wrapper context. + * \return 0 on success, or -1 on error. + */ +int br_sslio_close(br_sslio_context *cc); + +/* ===================================================================== */ + +/* + * Symbolic constants for cipher suites. + */ + +/* From RFC 5246 */ +#define BR_TLS_NULL_WITH_NULL_NULL 0x0000 +#define BR_TLS_RSA_WITH_NULL_MD5 0x0001 +#define BR_TLS_RSA_WITH_NULL_SHA 0x0002 +#define BR_TLS_RSA_WITH_NULL_SHA256 0x003B +#define BR_TLS_RSA_WITH_RC4_128_MD5 0x0004 +#define BR_TLS_RSA_WITH_RC4_128_SHA 0x0005 +#define BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A +#define BR_TLS_RSA_WITH_AES_128_CBC_SHA 0x002F +#define BR_TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 +#define BR_TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C +#define BR_TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D +#define BR_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D +#define BR_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 +#define BR_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 +#define BR_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 +#define BR_TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 +#define BR_TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 +#define BR_TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 +#define BR_TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 +#define BR_TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 +#define BR_TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 +#define BR_TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 +#define BR_TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 +#define BR_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 0x003E +#define BR_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 0x003F +#define BR_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040 +#define BR_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067 +#define BR_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 0x0068 +#define BR_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 0x0069 +#define BR_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A +#define BR_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B +#define BR_TLS_DH_anon_WITH_RC4_128_MD5 0x0018 +#define BR_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B +#define BR_TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 +#define BR_TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A +#define BR_TLS_DH_anon_WITH_AES_128_CBC_SHA256 0x006C +#define BR_TLS_DH_anon_WITH_AES_256_CBC_SHA256 0x006D + +/* From RFC 4492 */ +#define BR_TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001 +#define BR_TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002 +#define BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003 +#define BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 +#define BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 +#define BR_TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006 +#define BR_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007 +#define BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008 +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A +#define BR_TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B +#define BR_TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C +#define BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D +#define BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E +#define BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F +#define BR_TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010 +#define BR_TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011 +#define BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 +#define BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 +#define BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 +#define BR_TLS_ECDH_anon_WITH_NULL_SHA 0xC015 +#define BR_TLS_ECDH_anon_WITH_RC4_128_SHA 0xC016 +#define BR_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA 0xC017 +#define BR_TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018 +#define BR_TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019 + +/* From RFC 5288 */ +#define BR_TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C +#define BR_TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D +#define BR_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E +#define BR_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009F +#define BR_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 0x00A0 +#define BR_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 0x00A1 +#define BR_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 0x00A2 +#define BR_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 0x00A3 +#define BR_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 0x00A4 +#define BR_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 0x00A5 +#define BR_TLS_DH_anon_WITH_AES_128_GCM_SHA256 0x00A6 +#define BR_TLS_DH_anon_WITH_AES_256_GCM_SHA384 0x00A7 + +/* From RFC 5289 */ +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023 +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024 +#define BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025 +#define BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026 +#define BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027 +#define BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028 +#define BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029 +#define BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C +#define BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D +#define BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E +#define BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F +#define BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030 +#define BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 +#define BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032 + +/* From RFC 6655 and 7251 */ +#define BR_TLS_RSA_WITH_AES_128_CCM 0xC09C +#define BR_TLS_RSA_WITH_AES_256_CCM 0xC09D +#define BR_TLS_RSA_WITH_AES_128_CCM_8 0xC0A0 +#define BR_TLS_RSA_WITH_AES_256_CCM_8 0xC0A1 +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM 0xC0AC +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM 0xC0AD +#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE +#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 0xC0AF + +/* From RFC 7905 */ +#define BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8 +#define BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9 +#define BR_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA +#define BR_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAB +#define BR_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAC +#define BR_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD +#define BR_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE + +/* From RFC 7507 */ +#define BR_TLS_FALLBACK_SCSV 0x5600 + +/* + * Symbolic constants for alerts. + */ +#define BR_ALERT_CLOSE_NOTIFY 0 +#define BR_ALERT_UNEXPECTED_MESSAGE 10 +#define BR_ALERT_BAD_RECORD_MAC 20 +#define BR_ALERT_RECORD_OVERFLOW 22 +#define BR_ALERT_DECOMPRESSION_FAILURE 30 +#define BR_ALERT_HANDSHAKE_FAILURE 40 +#define BR_ALERT_BAD_CERTIFICATE 42 +#define BR_ALERT_UNSUPPORTED_CERTIFICATE 43 +#define BR_ALERT_CERTIFICATE_REVOKED 44 +#define BR_ALERT_CERTIFICATE_EXPIRED 45 +#define BR_ALERT_CERTIFICATE_UNKNOWN 46 +#define BR_ALERT_ILLEGAL_PARAMETER 47 +#define BR_ALERT_UNKNOWN_CA 48 +#define BR_ALERT_ACCESS_DENIED 49 +#define BR_ALERT_DECODE_ERROR 50 +#define BR_ALERT_DECRYPT_ERROR 51 +#define BR_ALERT_PROTOCOL_VERSION 70 +#define BR_ALERT_INSUFFICIENT_SECURITY 71 +#define BR_ALERT_INTERNAL_ERROR 80 +#define BR_ALERT_USER_CANCELED 90 +#define BR_ALERT_NO_RENEGOTIATION 100 +#define BR_ALERT_UNSUPPORTED_EXTENSION 110 +#define BR_ALERT_NO_APPLICATION_PROTOCOL 120 + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_x509.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_x509.h new file mode 100644 index 000000000..b86b488bd --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/bearssl_x509.h @@ -0,0 +1,1588 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef BR_BEARSSL_X509_H__ +#define BR_BEARSSL_X509_H__ + +#include +#include + +#include "bearssl_ec.h" +#include "bearssl_hash.h" +#include "bearssl_rsa.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** \file bearssl_x509.h + * + * # X.509 Certificate Chain Processing + * + * An X.509 processing engine receives an X.509 chain, chunk by chunk, + * as received from a SSL/TLS client or server (the client receives the + * server's certificate chain, and the server receives the client's + * certificate chain if it requested a client certificate). The chain + * is thus injected in the engine in SSL order (end-entity first). + * + * The engine's job is to return the public key to use for SSL/TLS. + * How exactly that key is obtained and verified is entirely up to the + * engine. + * + * **The "known key" engine** returns a public key which is already known + * from out-of-band information (e.g. the client _remembers_ the key from + * a previous connection, as in the usual SSH model). This is the simplest + * engine since it simply ignores the chain, thereby avoiding the need + * for any decoding logic. + * + * **The "minimal" engine** implements minimal X.509 decoding and chain + * validation: + * + * - The provided chain should validate "as is". There is no attempt + * at reordering, skipping or downloading extra certificates. + * + * - X.509 v1, v2 and v3 certificates are supported. + * + * - Trust anchors are a DN and a public key. Each anchor is either a + * "CA" anchor, or a non-CA. + * + * - If the end-entity certificate matches a non-CA anchor (subject DN + * is equal to the non-CA name, and public key is also identical to + * the anchor key), then this is a _direct trust_ case and the + * remaining certificates are ignored. + * + * - Unless direct trust is applied, the chain must be verifiable up to + * a certificate whose issuer DN matches the DN from a "CA" trust anchor, + * and whose signature is verifiable against that anchor's public key. + * Subsequent certificates in the chain are ignored. + * + * - The engine verifies subject/issuer DN matching, and enforces + * processing of Basic Constraints and Key Usage extensions. The + * Authority Key Identifier, Subject Key Identifier, Issuer Alt Name, + * Subject Directory Attribute, CRL Distribution Points, Freshest CRL, + * Authority Info Access and Subject Info Access extensions are + * ignored. The Subject Alt Name is decoded for the end-entity + * certificate under some conditions (see below). Other extensions + * are ignored if non-critical, or imply chain rejection if critical. + * + * - The Subject Alt Name extension is parsed for names of type `dNSName` + * when decoding the end-entity certificate, and only if there is a + * server name to match. If there is no SAN extension, then the + * Common Name from the subjectDN is used. That name matching is + * case-insensitive and honours a single starting wildcard (i.e. if + * the name in the certificate starts with "`*.`" then this matches + * any word as first element). Note: this name matching is performed + * also in the "direct trust" model. + * + * - DN matching is byte-to-byte equality (a future version might + * include some limited processing for case-insensitive matching and + * whitespace normalisation). + * + * - Successful validation produces a public key type but also a set + * of allowed usages (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * The caller is responsible for checking that the key type and + * usages are compatible with the expected values (e.g. with the + * selected cipher suite, when the client validates the server's + * certificate). + * + * **Important caveats:** + * + * - The "minimal" engine does not check revocation status. The relevant + * extensions are ignored, and CRL or OCSP responses are not gathered + * or checked. + * + * - The "minimal" engine does not currently support Name Constraints + * (some basic functionality to handle sub-domains may be added in a + * later version). + * + * - The decoder is not "validating" in the sense that it won't reject + * some certificates with invalid field values when these fields are + * not actually processed. + */ + +/* + * X.509 error codes are in the 32..63 range. + */ + +/** \brief X.509 status: validation was successful; this is not actually + an error. */ +#define BR_ERR_X509_OK 32 + +/** \brief X.509 status: invalid value in an ASN.1 structure. */ +#define BR_ERR_X509_INVALID_VALUE 33 + +/** \brief X.509 status: truncated certificate. */ +#define BR_ERR_X509_TRUNCATED 34 + +/** \brief X.509 status: empty certificate chain (no certificate at all). */ +#define BR_ERR_X509_EMPTY_CHAIN 35 + +/** \brief X.509 status: decoding error: inner element extends beyond + outer element size. */ +#define BR_ERR_X509_INNER_TRUNC 36 + +/** \brief X.509 status: decoding error: unsupported tag class (application + or private). */ +#define BR_ERR_X509_BAD_TAG_CLASS 37 + +/** \brief X.509 status: decoding error: unsupported tag value. */ +#define BR_ERR_X509_BAD_TAG_VALUE 38 + +/** \brief X.509 status: decoding error: indefinite length. */ +#define BR_ERR_X509_INDEFINITE_LENGTH 39 + +/** \brief X.509 status: decoding error: extraneous element. */ +#define BR_ERR_X509_EXTRA_ELEMENT 40 + +/** \brief X.509 status: decoding error: unexpected element. */ +#define BR_ERR_X509_UNEXPECTED 41 + +/** \brief X.509 status: decoding error: expected constructed element, but + is primitive. */ +#define BR_ERR_X509_NOT_CONSTRUCTED 42 + +/** \brief X.509 status: decoding error: expected primitive element, but + is constructed. */ +#define BR_ERR_X509_NOT_PRIMITIVE 43 + +/** \brief X.509 status: decoding error: BIT STRING length is not multiple + of 8. */ +#define BR_ERR_X509_PARTIAL_BYTE 44 + +/** \brief X.509 status: decoding error: BOOLEAN value has invalid length. */ +#define BR_ERR_X509_BAD_BOOLEAN 45 + +/** \brief X.509 status: decoding error: value is off-limits. */ +#define BR_ERR_X509_OVERFLOW 46 + +/** \brief X.509 status: invalid distinguished name. */ +#define BR_ERR_X509_BAD_DN 47 + +/** \brief X.509 status: invalid date/time representation. */ +#define BR_ERR_X509_BAD_TIME 48 + +/** \brief X.509 status: certificate contains unsupported features that + cannot be ignored. */ +#define BR_ERR_X509_UNSUPPORTED 49 + +/** \brief X.509 status: key or signature size exceeds internal limits. */ +#define BR_ERR_X509_LIMIT_EXCEEDED 50 + +/** \brief X.509 status: key type does not match that which was expected. */ +#define BR_ERR_X509_WRONG_KEY_TYPE 51 + +/** \brief X.509 status: signature is invalid. */ +#define BR_ERR_X509_BAD_SIGNATURE 52 + +/** \brief X.509 status: validation time is unknown. */ +#define BR_ERR_X509_TIME_UNKNOWN 53 + +/** \brief X.509 status: certificate is expired or not yet valid. */ +#define BR_ERR_X509_EXPIRED 54 + +/** \brief X.509 status: issuer/subject DN mismatch in the chain. */ +#define BR_ERR_X509_DN_MISMATCH 55 + +/** \brief X.509 status: expected server name was not found in the chain. */ +#define BR_ERR_X509_BAD_SERVER_NAME 56 + +/** \brief X.509 status: unknown critical extension in certificate. */ +#define BR_ERR_X509_CRITICAL_EXTENSION 57 + +/** \brief X.509 status: not a CA, or path length constraint violation */ +#define BR_ERR_X509_NOT_CA 58 + +/** \brief X.509 status: Key Usage extension prohibits intended usage. */ +#define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59 + +/** \brief X.509 status: public key found in certificate is too small. */ +#define BR_ERR_X509_WEAK_PUBLIC_KEY 60 + +/** \brief X.509 status: chain could not be linked to a trust anchor. */ +#define BR_ERR_X509_NOT_TRUSTED 62 + +/** + * \brief Aggregate structure for public keys. + */ +typedef struct { + /** \brief Key type: `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC` */ + unsigned char key_type; + /** \brief Actual public key. */ + union { + /** \brief RSA public key. */ + br_rsa_public_key rsa; + /** \brief EC public key. */ + br_ec_public_key ec; + } key; +} br_x509_pkey; + +/** + * \brief Distinguished Name (X.500) structure. + * + * The DN is DER-encoded. + */ +typedef struct { + /** \brief Encoded DN data. */ + unsigned char *data; + /** \brief Encoded DN length (in bytes). */ + size_t len; +} br_x500_name; + +/** + * \brief Trust anchor structure. + */ +typedef struct { + /** \brief Encoded DN (X.500 name). */ + br_x500_name dn; + /** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */ + unsigned flags; + /** \brief Anchor public key. */ + br_x509_pkey pkey; +} br_x509_trust_anchor; + +/** + * \brief Trust anchor flag: CA. + * + * A "CA" anchor is deemed fit to verify signatures on certificates. + * A "non-CA" anchor is accepted only for direct trust (server's + * certificate name and key match the anchor). + */ +#define BR_X509_TA_CA 0x0001 + +/* + * Key type: combination of a basic key type (low 4 bits) and some + * optional flags. + * + * For a public key, the basic key type only is set. + * + * For an expected key type, the flags indicate the intended purpose(s) + * for the key; the basic key type may be set to 0 to indicate that any + * key type compatible with the indicated purpose is acceptable. + */ +/** \brief Key type: algorithm is RSA. */ +#define BR_KEYTYPE_RSA 1 +/** \brief Key type: algorithm is EC. */ +#define BR_KEYTYPE_EC 2 + +/** + * \brief Key type: usage is "key exchange". + * + * This value is combined (with bitwise OR) with the algorithm + * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) when informing the X.509 + * validation engine that it should find a public key of that type, + * fit for key exchanges (e.g. `TLS_RSA_*` and `TLS_ECDH_*` cipher + * suites). + */ +#define BR_KEYTYPE_KEYX 0x10 + +/** + * \brief Key type: usage is "signature". + * + * This value is combined (with bitwise OR) with the algorithm + * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) when informing the X.509 + * validation engine that it should find a public key of that type, + * fit for signatures (e.g. `TLS_ECDHE_*` cipher suites). + */ +#define BR_KEYTYPE_SIGN 0x20 + +/* + * start_chain Called when a new chain is started. If 'server_name' + * is not NULL and non-empty, then it is a name that + * should be looked for in the EE certificate (in the + * SAN extension as dNSName, or in the subjectDN's CN + * if there is no SAN extension). + * The caller ensures that the provided 'server_name' + * pointer remains valid throughout validation. + * + * start_cert Begins a new certificate in the chain. The provided + * length is in bytes; this is the total certificate length. + * + * append Get some additional bytes for the current certificate. + * + * end_cert Ends the current certificate. + * + * end_chain Called at the end of the chain. Returned value is + * 0 on success, or a non-zero error code. + * + * get_pkey Returns the EE certificate public key. + * + * For a complete chain, start_chain() and end_chain() are always + * called. For each certificate, start_cert(), some append() calls, then + * end_cert() are called, in that order. There may be no append() call + * at all if the certificate is empty (which is not valid but may happen + * if the peer sends exactly that). + * + * get_pkey() shall return a pointer to a structure that is valid as + * long as a new chain is not started. This may be a sub-structure + * within the context for the engine. This function MAY return a valid + * pointer to a public key even in some cases of validation failure, + * depending on the validation engine. + */ + +/** + * \brief Class type for an X.509 engine. + * + * A certificate chain validation uses a caller-allocated context, which + * contains the running state for that validation. Methods are called + * in due order: + * + * - `start_chain()` is called at the start of the validation. + * - Certificates are processed one by one, in SSL order (end-entity + * comes first). For each certificate, the following methods are + * called: + * + * - `start_cert()` at the beginning of the certificate. + * - `append()` is called zero, one or more times, to provide + * the certificate (possibly in chunks). + * - `end_cert()` at the end of the certificate. + * + * - `end_chain()` is called when the last certificate in the chain + * was processed. + * - `get_pkey()` is called after chain processing, if the chain + * validation was successful. + * + * A context structure may be reused; the `start_chain()` method shall + * ensure (re)initialisation. + */ +typedef struct br_x509_class_ br_x509_class; +struct br_x509_class_ { + /** + * \brief X.509 context size, in bytes. + */ + size_t context_size; + + /** + * \brief Start a new chain. + * + * This method shall set the vtable (first field) of the context + * structure. + * + * The `server_name`, if not `NULL`, will be considered as a + * fully qualified domain name, to be matched against the `dNSName` + * elements of the end-entity certificate's SAN extension (if there + * is no SAN, then the Common Name from the subjectDN will be used). + * If `server_name` is `NULL` then no such matching is performed. + * + * \param ctx validation context. + * \param server_name server name to match (or `NULL`). + */ + void (*start_chain)(const br_x509_class **ctx, + const char *server_name); + + /** + * \brief Start a new certificate. + * + * \param ctx validation context. + * \param length new certificate length (in bytes). + */ + void (*start_cert)(const br_x509_class **ctx, uint32_t length); + + /** + * \brief Receive some bytes for the current certificate. + * + * This function may be called several times in succession for + * a given certificate. The caller guarantees that for each + * call, `len` is not zero, and the sum of all chunk lengths + * for a certificate matches the total certificate length which + * was provided in the previous `start_cert()` call. + * + * If the new certificate is empty (no byte at all) then this + * function won't be called at all. + * + * \param ctx validation context. + * \param buf certificate data chunk. + * \param len certificate data chunk length (in bytes). + */ + void (*append)(const br_x509_class **ctx, + const unsigned char *buf, size_t len); + + /** + * \brief Finish the current certificate. + * + * This function is called when the end of the current certificate + * is reached. + * + * \param ctx validation context. + */ + void (*end_cert)(const br_x509_class **ctx); + + /** + * \brief Finish the chain. + * + * This function is called at the end of the chain. It shall + * return either 0 if the validation was successful, or a + * non-zero error code. The `BR_ERR_X509_*` constants are + * error codes, though other values may be possible. + * + * \param ctx validation context. + * \return 0 on success, or a non-zero error code. + */ + unsigned (*end_chain)(const br_x509_class **ctx); + + /** + * \brief Get the resulting end-entity public key. + * + * The decoded public key is returned. The returned pointer + * may be valid only as long as the context structure is + * unmodified, i.e. it may cease to be valid if the context + * is released or reused. + * + * This function _may_ return `NULL` if the validation failed. + * However, returning a public key does not mean that the + * validation was wholly successful; some engines may return + * a decoded public key even if the chain did not end on a + * trusted anchor. + * + * If validation succeeded and `usage` is not `NULL`, then + * `*usage` is filled with a combination of `BR_KEYTYPE_SIGN` + * and/or `BR_KEYTYPE_KEYX` that specifies the validated key + * usage types. It is the caller's responsibility to check + * that value against the intended use of the public key. + * + * \param ctx validation context. + * \return the end-entity public key, or `NULL`. + */ + const br_x509_pkey *(*get_pkey)( + const br_x509_class *const *ctx, unsigned *usages); +}; + +/** + * \brief The "known key" X.509 engine structure. + * + * The structure contents are opaque (they shall not be accessed directly), + * except for the first field (the vtable). + * + * The "known key" engine returns an externally configured public key, + * and totally ignores the certificate contents. + */ +typedef struct { + /** \brief Reference to the context vtable. */ + const br_x509_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + br_x509_pkey pkey; + unsigned usages; +#endif +} br_x509_knownkey_context; + +/** + * \brief Class instance for the "known key" X.509 engine. + */ +extern const br_x509_class br_x509_knownkey_vtable; + +/** + * \brief Initialize a "known key" X.509 engine with a known RSA public key. + * + * The `usages` parameter indicates the allowed key usages for that key + * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * + * The provided pointers are linked in, not copied, so they must remain + * valid while the public key may be in usage. + * + * \param ctx context to initialise. + * \param pk known public key. + * \param usages allowed key usages. + */ +void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx, + const br_rsa_public_key *pk, unsigned usages); + +/** + * \brief Initialize a "known key" X.509 engine with a known EC public key. + * + * The `usages` parameter indicates the allowed key usages for that key + * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * + * The provided pointers are linked in, not copied, so they must remain + * valid while the public key may be in usage. + * + * \param ctx context to initialise. + * \param pk known public key. + * \param usages allowed key usages. + */ +void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, + const br_ec_public_key *pk, unsigned usages); + +#ifndef BR_DOXYGEN_IGNORE +/* + * The minimal X.509 engine has some state buffers which must be large + * enough to simultaneously accommodate: + * -- the public key extracted from the current certificate; + * -- the signature on the current certificate or on the previous + * certificate; + * -- the public key extracted from the EE certificate. + * + * We store public key elements in their raw unsigned big-endian + * encoding. We want to support up to RSA-4096 with a short (up to 64 + * bits) public exponent, thus a buffer for a public key must have + * length at least 520 bytes. Similarly, a RSA-4096 signature has length + * 512 bytes. + * + * Though RSA public exponents can formally be as large as the modulus + * (mathematically, even larger exponents would work, but PKCS#1 forbids + * them), exponents that do not fit on 32 bits are extremely rare, + * notably because some widespread implementations (e.g. Microsoft's + * CryptoAPI) don't support them. Moreover, large public exponent do not + * seem to imply any tangible security benefit, and they increase the + * cost of public key operations. The X.509 "minimal" engine will tolerate + * public exponents of arbitrary size as long as the modulus and the + * exponent can fit together in the dedicated buffer. + * + * EC public keys are shorter than RSA public keys; even with curve + * NIST P-521 (the largest curve we care to support), a public key is + * encoded over 133 bytes only. + */ +#define BR_X509_BUFSIZE_KEY 520 +#define BR_X509_BUFSIZE_SIG 512 +#endif + +/** + * \brief Type for receiving a name element. + * + * An array of such structures can be provided to the X.509 decoding + * engines. If the specified elements are found in the certificate + * subject DN or the SAN extension, then the name contents are copied + * as zero-terminated strings into the buffer. + * + * The decoder converts TeletexString and BMPString to UTF8String, and + * ensures that the resulting string is zero-terminated. If the string + * does not fit in the provided buffer, then the copy is aborted and an + * error is reported. + */ +typedef struct { + /** + * \brief Element OID. + * + * For X.500 name elements (to be extracted from the subject DN), + * this is the encoded OID for the requested name element; the + * first byte shall contain the length of the DER-encoded OID + * value, followed by the OID value (for instance, OID 2.5.4.3, + * for id-at-commonName, will be `03 55 04 03`). This is + * equivalent to full DER encoding with the length but without + * the tag. + * + * For SAN name elements, the first byte (`oid[0]`) has value 0, + * followed by another byte that matches the expected GeneralName + * tag. Allowed second byte values are then: + * + * - 1: `rfc822Name` + * + * - 2: `dNSName` + * + * - 6: `uniformResourceIdentifier` + * + * - 0: `otherName` + * + * If first and second byte are 0, then this is a SAN element of + * type `otherName`; the `oid[]` array should then contain, right + * after the two bytes of value 0, an encoded OID (with the same + * conventions as for X.500 name elements). If a match is found + * for that OID, then the corresponding name element will be + * extracted, as long as it is a supported string type. + */ + const unsigned char *oid; + + /** + * \brief Destination buffer. + */ + char *buf; + + /** + * \brief Length (in bytes) of the destination buffer. + * + * The buffer MUST NOT be smaller than 1 byte. + */ + size_t len; + + /** + * \brief Decoding status. + * + * Status is 0 if the name element was not found, 1 if it was + * found and decoded, or -1 on error. Error conditions include + * an unrecognised encoding, an invalid encoding, or a string + * too large for the destination buffer. + */ + int status; + +} br_name_element; + +/** + * \brief The "minimal" X.509 engine structure. + * + * The structure contents are opaque (they shall not be accessed directly), + * except for the first field (the vtable). + * + * The "minimal" engine performs a rudimentary but serviceable X.509 path + * validation. + */ +typedef struct { + const br_x509_class *vtable; + +#ifndef BR_DOXYGEN_IGNORE + /* Structure for returning the EE public key. */ + br_x509_pkey pkey; + + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + /* Server name to match with the SAN / CN of the EE certificate. */ + const char *server_name; + + /* Validated key usages. */ + unsigned char key_usages; + + /* Explicitly set date and time. */ + uint32_t days, seconds; + + /* Current certificate length (in bytes). Set to 0 when the + certificate has been fully processed. */ + uint32_t cert_length; + + /* Number of certificates processed so far in the current chain. + It is incremented at the end of the processing of a certificate, + so it is 0 for the EE. */ + uint32_t num_certs; + + /* Certificate data chunk. */ + const unsigned char *hbuf; + size_t hlen; + + /* The pad serves as destination for various operations. */ + unsigned char pad[256]; + + /* Buffer for EE public key data. */ + unsigned char ee_pkey_data[BR_X509_BUFSIZE_KEY]; + + /* Buffer for currently decoded public key. */ + unsigned char pkey_data[BR_X509_BUFSIZE_KEY]; + + /* Signature type: signer key type, offset to the hash + function OID (in the T0 data block) and hash function + output length (TBS hash length). */ + unsigned char cert_signer_key_type; + uint16_t cert_sig_hash_oid; + unsigned char cert_sig_hash_len; + + /* Current/last certificate signature. */ + unsigned char cert_sig[BR_X509_BUFSIZE_SIG]; + uint16_t cert_sig_len; + + /* Minimum RSA key length (difference in bytes from 128). */ + int16_t min_rsa_size; + + /* Configured trust anchors. */ + const br_x509_trust_anchor *trust_anchors; + size_t trust_anchors_num; + + /* private context for dynamic callbacks */ + void *trust_anchor_dynamic_ctx; + /* Dynamic trust anchor, for on-the-fly loading of TAs */ + const br_x509_trust_anchor* (*trust_anchor_dynamic)(void *ctx, void *hashed_dn, size_t hashed_dn_len); + /* And a chance to free any dynamically allocated TA returned from above */ + void (*trust_anchor_dynamic_free)(void *ctx, const br_x509_trust_anchor *ta); + + /* + * Multi-hasher for the TBS. + */ + unsigned char do_mhash; + br_multihash_context mhash; + unsigned char tbs_hash[64]; + + /* + * Simple hasher for the subject/issuer DN. + */ + unsigned char do_dn_hash; + const br_hash_class *dn_hash_impl; + br_hash_compat_context dn_hash; + unsigned char current_dn_hash[64]; + unsigned char next_dn_hash[64]; + unsigned char saved_dn_hash[64]; + + /* + * Name elements to gather. + */ + br_name_element *name_elts; + size_t num_name_elts; + + /* + * Public key cryptography implementations (signature verification). + */ + br_rsa_pkcs1_vrfy irsa; + br_ecdsa_vrfy iecdsa; + const br_ec_impl *iec; +#endif + +} br_x509_minimal_context; + +/** + * \brief Class instance for the "minimal" X.509 engine. + */ +extern const br_x509_class br_x509_minimal_vtable; + +/** + * \brief Initialise a "minimal" X.509 engine. + * + * The `dn_hash_impl` parameter shall be a hash function internally used + * to match X.500 names (subject/issuer DN, and anchor names). Any standard + * hash function may be used, but a collision-resistant hash function is + * advised. + * + * After initialization, some implementations for signature verification + * (hash functions and signature algorithms) MUST be added. + * + * \param ctx context to initialise. + * \param dn_hash_impl hash function for DN comparisons. + * \param trust_anchors trust anchors. + * \param trust_anchors_num number of trust anchors. + */ +void br_x509_minimal_init(br_x509_minimal_context *ctx, + const br_hash_class *dn_hash_impl, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); + +/** + * \brief Set the optional dynamic trust anchor lookup callbacks + * + * The dynamic trust anchor lookup callbacks allow an application to implement + * a non-memory resident trust anchor store. This can be useful on embedded + * systems where RAM is at a premium, but there is an external stable store, + * such as embedded flash or SD card, to keep many CA certificates. Set or + * leave these functions as NULL to not use such a feature. + * + * The dynamic routine will be passed in the hashed DN in question using the + * dn_hash_impl, and should compare this DN to its set of hashed known DNs. + * Of course, the same dn_hash_impl needs to be used in the dynamic routine. + * After the trust_anchor* is used, the dynamic_free callback is given a + * chance to deallocate its memory, if needed. + * + * \param ctx context to initialise. + * \param dynamic_ctx private context for the dynamic callback + * \param trust_anchor_dynamic provides a trust_anchor* for a hashed_dn + * \param trust_anchor_dynamic_free allows deallocation of returned TA + */ +static inline void +br_x509_minimal_set_dynamic(br_x509_minimal_context *ctx, void *dynamic_ctx, + const br_x509_trust_anchor* (*dynamic)(void *ctx, void *hashed_dn, size_t hashed_dn_len), + void (*dynamic_free)(void *ctx, const br_x509_trust_anchor *ta)) +{ + ctx->trust_anchor_dynamic_ctx = dynamic_ctx; + ctx->trust_anchor_dynamic = dynamic; + ctx->trust_anchor_dynamic_free = dynamic_free; +} + +/** + * \brief Set a supported hash function in an X.509 "minimal" engine. + * + * Hash functions are used with signature verification algorithms. + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the hash functions it shall support for that + * purpose. The hash function identifier MUST be one of the standard + * hash function identifiers (1 to 6, for MD5, SHA-1, SHA-224, SHA-256, + * SHA-384 and SHA-512). + * + * If `impl` is `NULL`, this _removes_ support for the designated + * hash function. + * + * \param ctx validation context. + * \param id hash function identifier (from 1 to 6). + * \param impl hash function implementation (or `NULL`). + */ +static inline void +br_x509_minimal_set_hash(br_x509_minimal_context *ctx, + int id, const br_hash_class *impl) +{ + br_multihash_setimpl(&ctx->mhash, id, impl); +} + +/** + * \brief Set a RSA signature verification implementation in the X.509 + * "minimal" engine. + * + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the signature verification implementations that + * it is supposed to support. If `irsa` is `0`, then the RSA support + * is disabled. + * + * \param ctx validation context. + * \param irsa RSA signature verification implementation (or `0`). + */ +static inline void +br_x509_minimal_set_rsa(br_x509_minimal_context *ctx, + br_rsa_pkcs1_vrfy irsa) +{ + ctx->irsa = irsa; +} + +/** + * \brief Set a ECDSA signature verification implementation in the X.509 + * "minimal" engine. + * + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the signature verification implementations that + * it is supposed to support. + * + * If `iecdsa` is `0`, then this call disables ECDSA support; in that + * case, `iec` may be `NULL`. Otherwise, `iecdsa` MUST point to a function + * that verifies ECDSA signatures with format "asn1", and it will use + * `iec` as underlying elliptic curve support. + * + * \param ctx validation context. + * \param iec elliptic curve implementation (or `NULL`). + * \param iecdsa ECDSA implementation (or `0`). + */ +static inline void +br_x509_minimal_set_ecdsa(br_x509_minimal_context *ctx, + const br_ec_impl *iec, br_ecdsa_vrfy iecdsa) +{ + ctx->iecdsa = iecdsa; + ctx->iec = iec; +} + +/** + * \brief Initialise a "minimal" X.509 engine with default algorithms. + * + * This function performs the same job as `br_x509_minimal_init()`, but + * also sets implementations for RSA, ECDSA, and the standard hash + * functions. + * + * \param ctx context to initialise. + * \param trust_anchors trust anchors. + * \param trust_anchors_num number of trust anchors. + */ +void br_x509_minimal_init_full(br_x509_minimal_context *ctx, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); + +/** + * \brief Set the validation time for the X.509 "minimal" engine. + * + * The validation time is set as two 32-bit integers, for days and + * seconds since a fixed epoch: + * + * - Days are counted in a proleptic Gregorian calendar since + * January 1st, 0 AD. Year "0 AD" is the one that preceded "1 AD"; + * it is also traditionally known as "1 BC". + * + * - Seconds are counted since midnight, from 0 to 86400 (a count of + * 86400 is possible only if a leap second happened). + * + * The validation date and time is understood in the UTC time zone. + * + * If the validation date and time are not explicitly set, but BearSSL + * was compiled with support for the system clock on the underlying + * platform, then the current time will automatically be used. Otherwise, + * not setting the validation date and time implies a validation + * failure (except in case of direct trust of the EE key). + * + * \param ctx validation context. + * \param days days since January 1st, 0 AD (Gregorian calendar). + * \param seconds seconds since midnight (0 to 86400). + */ +static inline void +br_x509_minimal_set_time(br_x509_minimal_context *ctx, + uint32_t days, uint32_t seconds) +{ + ctx->days = days; + ctx->seconds = seconds; +} + +/** + * \brief Set the minimal acceptable length for RSA keys (X.509 "minimal" + * engine). + * + * The RSA key length is expressed in bytes. The default minimum key + * length is 128 bytes, corresponding to 1017 bits. RSA keys shorter + * than the configured length will be rejected, implying validation + * failure. This setting applies to keys extracted from certificates + * (both end-entity, and intermediate CA) but not to "CA" trust anchors. + * + * \param ctx validation context. + * \param byte_length minimum RSA key length, **in bytes** (not bits). + */ +static inline void +br_x509_minimal_set_minrsa(br_x509_minimal_context *ctx, int byte_length) +{ + ctx->min_rsa_size = (int16_t)(byte_length - 128); +} + +/** + * \brief Set the name elements to gather. + * + * The provided array is linked in the context. The elements are + * gathered from the EE certificate. If the same element type is + * requested several times, then the relevant structures will be filled + * in the order the matching values are encountered in the certificate. + * + * \param ctx validation context. + * \param elts array of name element structures to fill. + * \param num_elts number of name element structures to fill. + */ +static inline void +br_x509_minimal_set_name_elements(br_x509_minimal_context *ctx, + br_name_element *elts, size_t num_elts) +{ + ctx->name_elts = elts; + ctx->num_name_elts = num_elts; +} + +/** + * \brief X.509 decoder context. + * + * This structure is _not_ for X.509 validation, but for extracting + * names and public keys from encoded certificates. Intended usage is + * to use (self-signed) certificates as trust anchors. + * + * Contents are opaque and shall not be accessed directly. + */ +typedef struct { + +#ifndef BR_DOXYGEN_IGNORE + /* Structure for returning the public key. */ + br_x509_pkey pkey; + + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + /* The pad serves as destination for various operations. */ + unsigned char pad[256]; + + /* Flag set when decoding succeeds. */ + unsigned char decoded; + + /* Validity dates. */ + uint32_t notbefore_days, notbefore_seconds; + uint32_t notafter_days, notafter_seconds; + + /* The "CA" flag. This is set to true if the certificate contains + a Basic Constraints extension that asserts CA status. */ + unsigned char isCA; + + /* DN processing: the subject DN is extracted and pushed to the + provided callback. */ + unsigned char copy_dn; + void *append_dn_ctx; + void (*append_dn)(void *ctx, const void *buf, size_t len); + + /* Certificate data chunk. */ + const unsigned char *hbuf; + size_t hlen; + + /* Buffer for decoded public key. */ + unsigned char pkey_data[BR_X509_BUFSIZE_KEY]; + + /* Type of key and hash function used in the certificate signature. */ + unsigned char signer_key_type; + unsigned char signer_hash_id; +#endif + +} br_x509_decoder_context_libmail; + +/** + * \brief Initialise an X.509 decoder context for processing a new + * certificate. + * + * The `append_dn()` callback (with opaque context `append_dn_ctx`) + * will be invoked to receive, chunk by chunk, the certificate's + * subject DN. If `append_dn` is `0` then the subject DN will be + * ignored. + * + * \param ctx X.509 decoder context to initialise. + * \param append_dn DN receiver callback (or `0`). + * \param append_dn_ctx context for the DN receiver callback. + */ +void br_x509_decoder_init_libmail(br_x509_decoder_context_libmail *ctx, + void (*append_dn)(void *ctx, const void *buf, size_t len), + void *append_dn_ctx); + +/** + * \brief Push some certificate bytes into a decoder context. + * + * If `len` is non-zero, then that many bytes are pushed, from address + * `data`, into the provided decoder context. + * + * \param ctx X.509 decoder context. + * \param data certificate data chunk. + * \param len certificate data chunk length (in bytes). + */ +void br_x509_decoder_push_libmail(br_x509_decoder_context_libmail *ctx, + const void *data, size_t len); + +/** + * \brief Obtain the decoded public key. + * + * Returned value is a pointer to a structure internal to the decoder + * context; releasing or reusing the decoder context invalidates that + * structure. + * + * If decoding was not finished, or failed, then `NULL` is returned. + * + * \param ctx X.509 decoder context. + * \return the public key, or `NULL` on unfinished/error. + */ +static inline br_x509_pkey * +br_x509_decoder_get_pkey(br_x509_decoder_context_libmail *ctx) +{ + if (ctx->decoded && ctx->err == 0) { + return &ctx->pkey; + } else { + return NULL; + } +} + +/** + * \brief Get decoder error status. + * + * If no error was reported yet but the certificate decoding is not + * finished, then the error code is `BR_ERR_X509_TRUNCATED`. If decoding + * was successful, then 0 is returned. + * + * \param ctx X.509 decoder context. + * \return 0 on successful decoding, or a non-zero error code. + */ +static inline int +br_x509_decoder_last_error(br_x509_decoder_context_libmail *ctx) +{ + if (ctx->err != 0) { + return ctx->err; + } + if (!ctx->decoded) { + return BR_ERR_X509_TRUNCATED; + } + return 0; +} + +/** + * \brief Get the "isCA" flag from an X.509 decoder context. + * + * This flag is set if the decoded certificate claims to be a CA through + * a Basic Constraints extension. This flag should not be read before + * decoding completed successfully. + * + * \param ctx X.509 decoder context. + * \return the "isCA" flag. + */ +static inline int +br_x509_decoder_isCA(br_x509_decoder_context_libmail *ctx) +{ + return ctx->isCA; +} + +/** + * \brief Get the issuing CA key type (type of algorithm used to sign the + * decoded certificate). + * + * This is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. The value 0 is returned + * if the signature type was not recognised. + * + * \param ctx X.509 decoder context. + * \return the issuing CA key type. + */ +static inline int +br_x509_decoder_get_signer_key_type(br_x509_decoder_context_libmail *ctx) +{ + return ctx->signer_key_type; +} + +/** + * \brief Get the identifier for the hash function used to sign the decoded + * certificate. + * + * This is 0 if the hash function was not recognised. + * + * \param ctx X.509 decoder context. + * \return the signature hash function identifier. + */ +static inline int +br_x509_decoder_get_signer_hash_id(br_x509_decoder_context_libmail *ctx) +{ + return ctx->signer_hash_id; +} + +/** + * \brief Type for an X.509 certificate (DER-encoded). + */ +typedef struct { + /** \brief The DER-encoded certificate data. */ + unsigned char *data; + /** \brief The DER-encoded certificate length (in bytes). */ + size_t data_len; +} br_x509_certificate; + +/** + * \brief Private key decoder context. + * + * The private key decoder recognises RSA and EC private keys, either in + * their raw, DER-encoded format, or wrapped in an unencrypted PKCS#8 + * archive (again DER-encoded). + * + * Structure contents are opaque and shall not be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + /* Structure for returning the private key. */ + union { + br_rsa_private_key rsa; + br_ec_private_key ec; + } key; + + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + /* Private key data chunk. */ + const unsigned char *hbuf; + size_t hlen; + + /* The pad serves as destination for various operations. */ + unsigned char pad[256]; + + /* Decoded key type; 0 until decoding is complete. */ + unsigned char key_type; + + /* Buffer for the private key elements. It shall be large enough + to accommodate all elements for a RSA-4096 private key (roughly + five 2048-bit integers, possibly a bit more). */ + unsigned char key_data[3 * BR_X509_BUFSIZE_SIG]; +#endif +} br_skey_decoder_context; + +/** + * \brief Initialise a private key decoder context. + * + * \param ctx key decoder context to initialise. + */ +void br_skey_decoder_init(br_skey_decoder_context *ctx); + +/** + * \brief Push some data bytes into a private key decoder context. + * + * If `len` is non-zero, then that many data bytes, starting at address + * `data`, are pushed into the decoder. + * + * \param ctx key decoder context. + * \param data private key data chunk. + * \param len private key data chunk length (in bytes). + */ +void br_skey_decoder_push(br_skey_decoder_context *ctx, + const void *data, size_t len); + +/** + * \brief Get the decoding status for a private key. + * + * Decoding status is 0 on success, or a non-zero error code. If the + * decoding is unfinished when this function is called, then the + * status code `BR_ERR_X509_TRUNCATED` is returned. + * + * \param ctx key decoder context. + * \return 0 on successful decoding, or a non-zero error code. + */ +static inline int +br_skey_decoder_last_error(const br_skey_decoder_context *ctx) +{ + if (ctx->err != 0) { + return ctx->err; + } + if (ctx->key_type == 0) { + return BR_ERR_X509_TRUNCATED; + } + return 0; +} + +/** + * \brief Get the decoded private key type. + * + * Private key type is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. If decoding is + * not finished or failed, then 0 is returned. + * + * \param ctx key decoder context. + * \return decoded private key type, or 0. + */ +static inline int +br_skey_decoder_key_type(const br_skey_decoder_context *ctx) +{ + if (ctx->err == 0) { + return ctx->key_type; + } else { + return 0; + } +} + +/** + * \brief Get the decoded RSA private key. + * + * This function returns `NULL` if the decoding failed, or is not + * finished, or the key is not RSA. The returned pointer references + * structures within the context that can become invalid if the context + * is reused or released. + * + * \param ctx key decoder context. + * \return decoded RSA private key, or `NULL`. + */ +static inline const br_rsa_private_key * +br_skey_decoder_get_rsa(const br_skey_decoder_context *ctx) +{ + if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_RSA) { + return &ctx->key.rsa; + } else { + return NULL; + } +} + +/** + * \brief Get the decoded EC private key. + * + * This function returns `NULL` if the decoding failed, or is not + * finished, or the key is not EC. The returned pointer references + * structures within the context that can become invalid if the context + * is reused or released. + * + * \param ctx key decoder context. + * \return decoded EC private key, or `NULL`. + */ +static inline const br_ec_private_key * +br_skey_decoder_get_ec(const br_skey_decoder_context *ctx) +{ + if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_EC) { + return &ctx->key.ec; + } else { + return NULL; + } +} + +/** + * \brief Public key decoder context. + * + * The public key decoder recognises RSA and EC private keys, either in + * their raw, DER-encoded format, or wrapped in an unencrypted PKCS#8 + * archive (again DER-encoded). + * + * Structure contents are opaque and shall not be accessed directly. + */ +typedef struct { +#ifndef BR_DOXYGEN_IGNORE + /* Structure for returning the private key. */ + union { + br_rsa_public_key rsa; + br_ec_public_key ec; + } key; + + /* CPU for the T0 virtual machine. */ + struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; + } cpu; + uint32_t dp_stack[32]; + uint32_t rp_stack[32]; + int err; + + /* Private key data chunk. */ + const unsigned char *hbuf; + size_t hlen; + + /* The pad serves as destination for various operations. */ + unsigned char pad[256]; + + /* Decoded key type; 0 until decoding is complete. */ + unsigned char key_type; + + /* Buffer for the private key elements. It shall be large enough + to accommodate all elements for a RSA-4096 private key (roughly + five 2048-bit integers, possibly a bit more). */ + unsigned char key_data[3 * BR_X509_BUFSIZE_SIG]; +#endif +} br_pkey_decoder_context; + + +/** + * \brief Initialise a public key decoder context. + * + * \param ctx key decoder context to initialise. + */ +void br_pkey_decoder_init(br_pkey_decoder_context *ctx); + +/** + * \brief Push some data bytes into a public key decoder context. + * + * If `len` is non-zero, then that many data bytes, starting at address + * `data`, are pushed into the decoder. + * + * \param ctx key decoder context. + * \param data private key data chunk. + * \param len private key data chunk length (in bytes). + */ +void br_pkey_decoder_push(br_pkey_decoder_context *ctx, + const void *data, size_t len); + +/** + * \brief Get the decoding status for a public key. + * + * Decoding status is 0 on success, or a non-zero error code. If the + * decoding is unfinished when this function is called, then the + * status code `BR_ERR_X509_TRUNCATED` is returned. + * + * \param ctx key decoder context. + * \return 0 on successful decoding, or a non-zero error code. + */ +static inline int +br_pkey_decoder_last_error(const br_pkey_decoder_context *ctx) +{ + if (ctx->err != 0) { + return ctx->err; + } + if (ctx->key_type == 0) { + return BR_ERR_X509_TRUNCATED; + } + return 0; +} + +/** + * \brief Get the decoded public key type. + * + * Public key type is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. If decoding is + * not finished or failed, then 0 is returned. + * + * \param ctx key decoder context. + * \return decoded private key type, or 0. + */ +static inline int +br_pkey_decoder_key_type(const br_pkey_decoder_context *ctx) +{ + if (ctx->err == 0) { + return ctx->key_type; + } else { + return 0; + } +} + +/** + * \brief Get the decoded RSA public key. + * + * This function returns `NULL` if the decoding failed, or is not + * finished, or the key is not RSA. The returned pointer references + * structures within the context that can become invalid if the context + * is reused or released. + * + * \param ctx key decoder context. + * \return decoded RSA public key, or `NULL`. + */ +static inline const br_rsa_public_key * +br_pkey_decoder_get_rsa(const br_pkey_decoder_context *ctx) +{ + if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_RSA) { + return &ctx->key.rsa; + } else { + return NULL; + } +} + +/** + * \brief Get the decoded EC private key. + * + * This function returns `NULL` if the decoding failed, or is not + * finished, or the key is not EC. The returned pointer references + * structures within the context that can become invalid if the context + * is reused or released. + * + * \param ctx key decoder context. + * \return decoded EC private key, or `NULL`. + */ +static inline const br_ec_public_key * +br_pkey_decoder_get_ec(const br_pkey_decoder_context *ctx) +{ + if (ctx->err == 0 && ctx->key_type == BR_KEYTYPE_EC) { + return &ctx->key.ec; + } else { + return NULL; + } +} + +/** + * \brief Encode an RSA private key (raw DER format). + * + * This function encodes the provided key into the "raw" format specified + * in PKCS#1 (RFC 8017, Appendix C, type `RSAPrivateKey`), with DER + * encoding rules. + * + * The key elements are: + * + * - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`) + * + * - `pk`: the public key (`n` and `e`) + * + * - `d` (size: `dlen` bytes): the private exponent + * + * The public key elements, and the private exponent `d`, can be + * recomputed from the private key (see `br_rsa_compute_modulus()`, + * `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`). + * + * If `dest` is not `NULL`, then the encoded key is written at that + * address, and the encoded length (in bytes) is returned. If `dest` is + * `NULL`, then nothing is written, but the encoded length is still + * computed and returned. + * + * \param dest the destination buffer (or `NULL`). + * \param sk the RSA private key. + * \param pk the RSA public key. + * \param d the RSA private exponent. + * \param dlen the RSA private exponent length (in bytes). + * \return the encoded key length (in bytes). + */ +size_t br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk, + const br_rsa_public_key *pk, const void *d, size_t dlen); + +/** + * \brief Encode an RSA private key (PKCS#8 DER format). + * + * This function encodes the provided key into the PKCS#8 format + * (RFC 5958, type `OneAsymmetricKey`). It wraps around the "raw DER" + * format for the RSA key, as implemented by `br_encode_rsa_raw_der()`. + * + * The key elements are: + * + * - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`) + * + * - `pk`: the public key (`n` and `e`) + * + * - `d` (size: `dlen` bytes): the private exponent + * + * The public key elements, and the private exponent `d`, can be + * recomputed from the private key (see `br_rsa_compute_modulus()`, + * `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`). + * + * If `dest` is not `NULL`, then the encoded key is written at that + * address, and the encoded length (in bytes) is returned. If `dest` is + * `NULL`, then nothing is written, but the encoded length is still + * computed and returned. + * + * \param dest the destination buffer (or `NULL`). + * \param sk the RSA private key. + * \param pk the RSA public key. + * \param d the RSA private exponent. + * \param dlen the RSA private exponent length (in bytes). + * \return the encoded key length (in bytes). + */ +size_t br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk, + const br_rsa_public_key *pk, const void *d, size_t dlen); + +/** + * \brief Encode an EC private key (raw DER format). + * + * This function encodes the provided key into the "raw" format specified + * in RFC 5915 (type `ECPrivateKey`), with DER encoding rules. + * + * The private key is provided in `sk`, the public key being `pk`. If + * `pk` is `NULL`, then the encoded key will not include the public key + * in its `publicKey` field (which is nominally optional). + * + * If `dest` is not `NULL`, then the encoded key is written at that + * address, and the encoded length (in bytes) is returned. If `dest` is + * `NULL`, then nothing is written, but the encoded length is still + * computed and returned. + * + * If the key cannot be encoded (e.g. because there is no known OBJECT + * IDENTIFIER for the used curve), then 0 is returned. + * + * \param dest the destination buffer (or `NULL`). + * \param sk the EC private key. + * \param pk the EC public key (or `NULL`). + * \return the encoded key length (in bytes), or 0. + */ +size_t br_encode_ec_raw_der(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk); + +/** + * \brief Encode an EC private key (PKCS#8 DER format). + * + * This function encodes the provided key into the PKCS#8 format + * (RFC 5958, type `OneAsymmetricKey`). The curve is identified + * by an OID provided as parameters to the `privateKeyAlgorithm` + * field. The private key value (contents of the `privateKey` field) + * contains the DER encoding of the `ECPrivateKey` type defined in + * RFC 5915, without the `parameters` field (since they would be + * redundant with the information in `privateKeyAlgorithm`). + * + * The private key is provided in `sk`, the public key being `pk`. If + * `pk` is not `NULL`, then the encoded public key is included in the + * `publicKey` field of the private key value (but not in the `publicKey` + * field of the PKCS#8 `OneAsymmetricKey` wrapper). + * + * If `dest` is not `NULL`, then the encoded key is written at that + * address, and the encoded length (in bytes) is returned. If `dest` is + * `NULL`, then nothing is written, but the encoded length is still + * computed and returned. + * + * If the key cannot be encoded (e.g. because there is no known OBJECT + * IDENTIFIER for the used curve), then 0 is returned. + * + * \param dest the destination buffer (or `NULL`). + * \param sk the EC private key. + * \param pk the EC public key (or `NULL`). + * \return the encoded key length (in bytes), or 0. + */ +size_t br_encode_ec_pkcs8_der(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk); + +/** + * \brief PEM banner for RSA private key (raw). + */ +#define BR_ENCODE_PEM_RSA_RAW "RSA PRIVATE KEY" + +/** + * \brief PEM banner for EC private key (raw). + */ +#define BR_ENCODE_PEM_EC_RAW "EC PRIVATE KEY" + +/** + * \brief PEM banner for an RSA or EC private key in PKCS#8 format. + */ +#define BR_ENCODE_PEM_PKCS8 "PRIVATE KEY" + +#ifdef __cplusplus +} +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/config.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/config.h new file mode 100644 index 000000000..08e78dedf --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/config.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef CONFIG_H__ +#define CONFIG_H__ + +/* + * This file contains compile-time flags that can override the + * autodetection performed in relevant files. Each flag is a macro; it + * deactivates the feature if defined to 0, activates it if defined to a + * non-zero integer (normally 1). If the macro is not defined, then + * autodetection applies. + */ + +/* + * When BR_64 is enabled, 64-bit integer types are assumed to be + * efficient (i.e. the architecture has 64-bit registers and can + * do 64-bit operations as fast as 32-bit operations). + * +#define BR_64 1 + */ + +/* + * When BR_LOMUL is enabled, then multiplications of 32-bit values whose + * result are truncated to the low 32 bits are assumed to be + * substantially more efficient than 32-bit multiplications that yield + * 64-bit results. This is typically the case on low-end ARM Cortex M + * systems (M0, M0+, M1, and arguably M3 and M4 as well). +#define BR_LOMUL 1 + */ + +/* + * When BR_SLOW_MUL is enabled, multiplications are assumed to be + * substantially slow with regards to other integer operations, thus + * making it worth to make more operations for a given task if it allows + * using less multiplications. + * +#define BR_SLOW_MUL 1 + */ + +/* + * When BR_SLOW_MUL15 is enabled, short multplications (on 15-bit words) + * are assumed to be substantially slow with regards to other integer + * operations, thus making it worth to make more integer operations if + * it allows using less multiplications. + * +#define BR_SLOW_MUL15 1 + */ + +/* + * When BR_CT_MUL31 is enabled, multiplications of 31-bit values (used + * in the "i31" big integer implementation) use an alternate implementation + * which is slower and larger than the normal multiplication, but should + * ensure constant-time multiplications even on architectures where the + * multiplication opcode takes a variable number of cycles to complete. + * +#define BR_CT_MUL31 1 + */ + +/* + * When BR_CT_MUL15 is enabled, multiplications of 15-bit values (held + * in 32-bit words) use an alternate implementation which is slower and + * larger than the normal multiplication, but should ensure + * constant-time multiplications on most/all architectures where the + * basic multiplication is not constant-time. +#define BR_CT_MUL15 1 + */ + +/* + * When BR_NO_ARITH_SHIFT is enabled, arithmetic right shifts (with sign + * extension) are performed with a sequence of operations which is bigger + * and slower than a simple right shift on a signed value. This avoids + * relying on an implementation-defined behaviour. However, most if not + * all C compilers use sign extension for right shifts on signed values, + * so this alternate macro is disabled by default. +#define BR_NO_ARITH_SHIFT 1 + */ + +/* + * When BR_RDRAND is enabled, the SSL engine will use the RDRAND opcode + * to automatically obtain quality randomness for seeding its internal + * PRNG. Since that opcode is present only in recent x86 CPU, its + * support is dynamically tested; if the current CPU does not support + * it, then another random source will be used, such as /dev/urandom or + * CryptGenRandom(). + * +#define BR_RDRAND 1 + */ + +/* + * When BR_USE_GETENTROPY is enabled, the SSL engine will use the + * getentropy() function to obtain quality randomness for seeding its + * internal PRNG. On Linux and FreeBSD, getentropy() is implemented by + * the standard library with the system call getrandom(); on OpenBSD, + * getentropy() is the system call, and there is no getrandom() wrapper, + * hence the use of the getentropy() function for maximum portability. + * + * If the getentropy() call fails, and BR_USE_URANDOM is not explicitly + * disabled, then /dev/urandom will be used as a fallback mechanism. On + * FreeBSD and OpenBSD, this does not change much, since /dev/urandom + * will block if not enough entropy has been obtained since last boot. + * On Linux, /dev/urandom might not block, which can be troublesome in + * early boot stages, which is why getentropy() is preferred. + * +#define BR_USE_GETENTROPY 1 + */ + +/* + * When BR_USE_URANDOM is enabled, the SSL engine will use /dev/urandom + * to automatically obtain quality randomness for seeding its internal + * PRNG. + * +#define BR_USE_URANDOM 1 + */ + +/* + * When BR_USE_WIN32_RAND is enabled, the SSL engine will use the Win32 + * (CryptoAPI) functions (CryptAcquireContext(), CryptGenRandom()...) to + * automatically obtain quality randomness for seeding its internal PRNG. + * + * Note: if both BR_USE_URANDOM and BR_USE_WIN32_RAND are defined, the + * former takes precedence. + * +#define BR_USE_WIN32_RAND 1 + */ + +/* + * When BR_USE_UNIX_TIME is enabled, the X.509 validation engine obtains + * the current time from the OS by calling time(), and assuming that the + * returned value (a 'time_t') is an integer that counts time in seconds + * since the Unix Epoch (Jan 1st, 1970, 00:00 UTC). + */ +#define BR_USE_UNIX_TIME 0 + + +/* + * When BR_USE_WIN32_TIME is enabled, the X.509 validation engine obtains + * the current time from the OS by calling the Win32 function + * GetSystemTimeAsFileTime(). + * + * Note: if both BR_USE_UNIX_TIME and BR_USE_WIN32_TIME are defined, the + * former takes precedence. + * +#define BR_USE_WIN32_TIME 1 + */ + +/* + * When BR_ARMEL_CORTEXM_GCC is enabled, some operations are replaced with + * inline assembly which is shorter and/or faster. This should be used + * only when all of the following are true: + * - target architecture is ARM in Thumb mode + * - target endianness is little-endian + * - compiler is GCC (or GCC-compatible for inline assembly syntax) + * + * This is meant for the low-end cores (Cortex M0, M0+, M1, M3). + * Note: if BR_LOMUL is not explicitly enabled or disabled, then + * enabling BR_ARMEL_CORTEXM_GCC also enables BR_LOMUL. + */ +#if defined(__arm__) && defined(__thumb__) +#define BR_ARMEL_CORTEXM_GCC 1 +#endif + +/* + * When BR_AES_X86NI is enabled, the AES implementation using the x86 "NI" + * instructions (dedicated AES opcodes) will be compiled. If this is not + * enabled explicitly, then that AES implementation will be compiled only + * if a compatible compiler is detected. If set explicitly to 0, the + * implementation will not be compiled at all. + * +#define BR_AES_X86NI 1 + */ + +/* + * When BR_SSE2 is enabled, SSE2 intrinsics will be used for some + * algorithm implementations that use them (e.g. chacha20_sse2). If this + * is not enabled explicitly, then support for SSE2 intrinsics will be + * automatically detected. If set explicitly to 0, then SSE2 code will + * not be compiled at all. + * +#define BR_SSE2 1 + */ + +/* + * When BR_POWER8 is enabled, the AES implementation using the POWER ISA + * 2.07 opcodes (available on POWER8 processors and later) is compiled. + * If this is not enabled explicitly, then that implementation will be + * compiled only if a compatible compiler is detected, _and_ the target + * architecture is POWER8 or later. + * +#define BR_POWER8 1 + */ + +/* + * When BR_INT128 is enabled, then code using the 'unsigned __int64' + * and 'unsigned __int128' types will be used to leverage 64x64->128 + * unsigned multiplications. This should work with GCC and compatible + * compilers on 64-bit architectures. + * +#define BR_INT128 1 + */ + +/* + * When BR_UMUL128 is enabled, then code using the '_umul128()' and + * '_addcarry_u64()' intrinsics will be used to implement 64x64->128 + * unsigned multiplications. This should work on Visual C on x64 systems. + * +#define BR_UMUL128 1 + */ + +/* + * When BR_LE_UNALIGNED is enabled, then the current architecture is + * assumed to use little-endian encoding for integers, and to tolerate + * unaligned accesses with no or minimal time penalty. + * +#define BR_LE_UNALIGNED 1 + */ + +/* + * When BR_BE_UNALIGNED is enabled, then the current architecture is + * assumed to use big-endian encoding for integers, and to tolerate + * unaligned accesses with no or minimal time penalty. + * +#define BR_BE_UNALIGNED 1 + */ + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/inner.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/inner.h new file mode 100644 index 000000000..1c4b4f3c5 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/inner.h @@ -0,0 +1,2583 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#ifndef INNER_H__ +#define INNER_H__ + +#include +#include + +#include "config.h" +#include "bearssl.h" + +/* + * On MSVC, disable the warning about applying unary minus on an + * unsigned type: it is standard, we do it all the time, and for + * good reasons. + */ +#if _MSC_VER +#pragma warning( disable : 4146 ) +#endif + +/* + * Maximum size for a RSA modulus (in bits). Allocated stack buffers + * depend on that size, so this value should be kept small. Currently, + * 2048-bit RSA keys offer adequate security, and should still do so for + * the next few decades; however, a number of widespread PKI have + * already set their root keys to RSA-4096, so we should be able to + * process such keys. + * + * This value MUST be a multiple of 64. This value MUST NOT exceed 47666 + * (some computations in RSA key generation rely on the factor size being + * no more than 23833 bits). RSA key sizes beyond 3072 bits don't make a + * lot of sense anyway. + */ +#define BR_MAX_RSA_SIZE 4096 + +/* + * Minimum size for a RSA modulus (in bits); this value is used only to + * filter out invalid parameters for key pair generation. Normally, + * applications should not use RSA keys smaller than 2048 bits; but some + * specific cases might need shorter keys, for legacy or research + * purposes. + */ +#define BR_MIN_RSA_SIZE 512 + +/* + * Maximum size for a RSA factor (in bits). This is for RSA private-key + * operations. Default is to support factors up to a bit more than half + * the maximum modulus size. + * + * This value MUST be a multiple of 32. + */ +#define BR_MAX_RSA_FACTOR ((BR_MAX_RSA_SIZE + 64) >> 1) + +/* + * Maximum size for an EC curve (modulus or order), in bits. Size of + * stack buffers depends on that parameter. This size MUST be a multiple + * of 8 (so that decoding an integer with that many bytes does not + * overflow). + */ +#define BR_MAX_EC_SIZE 528 + +/* + * Some macros to recognize the current architecture. Right now, we are + * interested into automatically recognizing architecture with efficient + * 64-bit types so that we may automatically use implementations that + * use 64-bit registers in that case. Future versions may detect, e.g., + * availability of SSE2 intrinsics. + * + * If 'unsigned long' is a 64-bit type, then we assume that 64-bit types + * are efficient. Otherwise, we rely on macros that depend on compiler, + * OS and architecture. In any case, failure to detect the architecture + * as 64-bit means that the 32-bit code will be used, and that code + * works also on 64-bit architectures (the 64-bit code may simply be + * more efficient). + * + * The test on 'unsigned long' should already catch most cases, the one + * notable exception being Windows code where 'unsigned long' is kept to + * 32-bit for compatibility with all the legacy code that liberally uses + * the 'DWORD' type for 32-bit values. + * + * Macro names are taken from: http://nadeausoftware.com/articles/2012/02/c_c_tip_how_detect_processor_type_using_compiler_predefined_macros + */ +#ifndef BR_64 +#if ((ULONG_MAX >> 31) >> 31) == 3 +#define BR_64 1 +#elif defined(__ia64) || defined(__itanium__) || defined(_M_IA64) +#define BR_64 1 +#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \ + || defined(__64BIT__) || defined(_LP64) || defined(__LP64__) +#define BR_64 1 +#elif defined(__sparc64__) +#define BR_64 1 +#elif defined(__x86_64__) || defined(_M_X64) +#define BR_64 1 +#elif defined(__aarch64__) || defined(_M_ARM64) +#define BR_64 1 +#elif defined(__mips64) +#define BR_64 1 +#endif +#endif + +/* + * Set BR_LOMUL on platforms where it makes sense. + */ +#ifndef BR_LOMUL +#if BR_ARMEL_CORTEXM_GCC +#define BR_LOMUL 1 +#endif +#endif + +/* + * Architecture detection. + */ +#ifndef BR_i386 +#if __i386__ || _M_IX86 +#define BR_i386 1 +#endif +#endif + +#ifndef BR_amd64 +#if __x86_64__ || _M_X64 +#define BR_amd64 1 +#endif +#endif + +/* + * Compiler brand and version. + * + * Implementations that use intrinsics need to detect the compiler type + * and version because some specific actions may be needed to activate + * the corresponding opcodes, both for header inclusion, and when using + * them in a function. + * + * BR_GCC, BR_CLANG and BR_MSC will be set to 1 for, respectively, GCC, + * Clang and MS Visual C. For each of them, sub-macros will be defined + * for versions; each sub-macro is set whenever the compiler version is + * at least as recent as the one corresponding to the macro. + */ + +/* + * GCC thresholds are on versions 4.4 to 4.9 and 5.0. + */ +#ifndef BR_GCC +#if __GNUC__ && !__clang__ +#define BR_GCC 1 + +#if __GNUC__ > 4 +#define BR_GCC_5_0 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9 +#define BR_GCC_4_9 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 8 +#define BR_GCC_4_8 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 7 +#define BR_GCC_4_7 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6 +#define BR_GCC_4_6 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 5 +#define BR_GCC_4_5 1 +#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 4 +#define BR_GCC_4_4 1 +#endif + +#if BR_GCC_5_0 +#define BR_GCC_4_9 1 +#endif +#if BR_GCC_4_9 +#define BR_GCC_4_8 1 +#endif +#if BR_GCC_4_8 +#define BR_GCC_4_7 1 +#endif +#if BR_GCC_4_7 +#define BR_GCC_4_6 1 +#endif +#if BR_GCC_4_6 +#define BR_GCC_4_5 1 +#endif +#if BR_GCC_4_5 +#define BR_GCC_4_4 1 +#endif + +#endif +#endif + +/* + * Clang thresholds are on versions 3.7.0 and 3.8.0. + */ +#ifndef BR_CLANG +#if __clang__ +#define BR_CLANG 1 + +#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8) +#define BR_CLANG_3_8 1 +#elif __clang_major__ == 3 && __clang_minor__ >= 7 +#define BR_CLANG_3_7 1 +#endif + +#if BR_CLANG_3_8 +#define BR_CLANG_3_7 1 +#endif + +#endif +#endif + +/* + * MS Visual C thresholds are on Visual Studio 2005 to 2015. + */ +#ifndef BR_MSC +#if _MSC_VER +#define BR_MSC 1 + +#if _MSC_VER >= 1900 +#define BR_MSC_2015 1 +#elif _MSC_VER >= 1800 +#define BR_MSC_2013 1 +#elif _MSC_VER >= 1700 +#define BR_MSC_2012 1 +#elif _MSC_VER >= 1600 +#define BR_MSC_2010 1 +#elif _MSC_VER >= 1500 +#define BR_MSC_2008 1 +#elif _MSC_VER >= 1400 +#define BR_MSC_2005 1 +#endif + +#if BR_MSC_2015 +#define BR_MSC_2013 1 +#endif +#if BR_MSC_2013 +#define BR_MSC_2012 1 +#endif +#if BR_MSC_2012 +#define BR_MSC_2010 1 +#endif +#if BR_MSC_2010 +#define BR_MSC_2008 1 +#endif +#if BR_MSC_2008 +#define BR_MSC_2005 1 +#endif + +#endif +#endif + +/* + * GCC 4.4+ and Clang 3.7+ allow tagging specific functions with a + * 'target' attribute that activates support for specific opcodes. + */ +#if BR_GCC_4_4 || BR_CLANG_3_7 +#define BR_TARGET(x) __attribute__((target(x))) +#else +#define BR_TARGET(x) +#endif + +/* + * AES-NI intrinsics are available on x86 (32-bit and 64-bit) with + * GCC 4.8+, Clang 3.7+ and MSC 2012+. + */ +#ifndef BR_AES_X86NI +#if (BR_i386 || BR_amd64) && (BR_GCC_4_8 || BR_CLANG_3_7 || BR_MSC_2012) +#define BR_AES_X86NI 1 +#endif +#endif + +/* + * SSE2 intrinsics are available on x86 (32-bit and 64-bit) with + * GCC 4.4+, Clang 3.7+ and MSC 2005+. + */ +#ifndef BR_SSE2 +#if (BR_i386 || BR_amd64) && (BR_GCC_4_4 || BR_CLANG_3_7 || BR_MSC_2005) +#define BR_SSE2 1 +#endif +#endif + +/* + * RDRAND intrinsics are available on x86 (32-bit and 64-bit) with + * GCC 4.6+, Clang 3.7+ and MSC 2012+. + */ +#ifndef BR_RDRAND +#if (BR_i386 || BR_amd64) && (BR_GCC_4_6 || BR_CLANG_3_7 || BR_MSC_2012) +#define BR_RDRAND 1 +#endif +#endif + +/* + * Determine type of OS for random number generation. Macro names and + * values are documented on: + * https://sourceforge.net/p/predef/wiki/OperatingSystems/ + * + * Win32's CryptGenRandom() should be available on Windows systems. + * + * /dev/urandom should work on all Unix-like systems (including macOS X). + * + * getentropy() is present on Linux (Glibc 2.25+), FreeBSD (12.0+) and + * OpenBSD (5.6+). For OpenBSD, there does not seem to be easy to use + * macros to test the minimum version, so we just assume that it is + * recent enough (last version without getentropy() has gone out of + * support in May 2015). + * + * Ideally we should use getentropy() on macOS (10.12+) too, but I don't + * know how to test the exact OS version with preprocessor macros. + * + * TODO: enrich the list of detected system. + */ + +#ifndef BR_USE_URANDOM +#if defined _AIX \ + || defined __ANDROID__ \ + || defined __FreeBSD__ \ + || defined __NetBSD__ \ + || defined __OpenBSD__ \ + || defined __DragonFly__ \ + || defined __linux__ \ + || (defined __sun && (defined __SVR4 || defined __svr4__)) \ + || (defined __APPLE__ && defined __MACH__) +#define BR_USE_URANDOM 1 +#endif +#endif + +#ifndef BR_USE_GETENTROPY +#if (defined __linux__ \ + && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 25))) \ + || (defined __FreeBSD__ && __FreeBSD__ >= 12) \ + || defined __OpenBSD__ +#define BR_USE_GETENTROPY 1 +#endif +#endif + +#ifndef BR_USE_WIN32_RAND +#if defined _WIN32 || defined _WIN64 +#define BR_USE_WIN32_RAND 1 +#endif +#endif + +/* + * POWER8 crypto support. We rely on compiler macros for the + * architecture, since we do not have a reliable, simple way to detect + * the required support at runtime (we could try running an opcode, and + * trapping the exception or signal on illegal instruction, but this + * induces some non-trivial OS dependencies that we would prefer to + * avoid if possible). + */ +#ifndef BR_POWER8 +#if __GNUC__ && ((_ARCH_PWR8 || _ARCH_PPC) && __CRYPTO__) +#define BR_POWER8 1 +#endif +#endif + +/* + * Detect endinanness on POWER8. + */ +#if BR_POWER8 +#if defined BR_POWER8_LE +#undef BR_POWER8_BE +#if BR_POWER8_LE +#define BR_POWER8_BE 0 +#else +#define BR_POWER8_BE 1 +#endif +#elif defined BR_POWER8_BE +#undef BR_POWER8_LE +#if BR_POWER8_BE +#define BR_POWER8_LE 0 +#else +#define BR_POWER8_LE 1 +#endif +#else +#if __LITTLE_ENDIAN__ +#define BR_POWER8_LE 1 +#define BR_POWER8_BE 0 +#else +#define BR_POWER8_LE 0 +#define BR_POWER8_BE 1 +#endif +#endif +#endif + +/* + * Detect support for 128-bit integers. + */ +#if !defined BR_INT128 && !defined BR_UMUL128 +#ifdef __SIZEOF_INT128__ +#define BR_INT128 1 +#elif _M_X64 +#define BR_UMUL128 1 +#endif +#endif + +/* + * Detect support for unaligned accesses with known endianness. + * + * x86 (both 32-bit and 64-bit) is little-endian and allows unaligned + * accesses. + * + * POWER/PowerPC allows unaligned accesses when big-endian. POWER8 and + * later also allow unaligned accesses when little-endian. + */ +#if !defined BR_LE_UNALIGNED && !defined BR_BE_UNALIGNED + +#if __i386 || __i386__ || __x86_64__ || _M_IX86 || _M_X64 +#define BR_LE_UNALIGNED 1 +#elif BR_POWER8_BE +#define BR_BE_UNALIGNED 1 +#elif BR_POWER8_LE +#define BR_LE_UNALIGNED 1 +#elif (__powerpc__ || __powerpc64__ || _M_PPC || _ARCH_PPC || _ARCH_PPC64) \ + && __BIG_ENDIAN__ +#define BR_BE_UNALIGNED 1 +#endif + +#endif + +/* + * Detect support for an OS-provided time source. + */ + +#ifndef BR_USE_UNIX_TIME +#if defined __unix__ || defined __linux__ \ + || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \ + || (defined __APPLE__ && defined __MACH__) +#define BR_USE_UNIX_TIME 1 +#endif +#endif + +#ifndef BR_USE_WIN32_TIME +#if defined _WIN32 || defined _WIN64 +#define BR_USE_WIN32_TIME 1 +#endif +#endif + +/* ==================================================================== */ +/* + * Encoding/decoding functions. + * + * 32-bit and 64-bit decoding, both little-endian and big-endian, is + * implemented with the inline functions below. + * + * When allowed by some compile-time options (autodetected or provided), + * optimised code is used, to perform direct memory access when the + * underlying architecture supports it, both for endianness and + * alignment. This, however, may trigger strict aliasing issues; the + * code below uses unions to perform (supposedly) safe type punning. + * Since the C aliasing rules are relatively complex and were amended, + * or at least re-explained with different phrasing, in all successive + * versions of the C standard, it is always a bit risky to bet that any + * specific version of a C compiler got it right, for some notion of + * "right". + */ + +typedef union { + uint16_t u; + unsigned char b[sizeof(uint16_t)]; +} br_union_u16; + +typedef union { + uint32_t u; + unsigned char b[sizeof(uint32_t)]; +} br_union_u32; + +typedef union { + uint64_t u; + unsigned char b[sizeof(uint64_t)]; +} br_union_u64; + +static inline void +br_enc16le(void *dst, unsigned x) +{ +#if BR_LE_UNALIGNED + ((br_union_u16 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)x; + buf[1] = (unsigned char)(x >> 8); +#endif +} + +static inline void +br_enc16be(void *dst, unsigned x) +{ +#if BR_BE_UNALIGNED + ((br_union_u16 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)(x >> 8); + buf[1] = (unsigned char)x; +#endif +} + +static inline unsigned +br_dec16le(const void *src) +{ +#if BR_LE_UNALIGNED + return ((const br_union_u16 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return (unsigned)buf[0] | ((unsigned)buf[1] << 8); +#endif +} + +static inline unsigned +br_dec16be(const void *src) +{ +#if BR_BE_UNALIGNED + return ((const br_union_u16 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return ((unsigned)buf[0] << 8) | (unsigned)buf[1]; +#endif +} + +static inline void +br_enc32le(void *dst, uint32_t x) +{ +#if BR_LE_UNALIGNED + ((br_union_u32 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)x; + buf[1] = (unsigned char)(x >> 8); + buf[2] = (unsigned char)(x >> 16); + buf[3] = (unsigned char)(x >> 24); +#endif +} + +static inline void +br_enc32be(void *dst, uint32_t x) +{ +#if BR_BE_UNALIGNED + ((br_union_u32 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + buf[0] = (unsigned char)(x >> 24); + buf[1] = (unsigned char)(x >> 16); + buf[2] = (unsigned char)(x >> 8); + buf[3] = (unsigned char)x; +#endif +} + +static inline uint32_t +br_dec32le(const void *src) +{ +#if BR_LE_UNALIGNED + return ((const br_union_u32 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return (uint32_t)buf[0] + | ((uint32_t)buf[1] << 8) + | ((uint32_t)buf[2] << 16) + | ((uint32_t)buf[3] << 24); +#endif +} + +static inline uint32_t +br_dec32be(const void *src) +{ +#if BR_BE_UNALIGNED + return ((const br_union_u32 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return ((uint32_t)buf[0] << 24) + | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[2] << 8) + | (uint32_t)buf[3]; +#endif +} + +static inline void +br_enc64le(void *dst, uint64_t x) +{ +#if BR_LE_UNALIGNED + ((br_union_u64 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + br_enc32le(buf, (uint32_t)x); + br_enc32le(buf + 4, (uint32_t)(x >> 32)); +#endif +} + +static inline void +br_enc64be(void *dst, uint64_t x) +{ +#if BR_BE_UNALIGNED + ((br_union_u64 *)dst)->u = x; +#else + unsigned char *buf; + + buf = dst; + br_enc32be(buf, (uint32_t)(x >> 32)); + br_enc32be(buf + 4, (uint32_t)x); +#endif +} + +static inline uint64_t +br_dec64le(const void *src) +{ +#if BR_LE_UNALIGNED + return ((const br_union_u64 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return (uint64_t)br_dec32le(buf) + | ((uint64_t)br_dec32le(buf + 4) << 32); +#endif +} + +static inline uint64_t +br_dec64be(const void *src) +{ +#if BR_BE_UNALIGNED + return ((const br_union_u64 *)src)->u; +#else + const unsigned char *buf; + + buf = src; + return ((uint64_t)br_dec32be(buf) << 32) + | (uint64_t)br_dec32be(buf + 4); +#endif +} + +/* + * Range decoding and encoding (for several successive values). + */ +void br_range_dec16le(uint16_t *v, size_t num, const void *src); +void br_range_dec16be(uint16_t *v, size_t num, const void *src); +void br_range_enc16le(void *dst, const uint16_t *v, size_t num); +void br_range_enc16be(void *dst, const uint16_t *v, size_t num); + +void br_range_dec32le(uint32_t *v, size_t num, const void *src); +void br_range_dec32be(uint32_t *v, size_t num, const void *src); +void br_range_enc32le(void *dst, const uint32_t *v, size_t num); +void br_range_enc32be(void *dst, const uint32_t *v, size_t num); + +void br_range_dec64le(uint64_t *v, size_t num, const void *src); +void br_range_dec64be(uint64_t *v, size_t num, const void *src); +void br_range_enc64le(void *dst, const uint64_t *v, size_t num); +void br_range_enc64be(void *dst, const uint64_t *v, size_t num); + +/* + * Byte-swap a 32-bit integer. + */ +static inline uint32_t +br_swap32(uint32_t x) +{ + x = ((x & (uint32_t)0x00FF00FF) << 8) + | ((x >> 8) & (uint32_t)0x00FF00FF); + return (x << 16) | (x >> 16); +} + +/* ==================================================================== */ +/* + * Support code for hash functions. + */ + +/* + * IV for MD5, SHA-1, SHA-224 and SHA-256. + */ +extern const uint32_t br_md5_IV[]; +extern const uint32_t br_sha1_IV[]; +extern const uint32_t br_sha224_IV[]; +extern const uint32_t br_sha256_IV[]; + +/* + * Round functions for MD5, SHA-1, SHA-224 and SHA-256 (SHA-224 and + * SHA-256 use the same round function). + */ +void br_md5_round(const unsigned char *buf, uint32_t *val); +void br_sha1_round(const unsigned char *buf, uint32_t *val); +void br_sha2small_round(const unsigned char *buf, uint32_t *val); + +/* + * The core function for the TLS PRF. It computes + * P_hash(secret, label + seed), and XORs the result into the dst buffer. + */ +void br_tls_phash(void *dst, size_t len, + const br_hash_class *dig, + const void *secret, size_t secret_len, const char *label, + size_t seed_num, const br_tls_prf_seed_chunk *seed); + +/* + * Copy all configured hash implementations from a multihash context + * to another. + */ +static inline void +br_multihash_copyimpl(br_multihash_context *dst, + const br_multihash_context *src) +{ + memcpy((void *)dst->impl, src->impl, sizeof src->impl); +} + +/* ==================================================================== */ +/* + * Constant-time primitives. These functions manipulate 32-bit values in + * order to provide constant-time comparisons and multiplexers. + * + * Boolean values (the "ctl" bits) MUST have value 0 or 1. + * + * Implementation notes: + * ===================== + * + * The uintN_t types are unsigned and with width exactly N bits; the C + * standard guarantees that computations are performed modulo 2^N, and + * there can be no overflow. Negation (unary '-') works on unsigned types + * as well. + * + * The intN_t types are guaranteed to have width exactly N bits, with no + * padding bit, and using two's complement representation. Casting + * intN_t to uintN_t really is conversion modulo 2^N. Beware that intN_t + * types, being signed, trigger implementation-defined behaviour on + * overflow (including raising some signal): with GCC, while modular + * arithmetics are usually applied, the optimizer may assume that + * overflows don't occur (unless the -fwrapv command-line option is + * added); Clang has the additional -ftrapv option to explicitly trap on + * integer overflow or underflow. + */ + +/* + * Negate a boolean. + */ +static inline uint32_t +NOT(uint32_t ctl) +{ + return ctl ^ 1; +} + +/* + * Multiplexer: returns x if ctl == 1, y if ctl == 0. + */ +static inline uint32_t +MUX(uint32_t ctl, uint32_t x, uint32_t y) +{ + return y ^ (-ctl & (x ^ y)); +} + +/* + * Equality check: returns 1 if x == y, 0 otherwise. + */ +static inline uint32_t +EQ(uint32_t x, uint32_t y) +{ + uint32_t q; + + q = x ^ y; + return NOT((q | -q) >> 31); +} + +/* + * Inequality check: returns 1 if x != y, 0 otherwise. + */ +static inline uint32_t +NEQ(uint32_t x, uint32_t y) +{ + uint32_t q; + + q = x ^ y; + return (q | -q) >> 31; +} + +/* + * Comparison: returns 1 if x > y, 0 otherwise. + */ +static inline uint32_t +GT(uint32_t x, uint32_t y) +{ + /* + * If both x < 2^31 and x < 2^31, then y-x will have its high + * bit set if x > y, cleared otherwise. + * + * If either x >= 2^31 or y >= 2^31 (but not both), then the + * result is the high bit of x. + * + * If both x >= 2^31 and y >= 2^31, then we can virtually + * subtract 2^31 from both, and we are back to the first case. + * Since (y-2^31)-(x-2^31) = y-x, the subtraction is already + * fine. + */ + uint32_t z; + + z = y - x; + return (z ^ ((x ^ y) & (x ^ z))) >> 31; +} + +/* + * Other comparisons (greater-or-equal, lower-than, lower-or-equal). + */ +#define GE(x, y) NOT(GT(y, x)) +#define LT(x, y) GT(y, x) +#define LE(x, y) NOT(GT(x, y)) + +/* + * General comparison: returned value is -1, 0 or 1, depending on + * whether x is lower than, equal to, or greater than y. + */ +static inline int32_t +CMP(uint32_t x, uint32_t y) +{ + return (int32_t)GT(x, y) | -(int32_t)GT(y, x); +} + +/* + * Returns 1 if x == 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +EQ0(int32_t x) +{ + uint32_t q; + + q = (uint32_t)x; + return ~(q | -q) >> 31; +} + +/* + * Returns 1 if x > 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +GT0(int32_t x) +{ + /* + * High bit of -x is 0 if x == 0, but 1 if x > 0. + */ + uint32_t q; + + q = (uint32_t)x; + return (~q & -q) >> 31; +} + +/* + * Returns 1 if x >= 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +GE0(int32_t x) +{ + return ~(uint32_t)x >> 31; +} + +/* + * Returns 1 if x < 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +LT0(int32_t x) +{ + return (uint32_t)x >> 31; +} + +/* + * Returns 1 if x <= 0, 0 otherwise. Take care that the operand is signed. + */ +static inline uint32_t +LE0(int32_t x) +{ + uint32_t q; + + /* + * ~-x has its high bit set if and only if -x is nonnegative (as + * a signed int), i.e. x is in the -(2^31-1) to 0 range. We must + * do an OR with x itself to account for x = -2^31. + */ + q = (uint32_t)x; + return (q | ~-q) >> 31; +} + +/* + * Conditional copy: src[] is copied into dst[] if and only if ctl is 1. + * dst[] and src[] may overlap completely (but not partially). + */ +void br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len); + +#define CCOPY br_ccopy + +/* + * Compute the bit length of a 32-bit integer. Returned value is between 0 + * and 32 (inclusive). + */ +static inline uint32_t +BIT_LENGTH(uint32_t x) +{ + uint32_t k, c; + + k = NEQ(x, 0); + c = GT(x, 0xFFFF); x = MUX(c, x >> 16, x); k += c << 4; + c = GT(x, 0x00FF); x = MUX(c, x >> 8, x); k += c << 3; + c = GT(x, 0x000F); x = MUX(c, x >> 4, x); k += c << 2; + c = GT(x, 0x0003); x = MUX(c, x >> 2, x); k += c << 1; + k += GT(x, 0x0001); + return k; +} + +/* + * Compute the minimum of x and y. + */ +static inline uint32_t +MIN(uint32_t x, uint32_t y) +{ + return MUX(GT(x, y), y, x); +} + +/* + * Compute the maximum of x and y. + */ +static inline uint32_t +MAX(uint32_t x, uint32_t y) +{ + return MUX(GT(x, y), x, y); +} + +/* + * Multiply two 32-bit integers, with a 64-bit result. This default + * implementation assumes that the basic multiplication operator + * yields constant-time code. + */ +#define MUL(x, y) ((uint64_t)(x) * (uint64_t)(y)) + +#if BR_CT_MUL31 + +/* + * Alternate implementation of MUL31, that will be constant-time on some + * (old) platforms where the default MUL31 is not. Unfortunately, it is + * also substantially slower, and yields larger code, on more modern + * platforms, which is why it is deactivated by default. + * + * MUL31_lo() must do some extra work because on some platforms, the + * _signed_ multiplication may return early if the top bits are 1. + * Simply truncating (casting) the output of MUL31() would not be + * sufficient, because the compiler may notice that we keep only the low + * word, and then replace automatically the unsigned multiplication with + * a signed multiplication opcode. + */ +#define MUL31(x, y) ((uint64_t)((x) | (uint32_t)0x80000000) \ + * (uint64_t)((y) | (uint32_t)0x80000000) \ + - ((uint64_t)(x) << 31) - ((uint64_t)(y) << 31) \ + - ((uint64_t)1 << 62)) +static inline uint32_t +MUL31_lo(uint32_t x, uint32_t y) +{ + uint32_t xl, xh; + uint32_t yl, yh; + + xl = (x & 0xFFFF) | (uint32_t)0x80000000; + xh = (x >> 16) | (uint32_t)0x80000000; + yl = (y & 0xFFFF) | (uint32_t)0x80000000; + yh = (y >> 16) | (uint32_t)0x80000000; + return (xl * yl + ((xl * yh + xh * yl) << 16)) & (uint32_t)0x7FFFFFFF; +} + +#else + +/* + * Multiply two 31-bit integers, with a 62-bit result. This default + * implementation assumes that the basic multiplication operator + * yields constant-time code. + * The MUL31_lo() macro returns only the low 31 bits of the product. + */ +#define MUL31(x, y) ((uint64_t)(x) * (uint64_t)(y)) +#define MUL31_lo(x, y) (((uint32_t)(x) * (uint32_t)(y)) & (uint32_t)0x7FFFFFFF) + +#endif + +/* + * Multiply two words together; the sum of the lengths of the two + * operands must not exceed 31 (for instance, one operand may use 16 + * bits if the other fits on 15). If BR_CT_MUL15 is non-zero, then the + * macro will contain some extra operations that help in making the + * operation constant-time on some platforms, where the basic 32-bit + * multiplication is not constant-time. + */ +#if BR_CT_MUL15 +#define MUL15(x, y) (((uint32_t)(x) | (uint32_t)0x80000000) \ + * ((uint32_t)(y) | (uint32_t)0x80000000) \ + & (uint32_t)0x7FFFFFFF) +#else +#define MUL15(x, y) ((uint32_t)(x) * (uint32_t)(y)) +#endif + +/* + * Arithmetic right shift (sign bit is copied). What happens when + * right-shifting a negative value is _implementation-defined_, so it + * does not trigger undefined behaviour, but it is still up to each + * compiler to define (and document) what it does. Most/all compilers + * will do an arithmetic shift, the sign bit being used to fill the + * holes; this is a native operation on the underlying CPU, and it would + * make little sense for the compiler to do otherwise. GCC explicitly + * documents that it follows that convention. + * + * Still, if BR_NO_ARITH_SHIFT is defined (and non-zero), then an + * alternate version will be used, that does not rely on such + * implementation-defined behaviour. Unfortunately, it is also slower + * and yields bigger code, which is why it is deactivated by default. + */ +#if BR_NO_ARITH_SHIFT +#define ARSH(x, n) (((uint32_t)(x) >> (n)) \ + | ((-((uint32_t)(x) >> 31)) << (32 - (n)))) +#else +#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n)) +#endif + +/* + * Constant-time division. The dividend hi:lo is divided by the + * divisor d; the quotient is returned and the remainder is written + * in *r. If hi == d, then the quotient does not fit on 32 bits; + * returned value is thus truncated. If hi > d, returned values are + * indeterminate. + */ +uint32_t br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r); + +/* + * Wrapper for br_divrem(); the remainder is returned, and the quotient + * is discarded. + */ +static inline uint32_t +br_rem(uint32_t hi, uint32_t lo, uint32_t d) +{ + uint32_t r; + + br_divrem(hi, lo, d, &r); + return r; +} + +/* + * Wrapper for br_divrem(); the quotient is returned, and the remainder + * is discarded. + */ +static inline uint32_t +br_div(uint32_t hi, uint32_t lo, uint32_t d) +{ + uint32_t r; + + return br_divrem(hi, lo, d, &r); +} + +/* ==================================================================== */ + +/* + * Integers 'i32' + * -------------- + * + * The 'i32' functions implement computations on big integers using + * an internal representation as an array of 32-bit integers. For + * an array x[]: + * -- x[0] contains the "announced bit length" of the integer + * -- x[1], x[2]... contain the value in little-endian order (x[1] + * contains the least significant 32 bits) + * + * Multiplications rely on the elementary 32x32->64 multiplication. + * + * The announced bit length specifies the number of bits that are + * significant in the subsequent 32-bit words. Unused bits in the + * last (most significant) word are set to 0; subsequent words are + * uninitialized and need not exist at all. + * + * The execution time and memory access patterns of all computations + * depend on the announced bit length, but not on the actual word + * values. For modular integers, the announced bit length of any integer + * modulo n is equal to the actual bit length of n; thus, computations + * on modular integers are "constant-time" (only the modulus length may + * leak). + */ + +/* + * Compute the actual bit length of an integer. The argument x should + * point to the first (least significant) value word of the integer. + * The len 'xlen' contains the number of 32-bit words to access. + * + * CT: value or length of x does not leak. + */ +uint32_t br_i32_bit_length(uint32_t *x, size_t xlen); + +/* + * Decode an integer from its big-endian unsigned representation. The + * "true" bit length of the integer is computed, but all words of x[] + * corresponding to the full 'len' bytes of the source are set. + * + * CT: value or length of x does not leak. + */ +void br_i32_decode(uint32_t *x, const void *src, size_t len); + +/* + * Decode an integer from its big-endian unsigned representation. The + * integer MUST be lower than m[]; the announced bit length written in + * x[] will be equal to that of m[]. All 'len' bytes from the source are + * read. + * + * Returned value is 1 if the decode value fits within the modulus, 0 + * otherwise. In the latter case, the x[] buffer will be set to 0 (but + * still with the announced bit length of m[]). + * + * CT: value or length of x does not leak. Memory access pattern depends + * only of 'len' and the announced bit length of m. Whether x fits or + * not does not leak either. + */ +uint32_t br_i32_decode_mod(uint32_t *x, + const void *src, size_t len, const uint32_t *m); + +/* + * Reduce an integer (a[]) modulo another (m[]). The result is written + * in x[] and its announced bit length is set to be equal to that of m[]. + * + * x[] MUST be distinct from a[] and m[]. + * + * CT: only announced bit lengths leak, not values of x, a or m. + */ +void br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m); + +/* + * Decode an integer from its big-endian unsigned representation, and + * reduce it modulo the provided modulus m[]. The announced bit length + * of the result is set to be equal to that of the modulus. + * + * x[] MUST be distinct from m[]. + */ +void br_i32_decode_reduce(uint32_t *x, + const void *src, size_t len, const uint32_t *m); + +/* + * Encode an integer into its big-endian unsigned representation. The + * output length in bytes is provided (parameter 'len'); if the length + * is too short then the integer is appropriately truncated; if it is + * too long then the extra bytes are set to 0. + */ +void br_i32_encode(void *dst, size_t len, const uint32_t *x); + +/* + * Multiply x[] by 2^32 and then add integer z, modulo m[]. This + * function assumes that x[] and m[] have the same announced bit + * length, and the announced bit length of m[] matches its true + * bit length. + * + * x[] and m[] MUST be distinct arrays. + * + * CT: only the common announced bit length of x and m leaks, not + * the values of x, z or m. + */ +void br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m); + +/* + * Extract one word from an integer. The offset is counted in bits. + * The word MUST entirely fit within the word elements corresponding + * to the announced bit length of a[]. + */ +static inline uint32_t +br_i32_word(const uint32_t *a, uint32_t off) +{ + size_t u; + unsigned j; + + u = (size_t)(off >> 5) + 1; + j = (unsigned)off & 31; + if (j == 0) { + return a[u]; + } else { + return (a[u] >> j) | (a[u + 1] << (32 - j)); + } +} + +/* + * Test whether an integer is zero. + */ +uint32_t br_i32_iszero(const uint32_t *x); + +/* + * Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[] + * is unmodified, but the carry is still computed and returned. The + * arrays a[] and b[] MUST have the same announced bit length. + * + * a[] and b[] MAY be the same array, but partial overlap is not allowed. + */ +uint32_t br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl); + +/* + * Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0, + * then a[] is unmodified, but the carry is still computed and returned. + * The arrays a[] and b[] MUST have the same announced bit length. + * + * a[] and b[] MAY be the same array, but partial overlap is not allowed. + */ +uint32_t br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl); + +/* + * Compute d+a*b, result in d. The initial announced bit length of d[] + * MUST match that of a[]. The d[] array MUST be large enough to + * accommodate the full result, plus (possibly) an extra word. The + * resulting announced bit length of d[] will be the sum of the announced + * bit lengths of a[] and b[] (therefore, it may be larger than the actual + * bit length of the numerical result). + * + * a[] and b[] may be the same array. d[] must be disjoint from both a[] + * and b[]. + */ +void br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b); + +/* + * Zeroize an integer. The announced bit length is set to the provided + * value, and the corresponding words are set to 0. + */ +static inline void +br_i32_zero(uint32_t *x, uint32_t bit_len) +{ + *x ++ = bit_len; + memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x); +} + +/* + * Compute -(1/x) mod 2^32. If x is even, then this function returns 0. + */ +uint32_t br_i32_ninv32(uint32_t x); + +/* + * Convert a modular integer to Montgomery representation. The integer x[] + * MUST be lower than m[], but with the same announced bit length. + */ +void br_i32_to_monty(uint32_t *x, const uint32_t *m); + +/* + * Convert a modular integer back from Montgomery representation. The + * integer x[] MUST be lower than m[], but with the same announced bit + * length. The "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is + * the least significant value word of m[] (this works only if m[] is + * an odd integer). + */ +void br_i32_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i); + +/* + * Compute a modular Montgomery multiplication. d[] is filled with the + * value of x*y/R modulo m[] (where R is the Montgomery factor). The + * array d[] MUST be distinct from x[], y[] and m[]. x[] and y[] MUST be + * numerically lower than m[]. x[] and y[] MAY be the same array. The + * "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). + */ +void br_i32_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y, + const uint32_t *m, uint32_t m0i); + +/* + * Compute a modular exponentiation. x[] MUST be an integer modulo m[] + * (same announced bit length, lower value). m[] MUST be odd. The + * exponent is in big-endian unsigned notation, over 'elen' bytes. The + * "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). The t1[] and t2[] parameters must be temporary arrays, + * each large enough to accommodate an integer with the same size as m[]. + */ +void br_i32_modpow(uint32_t *x, const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2); + +/* ==================================================================== */ + +/* + * Integers 'i31' + * -------------- + * + * The 'i31' functions implement computations on big integers using + * an internal representation as an array of 32-bit integers. For + * an array x[]: + * -- x[0] encodes the array length and the "announced bit length" + * of the integer: namely, if the announced bit length is k, + * then x[0] = ((k / 31) << 5) + (k % 31). + * -- x[1], x[2]... contain the value in little-endian order, 31 + * bits per word (x[1] contains the least significant 31 bits). + * The upper bit of each word is 0. + * + * Multiplications rely on the elementary 32x32->64 multiplication. + * + * The announced bit length specifies the number of bits that are + * significant in the subsequent 32-bit words. Unused bits in the + * last (most significant) word are set to 0; subsequent words are + * uninitialized and need not exist at all. + * + * The execution time and memory access patterns of all computations + * depend on the announced bit length, but not on the actual word + * values. For modular integers, the announced bit length of any integer + * modulo n is equal to the actual bit length of n; thus, computations + * on modular integers are "constant-time" (only the modulus length may + * leak). + */ + +/* + * Test whether an integer is zero. + */ +uint32_t br_i31_iszero(const uint32_t *x); + +/* + * Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[] + * is unmodified, but the carry is still computed and returned. The + * arrays a[] and b[] MUST have the same announced bit length. + * + * a[] and b[] MAY be the same array, but partial overlap is not allowed. + */ +uint32_t br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl); + +/* + * Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0, + * then a[] is unmodified, but the carry is still computed and returned. + * The arrays a[] and b[] MUST have the same announced bit length. + * + * a[] and b[] MAY be the same array, but partial overlap is not allowed. + */ +uint32_t br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl); + +/* + * Compute the ENCODED actual bit length of an integer. The argument x + * should point to the first (least significant) value word of the + * integer. The len 'xlen' contains the number of 32-bit words to + * access. The upper bit of each value word MUST be 0. + * Returned value is ((k / 31) << 5) + (k % 31) if the bit length is k. + * + * CT: value or length of x does not leak. + */ +uint32_t br_i31_bit_length(uint32_t *x, size_t xlen); + +/* + * Decode an integer from its big-endian unsigned representation. The + * "true" bit length of the integer is computed and set in the encoded + * announced bit length (x[0]), but all words of x[] corresponding to + * the full 'len' bytes of the source are set. + * + * CT: value or length of x does not leak. + */ +void br_i31_decode(uint32_t *x, const void *src, size_t len); + +/* + * Decode an integer from its big-endian unsigned representation. The + * integer MUST be lower than m[]; the (encoded) announced bit length + * written in x[] will be equal to that of m[]. All 'len' bytes from the + * source are read. + * + * Returned value is 1 if the decode value fits within the modulus, 0 + * otherwise. In the latter case, the x[] buffer will be set to 0 (but + * still with the announced bit length of m[]). + * + * CT: value or length of x does not leak. Memory access pattern depends + * only of 'len' and the announced bit length of m. Whether x fits or + * not does not leak either. + */ +uint32_t br_i31_decode_mod(uint32_t *x, + const void *src, size_t len, const uint32_t *m); + +/* + * Zeroize an integer. The announced bit length is set to the provided + * value, and the corresponding words are set to 0. The ENCODED bit length + * is expected here. + */ +static inline void +br_i31_zero(uint32_t *x, uint32_t bit_len) +{ + *x ++ = bit_len; + memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x); +} + +/* + * Right-shift an integer. The shift amount must be lower than 31 + * bits. + */ +void br_i31_rshift(uint32_t *x, int count); + +/* + * Reduce an integer (a[]) modulo another (m[]). The result is written + * in x[] and its announced bit length is set to be equal to that of m[]. + * + * x[] MUST be distinct from a[] and m[]. + * + * CT: only announced bit lengths leak, not values of x, a or m. + */ +void br_i31_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m); + +/* + * Decode an integer from its big-endian unsigned representation, and + * reduce it modulo the provided modulus m[]. The announced bit length + * of the result is set to be equal to that of the modulus. + * + * x[] MUST be distinct from m[]. + */ +void br_i31_decode_reduce(uint32_t *x, + const void *src, size_t len, const uint32_t *m); + +/* + * Multiply x[] by 2^31 and then add integer z, modulo m[]. This + * function assumes that x[] and m[] have the same announced bit + * length, the announced bit length of m[] matches its true + * bit length. + * + * x[] and m[] MUST be distinct arrays. z MUST fit in 31 bits (upper + * bit set to 0). + * + * CT: only the common announced bit length of x and m leaks, not + * the values of x, z or m. + */ +void br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m); + +/* + * Encode an integer into its big-endian unsigned representation. The + * output length in bytes is provided (parameter 'len'); if the length + * is too short then the integer is appropriately truncated; if it is + * too long then the extra bytes are set to 0. + */ +void br_i31_encode(void *dst, size_t len, const uint32_t *x); + +/* + * Compute -(1/x) mod 2^31. If x is even, then this function returns 0. + */ +uint32_t br_i31_ninv31(uint32_t x); + +/* + * Compute a modular Montgomery multiplication. d[] is filled with the + * value of x*y/R modulo m[] (where R is the Montgomery factor). The + * array d[] MUST be distinct from x[], y[] and m[]. x[] and y[] MUST be + * numerically lower than m[]. x[] and y[] MAY be the same array. The + * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). + */ +void br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y, + const uint32_t *m, uint32_t m0i); + +/* + * Convert a modular integer to Montgomery representation. The integer x[] + * MUST be lower than m[], but with the same announced bit length. + */ +void br_i31_to_monty(uint32_t *x, const uint32_t *m); + +/* + * Convert a modular integer back from Montgomery representation. The + * integer x[] MUST be lower than m[], but with the same announced bit + * length. The "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is + * the least significant value word of m[] (this works only if m[] is + * an odd integer). + */ +void br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i); + +/* + * Compute a modular exponentiation. x[] MUST be an integer modulo m[] + * (same announced bit length, lower value). m[] MUST be odd. The + * exponent is in big-endian unsigned notation, over 'elen' bytes. The + * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). The t1[] and t2[] parameters must be temporary arrays, + * each large enough to accommodate an integer with the same size as m[]. + */ +void br_i31_modpow(uint32_t *x, const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2); + +/* + * Compute a modular exponentiation. x[] MUST be an integer modulo m[] + * (same announced bit length, lower value). m[] MUST be odd. The + * exponent is in big-endian unsigned notation, over 'elen' bytes. The + * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least + * significant value word of m[] (this works only if m[] is an odd + * integer). The tmp[] array is used for temporaries, and has size + * 'twlen' words; it must be large enough to accommodate at least two + * temporary values with the same size as m[] (including the leading + * "bit length" word). If there is room for more temporaries, then this + * function may use the extra room for window-based optimisation, + * resulting in faster computations. + * + * Returned value is 1 on success, 0 on error. An error is reported if + * the provided tmp[] array is too short. + */ +uint32_t br_i31_modpow_opt(uint32_t *x, const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen); + +/* + * Compute d+a*b, result in d. The initial announced bit length of d[] + * MUST match that of a[]. The d[] array MUST be large enough to + * accommodate the full result, plus (possibly) an extra word. The + * resulting announced bit length of d[] will be the sum of the announced + * bit lengths of a[] and b[] (therefore, it may be larger than the actual + * bit length of the numerical result). + * + * a[] and b[] may be the same array. d[] must be disjoint from both a[] + * and b[]. + */ +void br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b); + +/* + * Compute x/y mod m, result in x. Values x and y must be between 0 and + * m-1, and have the same announced bit length as m. Modulus m must be + * odd. The "m0i" parameter is equal to -1/m mod 2^31. The array 't' + * must point to a temporary area that can hold at least three integers + * of the size of m. + * + * m may not overlap x and y. x and y may overlap each other (this can + * be useful to test whether a value is invertible modulo m). t must be + * disjoint from all other arrays. + * + * Returned value is 1 on success, 0 otherwise. Success is attained if + * y is invertible modulo m. + */ +uint32_t br_i31_moddiv(uint32_t *x, const uint32_t *y, + const uint32_t *m, uint32_t m0i, uint32_t *t); + +/* ==================================================================== */ + +/* + * FIXME: document "i15" functions. + */ + +static inline void +br_i15_zero(uint16_t *x, uint16_t bit_len) +{ + *x ++ = bit_len; + memset(x, 0, ((bit_len + 15) >> 4) * sizeof *x); +} + +uint32_t br_i15_iszero(const uint16_t *x); + +uint16_t br_i15_ninv15(uint16_t x); + +uint32_t br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl); + +uint32_t br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl); + +void br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m); + +void br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y, + const uint16_t *m, uint16_t m0i); + +void br_i15_to_monty(uint16_t *x, const uint16_t *m); + +void br_i15_modpow(uint16_t *x, const unsigned char *e, size_t elen, + const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2); + +uint32_t br_i15_modpow_opt(uint16_t *x, const unsigned char *e, size_t elen, + const uint16_t *m, uint16_t m0i, uint16_t *tmp, size_t twlen); + +void br_i15_encode(void *dst, size_t len, const uint16_t *x); + +uint32_t br_i15_decode_mod(uint16_t *x, + const void *src, size_t len, const uint16_t *m); + +void br_i15_rshift(uint16_t *x, int count); + +uint32_t br_i15_bit_length(uint16_t *x, size_t xlen); + +void br_i15_decode(uint16_t *x, const void *src, size_t len); + +void br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i); + +void br_i15_decode_reduce(uint16_t *x, + const void *src, size_t len, const uint16_t *m); + +void br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m); + +void br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b); + +uint32_t br_i15_moddiv(uint16_t *x, const uint16_t *y, + const uint16_t *m, uint16_t m0i, uint16_t *t); + +/* + * Variant of br_i31_modpow_opt() that internally uses 64x64->128 + * multiplications. It expects the same parameters as br_i31_modpow_opt(), + * except that the temporaries should be 64-bit integers, not 32-bit + * integers. + */ +uint32_t br_i62_modpow_opt(uint32_t *x31, const unsigned char *e, size_t elen, + const uint32_t *m31, uint32_t m0i31, uint64_t *tmp, size_t twlen); + +/* + * Type for a function with the same API as br_i31_modpow_opt() (some + * implementations of this type may have stricter alignment requirements + * on the temporaries). + */ +typedef uint32_t (*br_i31_modpow_opt_type)(uint32_t *x, + const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen); + +/* + * Wrapper for br_i62_modpow_opt() that uses the same type as + * br_i31_modpow_opt(); however, it requires its 'tmp' argument to the + * 64-bit aligned. + */ +uint32_t br_i62_modpow_opt_as_i31(uint32_t *x, + const unsigned char *e, size_t elen, + const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen); + +/* ==================================================================== */ + +static inline size_t +br_digest_size(const br_hash_class *digest_class) +{ + return (size_t)(digest_class->desc >> BR_HASHDESC_OUT_OFF) + & BR_HASHDESC_OUT_MASK; +} + +/* + * Get the output size (in bytes) of a hash function. + */ +size_t br_digest_size_by_ID(int digest_id); + +/* + * Get the OID (encoded OBJECT IDENTIFIER value, without tag and length) + * for a hash function. If digest_id is not a supported digest identifier + * (in particular if it is equal to 0, i.e. br_md5sha1_ID), then NULL is + * returned and *len is set to 0. + */ +const unsigned char *br_digest_OID(int digest_id, size_t *len); + +/* ==================================================================== */ +/* + * DES support functions. + */ + +/* + * Apply DES Initial Permutation. + */ +void br_des_do_IP(uint32_t *xl, uint32_t *xr); + +/* + * Apply DES Final Permutation (inverse of IP). + */ +void br_des_do_invIP(uint32_t *xl, uint32_t *xr); + +/* + * Key schedule unit: for a DES key (8 bytes), compute 16 subkeys. Each + * subkey is two 28-bit words represented as two 32-bit words; the PC-2 + * bit extration is NOT applied. + */ +void br_des_keysched_unit(uint32_t *skey, const void *key); + +/* + * Reversal of 16 DES sub-keys (for decryption). + */ +void br_des_rev_skey(uint32_t *skey); + +/* + * DES/3DES key schedule for 'des_tab' (encryption direction). Returned + * value is the number of rounds. + */ +unsigned br_des_tab_keysched(uint32_t *skey, const void *key, size_t key_len); + +/* + * DES/3DES key schedule for 'des_ct' (encryption direction). Returned + * value is the number of rounds. + */ +unsigned br_des_ct_keysched(uint32_t *skey, const void *key, size_t key_len); + +/* + * DES/3DES subkey decompression (from the compressed bitsliced subkeys). + */ +void br_des_ct_skey_expand(uint32_t *sk_exp, + unsigned num_rounds, const uint32_t *skey); + +/* + * DES/3DES block encryption/decryption ('des_tab'). + */ +void br_des_tab_process_block(unsigned num_rounds, + const uint32_t *skey, void *block); + +/* + * DES/3DES block encryption/decryption ('des_ct'). + */ +void br_des_ct_process_block(unsigned num_rounds, + const uint32_t *skey, void *block); + +/* ==================================================================== */ +/* + * AES support functions. + */ + +/* + * The AES S-box (256-byte table). + */ +extern const unsigned char br_aes_S[]; + +/* + * AES key schedule. skey[] is filled with n+1 128-bit subkeys, where n + * is the number of rounds (10 to 14, depending on key size). The number + * of rounds is returned. If the key size is invalid (not 16, 24 or 32), + * then 0 is returned. + * + * This implementation uses a 256-byte table and is NOT constant-time. + */ +unsigned br_aes_keysched(uint32_t *skey, const void *key, size_t key_len); + +/* + * AES key schedule for decryption ('aes_big' implementation). + */ +unsigned br_aes_big_keysched_inv(uint32_t *skey, + const void *key, size_t key_len); + +/* + * AES block encryption with the 'aes_big' implementation (fast, but + * not constant-time). This function encrypts a single block "in place". + */ +void br_aes_big_encrypt(unsigned num_rounds, const uint32_t *skey, void *data); + +/* + * AES block decryption with the 'aes_big' implementation (fast, but + * not constant-time). This function decrypts a single block "in place". + */ +void br_aes_big_decrypt(unsigned num_rounds, const uint32_t *skey, void *data); + +/* + * AES block encryption with the 'aes_small' implementation (small, but + * slow and not constant-time). This function encrypts a single block + * "in place". + */ +void br_aes_small_encrypt(unsigned num_rounds, + const uint32_t *skey, void *data); + +/* + * AES block decryption with the 'aes_small' implementation (small, but + * slow and not constant-time). This function decrypts a single block + * "in place". + */ +void br_aes_small_decrypt(unsigned num_rounds, + const uint32_t *skey, void *data); + +/* + * The constant-time implementation is "bitsliced": the 128-bit state is + * split over eight 32-bit words q* in the following way: + * + * -- Input block consists in 16 bytes: + * a00 a10 a20 a30 a01 a11 a21 a31 a02 a12 a22 a32 a03 a13 a23 a33 + * In the terminology of FIPS 197, this is a 4x4 matrix which is read + * column by column. + * + * -- Each byte is split into eight bits which are distributed over the + * eight words, at the same rank. Thus, for a byte x at rank k, bit 0 + * (least significant) of x will be at rank k in q0 (if that bit is b, + * then it contributes "b << k" to the value of q0), bit 1 of x will be + * at rank k in q1, and so on. + * + * -- Ranks given to bits are in "row order" and are either all even, or + * all odd. Two independent AES states are thus interleaved, one using + * the even ranks, the other the odd ranks. Row order means: + * a00 a01 a02 a03 a10 a11 a12 a13 a20 a21 a22 a23 a30 a31 a32 a33 + * + * Converting input bytes from two AES blocks to bitslice representation + * is done in the following way: + * -- Decode first block into the four words q0 q2 q4 q6, in that order, + * using little-endian convention. + * -- Decode second block into the four words q1 q3 q5 q7, in that order, + * using little-endian convention. + * -- Call br_aes_ct_ortho(). + * + * Converting back to bytes is done by using the reverse operations. Note + * that br_aes_ct_ortho() is its own inverse. + */ + +/* + * Perform bytewise orthogonalization of eight 32-bit words. Bytes + * of q0..q7 are spread over all words: for a byte x that occurs + * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit + * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j. + * + * This operation is an involution. + */ +void br_aes_ct_ortho(uint32_t *q); + +/* + * The AES S-box, as a bitsliced constant-time version. The input array + * consists in eight 32-bit words; 32 S-box instances are computed in + * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant) + * are spread over the words 0 to 7, at the same rank. + */ +void br_aes_ct_bitslice_Sbox(uint32_t *q); + +/* + * Like br_aes_bitslice_Sbox(), but for the inverse S-box. + */ +void br_aes_ct_bitslice_invSbox(uint32_t *q); + +/* + * Compute AES encryption on bitsliced data. Since input is stored on + * eight 32-bit words, two block encryptions are actually performed + * in parallel. + */ +void br_aes_ct_bitslice_encrypt(unsigned num_rounds, + const uint32_t *skey, uint32_t *q); + +/* + * Compute AES decryption on bitsliced data. Since input is stored on + * eight 32-bit words, two block decryptions are actually performed + * in parallel. + */ +void br_aes_ct_bitslice_decrypt(unsigned num_rounds, + const uint32_t *skey, uint32_t *q); + +/* + * AES key schedule, constant-time version. skey[] is filled with n+1 + * 128-bit subkeys, where n is the number of rounds (10 to 14, depending + * on key size). The number of rounds is returned. If the key size is + * invalid (not 16, 24 or 32), then 0 is returned. + */ +unsigned br_aes_ct_keysched(uint32_t *comp_skey, + const void *key, size_t key_len); + +/* + * Expand AES subkeys as produced by br_aes_ct_keysched(), into + * a larger array suitable for br_aes_ct_bitslice_encrypt() and + * br_aes_ct_bitslice_decrypt(). + */ +void br_aes_ct_skey_expand(uint32_t *skey, + unsigned num_rounds, const uint32_t *comp_skey); + +/* + * For the ct64 implementation, the same bitslicing technique is used, + * but four instances are interleaved. First instance uses bits 0, 4, + * 8, 12,... of each word; second instance uses bits 1, 5, 9, 13,... + * and so on. + */ + +/* + * Perform bytewise orthogonalization of eight 64-bit words. Bytes + * of q0..q7 are spread over all words: for a byte x that occurs + * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit + * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j. + * + * This operation is an involution. + */ +void br_aes_ct64_ortho(uint64_t *q); + +/* + * Interleave bytes for an AES input block. If input bytes are + * denoted 0123456789ABCDEF, and have been decoded with little-endian + * convention (w[0] contains 0123, with '3' being most significant; + * w[1] contains 4567, and so on), then output word q0 will be + * set to 08192A3B (again little-endian convention) and q1 will + * be set to 4C5D6E7F. + */ +void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w); + +/* + * Perform the opposite of br_aes_ct64_interleave_in(). + */ +void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1); + +/* + * The AES S-box, as a bitsliced constant-time version. The input array + * consists in eight 64-bit words; 64 S-box instances are computed in + * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant) + * are spread over the words 0 to 7, at the same rank. + */ +void br_aes_ct64_bitslice_Sbox(uint64_t *q); + +/* + * Like br_aes_bitslice_Sbox(), but for the inverse S-box. + */ +void br_aes_ct64_bitslice_invSbox(uint64_t *q); + +/* + * Compute AES encryption on bitsliced data. Since input is stored on + * eight 64-bit words, four block encryptions are actually performed + * in parallel. + */ +void br_aes_ct64_bitslice_encrypt(unsigned num_rounds, + const uint64_t *skey, uint64_t *q); + +/* + * Compute AES decryption on bitsliced data. Since input is stored on + * eight 64-bit words, four block decryptions are actually performed + * in parallel. + */ +void br_aes_ct64_bitslice_decrypt(unsigned num_rounds, + const uint64_t *skey, uint64_t *q); + +/* + * AES key schedule, constant-time version. skey[] is filled with n+1 + * 128-bit subkeys, where n is the number of rounds (10 to 14, depending + * on key size). The number of rounds is returned. If the key size is + * invalid (not 16, 24 or 32), then 0 is returned. + */ +unsigned br_aes_ct64_keysched(uint64_t *comp_skey, + const void *key, size_t key_len); + +/* + * Expand AES subkeys as produced by br_aes_ct64_keysched(), into + * a larger array suitable for br_aes_ct64_bitslice_encrypt() and + * br_aes_ct64_bitslice_decrypt(). + */ +void br_aes_ct64_skey_expand(uint64_t *skey, + unsigned num_rounds, const uint64_t *comp_skey); + +/* + * Test support for AES-NI opcodes. + */ +int br_aes_x86ni_supported(void); + +/* + * AES key schedule, using x86 AES-NI instructions. This yields the + * subkeys in the encryption direction. Number of rounds is returned. + * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned. + */ +unsigned br_aes_x86ni_keysched_enc(unsigned char *skni, + const void *key, size_t len); + +/* + * AES key schedule, using x86 AES-NI instructions. This yields the + * subkeys in the decryption direction. Number of rounds is returned. + * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned. + */ +unsigned br_aes_x86ni_keysched_dec(unsigned char *skni, + const void *key, size_t len); + +/* + * Test support for AES POWER8 opcodes. + */ +int br_aes_pwr8_supported(void); + +/* + * AES key schedule, using POWER8 instructions. This yields the + * subkeys in the encryption direction. Number of rounds is returned. + * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned. + */ +unsigned br_aes_pwr8_keysched(unsigned char *skni, + const void *key, size_t len); + +/* ==================================================================== */ +/* + * RSA. + */ + +/* + * Apply proper PKCS#1 v1.5 padding (for signatures). 'hash_oid' is + * the encoded hash function OID, or NULL. + */ +uint32_t br_rsa_pkcs1_sig_pad(const unsigned char *hash_oid, + const unsigned char *hash, size_t hash_len, + uint32_t n_bitlen, unsigned char *x); + +/* + * Check PKCS#1 v1.5 padding (for signatures). 'hash_oid' is the encoded + * hash function OID, or NULL. The provided 'sig' value is _after_ the + * modular exponentiation, i.e. it should be the padded hash. On + * success, the hashed message is extracted. + */ +uint32_t br_rsa_pkcs1_sig_unpad(const unsigned char *sig, size_t sig_len, + const unsigned char *hash_oid, size_t hash_len, + unsigned char *hash_out); + +/* + * Apply proper PSS padding. The 'x' buffer is output only: it + * receives the value that is to be exponentiated. + */ +uint32_t br_rsa_pss_sig_pad(const br_prng_class **rng, + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + uint32_t n_bitlen, unsigned char *x); + +/* + * Check PSS padding. The provided value is the one _after_ + * the modular exponentiation; it is modified by this function. + * This function infers the signature length from the public key + * size, i.e. it assumes that this has already been verified (as + * part of the exponentiation). + */ +uint32_t br_rsa_pss_sig_unpad( + const br_hash_class *hf_data, const br_hash_class *hf_mgf1, + const unsigned char *hash, size_t salt_len, + const br_rsa_public_key *pk, unsigned char *x); + +/* + * Apply OAEP padding. Returned value is the actual padded string length, + * or zero on error. + */ +size_t br_rsa_oaep_pad(const br_prng_class **rnd, const br_hash_class *dig, + const void *label, size_t label_len, const br_rsa_public_key *pk, + void *dst, size_t dst_nax_len, const void *src, size_t src_len); + +/* + * Unravel and check OAEP padding. If the padding is correct, then 1 is + * returned, '*len' is adjusted to the length of the message, and the + * data is moved to the start of the 'data' buffer. If the padding is + * incorrect, then 0 is returned and '*len' is untouched. Either way, + * the complete buffer contents are altered. + */ +uint32_t br_rsa_oaep_unpad(const br_hash_class *dig, + const void *label, size_t label_len, void *data, size_t *len); + +/* + * Compute MGF1 for a given seed, and XOR the output into the provided + * buffer. + */ +void br_mgf1_xor(void *data, size_t len, + const br_hash_class *dig, const void *seed, size_t seed_len); + +/* + * Inner function for RSA key generation; used by the "i31" and "i62" + * implementations. + */ +uint32_t br_rsa_i31_keygen_inner(const br_prng_class **rng, + br_rsa_private_key *sk, void *kbuf_priv, + br_rsa_public_key *pk, void *kbuf_pub, + unsigned size, uint32_t pubexp, br_i31_modpow_opt_type mp31); + +/* ==================================================================== */ +/* + * Elliptic curves. + */ + +/* + * Type for generic EC parameters: curve order (unsigned big-endian + * encoding) and encoded conventional generator. + */ +typedef struct { + int curve; + const unsigned char *order; + size_t order_len; + const unsigned char *generator; + size_t generator_len; +} br_ec_curve_def; + +extern const br_ec_curve_def br_secp256r1; +extern const br_ec_curve_def br_secp384r1; +extern const br_ec_curve_def br_secp521r1; + +/* + * For Curve25519, the advertised "order" really is 2^255-1, since the + * point multipliction function really works over arbitrary 255-bit + * scalars. This value is only meant as a hint for ECDH key generation; + * only ECDSA uses the exact curve order, and ECDSA is not used with + * that specific curve. + */ +extern const br_ec_curve_def br_curve25519; + +/* + * Decode some bytes as an i31 integer, with truncation (corresponding + * to the 'bits2int' operation in RFC 6979). The target ENCODED bit + * length is provided as last parameter. The resulting value will have + * this declared bit length, and consists the big-endian unsigned decoding + * of exactly that many bits in the source (capped at the source length). + */ +void br_ecdsa_i31_bits2int(uint32_t *x, + const void *src, size_t len, uint32_t ebitlen); + +/* + * Decode some bytes as an i15 integer, with truncation (corresponding + * to the 'bits2int' operation in RFC 6979). The target ENCODED bit + * length is provided as last parameter. The resulting value will have + * this declared bit length, and consists the big-endian unsigned decoding + * of exactly that many bits in the source (capped at the source length). + */ +void br_ecdsa_i15_bits2int(uint16_t *x, + const void *src, size_t len, uint32_t ebitlen); + +/* ==================================================================== */ +/* + * ASN.1 support functions. + */ + +/* + * A br_asn1_uint structure contains encoding information about an + * INTEGER nonnegative value: pointer to the integer contents (unsigned + * big-endian representation), length of the integer contents, + * and length of the encoded value. The data shall have minimal length: + * - If the integer value is zero, then 'len' must be zero. + * - If the integer value is not zero, then data[0] must be non-zero. + * + * Under these conditions, 'asn1len' is necessarily equal to either len + * or len+1. + */ +typedef struct { + const unsigned char *data; + size_t len; + size_t asn1len; +} br_asn1_uint; + +/* + * Given an encoded integer (unsigned big-endian, with possible leading + * bytes of value 0), returned the "prepared INTEGER" structure. + */ +br_asn1_uint br_asn1_uint_prepare(const void *xdata, size_t xlen); + +/* + * Encode an ASN.1 length. The length of the encoded length is returned. + * If 'dest' is NULL, then no encoding is performed, but the length of + * the encoded length is still computed and returned. + */ +size_t br_asn1_encode_length(void *dest, size_t len); + +/* + * Convenient macro for computing lengths of lengths. + */ +#define len_of_len(len) br_asn1_encode_length(NULL, len) + +/* + * Encode a (prepared) ASN.1 INTEGER. The encoded length is returned. + * If 'dest' is NULL, then no encoding is performed, but the length of + * the encoded integer is still computed and returned. + */ +size_t br_asn1_encode_uint(void *dest, br_asn1_uint pp); + +/* + * Get the OID that identifies an elliptic curve. Returned value is + * the DER-encoded OID, with the length (always one byte) but without + * the tag. Thus, the first byte of the returned buffer contains the + * number of subsequent bytes in the value. If the curve is not + * recognised, NULL is returned. + */ +const unsigned char *br_get_curve_OID(int curve); + +/* + * Inner function for EC private key encoding. This is equivalent to + * the API function br_encode_ec_raw_der(), except for an extra + * parameter: if 'include_curve_oid' is zero, then the curve OID is + * _not_ included in the output blob (this is for PKCS#8 support). + */ +size_t br_encode_ec_raw_der_inner(void *dest, + const br_ec_private_key *sk, const br_ec_public_key *pk, + int include_curve_oid); + +/* ==================================================================== */ +/* + * SSL/TLS support functions. + */ + +/* + * Record types. + */ +#define BR_SSL_CHANGE_CIPHER_SPEC 20 +#define BR_SSL_ALERT 21 +#define BR_SSL_HANDSHAKE 22 +#define BR_SSL_APPLICATION_DATA 23 + +/* + * Handshake message types. + */ +#define BR_SSL_HELLO_REQUEST 0 +#define BR_SSL_CLIENT_HELLO 1 +#define BR_SSL_SERVER_HELLO 2 +#define BR_SSL_CERTIFICATE 11 +#define BR_SSL_SERVER_KEY_EXCHANGE 12 +#define BR_SSL_CERTIFICATE_REQUEST 13 +#define BR_SSL_SERVER_HELLO_DONE 14 +#define BR_SSL_CERTIFICATE_VERIFY 15 +#define BR_SSL_CLIENT_KEY_EXCHANGE 16 +#define BR_SSL_FINISHED 20 + +/* + * Alert levels. + */ +#define BR_LEVEL_WARNING 1 +#define BR_LEVEL_FATAL 2 + +/* + * Low-level I/O state. + */ +#define BR_IO_FAILED 0 +#define BR_IO_IN 1 +#define BR_IO_OUT 2 +#define BR_IO_INOUT 3 + +/* + * Mark a SSL engine as failed. The provided error code is recorded if + * the engine was not already marked as failed. If 'err' is 0, then the + * engine is marked as closed (without error). + */ +void br_ssl_engine_fail(br_ssl_engine_context *cc, int err); + +/* + * Test whether the engine is closed (normally or as a failure). + */ +static inline int +br_ssl_engine_closed(const br_ssl_engine_context *cc) +{ + return cc->iomode == BR_IO_FAILED; +} + +/* + * Configure a new maximum fragment length. If possible, the maximum + * length for outgoing records is immediately adjusted (if there are + * not already too many buffered bytes for that). + */ +void br_ssl_engine_new_max_frag_len( + br_ssl_engine_context *rc, unsigned max_frag_len); + +/* + * Test whether the current incoming record has been fully received + * or not. This functions returns 0 only if a complete record header + * has been received, but some of the (possibly encrypted) payload + * has not yet been obtained. + */ +int br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc); + +/* + * Flush the current record (if not empty). This is meant to be called + * from the handshake processor only. + */ +void br_ssl_engine_flush_record(br_ssl_engine_context *cc); + +/* + * Test whether there is some accumulated payload to send. + */ +static inline int +br_ssl_engine_has_pld_to_send(const br_ssl_engine_context *rc) +{ + return rc->oxa != rc->oxb && rc->oxa != rc->oxc; +} + +/* + * Initialize RNG in engine. Returned value is 1 on success, 0 on error. + * This function will try to use the OS-provided RNG, if available. If + * there is no OS-provided RNG, or if it failed, and no entropy was + * injected by the caller, then a failure will be reported. On error, + * the context error code is set. + */ +int br_ssl_engine_init_rand(br_ssl_engine_context *cc); + +/* + * Reset the handshake-related parts of the engine. + */ +void br_ssl_engine_hs_reset(br_ssl_engine_context *cc, + void (*hsinit)(void *), void (*hsrun)(void *)); + +/* + * Get the PRF to use for this context, for the provided PRF hash + * function ID. + */ +br_tls_prf_impl br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id); + +/* + * Consume the provided pre-master secret and compute the corresponding + * master secret. The 'prf_id' is the ID of the hash function to use + * with the TLS 1.2 PRF (ignored if the version is TLS 1.0 or 1.1). + */ +void br_ssl_engine_compute_master(br_ssl_engine_context *cc, + int prf_id, const void *pms, size_t len); + +/* + * Switch to CBC decryption for incoming records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF (ignored if not TLS 1.2+) + * mac_id id of hash function for HMAC + * bc_impl block cipher implementation (CBC decryption) + * cipher_key_len block cipher key length (in bytes) + */ +void br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc, + int is_client, int prf_id, int mac_id, + const br_block_cbcdec_class *bc_impl, size_t cipher_key_len); + +/* + * Switch to CBC encryption for outgoing records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF (ignored if not TLS 1.2+) + * mac_id id of hash function for HMAC + * bc_impl block cipher implementation (CBC encryption) + * cipher_key_len block cipher key length (in bytes) + */ +void br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc, + int is_client, int prf_id, int mac_id, + const br_block_cbcenc_class *bc_impl, size_t cipher_key_len); + +/* + * Switch to GCM decryption for incoming records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + * bc_impl block cipher implementation (CTR) + * cipher_key_len block cipher key length (in bytes) + */ +void br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctr_class *bc_impl, size_t cipher_key_len); + +/* + * Switch to GCM encryption for outgoing records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + * bc_impl block cipher implementation (CTR) + * cipher_key_len block cipher key length (in bytes) + */ +void br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctr_class *bc_impl, size_t cipher_key_len); + +/* + * Switch to ChaCha20+Poly1305 decryption for incoming records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + */ +void br_ssl_engine_switch_chapol_in(br_ssl_engine_context *cc, + int is_client, int prf_id); + +/* + * Switch to ChaCha20+Poly1305 encryption for outgoing records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + */ +void br_ssl_engine_switch_chapol_out(br_ssl_engine_context *cc, + int is_client, int prf_id); + +/* + * Switch to CCM decryption for incoming records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + * bc_impl block cipher implementation (CTR+CBC) + * cipher_key_len block cipher key length (in bytes) + * tag_len tag length (in bytes) + */ +void br_ssl_engine_switch_ccm_in(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctrcbc_class *bc_impl, + size_t cipher_key_len, size_t tag_len); + +/* + * Switch to GCM encryption for outgoing records. + * cc the engine context + * is_client non-zero for a client, zero for a server + * prf_id id of hash function for PRF + * bc_impl block cipher implementation (CTR+CBC) + * cipher_key_len block cipher key length (in bytes) + * tag_len tag length (in bytes) + */ +void br_ssl_engine_switch_ccm_out(br_ssl_engine_context *cc, + int is_client, int prf_id, + const br_block_ctrcbc_class *bc_impl, + size_t cipher_key_len, size_t tag_len); + +/* + * Calls to T0-generated code. + */ +void br_ssl_hs_client_init_main(void *ctx); +void br_ssl_hs_client_run(void *ctx); +void br_ssl_hs_server_init_main(void *ctx); +void br_ssl_hs_server_run(void *ctx); + +/* + * Get the hash function to use for signatures, given a bit mask of + * supported hash functions. This implements a strict choice order + * (namely SHA-256, SHA-384, SHA-512, SHA-224, SHA-1). If the mask + * does not document support of any of these hash functions, then this + * functions returns 0. + */ +int br_ssl_choose_hash(unsigned bf); + +/* ==================================================================== */ + +/* + * PowerPC / POWER assembly stuff. The special BR_POWER_ASM_MACROS macro + * must be defined before including this file; this is done by source + * files that use some inline assembly for PowerPC / POWER machines. + */ + +#if BR_POWER_ASM_MACROS + +#define lxvw4x(xt, ra, rb) lxvw4x_(xt, ra, rb) +#define stxvw4x(xt, ra, rb) stxvw4x_(xt, ra, rb) + +#define bdnz(foo) bdnz_(foo) +#define bdz(foo) bdz_(foo) +#define beq(foo) beq_(foo) + +#define li(rx, value) li_(rx, value) +#define addi(rx, ra, imm) addi_(rx, ra, imm) +#define cmpldi(rx, imm) cmpldi_(rx, imm) +#define mtctr(rx) mtctr_(rx) +#define vspltb(vrt, vrb, uim) vspltb_(vrt, vrb, uim) +#define vspltw(vrt, vrb, uim) vspltw_(vrt, vrb, uim) +#define vspltisb(vrt, imm) vspltisb_(vrt, imm) +#define vspltisw(vrt, imm) vspltisw_(vrt, imm) +#define vrlw(vrt, vra, vrb) vrlw_(vrt, vra, vrb) +#define vsbox(vrt, vra) vsbox_(vrt, vra) +#define vxor(vrt, vra, vrb) vxor_(vrt, vra, vrb) +#define vand(vrt, vra, vrb) vand_(vrt, vra, vrb) +#define vsro(vrt, vra, vrb) vsro_(vrt, vra, vrb) +#define vsl(vrt, vra, vrb) vsl_(vrt, vra, vrb) +#define vsldoi(vt, va, vb, sh) vsldoi_(vt, va, vb, sh) +#define vsr(vrt, vra, vrb) vsr_(vrt, vra, vrb) +#define vaddcuw(vrt, vra, vrb) vaddcuw_(vrt, vra, vrb) +#define vadduwm(vrt, vra, vrb) vadduwm_(vrt, vra, vrb) +#define vsububm(vrt, vra, vrb) vsububm_(vrt, vra, vrb) +#define vsubuwm(vrt, vra, vrb) vsubuwm_(vrt, vra, vrb) +#define vsrw(vrt, vra, vrb) vsrw_(vrt, vra, vrb) +#define vcipher(vt, va, vb) vcipher_(vt, va, vb) +#define vcipherlast(vt, va, vb) vcipherlast_(vt, va, vb) +#define vncipher(vt, va, vb) vncipher_(vt, va, vb) +#define vncipherlast(vt, va, vb) vncipherlast_(vt, va, vb) +#define vperm(vt, va, vb, vc) vperm_(vt, va, vb, vc) +#define vpmsumd(vt, va, vb) vpmsumd_(vt, va, vb) +#define xxpermdi(vt, va, vb, d) xxpermdi_(vt, va, vb, d) + +#define lxvw4x_(xt, ra, rb) "\tlxvw4x\t" #xt "," #ra "," #rb "\n" +#define stxvw4x_(xt, ra, rb) "\tstxvw4x\t" #xt "," #ra "," #rb "\n" + +#define label(foo) #foo "%=:\n" +#define bdnz_(foo) "\tbdnz\t" #foo "%=\n" +#define bdz_(foo) "\tbdz\t" #foo "%=\n" +#define beq_(foo) "\tbeq\t" #foo "%=\n" + +#define li_(rx, value) "\tli\t" #rx "," #value "\n" +#define addi_(rx, ra, imm) "\taddi\t" #rx "," #ra "," #imm "\n" +#define cmpldi_(rx, imm) "\tcmpldi\t" #rx "," #imm "\n" +#define mtctr_(rx) "\tmtctr\t" #rx "\n" +#define vspltb_(vrt, vrb, uim) "\tvspltb\t" #vrt "," #vrb "," #uim "\n" +#define vspltw_(vrt, vrb, uim) "\tvspltw\t" #vrt "," #vrb "," #uim "\n" +#define vspltisb_(vrt, imm) "\tvspltisb\t" #vrt "," #imm "\n" +#define vspltisw_(vrt, imm) "\tvspltisw\t" #vrt "," #imm "\n" +#define vrlw_(vrt, vra, vrb) "\tvrlw\t" #vrt "," #vra "," #vrb "\n" +#define vsbox_(vrt, vra) "\tvsbox\t" #vrt "," #vra "\n" +#define vxor_(vrt, vra, vrb) "\tvxor\t" #vrt "," #vra "," #vrb "\n" +#define vand_(vrt, vra, vrb) "\tvand\t" #vrt "," #vra "," #vrb "\n" +#define vsro_(vrt, vra, vrb) "\tvsro\t" #vrt "," #vra "," #vrb "\n" +#define vsl_(vrt, vra, vrb) "\tvsl\t" #vrt "," #vra "," #vrb "\n" +#define vsldoi_(vt, va, vb, sh) "\tvsldoi\t" #vt "," #va "," #vb "," #sh "\n" +#define vsr_(vrt, vra, vrb) "\tvsr\t" #vrt "," #vra "," #vrb "\n" +#define vaddcuw_(vrt, vra, vrb) "\tvaddcuw\t" #vrt "," #vra "," #vrb "\n" +#define vadduwm_(vrt, vra, vrb) "\tvadduwm\t" #vrt "," #vra "," #vrb "\n" +#define vsububm_(vrt, vra, vrb) "\tvsububm\t" #vrt "," #vra "," #vrb "\n" +#define vsubuwm_(vrt, vra, vrb) "\tvsubuwm\t" #vrt "," #vra "," #vrb "\n" +#define vsrw_(vrt, vra, vrb) "\tvsrw\t" #vrt "," #vra "," #vrb "\n" +#define vcipher_(vt, va, vb) "\tvcipher\t" #vt "," #va "," #vb "\n" +#define vcipherlast_(vt, va, vb) "\tvcipherlast\t" #vt "," #va "," #vb "\n" +#define vncipher_(vt, va, vb) "\tvncipher\t" #vt "," #va "," #vb "\n" +#define vncipherlast_(vt, va, vb) "\tvncipherlast\t" #vt "," #va "," #vb "\n" +#define vperm_(vt, va, vb, vc) "\tvperm\t" #vt "," #va "," #vb "," #vc "\n" +#define vpmsumd_(vt, va, vb) "\tvpmsumd\t" #vt "," #va "," #vb "\n" +#define xxpermdi_(vt, va, vb, d) "\txxpermdi\t" #vt "," #va "," #vb "," #d "\n" + +#endif + +/* ==================================================================== */ +/* + * Special "activate intrinsics" code, needed for some compiler versions. + * This is defined at the end of this file, so that it won't impact any + * of the inline functions defined previously; and it is controlled by + * a specific macro defined in the caller code. + * + * Calling code conventions: + * + * - Caller must define BR_ENABLE_INTRINSICS before including "inner.h". + * - Functions that use intrinsics must be enclosed in an "enabled" + * region (between BR_TARGETS_X86_UP and BR_TARGETS_X86_DOWN). + * - Functions that use intrinsics must be tagged with the appropriate + * BR_TARGET(). + */ + +#if BR_ENABLE_INTRINSICS && (BR_GCC_4_4 || BR_CLANG_3_7 || BR_MSC_2005) + +/* + * x86 intrinsics (both 32-bit and 64-bit). + */ +#if BR_i386 || BR_amd64 + +/* + * On GCC before version 5.0, we need to use the pragma to enable the + * target options globally, because the 'target' function attribute + * appears to be unreliable. Before 4.6 we must also avoid the + * push_options / pop_options mechanism, because it tends to trigger + * some internal compiler errors. + */ +#if BR_GCC && !BR_GCC_5_0 +#if BR_GCC_4_6 +#define BR_TARGETS_X86_UP \ + _Pragma("GCC push_options") \ + _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul,rdrnd\")") +#define BR_TARGETS_X86_DOWN \ + _Pragma("GCC pop_options") +#else +#define BR_TARGETS_X86_UP \ + _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul\")") +#define BR_TARGETS_X86_DOWN +#endif +#pragma GCC diagnostic ignored "-Wpsabi" +#endif + +#if BR_CLANG && !BR_CLANG_3_8 +#undef __SSE2__ +#undef __SSE3__ +#undef __SSSE3__ +#undef __SSE4_1__ +#undef __AES__ +#undef __PCLMUL__ +#undef __RDRND__ +#define __SSE2__ 1 +#define __SSE3__ 1 +#define __SSSE3__ 1 +#define __SSE4_1__ 1 +#define __AES__ 1 +#define __PCLMUL__ 1 +#define __RDRND__ 1 +#endif + +#ifndef BR_TARGETS_X86_UP +#define BR_TARGETS_X86_UP +#endif +#ifndef BR_TARGETS_X86_DOWN +#define BR_TARGETS_X86_DOWN +#endif + +#if BR_GCC || BR_CLANG +BR_TARGETS_X86_UP +#include +#include +#define br_bswap32 __builtin_bswap32 +BR_TARGETS_X86_DOWN +#endif + +#if BR_MSC +#include +#include +#include +#define br_bswap32 _byteswap_ulong +#endif + +static inline int +br_cpuid(uint32_t mask_eax, uint32_t mask_ebx, + uint32_t mask_ecx, uint32_t mask_edx) +{ +#if BR_GCC || BR_CLANG + unsigned eax, ebx, ecx, edx; + + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { + if ((eax & mask_eax) == mask_eax + && (ebx & mask_ebx) == mask_ebx + && (ecx & mask_ecx) == mask_ecx + && (edx & mask_edx) == mask_edx) + { + return 1; + } + } +#elif BR_MSC + int info[4]; + + __cpuid(info, 1); + if (((uint32_t)info[0] & mask_eax) == mask_eax + && ((uint32_t)info[1] & mask_ebx) == mask_ebx + && ((uint32_t)info[2] & mask_ecx) == mask_ecx + && ((uint32_t)info[3] & mask_edx) == mask_edx) + { + return 1; + } +#endif + return 0; +} + +#endif + +#endif + +/* ==================================================================== */ + +#endif + + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/sysrng.c b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/sysrng.c new file mode 100644 index 000000000..9533079e0 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/sysrng.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2017 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#define BR_ENABLE_INTRINSICS 1 +#include "inner.h" + +#if BR_USE_GETENTROPY +#include +#endif + +#if BR_USE_URANDOM +#include +#include +#include +#include +#endif + +#if BR_USE_WIN32_RAND +#include +#include +#pragma comment(lib, "advapi32") +#endif + +/* + * Seeder that uses the RDRAND opcodes (on x86 CPU). + */ +#if BR_RDRAND +BR_TARGETS_X86_UP +BR_TARGET("rdrnd") +static int +seeder_rdrand(const br_prng_class **ctx) +{ + unsigned char tmp[32]; + size_t u; + + for (u = 0; u < sizeof tmp; u += sizeof(uint32_t)) { + int j; + uint32_t x; + + /* + * We use the 32-bit intrinsic so that code is compatible + * with both 32-bit and 64-bit architectures. + * + * Intel recommends trying at least 10 times in case of + * failure. + * + * AMD bug: there are reports that some AMD processors + * have a bug that makes them fail silently after a + * suspend/resume cycle, in which case RDRAND will report + * a success but always return 0xFFFFFFFF. + * see: https://bugzilla.kernel.org/show_bug.cgi?id=85911 + * + * As a mitigation, if the 32-bit value is 0 or -1, then + * it is considered a failure and tried again. This should + * reliably detect the buggy case, at least. This also + * implies that the selected seed values can never be + * 0x00000000 or 0xFFFFFFFF, which is not a problem since + * we are generating a seed for a PRNG, and we overdo it + * a bit (we generate 32 bytes of randomness, and 256 bits + * of entropy are really overkill). + */ + for (j = 0; j < 10; j ++) { + if (_rdrand32_step(&x) && x != 0 && x != (uint32_t)-1) { + goto next_word; + } + } + return 0; + next_word: + br_enc32le(tmp + u, x); + } + (*ctx)->update(ctx, tmp, sizeof tmp); + return 1; +} +BR_TARGETS_X86_DOWN + +static int +rdrand_supported(void) +{ + /* + * The RDRND support is bit 30 of ECX, as returned by CPUID. + */ + return br_cpuid(0, 0, 0x40000000, 0); +} +#endif + +/* + * Seeder that uses /dev/urandom (on Unix-like systems). + */ +#if BR_USE_URANDOM +static int +seeder_urandom(const br_prng_class **ctx) +{ + int f; + + f = open("/dev/urandom", O_RDONLY); + if (f >= 0) { + unsigned char tmp[32]; + size_t u; + + for (u = 0; u < sizeof tmp;) { + ssize_t len; + + len = read(f, tmp + u, (sizeof tmp) - u); + if (len < 0) { + if (errno == EINTR) { + continue; + } + break; + } + u += (size_t)len; + } + close(f); + if (u == sizeof tmp) { + (*ctx)->update(ctx, tmp, sizeof tmp); + return 1; + } + } + return 0; +} +#endif + +/* + * Seeder that uses getentropy() (backed by getrandom() on some systems, + * e.g. Linux). On failure, it will use the /dev/urandom seeder (if + * enabled). + */ +#if BR_USE_GETENTROPY +static int +seeder_getentropy(const br_prng_class **ctx) +{ + unsigned char tmp[32]; + + if (getentropy(tmp, sizeof tmp) == 0) { + (*ctx)->update(ctx, tmp, sizeof tmp); + return 1; + } +#if BR_USE_URANDOM + return seeder_urandom(ctx); +#else + return 0; +#endif +} +#endif + +/* + * Seeder that uses CryptGenRandom() (on Windows). + */ +#if BR_USE_WIN32_RAND +static int +seeder_win32(const br_prng_class **ctx) +{ + HCRYPTPROV hp; + + if (CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + BYTE buf[32]; + BOOL r; + + r = CryptGenRandom(hp, sizeof buf, buf); + CryptReleaseContext(hp, 0); + if (r) { + (*ctx)->update(ctx, buf, sizeof buf); + return 1; + } + } + return 0; +} +#endif + +/* + * An aggregate seeder that uses RDRAND, and falls back to an OS-provided + * source if RDRAND fails. + */ +#if BR_RDRAND && (BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND) +static int +seeder_rdrand_with_fallback(const br_prng_class **ctx) +{ + if (!seeder_rdrand(ctx)) { +#if BR_USE_GETENTROPY + return seeder_getentropy(ctx); +#elif BR_USE_URANDOM + return seeder_urandom(ctx); +#elif BR_USE_WIN32_RAND + return seeder_win32(ctx); +#else +#error "macro selection has gone wrong" +#endif + } + return 1; +} +#endif + +/* see bearssl_rand.h */ +br_prng_seeder +br_prng_seeder_system(const char **name) +{ +#if BR_RDRAND + if (rdrand_supported()) { + if (name != NULL) { + *name = "rdrand"; + } +#if BR_USE_GETENTROPY || BR_USE_URANDOM || BR_USE_WIN32_RAND + return &seeder_rdrand_with_fallback; +#else + return &seeder_rdrand; +#endif + } +#endif +#if BR_USE_GETENTROPY + if (name != NULL) { + *name = "getentropy"; + } + return &seeder_getentropy; +#elif BR_USE_URANDOM + if (name != NULL) { + *name = "urandom"; + } + return &seeder_urandom; +#elif BR_USE_WIN32_RAND + if (name != NULL) { + *name = "win32"; + } + return &seeder_win32; +#else + if (name != NULL) { + *name = "none"; + } + return 0; +#endif +} + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_decoder.c b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_decoder.c new file mode 100644 index 000000000..abf5df76f --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_decoder.c @@ -0,0 +1,779 @@ +/* Automatically generated code; do not modify directly. */ + + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#include +#include + +typedef struct { + uint32_t *dp; + uint32_t *rp; + const unsigned char *ip; +} t0_context; + +static uint32_t +t0_parse7E_unsigned(const unsigned char **p) +{ + uint32_t x; + + x = 0; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + return x; + } + } +} + +static int32_t +t0_parse7E_signed(const unsigned char **p) +{ + int neg; + uint32_t x; + + neg = ((**p) >> 6) & 1; + x = (uint32_t)-neg; + for (;;) { + unsigned y; + + y = *(*p) ++; + x = (x << 7) | (uint32_t)(y & 0x7F); + if (y < 0x80) { + if (neg) { + return -(int32_t)~x - 1; + } else { + return (int32_t)x; + } + } + } +} + +#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80) +#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F) +#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8) +#define T0_INT1(x) T0_FBYTE(x, 0) +#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) +#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0) + +/* static const unsigned char t0_datablock[]; */ + + +void br_x509_decoder_init_main_libmail(void *t0ctx); + +void br_x509_decoder_run_libmail(void *t0ctx); + + + +#include "inner.h" + + + + + +#include "inner.h" + +#define CTX ((br_x509_decoder_context_libmail *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context_libmail, cpu))) +#define CONTEXT_NAME br_x509_decoder_context_libmail + +/* see bearssl_x509.h */ +void +br_x509_decoder_init_libmail(br_x509_decoder_context_libmail *ctx, + void (*append_dn)(void *ctx, const void *buf, size_t len), + void *append_dn_ctx) +{ + memset(ctx, 0, sizeof *ctx); + /* obsolete + ctx->err = 0; + ctx->hbuf = NULL; + ctx->hlen = 0; + */ + ctx->append_dn = append_dn; + ctx->append_dn_ctx = append_dn_ctx; + ctx->cpu.dp = &ctx->dp_stack[0]; + ctx->cpu.rp = &ctx->rp_stack[0]; + br_x509_decoder_init_main_libmail(&ctx->cpu); + br_x509_decoder_run_libmail(&ctx->cpu); +} + +/* see bearssl_x509.h */ +void +br_x509_decoder_push_libmail(br_x509_decoder_context_libmail *ctx, + const void *data, size_t len) +{ + ctx->hbuf = data; + ctx->hlen = len; + br_x509_decoder_run_libmail(&ctx->cpu); +} + + + +static const unsigned char t0_datablock[] = { + 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x09, + 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x09, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E, 0x09, 0x2A, 0x86, 0x48, 0x86, + 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, + 0x01, 0x01, 0x0C, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, + 0x0D, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86, + 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, + 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, + 0x04, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x08, + 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x08, 0x2A, 0x86, 0x48, + 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, + 0x03, 0x04, 0x00, 0x1F, 0x03, 0xFC, 0x07, 0x7F, 0x0B, 0x5E, 0x0F, 0x1F, + 0x12, 0xFE, 0x16, 0xBF, 0x1A, 0x9F, 0x1E, 0x7E, 0x22, 0x3F, 0x26, 0x1E, + 0x29, 0xDF, 0x00, 0x1F, 0x03, 0xFD, 0x07, 0x9F, 0x0B, 0x7E, 0x0F, 0x3F, + 0x13, 0x1E, 0x16, 0xDF, 0x1A, 0xBF, 0x1E, 0x9E, 0x22, 0x5F, 0x26, 0x3E, + 0x29, 0xFF, 0x03, 0x55, 0x1D, 0x13 +}; + +static const unsigned char t0_codeblock[] = { + 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x01, + 0x01, 0x09, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x00, 0x00, 0x1A, 0x1A, 0x00, + 0x00, 0x01, T0_INT1(BR_ERR_X509_BAD_BOOLEAN), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_BAD_TIME), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_PARTIAL_BYTE), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01, + T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA), + 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, copy_dn)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(CONTEXT_NAME, decoded)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, isCA)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_x509_decoder_context_libmail, pkey_data)), 0x01, + T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, notafter_days)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, notafter_seconds)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, notbefore_days)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, notbefore_seconds)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, signer_hash_id)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(CONTEXT_NAME, signer_key_type)), 0x00, 0x00, 0x01, + 0x80, 0x45, 0x00, 0x00, 0x01, 0x80, 0x4E, 0x00, 0x00, 0x01, 0x80, 0x54, + 0x00, 0x00, 0x01, 0x81, 0x36, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x1B, + 0x02, 0x01, 0x13, 0x26, 0x02, 0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, + 0x34, 0x1D, 0x00, 0x00, 0x06, 0x02, 0x35, 0x1D, 0x00, 0x00, 0x01, 0x10, + 0x4F, 0x00, 0x00, 0x11, 0x05, 0x02, 0x38, 0x1D, 0x4C, 0x00, 0x00, 0x11, + 0x05, 0x02, 0x38, 0x1D, 0x4D, 0x00, 0x00, 0x06, 0x02, 0x30, 0x1D, 0x00, + 0x00, 0x1B, 0x19, 0x01, 0x08, 0x0E, 0x26, 0x29, 0x19, 0x09, 0x00, 0x00, + 0x01, 0x30, 0x0A, 0x1B, 0x01, 0x00, 0x01, 0x09, 0x4B, 0x05, 0x02, 0x2F, + 0x1D, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x01, 0x80, 0x5A, 0x00, 0x00, + 0x01, 0x80, 0x62, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x80, + 0x74, 0x00, 0x00, 0x01, 0x80, 0x7D, 0x00, 0x00, 0x01, 0x3D, 0x00, 0x00, + 0x20, 0x11, 0x06, 0x04, 0x2B, 0x6B, 0x7A, 0x71, 0x00, 0x04, 0x01, 0x00, + 0x3D, 0x25, 0x01, 0x00, 0x3C, 0x25, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x6D, + 0x6D, 0x70, 0x1B, 0x01, 0x20, 0x11, 0x06, 0x11, 0x1A, 0x4C, 0x6B, 0x70, + 0x01, 0x02, 0x50, 0x6E, 0x01, 0x02, 0x12, 0x06, 0x02, 0x39, 0x1D, 0x51, + 0x70, 0x01, 0x02, 0x50, 0x6C, 0x6D, 0x7A, 0x6D, 0x7A, 0x6D, 0x65, 0x43, + 0x24, 0x42, 0x24, 0x65, 0x41, 0x24, 0x40, 0x24, 0x51, 0x01, 0x01, 0x3C, + 0x25, 0x6D, 0x7A, 0x01, 0x00, 0x3C, 0x25, 0x6D, 0x6D, 0x60, 0x05, 0x02, + 0x39, 0x1D, 0x74, 0x1C, 0x06, 0x1C, 0x7A, 0x61, 0x6D, 0x3F, 0x68, 0x03, + 0x00, 0x3F, 0x26, 0x02, 0x00, 0x09, 0x26, 0x02, 0x00, 0x0A, 0x68, 0x03, + 0x01, 0x51, 0x51, 0x02, 0x00, 0x02, 0x01, 0x18, 0x04, 0x1E, 0x5A, 0x1C, + 0x06, 0x18, 0x64, 0x03, 0x02, 0x51, 0x61, 0x1B, 0x03, 0x03, 0x1B, 0x3F, + 0x23, 0x0D, 0x06, 0x02, 0x33, 0x1D, 0x62, 0x02, 0x02, 0x02, 0x03, 0x17, + 0x04, 0x02, 0x39, 0x1D, 0x51, 0x01, 0x00, 0x3E, 0x25, 0x71, 0x01, 0x21, + 0x5B, 0x01, 0x22, 0x5B, 0x1B, 0x01, 0x23, 0x11, 0x06, 0x28, 0x1A, 0x4C, + 0x6B, 0x6D, 0x1B, 0x06, 0x1D, 0x6D, 0x60, 0x1A, 0x70, 0x1B, 0x01, 0x01, + 0x11, 0x06, 0x03, 0x63, 0x1A, 0x70, 0x01, 0x04, 0x50, 0x6B, 0x4A, 0x1C, + 0x06, 0x03, 0x5F, 0x04, 0x01, 0x7B, 0x51, 0x51, 0x04, 0x60, 0x51, 0x51, + 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02, 0x38, 0x1D, 0x1A, 0x51, 0x6D, + 0x60, 0x06, 0x80, 0x63, 0x75, 0x1C, 0x06, 0x06, 0x01, 0x02, 0x3B, 0x04, + 0x80, 0x57, 0x76, 0x1C, 0x06, 0x06, 0x01, 0x03, 0x3B, 0x04, 0x80, 0x4D, + 0x77, 0x1C, 0x06, 0x06, 0x01, 0x04, 0x3B, 0x04, 0x80, 0x43, 0x78, 0x1C, + 0x06, 0x05, 0x01, 0x05, 0x3B, 0x04, 0x3A, 0x79, 0x1C, 0x06, 0x05, 0x01, + 0x06, 0x3B, 0x04, 0x31, 0x55, 0x1C, 0x06, 0x05, 0x01, 0x02, 0x3A, 0x04, + 0x28, 0x56, 0x1C, 0x06, 0x05, 0x01, 0x03, 0x3A, 0x04, 0x1F, 0x57, 0x1C, + 0x06, 0x05, 0x01, 0x04, 0x3A, 0x04, 0x16, 0x58, 0x1C, 0x06, 0x05, 0x01, + 0x05, 0x3A, 0x04, 0x0D, 0x59, 0x1C, 0x06, 0x05, 0x01, 0x06, 0x3A, 0x04, + 0x04, 0x01, 0x00, 0x01, 0x00, 0x04, 0x04, 0x01, 0x00, 0x01, 0x00, 0x46, + 0x25, 0x45, 0x25, 0x7A, 0x61, 0x7A, 0x51, 0x1A, 0x01, 0x01, 0x3D, 0x25, + 0x73, 0x30, 0x1D, 0x00, 0x00, 0x01, 0x81, 0x06, 0x00, 0x01, 0x54, 0x0D, + 0x06, 0x02, 0x32, 0x1D, 0x1B, 0x03, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00, + 0x6D, 0x71, 0x1B, 0x01, 0x01, 0x11, 0x06, 0x08, 0x63, 0x01, 0x01, 0x15, + 0x3E, 0x25, 0x04, 0x01, 0x2B, 0x7A, 0x00, 0x00, 0x70, 0x01, 0x06, 0x50, + 0x6F, 0x00, 0x00, 0x70, 0x01, 0x03, 0x50, 0x6B, 0x72, 0x06, 0x02, 0x37, + 0x1D, 0x00, 0x00, 0x26, 0x1B, 0x06, 0x07, 0x21, 0x1B, 0x06, 0x01, 0x16, + 0x04, 0x76, 0x2B, 0x00, 0x00, 0x01, 0x01, 0x50, 0x6A, 0x01, 0x01, 0x10, + 0x06, 0x02, 0x2C, 0x1D, 0x72, 0x27, 0x00, 0x00, 0x60, 0x05, 0x02, 0x39, + 0x1D, 0x47, 0x1C, 0x06, 0x04, 0x01, 0x17, 0x04, 0x12, 0x48, 0x1C, 0x06, + 0x04, 0x01, 0x18, 0x04, 0x0A, 0x49, 0x1C, 0x06, 0x04, 0x01, 0x19, 0x04, + 0x02, 0x39, 0x1D, 0x00, 0x04, 0x70, 0x1B, 0x01, 0x17, 0x01, 0x18, 0x4B, + 0x05, 0x02, 0x2F, 0x1D, 0x01, 0x18, 0x11, 0x03, 0x00, 0x4D, 0x6B, 0x66, + 0x02, 0x00, 0x06, 0x0C, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01, 0x66, 0x02, + 0x01, 0x09, 0x04, 0x0E, 0x1B, 0x01, 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80, + 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02, 0x01, 0x01, 0x82, + 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02, + 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01, + 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01, + 0x01, 0x01, 0x0C, 0x67, 0x2A, 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01, 0x04, + 0x07, 0x28, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07, 0x27, 0x02, 0x01, 0x01, + 0x83, 0x10, 0x07, 0x28, 0x1F, 0x15, 0x06, 0x03, 0x01, 0x18, 0x09, 0x5D, + 0x09, 0x52, 0x1B, 0x01, 0x05, 0x14, 0x02, 0x03, 0x09, 0x03, 0x03, 0x01, + 0x1F, 0x15, 0x01, 0x01, 0x26, 0x67, 0x02, 0x03, 0x09, 0x2A, 0x03, 0x03, + 0x01, 0x00, 0x01, 0x17, 0x67, 0x01, 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, + 0x00, 0x01, 0x3B, 0x67, 0x01, 0x3C, 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, + 0x01, 0x00, 0x01, 0x3C, 0x67, 0x02, 0x02, 0x09, 0x03, 0x02, 0x72, 0x1B, + 0x01, 0x2E, 0x11, 0x06, 0x0D, 0x1A, 0x72, 0x1B, 0x01, 0x30, 0x01, 0x39, + 0x4B, 0x06, 0x03, 0x1A, 0x04, 0x74, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, + 0x2F, 0x1D, 0x51, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x72, 0x53, 0x01, + 0x0A, 0x08, 0x03, 0x00, 0x72, 0x53, 0x02, 0x00, 0x09, 0x00, 0x02, 0x03, + 0x00, 0x03, 0x01, 0x66, 0x1B, 0x02, 0x01, 0x02, 0x00, 0x4B, 0x05, 0x02, + 0x2F, 0x1D, 0x00, 0x00, 0x23, 0x70, 0x01, 0x02, 0x50, 0x0B, 0x69, 0x00, + 0x03, 0x1B, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x6B, 0x72, 0x1B, 0x01, + 0x81, 0x00, 0x13, 0x06, 0x02, 0x36, 0x1D, 0x1B, 0x01, 0x00, 0x11, 0x06, + 0x0B, 0x1A, 0x1B, 0x05, 0x04, 0x1A, 0x01, 0x00, 0x00, 0x72, 0x04, 0x6F, + 0x02, 0x01, 0x1B, 0x05, 0x02, 0x33, 0x1D, 0x2A, 0x03, 0x01, 0x02, 0x02, + 0x25, 0x02, 0x02, 0x29, 0x03, 0x02, 0x1B, 0x06, 0x03, 0x72, 0x04, 0x68, + 0x1A, 0x02, 0x00, 0x02, 0x01, 0x0A, 0x00, 0x01, 0x72, 0x1B, 0x01, 0x81, + 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01, 0x81, 0x00, 0x0A, 0x1B, 0x05, 0x02, + 0x31, 0x1D, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, + 0x19, 0x02, 0x00, 0x2A, 0x03, 0x00, 0x1B, 0x01, 0x83, 0xFF, 0xFF, 0x7F, + 0x12, 0x06, 0x02, 0x32, 0x1D, 0x01, 0x08, 0x0E, 0x26, 0x72, 0x23, 0x09, + 0x04, 0x60, 0x00, 0x00, 0x6A, 0x5E, 0x00, 0x00, 0x6B, 0x7A, 0x00, 0x00, + 0x70, 0x4E, 0x6B, 0x00, 0x01, 0x6B, 0x1B, 0x05, 0x02, 0x36, 0x1D, 0x72, + 0x1B, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x36, 0x1D, 0x03, 0x00, 0x1B, + 0x06, 0x16, 0x72, 0x02, 0x00, 0x1B, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, + 0x06, 0x02, 0x36, 0x1D, 0x01, 0x08, 0x0E, 0x09, 0x03, 0x00, 0x04, 0x67, + 0x1A, 0x02, 0x00, 0x00, 0x00, 0x6B, 0x1B, 0x01, 0x81, 0x7F, 0x12, 0x06, + 0x08, 0x7A, 0x01, 0x00, 0x44, 0x25, 0x01, 0x00, 0x00, 0x1B, 0x44, 0x25, + 0x44, 0x29, 0x62, 0x01, 0x7F, 0x00, 0x01, 0x72, 0x03, 0x00, 0x02, 0x00, + 0x01, 0x05, 0x14, 0x01, 0x01, 0x15, 0x1E, 0x02, 0x00, 0x01, 0x06, 0x14, + 0x1B, 0x01, 0x01, 0x15, 0x06, 0x02, 0x2D, 0x1D, 0x01, 0x04, 0x0E, 0x02, + 0x00, 0x01, 0x1F, 0x15, 0x1B, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x2E, 0x1D, + 0x09, 0x00, 0x00, 0x1B, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x70, + 0x00, 0x00, 0x1B, 0x05, 0x02, 0x32, 0x1D, 0x2A, 0x73, 0x00, 0x00, 0x22, + 0x1B, 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x1A, 0x16, 0x04, 0x74, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, + 0x01, 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, + 0x7B, 0x1A, 0x00, 0x00, 0x1B, 0x06, 0x07, 0x7C, 0x1B, 0x06, 0x01, 0x16, + 0x04, 0x76, 0x00, 0x00, 0x01, 0x00, 0x20, 0x21, 0x0B, 0x2B, 0x00 +}; + +static const uint16_t t0_caddr[] = { + 0, + 5, + 10, + 15, + 20, + 24, + 28, + 32, + 36, + 40, + 44, + 48, + 52, + 56, + 60, + 64, + 68, + 72, + 76, + 80, + 84, + 88, + 93, + 98, + 103, + 111, + 116, + 121, + 126, + 131, + 136, + 141, + 146, + 151, + 156, + 161, + 166, + 181, + 187, + 193, + 198, + 206, + 214, + 220, + 231, + 246, + 250, + 255, + 260, + 265, + 270, + 275, + 279, + 289, + 620, + 625, + 639, + 659, + 666, + 678, + 692, + 707, + 740, + 960, + 974, + 991, + 1000, + 1067, + 1123, + 1127, + 1131, + 1136, + 1184, + 1210, + 1254, + 1265, + 1274, + 1287, + 1291, + 1295, + 1299, + 1303, + 1307, + 1311, + 1315, + 1327 +}; + +#define T0_INTERPRETED 39 + +#define T0_ENTER(ip, rp, slot) do { \ + const unsigned char *t0_newip; \ + uint32_t t0_lnum; \ + t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \ + t0_lnum = t0_parse7E_unsigned(&t0_newip); \ + (rp) += t0_lnum; \ + *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \ + (ip) = t0_newip; \ + } while (0) + +#define T0_DEFENTRY(name, slot) \ +void \ +name(void *ctx) \ +{ \ + t0_context *t0ctx = ctx; \ + t0ctx->ip = &t0_codeblock[0]; \ + T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ +} + +T0_DEFENTRY(br_x509_decoder_init_main_libmail, 92) + +#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++) + +void +br_x509_decoder_run_libmail(void *t0ctx) +{ + uint32_t *dp, *rp; + const unsigned char *ip; + +#define T0_LOCAL(x) (*(rp - 2 - (x))) +#define T0_POP() (*-- dp) +#define T0_POPi() (*(int32_t *)(-- dp)) +#define T0_PEEK(x) (*(dp - 1 - (x))) +#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x))) +#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0) +#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0) +#define T0_RPOP() (*-- rp) +#define T0_RPOPi() (*(int32_t *)(-- rp)) +#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0) +#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0) +#define T0_ROLL(x) do { \ + size_t t0len = (size_t)(x); \ + uint32_t t0tmp = *(dp - 1 - t0len); \ + memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_SWAP() do { \ + uint32_t t0tmp = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_ROT() do { \ + uint32_t t0tmp = *(dp - 3); \ + *(dp - 3) = *(dp - 2); \ + *(dp - 2) = *(dp - 1); \ + *(dp - 1) = t0tmp; \ +} while (0) +#define T0_NROT() do { \ + uint32_t t0tmp = *(dp - 1); \ + *(dp - 1) = *(dp - 2); \ + *(dp - 2) = *(dp - 3); \ + *(dp - 3) = t0tmp; \ +} while (0) +#define T0_PICK(x) do { \ + uint32_t t0depth = (x); \ + T0_PUSH(T0_PEEK(t0depth)); \ +} while (0) +#define T0_CO() do { \ + goto t0_exit; \ +} while (0) +#define T0_RET() goto t0_next + + dp = ((t0_context *)t0ctx)->dp; + rp = ((t0_context *)t0ctx)->rp; + ip = ((t0_context *)t0ctx)->ip; + goto t0_next; + for (;;) { + uint32_t t0x; + + t0_next: + t0x = T0_NEXT(&ip); + if (t0x < T0_INTERPRETED) { + switch (t0x) { + int32_t t0off; + + case 0: /* ret */ + t0x = T0_RPOP(); + rp -= (t0x >> 16); + t0x &= 0xFFFF; + if (t0x == 0) { + ip = NULL; + goto t0_exit; + } + ip = &t0_codeblock[t0x]; + break; + case 1: /* literal constant */ + T0_PUSHi(t0_parse7E_signed(&ip)); + break; + case 2: /* read local */ + T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip))); + break; + case 3: /* write local */ + T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP(); + break; + case 4: /* jump */ + t0off = t0_parse7E_signed(&ip); + ip += t0off; + break; + case 5: /* jump if */ + t0off = t0_parse7E_signed(&ip); + if (T0_POP()) { + ip += t0off; + } + break; + case 6: /* jump if not */ + t0off = t0_parse7E_signed(&ip); + if (!T0_POP()) { + ip += t0off; + } + break; + case 7: { + /* %25 */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSHi(a % b); + + } + break; + case 8: { + /* * */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a * b); + + } + break; + case 9: { + /* + */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a + b); + + } + break; + case 10: { + /* - */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a - b); + + } + break; + case 11: { + /* -rot */ + T0_NROT(); + } + break; + case 12: { + /* / */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSHi(a / b); + + } + break; + case 13: { + /* < */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a < b)); + + } + break; + case 14: { + /* << */ + + int c = (int)T0_POPi(); + uint32_t x = T0_POP(); + T0_PUSH(x << c); + + } + break; + case 15: { + /* <= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a <= b)); + + } + break; + case 16: { + /* <> */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a != b)); + + } + break; + case 17: { + /* = */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(-(uint32_t)(a == b)); + + } + break; + case 18: { + /* > */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a > b)); + + } + break; + case 19: { + /* >= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a >= b)); + + } + break; + case 20: { + /* >> */ + + int c = (int)T0_POPi(); + int32_t x = T0_POPi(); + T0_PUSHi(x >> c); + + } + break; + case 21: { + /* and */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a & b); + + } + break; + case 22: { + /* co */ + T0_CO(); + } + break; + case 23: { + /* copy-ec-pkey */ + + size_t qlen = T0_POP(); + uint32_t curve = T0_POP(); + CTX->pkey.key_type = BR_KEYTYPE_EC; + CTX->pkey.key.ec.curve = curve; + CTX->pkey.key.ec.q = CTX->pkey_data; + CTX->pkey.key.ec.qlen = qlen; + + } + break; + case 24: { + /* copy-rsa-pkey */ + + size_t elen = T0_POP(); + size_t nlen = T0_POP(); + CTX->pkey.key_type = BR_KEYTYPE_RSA; + CTX->pkey.key.rsa.n = CTX->pkey_data; + CTX->pkey.key.rsa.nlen = nlen; + CTX->pkey.key.rsa.e = CTX->pkey_data + nlen; + CTX->pkey.key.rsa.elen = elen; + + } + break; + case 25: { + /* data-get8 */ + + size_t addr = T0_POP(); + T0_PUSH(t0_datablock[addr]); + + } + break; + case 26: { + /* drop */ + (void)T0_POP(); + } + break; + case 27: { + /* dup */ + T0_PUSH(T0_PEEK(0)); + } + break; + case 28: { + /* eqOID */ + + const unsigned char *a2 = &t0_datablock[T0_POP()]; + const unsigned char *a1 = &CTX->pad[0]; + size_t len = a1[0]; + int x; + if (len == a2[0]) { + x = -(memcmp(a1 + 1, a2 + 1, len) == 0); + } else { + x = 0; + } + T0_PUSH((uint32_t)x); + + } + break; + case 29: { + /* fail */ + + CTX->err = T0_POPi(); + T0_CO(); + + } + break; + case 30: { + /* neg */ + + uint32_t a = T0_POP(); + T0_PUSH(-a); + + } + break; + case 31: { + /* or */ + + uint32_t b = T0_POP(); + uint32_t a = T0_POP(); + T0_PUSH(a | b); + + } + break; + case 32: { + /* over */ + T0_PUSH(T0_PEEK(1)); + } + break; + case 33: { + /* read-blob-inner */ + + uint32_t len = T0_POP(); + uint32_t addr = T0_POP(); + size_t clen = CTX->hlen; + if (clen > len) { + clen = (size_t)len; + } + if (addr != 0) { + memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); + } + if (CTX->copy_dn && CTX->append_dn) { + CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen); + } + CTX->hbuf += clen; + CTX->hlen -= clen; + T0_PUSH(addr + clen); + T0_PUSH(len - clen); + + } + break; + case 34: { + /* read8-low */ + + if (CTX->hlen == 0) { + T0_PUSHi(-1); + } else { + unsigned char x = *CTX->hbuf ++; + if (CTX->copy_dn && CTX->append_dn) { + CTX->append_dn(CTX->append_dn_ctx, &x, 1); + } + CTX->hlen --; + T0_PUSH(x); + } + + } + break; + case 35: { + /* rot */ + T0_ROT(); + } + break; + case 36: { + /* set32 */ + + uint32_t addr = T0_POP(); + *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP(); + + } + break; + case 37: { + /* set8 */ + + uint32_t addr = T0_POP(); + *((unsigned char *)CTX + addr) = (unsigned char)T0_POP(); + + } + break; + case 38: { + /* swap */ + T0_SWAP(); + } + break; + } + + } else { + T0_ENTER(ip, rp, t0x); + } + } +t0_exit: + ((t0_context *)t0ctx)->dp = dp; + ((t0_context *)t0ctx)->rp = rp; + ((t0_context *)t0ctx)->ip = ip; +} + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_knownkey.c b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_knownkey.c new file mode 100644 index 000000000..f1f5af1bc --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_knownkey.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#include "inner.h" + +/* see bearssl_x509.h */ +void +br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx, + const br_rsa_public_key *pk, unsigned usages) +{ + ctx->vtable = &br_x509_knownkey_vtable; + ctx->pkey.key_type = BR_KEYTYPE_RSA; + ctx->pkey.key.rsa = *pk; + ctx->usages = usages; +} + +/* see bearssl_x509.h */ +void +br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, + const br_ec_public_key *pk, unsigned usages) +{ + ctx->vtable = &br_x509_knownkey_vtable; + ctx->pkey.key_type = BR_KEYTYPE_EC; + ctx->pkey.key.ec = *pk; + ctx->usages = usages; +} + +static void +kk_start_chain(const br_x509_class **ctx, const char *server_name) +{ + (void)ctx; + (void)server_name; +} + +static void +kk_start_cert(const br_x509_class **ctx, uint32_t length) +{ + (void)ctx; + (void)length; +} + +static void +kk_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) +{ + (void)ctx; + (void)buf; + (void)len; +} + +static void +kk_end_cert(const br_x509_class **ctx) +{ + (void)ctx; +} + +static unsigned +kk_end_chain(const br_x509_class **ctx) +{ + (void)ctx; + return 0; +} + +static const br_x509_pkey * +kk_get_pkey(const br_x509_class *const *ctx, unsigned *usages) +{ + const br_x509_knownkey_context *xc; + + xc = (const br_x509_knownkey_context *)ctx; + if (usages != NULL) { + *usages = xc->usages; + } + return &xc->pkey; +} + +/* see bearssl_x509.h */ +const br_x509_class br_x509_knownkey_vtable = { + sizeof(br_x509_knownkey_context), + kk_start_chain, + kk_start_cert, + kk_append, + kk_end_cert, + kk_end_chain, + kk_get_pkey +}; + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_minimal_full.c b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_minimal_full.c new file mode 100644 index 000000000..9ca15d263 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/bssl/x509_minimal_full.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "../ESP_SSLClient_FS.h" +#if defined(USE_LIB_SSL_ENGINE) + +#include "inner.h" + +/* see bearssl_x509.h */ +void +br_x509_minimal_init_full(br_x509_minimal_context *xc, + const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num) +{ + /* + * All hash functions are activated. + * Note: the X.509 validation engine will nonetheless refuse to + * validate signatures that use MD5 as hash function. + */ + static const br_hash_class *hashes[] = { + &br_md5_vtable, + &br_sha1_vtable, + &br_sha224_vtable, + &br_sha256_vtable, + &br_sha384_vtable, + &br_sha512_vtable + }; + + int id; + + br_x509_minimal_init(xc, &br_sha256_vtable, + trust_anchors, trust_anchors_num); + br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy); + br_x509_minimal_set_ecdsa(xc, + &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); + for (id = br_md5_ID; id <= br_sha512_ID; id ++) { + const br_hash_class *hc; + + hc = hashes[id - 1]; + br_x509_minimal_set_hash(xc, id, hc); + } +} + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_CertStore.cpp b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_CertStore.cpp new file mode 100644 index 000000000..f4f06eac5 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_CertStore.cpp @@ -0,0 +1,282 @@ +/* + CertStoreBearSSL.cpp - Library for Arduino ESP8266 + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef BSSL_CERTSTORE_CPP +#define BSSL_CERTSTORE_CPP + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wvla" + +#include +#include "../ESP_SSLClient_FS.h" +#include "../ESP_SSLClient_Const.h" +#if defined(USE_LIB_SSL_ENGINE) + +#include "BSSL_CertStore.h" + +#if defined(ESP_SSL_FS_SUPPORTED) + +#include + +#if defined(DEBUG_ESP_SSL) && defined(DEBUG_ESP_PORT) +#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR("BSSL:" fmt), ##__VA_ARGS__) +#else +#define DEBUG_BSSL(...) +#endif + +namespace bssl +{ + + extern "C" + { + // Callback for the x509 decoder + static void dn_append(void *ctx, const void *buf, size_t len) + { + br_sha256_context *sha1 = (br_sha256_context *)ctx; + br_sha256_update(sha1, buf, len); + } + } + + CertStore::~CertStore() + { + free(_indexName); + free(_dataName); + } + + CertStore::CertInfo CertStore::_preprocessCert(uint32_t length, uint32_t offset, const void *raw) + { + CertStore::CertInfo ci; + + // Clear the CertInfo + memset(&ci, 0, sizeof(ci)); + + // Process it using SHA256, same as the hashed_dn + br_x509_decoder_context_libmail *ctx = new (std::nothrow) br_x509_decoder_context_libmail; + br_sha256_context *sha256 = new (std::nothrow) br_sha256_context; + if (!ctx || !sha256) + { + if (ctx) + delete ctx; + if (sha256) + delete sha256; + DEBUG_BSSL("CertStore::_preprocessCert: OOM\n"); + return ci; + } + + br_sha256_init(sha256); + br_x509_decoder_init_libmail(ctx, dn_append, sha256); + br_x509_decoder_push_libmail(ctx, (const void *)raw, length); + + // Copy result to structure + br_sha256_out(sha256, &ci.sha256); + ci.length = length; + ci.offset = offset; + + // Clean up allocated memory + delete sha256; + delete ctx; + + // Return result + return ci; + } + + // The certs.ar file is a UNIX ar format file, concatenating all the + // individual certificates into a single blob in a space-efficient way. + int CertStore::initCertStore(FS &fs, const char *indexFileName, const char *dataFileName) + { + int count = 0; + uint32_t offset = 0; + + _fs = &fs; + + // In case initCertStore called multiple times, don't leak old filenames + free(_indexName); + free(_dataName); + + // No strdup_P, so manually do it + _indexName = (char *)malloc(strlen_P(indexFileName) + 1); + _dataName = (char *)malloc(strlen_P(dataFileName) + 1); + if (!_indexName || !_dataName) + { + free(_indexName); + free(_dataName); + return 0; + } + memcpy_P(_indexName, indexFileName, strlen_P(indexFileName) + 1); + memcpy_P(_dataName, dataFileName, strlen_P(dataFileName) + 1); + + File index = _fs->open(_indexName, FILE_WRITE); + if (!index) + { + return 0; + } + + File data = _fs->open(_dataName, FILE_READ); + if (!data) + { + index.close(); + return 0; + } + + uint8_t magic[8]; + if (data.read(magic, sizeof(magic)) != sizeof(magic) || + memcmp(magic, "!\n", sizeof(magic))) + { + data.close(); + index.close(); + return 0; + } + offset += sizeof(magic); + + while (true) + { + uint8_t fileHeader[60]; + // 0..15 = filename in ASCII + // 48...57 = length in decimal ASCII + int32_t length; + if (data.read(fileHeader, sizeof(fileHeader)) != sizeof(fileHeader)) + { + break; + } + offset += sizeof(fileHeader); + fileHeader[58] = 0; + if (1 != sscanf((char *)(fileHeader + 48), "%d", (int *)(&length)) || !length) + { + break; + } + + void *raw = malloc(length); + if (!raw) + { + break; + } + if ((int)data.read((uint8_t *)raw, length) != length) + { + free(raw); + break; + } + + // If the filename starts with "//" then this is a rename file, skip it + if (fileHeader[0] != '/' || fileHeader[1] != '/') + { + CertStore::CertInfo ci = _preprocessCert(length, offset, raw); + if (index.write((uint8_t *)&ci, sizeof(ci)) != (ssize_t)sizeof(ci)) + { + free(raw); + break; + } + count++; + } + + offset += length; + free(raw); + if (offset & 1) + { + uint8_t x; + data.read(&x, 1); + offset++; + } + } + data.close(); + index.close(); + return count; + } + + void CertStore::installCertStore(br_x509_minimal_context *ctx) + { + br_x509_minimal_set_dynamic(ctx, (void *)this, findHashedTA, freeHashedTA); + } + + const br_x509_trust_anchor *CertStore::findHashedTA(void *ctx, void *hashed_dn, size_t len) + { + CertStore *cs = static_cast(ctx); + CertStore::CertInfo ci; + + if (!cs || len != sizeof(ci.sha256) || !cs->_indexName || !cs->_dataName || !cs->_fs) + { + return nullptr; + } + + File index = cs->_fs->open(cs->_indexName, FILE_READ); + if (!index) + { + return nullptr; + } + + while (index.read((uint8_t *)&ci, sizeof(ci)) == sizeof(ci)) + { + if (!memcmp(ci.sha256, hashed_dn, sizeof(ci.sha256))) + { + index.close(); + uint8_t *der = (uint8_t *)malloc(ci.length); + if (!der) + { + return nullptr; + } + File data = cs->_fs->open(cs->_dataName, FILE_READ); + if (!data) + { + free(der); + return nullptr; + } + if (!data.seek(ci.offset, SeekSet)) + { + data.close(); + free(der); + return nullptr; + } + if ((int)data.read(der, ci.length) != (int)ci.length) + { + free(der); + return nullptr; + } + data.close(); + cs->_x509 = new (std::nothrow) X509List(der, ci.length); + free(der); + if (!cs->_x509) + { + DEBUG_BSSL("CertStore::findHashedTA: OOM\n"); + return nullptr; + } + + br_x509_trust_anchor *ta = (br_x509_trust_anchor *)cs->_x509->getTrustAnchors(); + memcpy(ta->dn.data, ci.sha256, sizeof(ci.sha256)); + ta->dn.len = sizeof(ci.sha256); + + return ta; + } + } + index.close(); + return nullptr; + } + + void CertStore::freeHashedTA(void *ctx, const br_x509_trust_anchor *ta) + { + CertStore *cs = static_cast(ctx); + (void)ta; // Unused + delete cs->_x509; + cs->_x509 = nullptr; + } + +} + +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_CertStore.h similarity index 62% rename from lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.h rename to lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_CertStore.h index fd9f8c537..42b963340 100644 --- a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.h +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_CertStore.h @@ -1,5 +1,5 @@ /* - Copy of CertStoreBearSSL.h - Library for Arduino ESP8266 + CertStoreBearSSL.h - Library for Arduino ESP8266 Copyright (c) 2018 Earle F. Philhower, III This library is free software; you can redistribute it and/or @@ -16,27 +16,54 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef BSSL_CERTSTORE_H +#define BSSL_CERTSTORE_H -#ifndef ESP_Mail_CertStoreBearSSL_H -#define ESP_Mail_CertStoreBearSSL_H - -#ifdef ESP8266 +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wvla" #include -#include "ESP_Mail_BearSSLHelpers.h" -#include +#include "../ESP_SSLClient_FS.h" +#include "../ESP_SSLClient_Const.h" +#if defined(USE_LIB_SSL_ENGINE) + + +#if defined __has_include +#if __has_include() && defined(ESP_SSLCLIENT_USE_FILESYSTEM) #include +#define ESP_SSL_FS_SUPPORTED +#endif +#endif + +#if defined(ESP_SSL_FS_SUPPORTED) + + +#include "../bssl/bearssl.h" +#include "BSSL_Helper.h" + +using namespace bssl; // Base class for the certificate stores, which allow use // of a large set of certificates stored on FS or SD card to // be dynamically used when validating a X509 certificate -namespace ESP_Mail { +namespace bssl +{ -class ESP_Mail_CertStore { + class CertStoreBase + { public: - ESP_Mail_CertStore() { }; - ~ESP_Mail_CertStore(); + virtual ~CertStoreBase() {} + + // Installs the cert store into the X509 decoder (normally via static function callbacks) + virtual void installCertStore(br_x509_minimal_context *ctx) = 0; + }; + + class CertStore : public CertStoreBase + { + public: + CertStore(){}; + ~CertStore(); // Set the file interface instances, do preprocessing int initCertStore(FS &fs, const char *indexFileName, const char *dataFileName); @@ -48,25 +75,27 @@ class ESP_Mail_CertStore { FS *_fs = nullptr; char *_indexName = nullptr; char *_dataName = nullptr; - ESP_Mail_X509List *_x509 = nullptr; + X509List *_x509 = nullptr; // These need to be static as they are callbacks from BearSSL C code static const br_x509_trust_anchor *findHashedTA(void *ctx, void *hashed_dn, size_t len); static void freeHashedTA(void *ctx, const br_x509_trust_anchor *ta); // The binary format of the index file - class ESP_Mail_CertInfo { + class CertInfo + { public: uint8_t sha256[32]; uint32_t offset; uint32_t length; }; - static ESP_Mail_CertInfo _preprocessCert(uint32_t length, uint32_t offset, const void *raw); + static CertInfo _preprocessCert(uint32_t length, uint32_t offset, const void *raw); + }; }; -}; +#endif -#endif /* ESP8266 */ +#endif -#endif /* ESP_Mail_CertStoreBearSSL_H */ +#endif diff --git a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.cpp b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_Helper.cpp similarity index 82% rename from lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.cpp rename to lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_Helper.cpp index 9c44c94ce..3d4d62684 100644 --- a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.cpp +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_Helper.cpp @@ -1,1108 +1,1053 @@ -/* - Copy of BearSSLHelpers.cpp - - WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries - - Mostly compatible with Arduino WiFi shield library and standard - WiFiClient/ServerSecure (except for certificate handling). - - Copyright (c) 2018 Earle F. Philhower, III - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef ESP_Mail_BearSSLHelpers_CPP -#define ESP_Mail_BearSSLHelpers_CPP - -#ifdef ESP8266 - -#include "ESP_Mail_BearSSLHelpers.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef ARDUINO_SIGNING -#define ARDUINO_SIGNING 0 -#endif - -namespace ESP_Mail_brssl -{ - // Code here is pulled from brssl sources, with the copyright and license - // shown below. I've rewritten things using C++ semantics and removed - // custom VEC_* calls (std::vector to the rescue) and adjusted things to - // allow for long-running operation (i.e. some memory issues when DERs - // passed into the decoders). Bugs are most likely my fault. - - // Original (c) message follows: - /* - Copyright (c) 2016 Thomas Pornin - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - - class private_key - { - public: - int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */ - union - { - br_rsa_private_key rsa; - br_ec_private_key ec; - } key; - }; - - class public_key - { - public: - int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */ - union - { - br_rsa_public_key rsa; - br_ec_public_key ec; - } key; - }; - - class pem_object - { - public: - char *name; - unsigned char *data; - size_t data_len; - }; - - // Forward definitions - void free_ta_contents(br_x509_trust_anchor *ta); - void free_public_key(public_key *pk); - void free_private_key(private_key *sk); - bool looks_like_DER(const unsigned char *buf, size_t len); - pem_object *decode_pem(const void *src, size_t len, size_t *num); - void free_pem_object_contents(pem_object *po); - - // Used as callback multiple places to append a string to a vector - static void byte_vector_append(void *ctx, const void *buff, size_t len) - { - std::vector *vec = static_cast *>(ctx); - vec->reserve(vec->size() + len); // Allocate extra space all at once - for (size_t i = 0; i < len; i++) - { - vec->push_back(((uint8_t *)buff)[i]); - } - } - - static bool certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta, const br_x509_certificate *xc) - { - std::unique_ptr dc(new br_x509_decoder_context); // auto-delete on exit - std::vector vdn; - br_x509_pkey *pk; - - // Clear everything in the Trust Anchor - memset(ta, 0, sizeof(*ta)); - - br_x509_decoder_init(dc.get(), byte_vector_append, (void *)&vdn, 0, 0); - br_x509_decoder_push(dc.get(), xc->data, xc->data_len); - pk = br_x509_decoder_get_pkey(dc.get()); - if (pk == nullptr) - { - return false; // No key present, something broken in the cert! - } - - // Copy the raw certificate data - ta->dn.data = (uint8_t *)malloc(vdn.size()); - if (!ta->dn.data) - { - return false; // OOM, but nothing yet allocated - } - memcpy(ta->dn.data, &vdn[0], vdn.size()); - ta->dn.len = vdn.size(); - ta->flags = 0; - if (br_x509_decoder_isCA(dc.get())) - { - ta->flags |= BR_X509_TA_CA; - } - - // Extract the public key - switch (pk->key_type) - { - case BR_KEYTYPE_RSA: - ta->pkey.key_type = BR_KEYTYPE_RSA; - ta->pkey.key.rsa.n = (uint8_t *)malloc(pk->key.rsa.nlen); - ta->pkey.key.rsa.e = (uint8_t *)malloc(pk->key.rsa.elen); - if ((ta->pkey.key.rsa.n == nullptr) || (ta->pkey.key.rsa.e == nullptr)) - { - free_ta_contents(ta); // OOM, so clean up - return false; - } - memcpy(ta->pkey.key.rsa.n, pk->key.rsa.n, pk->key.rsa.nlen); - ta->pkey.key.rsa.nlen = pk->key.rsa.nlen; - memcpy(ta->pkey.key.rsa.e, pk->key.rsa.e, pk->key.rsa.elen); - ta->pkey.key.rsa.elen = pk->key.rsa.elen; - return true; - case BR_KEYTYPE_EC: - ta->pkey.key_type = BR_KEYTYPE_EC; - ta->pkey.key.ec.curve = pk->key.ec.curve; - ta->pkey.key.ec.q = (uint8_t *)malloc(pk->key.ec.qlen); - if (ta->pkey.key.ec.q == nullptr) - { - free_ta_contents(ta); // OOM, so clean up - return false; - } - memcpy(ta->pkey.key.ec.q, pk->key.ec.q, pk->key.ec.qlen); - ta->pkey.key.ec.qlen = pk->key.ec.qlen; - return true; - default: - free_ta_contents(ta); // Unknown key type - return false; - } - - // Should never get here, if so there was an unknown error - return false; - } - - br_x509_trust_anchor *certificate_to_trust_anchor(const br_x509_certificate *xc) - { - br_x509_trust_anchor *ta = (br_x509_trust_anchor *)malloc(sizeof(br_x509_trust_anchor)); - if (!ta) - { - return nullptr; - } - - if (!certificate_to_trust_anchor_inner(ta, xc)) - { - free(ta); - return nullptr; - } - return ta; - } - - void free_ta_contents(br_x509_trust_anchor *ta) - { - if (ta) - { - free(ta->dn.data); - if (ta->pkey.key_type == BR_KEYTYPE_RSA) - { - free(ta->pkey.key.rsa.n); - free(ta->pkey.key.rsa.e); - } - else if (ta->pkey.key_type == BR_KEYTYPE_EC) - { - free(ta->pkey.key.ec.q); - } - memset(ta, 0, sizeof(*ta)); - } - } - - // Checks if a bitstream looks like a valid DER(binary) encoding. - // Basically tries to verify the length of all included segments - // matches the length of the input buffer. Does not actually - // validate any contents. - bool looks_like_DER(const unsigned char *buff, size_t len) - { - if (len < 2) - { - return false; - } - if (pgm_read_byte(buff++) != 0x30) - { - return false; - } - int fb = pgm_read_byte(buff++); - len -= 2; - if (fb < 0x80) - { - return (size_t)fb == len; - } - else if (fb == 0x80) - { - return false; - } - else - { - fb -= 0x80; - if (len < (size_t)fb + 2) - { - return false; - } - len -= (size_t)fb; - size_t dlen = 0; - while (fb-- > 0) - { - if (dlen > (len >> 8)) - { - return false; - } - dlen = (dlen << 8) + (size_t)pgm_read_byte(buff++); - } - return dlen == len; - } - } - - void free_pem_object_contents(pem_object *po) - { - if (po) - { - free(po->name); - free(po->data); - po->name = nullptr; - po->data = nullptr; - } - } - - // Converts a PEM (~=base64) source into a set of DER-encoded binary blobs. - // Each blob is named by the ---- BEGIN xxx ---- field, and multiple - // blobs may be returned. - pem_object *decode_pem(const void *src, size_t len, size_t *num) - { - std::vector pem_list; - std::unique_ptr pc(new br_pem_decoder_context); // auto-delete on exit - if (!pc.get()) - { - return nullptr; - } - pem_object po, *pos; - const unsigned char *buff; - std::vector bv; - - *num = 0; - br_pem_decoder_init(pc.get()); - buff = (const unsigned char *)src; - po.name = nullptr; - po.data = nullptr; - po.data_len = 0; - bool inobj = false; - bool extra_nl = true; - - while (len > 0) - { - size_t tlen; - - tlen = br_pem_decoder_push(pc.get(), buff, len); - buff += tlen; - len -= tlen; - switch (br_pem_decoder_event(pc.get())) - { - case BR_PEM_BEGIN_OBJ: - po.name = strdup(br_pem_decoder_name(pc.get())); - br_pem_decoder_setdest(pc.get(), byte_vector_append, &bv); - inobj = true; - break; - - case BR_PEM_END_OBJ: - if (inobj) - { - // Stick data into the vector - po.data = (uint8_t *)malloc(bv.size()); - if (po.data) - { - memcpy(po.data, &bv[0], bv.size()); - po.data_len = bv.size(); - pem_list.push_back(po); - } - // Clean up state for next blob processing - bv.clear(); - po.name = nullptr; - po.data = nullptr; - po.data_len = 0; - inobj = false; - } - break; - - case BR_PEM_ERROR: - free(po.name); - for (size_t i = 0; i < pem_list.size(); i++) - { - free_pem_object_contents(&pem_list[i]); - } - return nullptr; - - default: - // Do nothing here, the parser is still working on things - break; - } - - if (len == 0 && extra_nl) - { - extra_nl = false; - buff = (const unsigned char *)"\n"; - len = 1; - } - } - - if (inobj) - { - free(po.name); - for (size_t i = 0; i < pem_list.size(); i++) - { - free_pem_object_contents(&pem_list[i]); - } - return nullptr; - } - - pos = (pem_object *)malloc((1 + pem_list.size()) * sizeof(*pos)); - if (pos) - { - *num = pem_list.size(); - pem_list.push_back(po); // Null-terminate list - memcpy(pos, &pem_list[0], pem_list.size() * sizeof(*pos)); - } - return pos; - } - - // Parse out DER or PEM encoded certificates from a binary buffer, - // potentially stored in PROGMEM. - br_x509_certificate *read_certificates(const char *buff, size_t len, size_t *num) - { - std::vector cert_list; - pem_object *pos; - size_t u, num_pos; - br_x509_certificate *xcs; - br_x509_certificate dummy; - - *num = 0; - - if (looks_like_DER((const unsigned char *)buff, len)) - { - xcs = (br_x509_certificate *)malloc(2 * sizeof(*xcs)); - if (!xcs) - { - return nullptr; - } - xcs[0].data = (uint8_t *)malloc(len); - if (!xcs[0].data) - { - free(xcs); - return nullptr; - } - memcpy_P(xcs[0].data, buff, len); - xcs[0].data_len = len; - xcs[1].data = nullptr; - xcs[1].data_len = 0; - *num = 1; - return xcs; - } - - pos = decode_pem(buff, len, &num_pos); - if (!pos) - { - return nullptr; - } - for (u = 0; u < num_pos; u++) - { - if (!strcmp_P(pos[u].name, PSTR("CERTIFICATE")) || !strcmp_P(pos[u].name, PSTR("X509 CERTIFICATE"))) - { - br_x509_certificate xc; - xc.data = pos[u].data; - xc.data_len = pos[u].data_len; - pos[u].data = nullptr; // Don't free the data we moved to the xc vector! - cert_list.push_back(xc); - } - } - for (u = 0; u < num_pos; u++) - { - free_pem_object_contents(&pos[u]); - } - free(pos); - - if (cert_list.size() == 0) - { - return nullptr; - } - *num = cert_list.size(); - dummy.data = nullptr; - dummy.data_len = 0; - cert_list.push_back(dummy); - xcs = (br_x509_certificate *)malloc(cert_list.size() * sizeof(*xcs)); - if (!xcs) - { - for (size_t i = 0; i < cert_list.size(); i++) - { - free(cert_list[i].data); // Clean up any captured data blobs - } - return nullptr; - } - memcpy(xcs, &cert_list[0], cert_list.size() * sizeof(br_x509_certificate)); - // XCS now has [].data pointing to the previously allocated blobs, so don't - // want to free anything in cert_list[]. - return xcs; - } - - void free_certificates(br_x509_certificate *certs, size_t num) - { - if (certs) - { - for (size_t u = 0; u < num; u++) - { - free(certs[u].data); - } - free(certs); - } - } - - static public_key *decode_public_key(const unsigned char *buff, size_t len) - { - std::unique_ptr dc(new br_pkey_decoder_context); // auto-delete on exit - if (!dc.get()) - { - return nullptr; - } - - public_key *pk = nullptr; - - br_pkey_decoder_init(dc.get()); - br_pkey_decoder_push(dc.get(), buff, len); - int err = br_pkey_decoder_last_error(dc.get()); - if (err != 0) - { - return nullptr; - } - - const br_rsa_public_key *rk = nullptr; - const br_ec_public_key *ek = nullptr; - switch (br_pkey_decoder_key_type(dc.get())) - { - case BR_KEYTYPE_RSA: - rk = br_pkey_decoder_get_rsa(dc.get()); - pk = (public_key *)malloc(sizeof *pk); - if (!pk) - { - return nullptr; - } - pk->key_type = BR_KEYTYPE_RSA; - pk->key.rsa.n = (uint8_t *)malloc(rk->nlen); - pk->key.rsa.e = (uint8_t *)malloc(rk->elen); - if (!pk->key.rsa.n || !pk->key.rsa.e) - { - free(pk->key.rsa.n); - free(pk->key.rsa.e); - free(pk); - return nullptr; - } - memcpy(pk->key.rsa.n, rk->n, rk->nlen); - pk->key.rsa.nlen = rk->nlen; - memcpy(pk->key.rsa.e, rk->e, rk->elen); - pk->key.rsa.elen = rk->elen; - return pk; - - case BR_KEYTYPE_EC: - ek = br_pkey_decoder_get_ec(dc.get()); - pk = (public_key *)malloc(sizeof *pk); - if (!pk) - { - return nullptr; - } - pk->key_type = BR_KEYTYPE_EC; - pk->key.ec.q = (uint8_t *)malloc(ek->qlen); - if (!pk->key.ec.q) - { - free(pk); - return nullptr; - } - memcpy(pk->key.ec.q, ek->q, ek->qlen); - pk->key.ec.qlen = ek->qlen; - return pk; - - default: - return nullptr; - } - } - - void free_public_key(public_key *pk) - { - if (pk) - { - if (pk->key_type == BR_KEYTYPE_RSA) - { - free(pk->key.rsa.n); - free(pk->key.rsa.e); - } - else if (pk->key_type == BR_KEYTYPE_EC) - { - free(pk->key.ec.q); - } - free(pk); - } - } - - static private_key *decode_private_key(const unsigned char *buff, size_t len) - { - std::unique_ptr dc(new br_skey_decoder_context); // auto-delete on exit - if (!dc.get()) - { - return nullptr; - } - - private_key *sk = nullptr; - - br_skey_decoder_init(dc.get()); - br_skey_decoder_push(dc.get(), buff, len); - int err = br_skey_decoder_last_error(dc.get()); - if (err != 0) - { - return nullptr; - } - - const br_rsa_private_key *rk = nullptr; - const br_ec_private_key *ek = nullptr; - switch (br_skey_decoder_key_type(dc.get())) - { - case BR_KEYTYPE_RSA: - rk = br_skey_decoder_get_rsa(dc.get()); - sk = (private_key *)malloc(sizeof *sk); - if (!sk) - { - return nullptr; - } - sk->key_type = BR_KEYTYPE_RSA; - sk->key.rsa.p = (uint8_t *)malloc(rk->plen); - sk->key.rsa.q = (uint8_t *)malloc(rk->qlen); - sk->key.rsa.dp = (uint8_t *)malloc(rk->dplen); - sk->key.rsa.dq = (uint8_t *)malloc(rk->dqlen); - sk->key.rsa.iq = (uint8_t *)malloc(rk->iqlen); - if (!sk->key.rsa.p || !sk->key.rsa.q || !sk->key.rsa.dp || !sk->key.rsa.dq || !sk->key.rsa.iq) - { - free_private_key(sk); - return nullptr; - } - sk->key.rsa.n_bitlen = rk->n_bitlen; - memcpy(sk->key.rsa.p, rk->p, rk->plen); - sk->key.rsa.plen = rk->plen; - memcpy(sk->key.rsa.q, rk->q, rk->qlen); - sk->key.rsa.qlen = rk->qlen; - memcpy(sk->key.rsa.dp, rk->dp, rk->dplen); - sk->key.rsa.dplen = rk->dplen; - memcpy(sk->key.rsa.dq, rk->dq, rk->dqlen); - sk->key.rsa.dqlen = rk->dqlen; - memcpy(sk->key.rsa.iq, rk->iq, rk->iqlen); - sk->key.rsa.iqlen = rk->iqlen; - return sk; - - case BR_KEYTYPE_EC: - ek = br_skey_decoder_get_ec(dc.get()); - sk = (private_key *)malloc(sizeof *sk); - sk->key_type = BR_KEYTYPE_EC; - sk->key.ec.curve = ek->curve; - sk->key.ec.x = (uint8_t *)malloc(ek->xlen); - if (!sk->key.ec.x) - { - free_private_key(sk); - return nullptr; - } - memcpy(sk->key.ec.x, ek->x, ek->xlen); - sk->key.ec.xlen = ek->xlen; - return sk; - - default: - return nullptr; - } - } - - void free_private_key(private_key *sk) - { - if (sk) - { - switch (sk->key_type) - { - case BR_KEYTYPE_RSA: - free(sk->key.rsa.p); - free(sk->key.rsa.q); - free(sk->key.rsa.dp); - free(sk->key.rsa.dq); - free(sk->key.rsa.iq); - break; - case BR_KEYTYPE_EC: - free(sk->key.ec.x); - break; - default: - // Could be an uninitted key, no sub elements to free - break; - } - free(sk); - } - } - - void free_pem_object(pem_object *pos) - { - if (pos != nullptr) - { - for (size_t u = 0; pos[u].name; u++) - { - free_pem_object_contents(&pos[u]); - } - free(pos); - } - } - - private_key *read_private_key(const char *buff, size_t len) - { - private_key *sk = nullptr; - pem_object *pos = nullptr; - - if (looks_like_DER((const unsigned char *)buff, len)) - { - sk = decode_private_key((const unsigned char *)buff, len); - return sk; - } - - size_t num; - pos = decode_pem(buff, len, &num); - if (pos == nullptr) - { - return nullptr; // PEM decode error - } - for (size_t u = 0; pos[u].name; u++) - { - const char *name = pos[u].name; - if (!strcmp_P(name, PSTR("RSA PRIVATE KEY")) || !strcmp_P(name, PSTR("EC PRIVATE KEY")) || !strcmp_P(name, PSTR("PRIVATE KEY"))) - { - sk = decode_private_key(pos[u].data, pos[u].data_len); - free_pem_object(pos); - return sk; - } - } - // If we hit here, no match - free_pem_object(pos); - return nullptr; - } - - public_key *read_public_key(const char *buff, size_t len) - { - public_key *pk = nullptr; - pem_object *pos = nullptr; - - if (looks_like_DER((const unsigned char *)buff, len)) - { - pk = decode_public_key((const unsigned char *)buff, len); - return pk; - } - size_t num; - pos = decode_pem(buff, len, &num); - if (pos == nullptr) - { - return nullptr; // PEM decode error - } - for (size_t u = 0; pos[u].name; u++) - { - const char *name = pos[u].name; - if (!strcmp_P(name, PSTR("RSA PUBLIC KEY")) || !strcmp_P(name, PSTR("EC PUBLIC KEY")) || !strcmp_P(name, PSTR("PUBLIC KEY"))) - { - pk = decode_public_key(pos[u].data, pos[u].data_len); - free_pem_object(pos); - return pk; - } - } - - // We hit here == no key found - free_pem_object(pos); - return pk; - } - -}; // namespace ESP_Mail_brssl - -namespace ESP_Mail -{ - - // ----- Public Key ----- - - PublicKey::PublicKey() - { - _key = nullptr; - } - - PublicKey::PublicKey(const char *pemKey) - { - _key = nullptr; - parse(pemKey); - } - - PublicKey::PublicKey(const uint8_t *derKey, size_t derLen) - { - _key = nullptr; - parse(derKey, derLen); - } - - PublicKey::~PublicKey() - { - if (_key) - { - ESP_Mail_brssl::free_public_key(_key); - } - } - - bool PublicKey::parse(const char *pemKey) - { - return parse((const uint8_t *)pemKey, strlen_P(pemKey)); - } - - bool PublicKey::parse(const uint8_t *derKey, size_t derLen) - { - if (_key) - { - ESP_Mail_brssl::free_public_key(_key); - _key = nullptr; - } - _key = ESP_Mail_brssl::read_public_key((const char *)derKey, derLen); - return _key ? true : false; - } - - bool PublicKey::isRSA() const - { - if (!_key || _key->key_type != BR_KEYTYPE_RSA) - { - return false; - } - return true; - } - - bool PublicKey::isEC() const - { - if (!_key || _key->key_type != BR_KEYTYPE_EC) - { - return false; - } - return true; - } - - const br_rsa_public_key *PublicKey::getRSA() const - { - if (!_key || _key->key_type != BR_KEYTYPE_RSA) - { - return nullptr; - } - return &_key->key.rsa; - } - - const br_ec_public_key *PublicKey::getEC() const - { - if (!_key || _key->key_type != BR_KEYTYPE_EC) - { - return nullptr; - } - return &_key->key.ec; - } - - // ----- Private Key ----- - - PrivateKey::PrivateKey() - { - _key = nullptr; - } - - PrivateKey::PrivateKey(const char *pemKey) - { - _key = nullptr; - parse(pemKey); - } - - PrivateKey::PrivateKey(const uint8_t *derKey, size_t derLen) - { - _key = nullptr; - parse(derKey, derLen); - } - - PrivateKey::~PrivateKey() - { - if (_key) - { - ESP_Mail_brssl::free_private_key(_key); - } - } - - bool PrivateKey::parse(const char *pemKey) - { - return parse((const uint8_t *)pemKey, strlen_P(pemKey)); - } - - bool PrivateKey::parse(const uint8_t *derKey, size_t derLen) - { - if (_key) - { - ESP_Mail_brssl::free_private_key(_key); - _key = nullptr; - } - _key = ESP_Mail_brssl::read_private_key((const char *)derKey, derLen); - return _key ? true : false; - } - - bool PrivateKey::isRSA() const - { - if (!_key || _key->key_type != BR_KEYTYPE_RSA) - { - return false; - } - return true; - } - - bool PrivateKey::isEC() const - { - if (!_key || _key->key_type != BR_KEYTYPE_EC) - { - return false; - } - return true; - } - - const br_rsa_private_key *PrivateKey::getRSA() const - { - if (!_key || _key->key_type != BR_KEYTYPE_RSA) - { - return nullptr; - } - return &_key->key.rsa; - } - - const br_ec_private_key *PrivateKey::getEC() const - { - if (!_key || _key->key_type != BR_KEYTYPE_EC) - { - return nullptr; - } - return &_key->key.ec; - } - - // ----- Certificate Lists ----- - - ESP_Mail_X509List::ESP_Mail_X509List() - { - _count = 0; - _cert = nullptr; - _ta = nullptr; - } - - ESP_Mail_X509List::ESP_Mail_X509List(const char *pemCert) - { - _count = 0; - _cert = nullptr; - _ta = nullptr; - append(pemCert); - } - - ESP_Mail_X509List::ESP_Mail_X509List(const uint8_t *derCert, size_t derLen) - { - _count = 0; - _cert = nullptr; - _ta = nullptr; - append(derCert, derLen); - } - - ESP_Mail_X509List::~ESP_Mail_X509List() - { - ESP_Mail_brssl::free_certificates(_cert, _count); // also frees cert - for (size_t i = 0; i < _count; i++) - { - ESP_Mail_brssl::free_ta_contents(&_ta[i]); - } - free(_ta); - } - - bool ESP_Mail_X509List::append(const char *pemCert) - { - return append((const uint8_t *)pemCert, strlen_P(pemCert)); - } - - bool ESP_Mail_X509List::append(const uint8_t *derCert, size_t derLen) - { - size_t numCerts; - br_x509_certificate *newCerts = ESP_Mail_brssl::read_certificates((const char *)derCert, derLen, &numCerts); - if (!newCerts) - { - return false; - } - - // Add in the certificates - br_x509_certificate *saveCert = _cert; - _cert = (br_x509_certificate *)realloc(_cert, (numCerts + _count) * sizeof(br_x509_certificate)); - if (!_cert) - { - free(newCerts); - _cert = saveCert; - return false; - } - memcpy(&_cert[_count], newCerts, numCerts * sizeof(br_x509_certificate)); - free(newCerts); - - // Build TAs for each certificate - br_x509_trust_anchor *saveTa = _ta; - _ta = (br_x509_trust_anchor *)realloc(_ta, (numCerts + _count) * sizeof(br_x509_trust_anchor)); - if (!_ta) - { - _ta = saveTa; - return false; - } - for (size_t i = 0; i < numCerts; i++) - { - br_x509_trust_anchor *newTa = ESP_Mail_brssl::certificate_to_trust_anchor(&_cert[_count + i]); - if (newTa) - { - _ta[_count + i] = *newTa; - free(newTa); - } - else - { - return false; // OOM - } - } - _count += numCerts; - - return true; - } - - // SHA256 hash for updater - void HashSHA256::begin() - { - br_sha256_init(&_cc); - memset(_sha256, 0, sizeof(_sha256)); - } - - void HashSHA256::add(const void *data, uint32_t len) - { - br_sha256_update(&_cc, data, len); - } - - void HashSHA256::end() - { - br_sha256_out(&_cc, _sha256); - } - - int HashSHA256::len() - { - return sizeof(_sha256); - } - - const void *HashSHA256::hash() - { - return (const void *)_sha256; - } - - const unsigned char *HashSHA256::oid() - { - return BR_HASH_OID_SHA256; - } - - // SHA256 verifier - uint32_t SigningVerifier::length() - { - if (!_pubKey) - { - return 0; - } - else if (_pubKey->isRSA()) - { - return _pubKey->getRSA()->nlen; - } - else if (_pubKey->isEC()) - { - return _pubKey->getEC()->qlen; - } - else - { - return 0; - } - } - /* - -// We need to use the 2nd stack to do a verification, so do the thunk -// directly inside the class function for ease of use. -extern "C" bool SigningVerifier_verify(PublicKey *_pubKey, UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) { - if (_pubKey->isRSA()) { - bool ret; - unsigned char vrf[hash->len()]; - br_rsa_pkcs1_vrfy vrfy = br_rsa_pkcs1_vrfy_get_default(); - ret = vrfy((const unsigned char *)signature, signatureLen, hash->oid(), sizeof(vrf), _pubKey->getRSA(), vrf); - if (!ret || memcmp(vrf, hash->hash(), sizeof(vrf)) ) { - return false; - } else { - return true; - } - } else { - br_ecdsa_vrfy vrfy = br_ecdsa_vrfy_raw_get_default(); - // The EC verifier actually does the compare, unlike the RSA one - return vrfy(br_ec_get_default(), hash->hash(), hash->len(), _pubKey->getEC(), (const unsigned char *)signature, signatureLen); - } -}; - - - -#if !CORE_MOCK -make_stack_thunk(SigningVerifier_verify); -extern "C" bool thunk_SigningVerifier_verify(PublicKey *_pubKey, UpdaterHashClass *hash, const void *signature, uint32_t signatureLen); -#endif - -bool SigningVerifier::verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) { - if (!_pubKey || !hash || !signature || signatureLen != length()) return false; -#if !CORE_MOCK - return thunk_SigningVerifier_verify(_pubKey, hash, signature, signatureLen); -#else - return SigningVerifier_verify(_pubKey, hash, signature, signatureLen); -#endif -} - - - -#if !CORE_MOCK - -// Second stack thunked helpers -make_stack_thunk(br_ssl_engine_recvapp_ack); -make_stack_thunk(br_ssl_engine_recvapp_buf); -make_stack_thunk(br_ssl_engine_recvrec_ack); -make_stack_thunk(br_ssl_engine_recvrec_buf); -make_stack_thunk(br_ssl_engine_sendapp_ack); -make_stack_thunk(br_ssl_engine_sendapp_buf); -make_stack_thunk(br_ssl_engine_sendrec_ack); -make_stack_thunk(br_ssl_engine_sendrec_buf); - -#endif -*/ - -}; // namespace ESP_Mail - -#if ARDUINO_SIGNING -namespace -{ - static ESP_Mail::PublicKey signingPubKey(signing_pubkey); - static ESP_Mail::HashSHA256 __signingHash; - static ESP_Mail::SigningVerifier __signingVerifier(&signingPubKey); -}; // namespace - -namespace esp8266 -{ - UpdaterHashClass &updaterSigningHash = __signingHash; - UpdaterVerifyClass &updaterSigningVerifier = __signingVerifier; -}; // namespace esp8266 -#endif - -#endif /* ESP8266 */ - -#endif /* ESP_Mail_BearSSLHelpers_CPP */ \ No newline at end of file +/* + WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries + - Mostly compatible with Arduino WiFi shield library and standard + WiFiClient/ServerSecure (except for certificate handling). + + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef BSSL_HELPER_CPP +#define BSSL_HELPER_CPP + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wvla" + +#include +#include "../ESP_SSLClient_FS.h" +#include "../ESP_SSLClient_Const.h" +#if defined(USE_LIB_SSL_ENGINE) + +#include "BSSL_Helper.h" +#include +#include +#include "../bssl/bearssl.h" +#include +#include +#if defined __has_include +#if __has_include() +#include +#endif +#endif + +namespace key_bssl +{ + // Code here is pulled from brssl sources, with the copyright and license + // shown below. I've rewritten things using C++ semantics and removed + // custom VEC_* calls (std::vector to the rescue) and adjusted things to + // allow for long-running operation (i.e. some memory issues when DERs + // passed into the decoders). Bugs are most likely my fault. + + // Original (c) message follows: + /* + Copyright (c) 2016 Thomas Pornin + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + */ + + class private_key + { + public: + int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */ + union + { + br_rsa_private_key rsa; + br_ec_private_key ec; + } key; + }; + + class public_key + { + public: + int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */ + union + { + br_rsa_public_key rsa; + br_ec_public_key ec; + } key; + }; + + class pem_object + { + public: + char *name; + unsigned char *data; + size_t data_len; + }; + + // Forward definitions + void free_ta_contents(br_x509_trust_anchor *ta); + void free_public_key(public_key *pk); + void free_private_key(private_key *sk); + bool looks_like_DER(const unsigned char *buf, size_t len); + pem_object *decode_pem(const void *src, size_t len, size_t *num); + void free_pem_object_contents(pem_object *po); + char *strdupImpl(const char *s); + + // Used as callback multiple places to append a string to a vector + static void byte_vector_append(void *ctx, const void *buff, size_t len) + { + std::vector *vec = static_cast *>(ctx); + vec->reserve(vec->size() + len); // Allocate extra space all at once + for (size_t i = 0; i < len; i++) + { + vec->push_back(((uint8_t *)buff)[i]); + } + } + + static bool certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta, const br_x509_certificate *xc) + { + std::unique_ptr dc(new br_x509_decoder_context_libmail); // auto-delete on exit + std::vector vdn; + br_x509_pkey *pk; + + // Clear everything in the Trust Anchor + memset(ta, 0, sizeof(*ta)); + + br_x509_decoder_init_libmail(dc.get(), byte_vector_append, (void *)&vdn); + br_x509_decoder_push_libmail(dc.get(), xc->data, xc->data_len); + pk = br_x509_decoder_get_pkey(dc.get()); + if (pk == nullptr) + { + return false; // No key present, something broken in the cert! + } + + // Copy the raw certificate data + ta->dn.data = (uint8_t *)malloc(vdn.size()); + if (!ta->dn.data) + { + return false; // OOM, but nothing yet allocated + } + memcpy(ta->dn.data, &vdn[0], vdn.size()); + ta->dn.len = vdn.size(); + ta->flags = 0; + if (br_x509_decoder_isCA(dc.get())) + { + ta->flags |= BR_X509_TA_CA; + } + + // Extract the public key + switch (pk->key_type) + { + case BR_KEYTYPE_RSA: + ta->pkey.key_type = BR_KEYTYPE_RSA; + ta->pkey.key.rsa.n = (uint8_t *)malloc(pk->key.rsa.nlen); + ta->pkey.key.rsa.e = (uint8_t *)malloc(pk->key.rsa.elen); + if ((ta->pkey.key.rsa.n == nullptr) || (ta->pkey.key.rsa.e == nullptr)) + { + free_ta_contents(ta); // OOM, so clean up + return false; + } + memcpy(ta->pkey.key.rsa.n, pk->key.rsa.n, pk->key.rsa.nlen); + ta->pkey.key.rsa.nlen = pk->key.rsa.nlen; + memcpy(ta->pkey.key.rsa.e, pk->key.rsa.e, pk->key.rsa.elen); + ta->pkey.key.rsa.elen = pk->key.rsa.elen; + return true; + case BR_KEYTYPE_EC: + ta->pkey.key_type = BR_KEYTYPE_EC; + ta->pkey.key.ec.curve = pk->key.ec.curve; + ta->pkey.key.ec.q = (uint8_t *)malloc(pk->key.ec.qlen); + if (ta->pkey.key.ec.q == nullptr) + { + free_ta_contents(ta); // OOM, so clean up + return false; + } + memcpy(ta->pkey.key.ec.q, pk->key.ec.q, pk->key.ec.qlen); + ta->pkey.key.ec.qlen = pk->key.ec.qlen; + return true; + default: + free_ta_contents(ta); // Unknown key type + return false; + } + + // Should never get here, if so there was an unknown error + return false; + } + + br_x509_trust_anchor *certificate_to_trust_anchor(const br_x509_certificate *xc) + { + br_x509_trust_anchor *ta = (br_x509_trust_anchor *)malloc(sizeof(br_x509_trust_anchor)); + if (!ta) + { + return nullptr; + } + + if (!certificate_to_trust_anchor_inner(ta, xc)) + { + free(ta); + return nullptr; + } + return ta; + } + + void free_ta_contents(br_x509_trust_anchor *ta) + { + if (ta) + { + free(ta->dn.data); + if (ta->pkey.key_type == BR_KEYTYPE_RSA) + { + free(ta->pkey.key.rsa.n); + free(ta->pkey.key.rsa.e); + } + else if (ta->pkey.key_type == BR_KEYTYPE_EC) + { + free(ta->pkey.key.ec.q); + } + memset(ta, 0, sizeof(*ta)); + } + } + + // Checks if a bitstream looks like a valid DER(binary) encoding. + // Basically tries to verify the length of all included segments + // matches the length of the input buffer. Does not actually + // validate any contents. + bool looks_like_DER(const unsigned char *buff, size_t len) + { + if (len < 2) + { + return false; + } + if (pgm_read_byte(buff++) != 0x30) + { + return false; + } + int fb = pgm_read_byte(buff++); + len -= 2; + if (fb < 0x80) + { + return (size_t)fb == len; + } + else if (fb == 0x80) + { + return false; + } + else + { + fb -= 0x80; + if (len < (size_t)fb + 2) + { + return false; + } + len -= (size_t)fb; + size_t dlen = 0; + while (fb-- > 0) + { + if (dlen > (len >> 8)) + { + return false; + } + dlen = (dlen << 8) + (size_t)pgm_read_byte(buff++); + } + return dlen == len; + } + } + + void free_pem_object_contents(pem_object *po) + { + if (po) + { + free(po->name); + free(po->data); + po->name = nullptr; + po->data = nullptr; + } + } + + char *strdupImpl(const char *s) + { + size_t slen = strlen(s); + char *result = (char *)malloc(slen + 1); + if (!result) + return NULL; + memcpy(result, s, slen + 1); + return result; + } + + // Converts a PEM (~=base64) source into a set of DER-encoded binary blobs. + // Each blob is named by the ---- BEGIN xxx ---- field, and multiple + // blobs may be returned. + pem_object *decode_pem(const void *src, size_t len, size_t *num) + { + std::vector pem_list; + std::unique_ptr pc(new br_pem_decoder_context); // auto-delete on exit + if (!pc.get()) + { + return nullptr; + } + pem_object po, *pos; + const unsigned char *buff; + std::vector bv; + + *num = 0; + br_pem_decoder_init(pc.get()); + buff = (const unsigned char *)src; + po.name = nullptr; + po.data = nullptr; + po.data_len = 0; + bool inobj = false; + bool extra_nl = true; + + while (len > 0) + { + size_t tlen; + + tlen = br_pem_decoder_push(pc.get(), buff, len); + buff += tlen; + len -= tlen; + switch (br_pem_decoder_event(pc.get())) + { + case BR_PEM_BEGIN_OBJ: + po.name = strdupImpl(br_pem_decoder_name(pc.get())); + br_pem_decoder_setdest(pc.get(), byte_vector_append, &bv); + inobj = true; + break; + + case BR_PEM_END_OBJ: + if (inobj) + { + // Stick data into the vector + po.data = (uint8_t *)malloc(bv.size()); + if (po.data) + { + memcpy(po.data, &bv[0], bv.size()); + po.data_len = bv.size(); + pem_list.push_back(po); + } + // Clean up state for next blob processing + bv.clear(); + po.name = nullptr; + po.data = nullptr; + po.data_len = 0; + inobj = false; + } + break; + + case BR_PEM_ERROR: + free(po.name); + for (size_t i = 0; i < pem_list.size(); i++) + { + free_pem_object_contents(&pem_list[i]); + } + return nullptr; + + default: + // Do nothing here, the parser is still working on things + break; + } + + if (len == 0 && extra_nl) + { + extra_nl = false; + buff = (const unsigned char *)"\n"; + len = 1; + } + } + + if (inobj) + { + free(po.name); + for (size_t i = 0; i < pem_list.size(); i++) + { + free_pem_object_contents(&pem_list[i]); + } + return nullptr; + } + + pos = (pem_object *)malloc((1 + pem_list.size()) * sizeof(*pos)); + if (pos) + { + *num = pem_list.size(); + pem_list.push_back(po); // Null-terminate list + memcpy(pos, &pem_list[0], pem_list.size() * sizeof(*pos)); + } + return pos; + } + + // Parse out DER or PEM encoded certificates from a binary buffer, + // potentially stored in PROGMEM. + br_x509_certificate *read_certificates(const char *buff, size_t len, size_t *num) + { + std::vector cert_list; + pem_object *pos; + size_t u, num_pos; + br_x509_certificate *xcs; + br_x509_certificate dummy; + + *num = 0; + + if (looks_like_DER((const unsigned char *)buff, len)) + { + xcs = (br_x509_certificate *)malloc(2 * sizeof(*xcs)); + if (!xcs) + { + return nullptr; + } + xcs[0].data = (uint8_t *)malloc(len); + if (!xcs[0].data) + { + free(xcs); + return nullptr; + } + memcpy_P(xcs[0].data, buff, len); + xcs[0].data_len = len; + xcs[1].data = nullptr; + xcs[1].data_len = 0; + *num = 1; + return xcs; + } + + pos = decode_pem(buff, len, &num_pos); + if (!pos) + { + return nullptr; + } + for (u = 0; u < num_pos; u++) + { + if (!strcmp_P(pos[u].name, PSTR("CERTIFICATE")) || !strcmp_P(pos[u].name, PSTR("X509 CERTIFICATE"))) + { + br_x509_certificate xc; + xc.data = pos[u].data; + xc.data_len = pos[u].data_len; + pos[u].data = nullptr; // Don't free the data we moved to the xc vector! + cert_list.push_back(xc); + } + } + for (u = 0; u < num_pos; u++) + { + free_pem_object_contents(&pos[u]); + } + free(pos); + + if (cert_list.size() == 0) + { + return nullptr; + } + *num = cert_list.size(); + dummy.data = nullptr; + dummy.data_len = 0; + cert_list.push_back(dummy); + xcs = (br_x509_certificate *)malloc(cert_list.size() * sizeof(*xcs)); + if (!xcs) + { + for (size_t i = 0; i < cert_list.size(); i++) + { + free(cert_list[i].data); // Clean up any captured data blobs + } + return nullptr; + } + memcpy(xcs, &cert_list[0], cert_list.size() * sizeof(br_x509_certificate)); + // XCS now has [].data pointing to the previously allocated blobs, so don't + // want to free anything in cert_list[]. + return xcs; + } + + void free_certificates(br_x509_certificate *certs, size_t num) + { + if (certs) + { + for (size_t u = 0; u < num; u++) + { + free(certs[u].data); + } + free(certs); + } + } + + static public_key *decode_public_key(const unsigned char *buff, size_t len) + { + std::unique_ptr dc(new br_pkey_decoder_context); // auto-delete on exit + if (!dc.get()) + { + return nullptr; + } + + public_key *pk = nullptr; + // https://github.com/yglukhov/bearssl_pkey_decoder + br_pkey_decoder_init(dc.get()); + br_pkey_decoder_push(dc.get(), buff, len); + int err = br_pkey_decoder_last_error(dc.get()); + if (err != 0) + { + return nullptr; + } + + const br_rsa_public_key *rk = nullptr; + const br_ec_public_key *ek = nullptr; + switch (br_pkey_decoder_key_type(dc.get())) + { + case BR_KEYTYPE_RSA: + rk = br_pkey_decoder_get_rsa(dc.get()); + pk = (public_key *)malloc(sizeof *pk); + if (!pk) + { + return nullptr; + } + pk->key_type = BR_KEYTYPE_RSA; + pk->key.rsa.n = (uint8_t *)malloc(rk->nlen); + pk->key.rsa.e = (uint8_t *)malloc(rk->elen); + if (!pk->key.rsa.n || !pk->key.rsa.e) + { + free(pk->key.rsa.n); + free(pk->key.rsa.e); + free(pk); + return nullptr; + } + memcpy(pk->key.rsa.n, rk->n, rk->nlen); + pk->key.rsa.nlen = rk->nlen; + memcpy(pk->key.rsa.e, rk->e, rk->elen); + pk->key.rsa.elen = rk->elen; + return pk; + + case BR_KEYTYPE_EC: + ek = br_pkey_decoder_get_ec(dc.get()); + pk = (public_key *)malloc(sizeof *pk); + if (!pk) + { + return nullptr; + } + pk->key_type = BR_KEYTYPE_EC; + pk->key.ec.q = (uint8_t *)malloc(ek->qlen); + if (!pk->key.ec.q) + { + free(pk); + return nullptr; + } + memcpy(pk->key.ec.q, ek->q, ek->qlen); + pk->key.ec.qlen = ek->qlen; + pk->key.ec.curve = ek->curve; + return pk; + + default: + return nullptr; + } + } + + void free_public_key(public_key *pk) + { + if (pk) + { + if (pk->key_type == BR_KEYTYPE_RSA) + { + free(pk->key.rsa.n); + free(pk->key.rsa.e); + } + else if (pk->key_type == BR_KEYTYPE_EC) + { + free(pk->key.ec.q); + } + free(pk); + } + } + + static private_key *decode_private_key(const unsigned char *buff, size_t len) + { + std::unique_ptr dc(new br_skey_decoder_context); // auto-delete on exit + if (!dc.get()) + { + return nullptr; + } + + private_key *sk = nullptr; + + br_skey_decoder_init(dc.get()); + br_skey_decoder_push(dc.get(), buff, len); + int err = br_skey_decoder_last_error(dc.get()); + if (err != 0) + { + return nullptr; + } + + const br_rsa_private_key *rk = nullptr; + const br_ec_private_key *ek = nullptr; + switch (br_skey_decoder_key_type(dc.get())) + { + case BR_KEYTYPE_RSA: + rk = br_skey_decoder_get_rsa(dc.get()); + sk = (private_key *)malloc(sizeof *sk); + if (!sk) + { + return nullptr; + } + sk->key_type = BR_KEYTYPE_RSA; + sk->key.rsa.p = (uint8_t *)malloc(rk->plen); + sk->key.rsa.q = (uint8_t *)malloc(rk->qlen); + sk->key.rsa.dp = (uint8_t *)malloc(rk->dplen); + sk->key.rsa.dq = (uint8_t *)malloc(rk->dqlen); + sk->key.rsa.iq = (uint8_t *)malloc(rk->iqlen); + if (!sk->key.rsa.p || !sk->key.rsa.q || !sk->key.rsa.dp || !sk->key.rsa.dq || !sk->key.rsa.iq) + { + free_private_key(sk); + return nullptr; + } + sk->key.rsa.n_bitlen = rk->n_bitlen; + memcpy(sk->key.rsa.p, rk->p, rk->plen); + sk->key.rsa.plen = rk->plen; + memcpy(sk->key.rsa.q, rk->q, rk->qlen); + sk->key.rsa.qlen = rk->qlen; + memcpy(sk->key.rsa.dp, rk->dp, rk->dplen); + sk->key.rsa.dplen = rk->dplen; + memcpy(sk->key.rsa.dq, rk->dq, rk->dqlen); + sk->key.rsa.dqlen = rk->dqlen; + memcpy(sk->key.rsa.iq, rk->iq, rk->iqlen); + sk->key.rsa.iqlen = rk->iqlen; + return sk; + + case BR_KEYTYPE_EC: + ek = br_skey_decoder_get_ec(dc.get()); + sk = (private_key *)malloc(sizeof *sk); + if (!sk) + { + return nullptr; + } + sk->key_type = BR_KEYTYPE_EC; + sk->key.ec.curve = ek->curve; + sk->key.ec.x = (uint8_t *)malloc(ek->xlen); + if (!sk->key.ec.x) + { + free_private_key(sk); + return nullptr; + } + memcpy(sk->key.ec.x, ek->x, ek->xlen); + sk->key.ec.xlen = ek->xlen; + return sk; + + default: + return nullptr; + } + } + + void free_private_key(private_key *sk) + { + if (sk) + { + switch (sk->key_type) + { + case BR_KEYTYPE_RSA: + free(sk->key.rsa.p); + free(sk->key.rsa.q); + free(sk->key.rsa.dp); + free(sk->key.rsa.dq); + free(sk->key.rsa.iq); + break; + case BR_KEYTYPE_EC: + free(sk->key.ec.x); + break; + default: + // Could be an uninitted key, no sub elements to free + break; + } + free(sk); + } + } + + void free_pem_object(pem_object *pos) + { + if (pos != nullptr) + { + for (size_t u = 0; pos[u].name; u++) + { + free_pem_object_contents(&pos[u]); + } + free(pos); + } + } + + private_key *read_private_key(const char *buff, size_t len) + { + private_key *sk = nullptr; + pem_object *pos = nullptr; + + if (looks_like_DER((const unsigned char *)buff, len)) + { + sk = decode_private_key((const unsigned char *)buff, len); + return sk; + } + + size_t num; + pos = decode_pem(buff, len, &num); + if (pos == nullptr) + { + return nullptr; // PEM decode error + } + for (size_t u = 0; pos[u].name; u++) + { + const char *name = pos[u].name; + if (!strcmp_P(name, PSTR("RSA PRIVATE KEY")) || !strcmp_P(name, PSTR("EC PRIVATE KEY")) || !strcmp_P(name, PSTR("PRIVATE KEY"))) + { + sk = decode_private_key(pos[u].data, pos[u].data_len); + free_pem_object(pos); + return sk; + } + } + // If we hit here, no match + free_pem_object(pos); + return nullptr; + } + + public_key *read_public_key(const char *buff, size_t len) + { + public_key *pk = nullptr; + pem_object *pos = nullptr; + + if (looks_like_DER((const unsigned char *)buff, len)) + { + pk = decode_public_key((const unsigned char *)buff, len); + return pk; + } + size_t num; + pos = decode_pem(buff, len, &num); + if (pos == nullptr) + { + return nullptr; // PEM decode error + } + for (size_t u = 0; pos[u].name; u++) + { + const char *name = pos[u].name; + if (!strcmp_P(name, PSTR("RSA PUBLIC KEY")) || !strcmp_P(name, PSTR("EC PUBLIC KEY")) || !strcmp_P(name, PSTR("PUBLIC KEY"))) + { + pk = decode_public_key(pos[u].data, pos[u].data_len); + free_pem_object(pos); + return pk; + } + } + + // We hit here == no key found + free_pem_object(pos); + return pk; + } + + static uint8_t *loadStream(Stream &stream, size_t size) + { + uint8_t *dest = (uint8_t *)malloc(size); + if (!dest) + { + return nullptr; // OOM error + } + if (size != stream.readBytes(dest, size)) + { + free(dest); // Error during read + return nullptr; + } + return dest; + } +}; + +namespace bssl +{ + + // ----- Public Key ----- + + PublicKey::PublicKey() + { + _key = nullptr; + } + + PublicKey::PublicKey(const char *pemKey) + { + _key = nullptr; + parse(pemKey); + } + + PublicKey::PublicKey(const uint8_t *derKey, size_t derLen) + { + _key = nullptr; + parse(derKey, derLen); + } + + PublicKey::PublicKey(Stream &stream, size_t size) + { + _key = nullptr; + auto buff = key_bssl::loadStream(stream, size); + if (buff) + { + parse(buff, size); + free(buff); + } + } + + PublicKey::~PublicKey() + { + if (_key) + { + key_bssl::free_public_key(_key); + } + } + + bool PublicKey::parse(const char *pemKey) + { + return parse((const uint8_t *)pemKey, strlen_P(pemKey)); + } + + bool PublicKey::parse(const uint8_t *derKey, size_t derLen) + { + if (_key) + { + key_bssl::free_public_key(_key); + _key = nullptr; + } + _key = key_bssl::read_public_key((const char *)derKey, derLen); + return _key ? true : false; + } + + bool PublicKey::isRSA() const + { + if (!_key || _key->key_type != BR_KEYTYPE_RSA) + { + return false; + } + return true; + } + + bool PublicKey::isEC() const + { + if (!_key || _key->key_type != BR_KEYTYPE_EC) + { + return false; + } + return true; + } + + const br_rsa_public_key *PublicKey::getRSA() const + { + if (!_key || _key->key_type != BR_KEYTYPE_RSA) + { + return nullptr; + } + return &_key->key.rsa; + } + + const br_ec_public_key *PublicKey::getEC() const + { + if (!_key || _key->key_type != BR_KEYTYPE_EC) + { + return nullptr; + } + return &_key->key.ec; + } + + // ----- Private Key ----- + + PrivateKey::PrivateKey() + { + _key = nullptr; + } + + PrivateKey::PrivateKey(const char *pemKey) + { + _key = nullptr; + parse(pemKey); + } + + PrivateKey::PrivateKey(const uint8_t *derKey, size_t derLen) + { + _key = nullptr; + parse(derKey, derLen); + } + + PrivateKey::PrivateKey(Stream &stream, size_t size) + { + _key = nullptr; + auto buff = key_bssl::loadStream(stream, size); + if (buff) + { + parse(buff, size); + free(buff); + } + } + + PrivateKey::~PrivateKey() + { + if (_key) + { + key_bssl::free_private_key(_key); + } + } + + bool PrivateKey::parse(const char *pemKey) + { + return parse((const uint8_t *)pemKey, strlen_P(pemKey)); + } + + bool PrivateKey::parse(const uint8_t *derKey, size_t derLen) + { + if (_key) + { + key_bssl::free_private_key(_key); + _key = nullptr; + } + _key = key_bssl::read_private_key((const char *)derKey, derLen); + return _key ? true : false; + } + + bool PrivateKey::isRSA() const + { + if (!_key || _key->key_type != BR_KEYTYPE_RSA) + { + return false; + } + return true; + } + + bool PrivateKey::isEC() const + { + if (!_key || _key->key_type != BR_KEYTYPE_EC) + { + return false; + } + return true; + } + + const br_rsa_private_key *PrivateKey::getRSA() const + { + if (!_key || _key->key_type != BR_KEYTYPE_RSA) + { + return nullptr; + } + return &_key->key.rsa; + } + + const br_ec_private_key *PrivateKey::getEC() const + { + if (!_key || _key->key_type != BR_KEYTYPE_EC) + { + return nullptr; + } + return &_key->key.ec; + } + + // ----- Certificate Lists ----- + + X509List::X509List() + { + _count = 0; + _cert = nullptr; + _ta = nullptr; + } + + X509List::X509List(const char *pemCert) + { + _count = 0; + _cert = nullptr; + _ta = nullptr; + append(pemCert); + } + + X509List::X509List(const uint8_t *derCert, size_t derLen) + { + _count = 0; + _cert = nullptr; + _ta = nullptr; + append(derCert, derLen); + } + + X509List::X509List(Stream &stream, size_t size) + { + _count = 0; + _cert = nullptr; + _ta = nullptr; + auto buff = key_bssl::loadStream(stream, size); + if (buff) + { + append(buff, size); + free(buff); + } + } + + X509List::~X509List() + { + key_bssl::free_certificates(_cert, _count); // also frees cert + for (size_t i = 0; i < _count; i++) + { + key_bssl::free_ta_contents(&_ta[i]); + } + free(_ta); + } + + bool X509List::append(const char *pemCert) + { + return append((const uint8_t *)pemCert, strlen_P(pemCert)); + } + + bool X509List::append(const uint8_t *derCert, size_t derLen) + { + size_t numCerts; + br_x509_certificate *newCerts = key_bssl::read_certificates((const char *)derCert, derLen, &numCerts); + if (!newCerts) + { + return false; + } + + // Add in the certificates + br_x509_certificate *saveCert = _cert; + _cert = (br_x509_certificate *)realloc(_cert, (numCerts + _count) * sizeof(br_x509_certificate)); + if (!_cert) + { + free(newCerts); + _cert = saveCert; + return false; + } + memcpy(&_cert[_count], newCerts, numCerts * sizeof(br_x509_certificate)); + free(newCerts); + + // Build TAs for each certificate + br_x509_trust_anchor *saveTa = _ta; + _ta = (br_x509_trust_anchor *)realloc(_ta, (numCerts + _count) * sizeof(br_x509_trust_anchor)); + if (!_ta) + { + _ta = saveTa; + return false; + } + for (size_t i = 0; i < numCerts; i++) + { + br_x509_trust_anchor *newTa = key_bssl::certificate_to_trust_anchor(&_cert[_count + i]); + if (newTa) + { + _ta[_count + i] = *newTa; + free(newTa); + } + else + { + return false; // OOM + } + } + _count += numCerts; + + return true; + } + +}; + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_Helper.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_Helper.h new file mode 100644 index 000000000..ca7ff0c1f --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_Helper.h @@ -0,0 +1,447 @@ + +/* + WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries + - Mostly compatible with Arduino WiFi shield library and standard + WiFiClient/ServerSecure (except for certificate handling). + + Copyright (c) 2018 Earle F. Philhower, III + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef BSSL_HELPER_H +#define BSSL_HELPER_H + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wvla" + +#include +#include "../ESP_SSLClient_FS.h" +#include "../ESP_SSLClient_Const.h" + +#if defined(USE_EMBED_SSL_ENGINE) + +#if defined(ESP8266) + +#ifdef __GNUC__ +#if __GNUC__ > 4 || __GNUC__ == 10 +#if defined(ARDUINO_ESP8266_GIT_VER) +#if ARDUINO_ESP8266_GIT_VER > 0 +#define ESP8266_CORE_SDK_V3_X_X +#endif +#endif +#endif +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#else + +#include +#include +#include +#include + +#endif + +#elif defined(USE_LIB_SSL_ENGINE) + +#include "../bssl/bearssl.h" + +#endif + +#if defined(USE_LIB_SSL_ENGINE) || defined(USE_EMBED_SSL_ENGINE) +// Cache for a TLS session with a server +// Use with BearSSL::WiFiClientSecure::setSession +// to accelerate the TLS handshake +class BearSSL_Session +{ + friend class BSSL_SSL_Client; + +public: + BearSSL_Session() + { + memset(&_session, 0, sizeof(_session)); + } + + br_ssl_session_parameters *getSession() + { + return &_session; + } + +private: + // The actual BearSSL session information + br_ssl_session_parameters _session; +}; + +static const uint16_t suites_P[] PROGMEM = { +#ifndef BEARSSL_SSL_BASIC + BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_GCM_SHA256, + BR_TLS_RSA_WITH_AES_256_GCM_SHA384, + BR_TLS_RSA_WITH_AES_128_CCM, + BR_TLS_RSA_WITH_AES_256_CCM, + BR_TLS_RSA_WITH_AES_128_CCM_8, + BR_TLS_RSA_WITH_AES_256_CCM_8, +#endif + BR_TLS_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_256_CBC_SHA256, + BR_TLS_RSA_WITH_AES_128_CBC_SHA, + BR_TLS_RSA_WITH_AES_256_CBC_SHA, +#ifndef BEARSSL_SSL_BASIC + BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA +#endif +}; + +// For apps which want to use less secure but faster ciphers, only +static const uint16_t faster_suites_P[] PROGMEM = { + BR_TLS_RSA_WITH_AES_256_CBC_SHA256, + BR_TLS_RSA_WITH_AES_128_CBC_SHA256, + BR_TLS_RSA_WITH_AES_256_CBC_SHA, + BR_TLS_RSA_WITH_AES_128_CBC_SHA}; + +// Internal opaque structures, not needed by user applications +namespace key_bssl +{ + class public_key; + class private_key; +}; + +namespace bssl +{ + + // Holds either a single public RSA or EC key for use when BearSSL wants a pubkey. + // Copies all associated data so no need to keep input PEM/DER keys. + // All inputs can be either in RAM or PROGMEM. + class PublicKey + { + public: + PublicKey(); + PublicKey(const char *pemKey); + PublicKey(const uint8_t *derKey, size_t derLen); + PublicKey(Stream &stream, size_t size); + PublicKey(Stream &stream) : PublicKey(stream, stream.available()){}; + ~PublicKey(); + + bool parse(const char *pemKey); + bool parse(const uint8_t *derKey, size_t derLen); + + // Accessors for internal use, not needed by apps + bool isRSA() const; + bool isEC() const; + const br_rsa_public_key *getRSA() const; + const br_ec_public_key *getEC() const; + + // Disable the copy constructor, we're pointer based + PublicKey(const PublicKey &that) = delete; + PublicKey &operator=(const PublicKey &that) = delete; + + private: + key_bssl::public_key *_key; + }; + + // Holds either a single private RSA or EC key for use when BearSSL wants a secretkey. + // Copies all associated data so no need to keep input PEM/DER keys. + // All inputs can be either in RAM or PROGMEM. + class PrivateKey + { + public: + PrivateKey(); + PrivateKey(const char *pemKey); + PrivateKey(const uint8_t *derKey, size_t derLen); + PrivateKey(Stream &stream, size_t size); + PrivateKey(Stream &stream) : PrivateKey(stream, stream.available()){}; + ~PrivateKey(); + + bool parse(const char *pemKey); + bool parse(const uint8_t *derKey, size_t derLen); + + // Accessors for internal use, not needed by apps + bool isRSA() const; + bool isEC() const; + const br_rsa_private_key *getRSA() const; + const br_ec_private_key *getEC() const; + + // Disable the copy constructor, we're pointer based + PrivateKey(const PrivateKey &that) = delete; + PrivateKey &operator=(const PrivateKey &that) = delete; + + private: + key_bssl::private_key *_key; + }; + + // Holds one or more X.509 certificates and associated trust anchors for + // use whenever BearSSL needs a cert or TA. May want to have multiple + // certs for things like a series of trusted CAs (but check the CertStore class + // for a more memory efficient way). + // Copies all associated data so no need to keep input PEM/DER certs. + // All inputs can be either in RAM or PROGMEM. + class X509List + { + public: + X509List(); + X509List(const char *pemCert); + X509List(const uint8_t *derCert, size_t derLen); + X509List(Stream &stream, size_t size); + X509List(Stream &stream) : X509List(stream, stream.available()){}; + ~X509List(); + + bool append(const char *pemCert); + bool append(const uint8_t *derCert, size_t derLen); + + // Accessors + size_t getCount() const + { + return _count; + } + const br_x509_certificate *getX509Certs() const + { + return _cert; + } + const br_x509_trust_anchor *getTrustAnchors() const + { + return _ta; + } + + // Disable the copy constructor, we're pointer based + X509List(const X509List &that) = delete; + X509List &operator=(const X509List &that) = delete; + + private: + size_t _count; + br_x509_certificate *_cert; + br_x509_trust_anchor *_ta; + }; + + extern "C" + { + + // Install hashes into the SSL engine + static void br_ssl_client_install_hashes(br_ssl_engine_context *eng) + { + br_ssl_engine_set_hash(eng, br_md5_ID, &br_md5_vtable); + br_ssl_engine_set_hash(eng, br_sha1_ID, &br_sha1_vtable); + br_ssl_engine_set_hash(eng, br_sha224_ID, &br_sha224_vtable); + br_ssl_engine_set_hash(eng, br_sha256_ID, &br_sha256_vtable); + br_ssl_engine_set_hash(eng, br_sha384_ID, &br_sha384_vtable); + br_ssl_engine_set_hash(eng, br_sha512_ID, &br_sha512_vtable); + } + + static void br_x509_minimal_install_hashes(br_x509_minimal_context *x509) + { + br_x509_minimal_set_hash(x509, br_md5_ID, &br_md5_vtable); + br_x509_minimal_set_hash(x509, br_sha1_ID, &br_sha1_vtable); + br_x509_minimal_set_hash(x509, br_sha224_ID, &br_sha224_vtable); + br_x509_minimal_set_hash(x509, br_sha256_ID, &br_sha256_vtable); + br_x509_minimal_set_hash(x509, br_sha384_ID, &br_sha384_vtable); + br_x509_minimal_set_hash(x509, br_sha512_ID, &br_sha512_vtable); + } + + // Default initializion for our SSL clients + static void br_ssl_client_base_init(br_ssl_client_context *cc, const uint16_t *cipher_list, int cipher_cnt) + { + uint16_t suites[cipher_cnt]; + memcpy_P(suites, cipher_list, cipher_cnt * sizeof(cipher_list[0])); + br_ssl_client_zero(cc); + br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION); // forbid SSL renegotiation, as we free the Private Key after handshake + br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); + br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0])); + br_ssl_client_set_default_rsapub(cc); + br_ssl_engine_set_default_rsavrfy(&cc->eng); +#ifndef BEARSSL_SSL_BASIC + br_ssl_engine_set_default_ecdsa(&cc->eng); +#endif + br_ssl_client_install_hashes(&cc->eng); + br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); + br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); + br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); + br_ssl_engine_set_default_aes_cbc(&cc->eng); +#ifndef BEARSSL_SSL_BASIC + br_ssl_engine_set_default_aes_gcm(&cc->eng); + br_ssl_engine_set_default_aes_ccm(&cc->eng); + br_ssl_engine_set_default_des_cbc(&cc->eng); + br_ssl_engine_set_default_chapol(&cc->eng); +#endif + } + + // BearSSL doesn't define a true insecure decoder, so we make one ourselves + // from the simple parser. It generates the issuer and subject hashes and + // the SHA1 fingerprint, only one (or none!) of which will be used to + // "verify" the certificate. + + // Private x509 decoder state + struct br_x509_insecure_context + { + const br_x509_class *vtable; + bool done_cert; + const uint8_t *match_fingerprint; + br_sha1_context sha1_cert; + bool allow_self_signed; + br_sha256_context sha256_subject; + br_sha256_context sha256_issuer; + br_x509_decoder_context_libmail ctx; + }; + + // Callback for the x509_minimal subject DN + static void insecure_subject_dn_append(void *ctx, const void *buf, size_t len) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + br_sha256_update(&xc->sha256_subject, buf, len); + } + + // Callback for the x509_minimal issuer DN + static void insecure_issuer_dn_append(void *ctx, const void *buf, size_t len) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + br_sha256_update(&xc->sha256_issuer, buf, len); + } + + // Callback for each certificate present in the chain (but only operates + // on the first one by design). + static void insecure_start_cert(const br_x509_class **ctx, uint32_t length) + { + (void)ctx; + (void)length; + } + + // Callback for each byte stream in the chain. Only process first cert. + static void insecure_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + // Don't process anything but the first certificate in the chain + if (!xc->done_cert) + { + br_sha1_update(&xc->sha1_cert, buf, len); + br_x509_decoder_push_libmail(&xc->ctx, (const void *)buf, len); + } + } + // Callback on the first byte of any certificate + static void insecure_start_chain(const br_x509_class **ctx, const char *server_name) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; +#if defined(USE_EMBED_SSL_ENGINE) + br_x509_decoder_init_libmail(&xc->ctx, insecure_subject_dn_append, xc, insecure_issuer_dn_append, xc); +#elif defined(ESP32) || defined(USE_LIB_SSL_ENGINE) + br_x509_decoder_init_libmail(&xc->ctx, insecure_subject_dn_append, xc); +#endif + xc->done_cert = false; + br_sha1_init(&xc->sha1_cert); + br_sha256_init(&xc->sha256_subject); + br_sha256_init(&xc->sha256_issuer); + (void)server_name; + } + + // Callback on individual cert end. + static void insecure_end_cert(const br_x509_class **ctx) + { + br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; + xc->done_cert = true; + } + + // Callback when complete chain has been parsed. + // Return 0 on validation success, !0 on validation error + static unsigned insecure_end_chain(const br_x509_class **ctx) + { + const br_x509_insecure_context *xc = (const br_x509_insecure_context *)ctx; + if (!xc->done_cert) + { + // BSSL_BSSL_SSL_Client_DEBUG_PRINTF("insecure_end_chain: No cert seen\n"); + return 1; // error + } + + // Handle SHA1 fingerprint matching + char res[20]; + br_sha1_out(&xc->sha1_cert, res); + if (xc->match_fingerprint && memcmp(res, xc->match_fingerprint, sizeof(res))) + { + + return BR_ERR_X509_NOT_TRUSTED; + } + + // Handle self-signer certificate acceptance + char res_issuer[32]; + char res_subject[32]; + br_sha256_out(&xc->sha256_issuer, res_issuer); + br_sha256_out(&xc->sha256_subject, res_subject); + if (xc->allow_self_signed && memcmp(res_subject, res_issuer, sizeof(res_issuer))) + { + // BSSL_BSSL_SSL_Client_DEBUG_PRINTF("insecure_end_chain: Didn't get self-signed cert\n"); + return BR_ERR_X509_NOT_TRUSTED; + } + + // Default (no validation at all) or no errors in prior checks = success. + return 0; + } + + // Return the public key from the validator (set by x509_minimal) + static const br_x509_pkey *insecure_get_pkey(const br_x509_class *const *ctx, unsigned *usages) + { + const br_x509_insecure_context *xc = (const br_x509_insecure_context *)ctx; + if (usages != nullptr) + { + *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN; // I said we were insecure! + } + return &xc->ctx.pkey; + } + } + +}; +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_SSL_Client.cpp b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_SSL_Client.cpp new file mode 100644 index 000000000..2b90a1859 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_SSL_Client.cpp @@ -0,0 +1,2203 @@ +/** + * BSSL_SSL_Client library v1.0.11 for Arduino devices. + * + * Created August 27, 2003 + * + * This work contains codes based on WiFiClientSecure from Earle F. Philhower and SSLClient from OSU OPEnS Lab. + * + * Copyright (c) 2018 Earle F. Philhower, III + * + * Copyright 2019 OSU OPEnS Lab + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef BSSL_SSL_CLIENT_CPP +#define BSSL_SSL_CLIENT_CPP + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wvla" + +#include +#include "../ESP_SSLClient_FS.h" +#include "../ESP_SSLClient_Const.h" +#if defined(USE_LIB_SSL_ENGINE) || defined(USE_EMBED_SSL_ENGINE) + +#include "BSSL_Helper.h" +#include "BSSL_SSL_Client.h" + +#if defined(ESP8266) && defined(MMU_EXTERNAL_HEAP) && defined(ESP_SSLCLIENT_USE_PSRAM) +#include +#include +#define ESP_SSLCLIENT_ESP8266_USE_EXTERNAL_HEAP +#endif + +#if defined(USE_EMBED_SSL_ENGINE) +#include +#include +#include +#include "StackThunk.h" +#include "lwip/opt.h" +#include "lwip/ip.h" +#include "lwip/tcp.h" +#include "lwip/inet.h" +#include "lwip/netif.h" + +#if 1 +#if !CORE_MOCK + +// The BearSSL thunks in use for now +#define br_ssl_engine_recvapp_ack thunk_br_ssl_engine_recvapp_ack +#define br_ssl_engine_recvapp_buf thunk_br_ssl_engine_recvapp_buf +#define br_ssl_engine_recvrec_ack thunk_br_ssl_engine_recvrec_ack +#define br_ssl_engine_recvrec_buf thunk_br_ssl_engine_recvrec_buf +#define br_ssl_engine_sendapp_ack thunk_br_ssl_engine_sendapp_ack +#define br_ssl_engine_sendapp_buf thunk_br_ssl_engine_sendapp_buf +#define br_ssl_engine_sendrec_ack thunk_br_ssl_engine_sendrec_ack +#define br_ssl_engine_sendrec_buf thunk_br_ssl_engine_sendrec_buf + +#endif +#endif + +#endif + +BSSL_SSL_Client::BSSL_SSL_Client(Client *client) +{ + setClient(client); + mClear(); + mClearAuthenticationSettings(); +#if defined(ESP_SSL_FS_SUPPORTED) + _certStore = nullptr; // Don't want to remove cert store on a clear, should be long lived +#endif + _sk = nullptr; +#if defined(USE_EMBED_SSL_ENGINE) + stack_thunk_add_ref(); +#endif +} + +BSSL_SSL_Client::~BSSL_SSL_Client() +{ + if (_basic_client) + { + if (_basic_client->connected()) + _basic_client->stop(); + _basic_client = nullptr; + } + freeImpl(&_cipher_list); + mFreeSSL(); +#if defined(USE_EMBED_SSL_ENGINE) + stack_thunk_del_ref(); +#endif +} + +void BSSL_SSL_Client::setClient(Client *client, bool ssl) +{ + _basic_client = client; + _isSSLEnabled = ssl; +} + +void BSSL_SSL_Client::setDebugLevel(int level) +{ + if (level < esp_ssl_debug_none || level > esp_ssl_debug_dump) + _debug_level = esp_ssl_debug_none; + else + _debug_level = level; +} + +int BSSL_SSL_Client::connect(IPAddress ip, uint16_t port) +{ + if (_isSSLEnabled && mIsSecurePort(port)) // SSL connect + return connectSSL(ip, port); + + if (!mConnectBasicClient(nullptr, ip, port)) + return 0; + + return 1; +} + +int BSSL_SSL_Client::connect(const char *host, uint16_t port) +{ + if (_isSSLEnabled && mIsSecurePort(port)) + return connectSSL(host, port); + + if (!mConnectBasicClient(host, IPAddress(), port)) + return 0; + + return 1; +} + +uint8_t BSSL_SSL_Client::connected() +{ + if (!mIsClientInitialized(false)) + return 0; + + if (!_secure) + return _basic_client->connected(); + + // check all of the error cases + const auto c_con = _basic_client->connected(); + const auto br_con = br_ssl_engine_current_state(_eng) != BR_SSL_CLOSED && _is_connected; + const auto wr_ok = getWriteError() == 0; + // if we're in an error state, close the connection and set a write error + if (br_con && !c_con) + { + // If we've got a write error, the client probably failed for some reason + if (_basic_client->getWriteError()) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + String s = PSTR("Socket was unexpectedly interrupted. m_client error: "); + s += _basic_client->getWriteError(); + esp_ssl_debug_print(s.c_str(), _debug_level, esp_ssl_debug_info, __func__); +#endif + setWriteError(esp_ssl_write_error); + } + // Else tell the user the endpoint closed the socket on us (ouch) + else + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + // esp_ssl_debug_print(PSTR("Socket was dropped unexpectedly (this can be an alternative to closing the connection)."), _debug_level, esp_ssl_debug_warn, func_name); +#endif + } + + // set the write error so the engine doesn't try to close the connection + _is_connected = false; + stop(); + } + else if (!wr_ok) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Not connected because write error is set."), _debug_level, esp_ssl_debug_error, __func__); + mPrintClientError(getWriteError(), esp_ssl_debug_error, __func__); +#endif + } + + return c_con && br_con; +} + +void BSSL_SSL_Client::validate(const char *host, uint16_t port) +{ + mConnectionValidate(host, IPAddress(), port); +} + +void BSSL_SSL_Client::validate(IPAddress ip, uint16_t port) +{ + mConnectionValidate(nullptr, ip, port); +} + +int BSSL_SSL_Client::available() +{ + if (!mIsClientInitialized(false)) + return 0; + + if (!_secure) + return _basic_client->available(); + + // connection check + if (!mSoftConnected(__func__)) + return 0; + + // run the SSL engine until we are waiting for either user input or a server response + unsigned state = mUpdateEngine(); + if (state == 0) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("SSL engine failed to update."), _debug_level, esp_ssl_debug_error, __func__); +#endif + } + else if (state & BR_SSL_RECVAPP) + { + // return how many received bytes we have + _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len); + return (int)(_recvapp_len); + } + else if (state == BR_SSL_CLOSED) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("SSL Engine closed after update."), _debug_level, esp_ssl_debug_info, __func__); +#endif + } + // flush the buffer if it's stuck in the SENDAPP state + else if (state & BR_SSL_SENDAPP) + br_ssl_engine_flush(_eng, 0); + // other state, or client is closed + return 0; +} + +int BSSL_SSL_Client::read() +{ + uint8_t read_val; + return read(&read_val, 1) > 0 ? read_val : -1; +}; + +int BSSL_SSL_Client::read(uint8_t *buf, size_t size) +{ + if (!mIsClientInitialized(false)) + return 0; + + if (!_secure) + return _basic_client->read(buf, size); + + // check that the engine is ready to read + if (available() <= 0 || !size) + return -1; + // read the buffer, send the ack, and return the bytes read + _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len); + const size_t read_amount = size > _recvapp_len ? _recvapp_len : size; + if (buf) + memcpy(buf, _recvapp_buf, read_amount); + // tell engine we read that many bytes + br_ssl_engine_recvapp_ack(_eng, read_amount); + // tell the user we read that many bytes + return read_amount; +} + +size_t BSSL_SSL_Client::write(const uint8_t *buf, size_t size) +{ + if (!mIsClientInitialized(false)) + return 0; + + if (!_secure) + return _basic_client->write(buf, size); + + const char *func_name = __func__; +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + // super debug + if (_debug_level >= esp_ssl_debug_dump) + ESP_SSLCLIENT_DEBUG_PORT.write(buf, size); +#endif + // check if the socket is still open and such + if (!mSoftConnected(func_name) || !buf || !size) + return 0; + // wait until bearssl is ready to send + if (mRunUntil(BR_SSL_SENDAPP) < 0) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Failed while waiting for the engine to enter BR_SSL_SENDAPP."), _debug_level, esp_ssl_debug_error, func_name); +#endif + return 0; + } + // add to the bearssl io buffer, simply appending whatever we want to write + size_t alen; + unsigned char *br_buf = br_ssl_engine_sendapp_buf(_eng, &alen); + size_t cur_idx = 0; + if (alen == 0) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("BearSSL returned zero length buffer for sending, did an internal error occur?"), _debug_level, esp_ssl_debug_error, func_name); +#endif + return 0; + } + // while there are still elements to write + while (cur_idx < size) + { + // if we're about to fill the buffer, we need to send the data and then wait + // for another oppurtinity to send + // so we only send the smallest of the buffer size or our data size - how much we've already sent + const size_t cpamount = size - cur_idx >= alen - _write_idx ? alen - _write_idx : size - cur_idx; + memcpy(br_buf + _write_idx, buf + cur_idx, cpamount); + // increment write idx + _write_idx += cpamount; + // increment the buffer pointer + cur_idx += cpamount; + // if we filled the buffer, reset _write_idx, and mark the data for sending + if (_write_idx == alen) + { + // indicate to bearssl that we are done writing + br_ssl_engine_sendapp_ack(_eng, _write_idx); + // reset the write index + _write_idx = 0; + // write to the socket immediatly + if (mRunUntil(BR_SSL_SENDAPP) < 0) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Failed while waiting for the engine to enter BR_SSL_SENDAPP."), _debug_level, esp_ssl_debug_error, func_name); +#endif + return 0; + } + // reset the buffer pointer + br_buf = br_ssl_engine_sendapp_buf(_eng, &alen); + } + } + // works oky + return size; +} + +size_t BSSL_SSL_Client::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t BSSL_SSL_Client::write_P(PGM_P buf, size_t size) +{ + char dest[size]; + memcpy_P((void *)dest, buf, size); + return write((const uint8_t *)dest, size); +} + +size_t BSSL_SSL_Client::write(Stream &stream) +{ + if (!mIsClientInitialized(false)) + return 0; + + if (!connected()) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Connect not completed yet."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return 0; + } + + size_t dl = stream.available(); + uint8_t buf[dl]; + stream.readBytes(buf, dl); + return write(buf, dl); +} + +int BSSL_SSL_Client::peek() +{ + + if (!_sc || !available()) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Not connected, none left available."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return -1; + } + + if (!_secure) + return _basic_client->peek(); + + _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len); + if (_recvapp_buf && _recvapp_len) + return _recvapp_buf[0]; + +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("No data left."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return -1; +} + +size_t BSSL_SSL_Client::peekBytes(uint8_t *buffer, size_t length) +{ + if (!mIsClientInitialized(false) || !_secure) + return 0; + + size_t to_copy = 0; + if (!_sc) + return 0; + + unsigned long _startMillis = millis(); + while ((available() < (int)length) && ((millis() - _startMillis) < 5000)) + { + yield(); + } + + to_copy = _recvapp_len < length ? _recvapp_len : length; + memcpy(buffer, _recvapp_buf, to_copy); + return to_copy; +} + +// Don't validate the chain, just accept whatever is given. VERY INSECURE! +void BSSL_SSL_Client::setInsecure() +{ + mClearAuthenticationSettings(); + _use_insecure = true; +} + +void BSSL_SSL_Client::enableSSL(bool enable) +{ + _isSSLEnabled = enable; +} + +int BSSL_SSL_Client::connectSSL(IPAddress ip, uint16_t port) +{ + + if (!mIsClientInitialized(true)) + return 0; + + if (!_basic_client->connected() && !mConnectBasicClient(nullptr, ip, port)) + return 0; + + _ip = ip; + _port = port; + + return mConnectSSL(nullptr); +} + +int BSSL_SSL_Client::connectSSL(const char *host, uint16_t port) +{ + + if (!mIsClientInitialized(true)) + return 0; + + if (!_basic_client->connected() && !mConnectBasicClient(host, IPAddress(), port)) + return 0; + + _host = host; + _port = port; + + return mConnectSSL(host); +} + +void BSSL_SSL_Client::stop() +{ + if (!_secure) + return; + + // Only if we've already connected, store session params and clear the connection options + if (_session) + br_ssl_engine_get_session_parameters(_eng, _session->getSession()); + + // tell the SSL connection to gracefully close + // Disabled to prevent close_notify from hanging BSSL_SSL_Client + // br_ssl_engine_close(_eng); + // if the engine isn't closed, and the socket is still open + auto state = br_ssl_engine_current_state(_eng); + if (state != BR_SSL_CLOSED && state != 0 && connected()) + { + // Discard any incoming application data. + _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len); + if (_recvapp_buf != nullptr) + br_ssl_engine_recvapp_ack(_eng, _recvapp_len); + // run SSL to finish any existing transactions + flush(); + } + + // close the socket + if (_basic_client) + { + _basic_client->flush(); + _basic_client->stop(); + } + + mFreeSSL(); +} + +void BSSL_SSL_Client::setTimeout(unsigned int timeoutMs) { _timeout = timeoutMs; } + +void BSSL_SSL_Client::setHandshakeTimeout(unsigned int timeoutMs) { _handshake_timeout = timeoutMs; } + +void BSSL_SSL_Client::flush() +{ + if (!_secure && _basic_client) + { + _basic_client->flush(); + return; + } + + if (_write_idx > 0) + { + if (mRunUntil(BR_SSL_RECVAPP) < 0) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Could not flush write buffer!"), _debug_level, esp_ssl_debug_error, __func__); + int error = br_ssl_engine_last_error(_eng); + if (error != BR_ERR_OK) + mPrintSSLError(error, esp_ssl_debug_error, __func__); + if (getWriteError()) + mPrintClientError(getWriteError(), esp_ssl_debug_error, __func__); +#endif + } + } +} + +void BSSL_SSL_Client::setBufferSizes(int recv, int xmit) +{ + // Following constants taken from bearssl/src/ssl/ssl_engine.c (not exported unfortunately) + const int MAX_OUT_OVERHEAD = 85; + const int MAX_IN_OVERHEAD = 325; + + // The data buffers must be between 512B and 16KB + recv = std::max(512, std::min(16384, recv)); + xmit = std::max(512, std::min(16384, xmit)); + + // Add in overhead for SSL protocol + recv += MAX_IN_OVERHEAD; + xmit += MAX_OUT_OVERHEAD; + _iobuf_in_size = recv; + _iobuf_out_size = xmit; +} + +int BSSL_SSL_Client::availableForWrite() +{ + if (!mIsClientInitialized(false) || !_secure) + return 0; + + // code taken from ::write() + if (!connected() || !_handshake_done) + { + return 0; + } + // Get BearSSL to a state where we can send + if (mRunUntil(BR_SSL_SENDAPP) < 0) + { + return 0; + } + if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) + { + size_t sendapp_len; + (void)br_ssl_engine_sendapp_buf(_eng, &sendapp_len); + // We want to call br_ssl_engine_sendapp_ack(0) but 0 is forbidden (bssl doc). + // After checking br_ssl_engine_sendapp_buf() src code, + // it seems that it is OK to not call ack when the buffer is left untouched. + // forbidden: br_ssl_engine_sendapp_ack(_eng, 0); + return (int)sendapp_len; + } + return 0; +} + +void BSSL_SSL_Client::setSession(BearSSL_Session *session) { _session = session; }; + +// Assume a given public key, don't validate or use cert info at all +void BSSL_SSL_Client::setKnownKey(const PublicKey *pk, unsigned usages) +{ + mClearAuthenticationSettings(); + _knownkey = pk; + _knownkey_usages = usages; +} + +// Only check SHA1 fingerprint of certificate +bool BSSL_SSL_Client::setFingerprint(const uint8_t fingerprint[20]) +{ + mClearAuthenticationSettings(); + _use_fingerprint = true; + memcpy_P(_fingerprint, fingerprint, 20); + return true; +} + +// Set a fingerprint by parsing an ASCII string +bool BSSL_SSL_Client::setFingerprint(const char *fpStr) +{ + int idx = 0; + uint8_t c, d; + uint8_t fp[20]; + + while (idx < 20) + { + c = pgm_read_byte(fpStr++); + if (!c) + { + break; // String ended, done processing + } + d = pgm_read_byte(fpStr++); + if (!d) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("FP too short"), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; // Only half of the last hex digit, error + } + c = htoi(c); + d = htoi(d); + if ((c > 15) || (d > 15)) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Invalid char"), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; // Error in one of the hex characters + } + fp[idx++] = (c << 4) | d; + + // Skip 0 or more spaces or colons + while (pgm_read_byte(fpStr) && (pgm_read_byte(fpStr) == ' ' || pgm_read_byte(fpStr) == ':')) + { + fpStr++; + } + } + if ((idx != 20) || pgm_read_byte(fpStr)) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Garbage at end of fp"), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; // Garbage at EOL or we didn't have enough hex digits + } + return setFingerprint(fp); +} + +// Accept any certificate that's self-signed +void BSSL_SSL_Client::allowSelfSignedCerts() +{ + mClearAuthenticationSettings(); + _use_self_signed = true; +} + +// Install certificates of trusted CAs or specific site +void BSSL_SSL_Client::setTrustAnchors(const X509List *ta) +{ + mClearAuthenticationSettings(); + _ta = ta; +} + +// In cases when NTP is not used, app must set a time manually to check cert validity +void BSSL_SSL_Client::setX509Time(time_t now) +{ + _now = now; +} + +void BSSL_SSL_Client::setClientRSACert(const X509List *chain, const PrivateKey *sk) +{ + if (_esp32_chain) + { + delete _esp32_chain; + _esp32_chain = nullptr; + } + if (_esp32_sk) + { + delete _esp32_sk; + _esp32_sk = nullptr; + } + _chain = chain; + _sk = sk; +} + +void BSSL_SSL_Client::setClientECCert(const X509List *chain, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) +{ + if (_esp32_chain) + { + delete _esp32_chain; + _esp32_chain = nullptr; + } + if (_esp32_sk) + { + delete _esp32_sk; + _esp32_sk = nullptr; + } + _chain = chain; + _sk = sk; + _allowed_usages = allowed_usages; + _cert_issuer_key_type = cert_issuer_key_type; +} + +// Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection) +int BSSL_SSL_Client::getMFLNStatus() +{ + return connected() && br_ssl_engine_get_mfln_negotiated(_eng); +} + +// Returns an error ID and possibly a string (if dest != null) of the last +// BearSSL reported error. +int BSSL_SSL_Client::getLastSSLError(char *dest, size_t len) +{ + int err = 0; + const char *t = ""; + const char *recv_fatal = ""; + const char *send_fatal = ""; + if (_sc) + err = br_ssl_engine_last_error(_eng); + + if (_oom_err) + err = -1000; + else + { + if (err & BR_ERR_RECV_FATAL_ALERT) + { +#if defined(ESP_SSLCLIENT_ENABLE_SSL_ERROR_STRING) + recv_fatal = PSTR("SSL received fatal alert - "); +#endif + err &= ~BR_ERR_RECV_FATAL_ALERT; + } + if (err & BR_ERR_SEND_FATAL_ALERT) + { +#if defined(ESP_SSLCLIENT_ENABLE_SSL_ERROR_STRING) + send_fatal = PSTR("SSL sent fatal alert - "); +#endif + err &= ~BR_ERR_SEND_FATAL_ALERT; + } + } +#if defined(ESP_SSLCLIENT_ENABLE_SSL_ERROR_STRING) + switch (err) + { + case -1000: + t = PSTR("Unable to allocate memory for SSL structures and buffers."); + break; + case BR_ERR_BAD_PARAM: + t = PSTR("Caller-provided parameter is incorrect."); + break; + case BR_ERR_BAD_STATE: + t = PSTR("Operation requested by the caller cannot be applied with the current context state (e.g. reading data while outgoing data is waiting to be sent)."); + break; + case BR_ERR_UNSUPPORTED_VERSION: + t = PSTR("Incoming protocol or record version is unsupported."); + break; + case BR_ERR_BAD_VERSION: + t = PSTR("Incoming record version does not match the expected version."); + break; + case BR_ERR_BAD_LENGTH: + t = PSTR("Incoming record length is invalid."); + break; + case BR_ERR_TOO_LARGE: + t = PSTR("Incoming record is too large to be processed, or buffer is too small for the handshake message to send."); + break; + case BR_ERR_BAD_MAC: + t = PSTR("Decryption found an invalid padding, or the record MAC is not correct."); + break; + case BR_ERR_NO_RANDOM: + t = PSTR("No initial entropy was provided, and none can be obtained from the OS."); + break; + case BR_ERR_UNKNOWN_TYPE: + t = PSTR("Incoming record type is unknown."); + break; + case BR_ERR_UNEXPECTED: + t = PSTR("Incoming record or message has wrong type with regards to the current engine state."); + break; + case BR_ERR_BAD_CCS: + t = PSTR("ChangeCipherSpec message from the peer has invalid contents."); + break; + case BR_ERR_BAD_ALERT: + t = PSTR("Alert message from the peer has invalid contents (odd length)."); + break; + case BR_ERR_BAD_HANDSHAKE: + t = PSTR("Incoming handshake message decoding failed."); + break; + case BR_ERR_OVERSIZED_ID: + t = PSTR("ServerHello contains a session ID which is larger than 32 bytes."); + break; + case BR_ERR_BAD_CIPHER_SUITE: + t = PSTR("Server wants to use a cipher suite that we did not claim to support. This is also reported if we tried to advertise a cipher suite that we do not support."); + break; + case BR_ERR_BAD_COMPRESSION: + t = PSTR("Server wants to use a compression that we did not claim to support."); + break; + case BR_ERR_BAD_FRAGLEN: + t = PSTR("Server's max fragment length does not match client's."); + break; + case BR_ERR_BAD_SECRENEG: + t = PSTR("Secure renegotiation failed."); + break; + case BR_ERR_EXTRA_EXTENSION: + t = PSTR("Server sent an extension type that we did not announce, or used the same extension type several times in a single ServerHello."); + break; + case BR_ERR_BAD_SNI: + t = PSTR("Invalid Server Name Indication contents (when used by the server, this extension shall be empty)."); + break; + case BR_ERR_BAD_HELLO_DONE: + t = PSTR("Invalid ServerHelloDone from the server (length is not 0)."); + break; + case BR_ERR_LIMIT_EXCEEDED: + t = PSTR("Internal limit exceeded (e.g. server's public key is too large)."); + break; + case BR_ERR_BAD_FINISHED: + t = PSTR("Finished message from peer does not match the expected value."); + break; + case BR_ERR_RESUME_MISMATCH: + t = PSTR("Session resumption attempt with distinct version or cipher suite."); + break; + case BR_ERR_INVALID_ALGORITHM: + t = PSTR("Unsupported or invalid algorithm (ECDHE curve, signature algorithm, hash function)."); + break; + case BR_ERR_BAD_SIGNATURE: + t = PSTR("Invalid signature in ServerKeyExchange or CertificateVerify message."); + break; + case BR_ERR_WRONG_KEY_USAGE: + t = PSTR("Peer's public key does not have the proper type or is not allowed for the requested operation."); + break; + case BR_ERR_NO_CLIENT_AUTH: + t = PSTR("Client did not send a certificate upon request, or the client certificate could not be validated."); + break; + case BR_ERR_IO: + t = PSTR("I/O error or premature close on transport stream."); + break; + case BR_ERR_X509_INVALID_VALUE: + t = PSTR("Invalid value in an ASN.1 structure."); + break; + case BR_ERR_X509_TRUNCATED: + t = PSTR("Truncated certificate or other ASN.1 object."); + break; + case BR_ERR_X509_EMPTY_CHAIN: + t = PSTR("Empty certificate chain (no certificate at all)."); + break; + case BR_ERR_X509_INNER_TRUNC: + t = PSTR("Decoding error: inner element extends beyond outer element size."); + break; + case BR_ERR_X509_BAD_TAG_CLASS: + t = PSTR("Decoding error: unsupported tag class (application or private)."); + break; + case BR_ERR_X509_BAD_TAG_VALUE: + t = PSTR("Decoding error: unsupported tag value."); + break; + case BR_ERR_X509_INDEFINITE_LENGTH: + t = PSTR("Decoding error: indefinite length."); + break; + case BR_ERR_X509_EXTRA_ELEMENT: + t = PSTR("Decoding error: extraneous element."); + break; + case BR_ERR_X509_UNEXPECTED: + t = PSTR("Decoding error: unexpected element."); + break; + case BR_ERR_X509_NOT_CONSTRUCTED: + t = PSTR("Decoding error: expected constructed element, but is primitive."); + break; + case BR_ERR_X509_NOT_PRIMITIVE: + t = PSTR("Decoding error: expected primitive element, but is constructed."); + break; + case BR_ERR_X509_PARTIAL_BYTE: + t = PSTR("Decoding error: BIT STRING length is not multiple of 8."); + break; + case BR_ERR_X509_BAD_BOOLEAN: + t = PSTR("Decoding error: BOOLEAN value has invalid length."); + break; + case BR_ERR_X509_OVERFLOW: + t = PSTR("Decoding error: value is off-limits."); + break; + case BR_ERR_X509_BAD_DN: + t = PSTR("Invalid distinguished name."); + break; + case BR_ERR_X509_BAD_TIME: + t = PSTR("Invalid date/time representation."); + break; + case BR_ERR_X509_UNSUPPORTED: + t = PSTR("Certificate contains unsupported features that cannot be ignored."); + break; + case BR_ERR_X509_LIMIT_EXCEEDED: + t = PSTR("Key or signature size exceeds internal limits."); + break; + case BR_ERR_X509_WRONG_KEY_TYPE: + t = PSTR("Key type does not match that which was expected."); + break; + case BR_ERR_X509_BAD_SIGNATURE: + t = PSTR("Signature is invalid."); + break; + case BR_ERR_X509_TIME_UNKNOWN: + t = PSTR("Validation time is unknown."); + break; + case BR_ERR_X509_EXPIRED: + t = PSTR("Certificate is expired or not yet valid."); + break; + case BR_ERR_X509_DN_MISMATCH: + t = PSTR("Issuer/Subject DN mismatch in the chain."); + break; + case BR_ERR_X509_BAD_SERVER_NAME: + t = PSTR("Expected server name was not found in the chain."); + break; + case BR_ERR_X509_CRITICAL_EXTENSION: + t = PSTR("Unknown critical extension in certificate."); + break; + case BR_ERR_X509_NOT_CA: + t = PSTR("Not a CA, or path length constraint violation."); + break; + case BR_ERR_X509_FORBIDDEN_KEY_USAGE: + t = PSTR("Key Usage extension prohibits intended usage."); + break; + case BR_ERR_X509_WEAK_PUBLIC_KEY: + t = PSTR("Public key found in certificate is too small."); + break; + case BR_ERR_X509_NOT_TRUSTED: + t = PSTR("Chain could not be linked to a trust anchor."); + break; + default: + t = PSTR("Unknown error code."); + break; + } + + if (dest) + { + // snprintf is PSTR safe and guaranteed to 0-terminate + snprintf(dest, len, "%s%s%s", recv_fatal, send_fatal, t); + } + +#endif + + return err; +} + +// Attach a preconfigured certificate store +#if defined(ESP_SSL_FS_SUPPORTED) +void BSSL_SSL_Client::setCertStore(CertStoreBase *certStore) +{ + _certStore = certStore; +} +#endif + +// Set custom list of ciphers +bool BSSL_SSL_Client::setCiphers(const uint16_t *cipherAry, int cipherCount) +{ + _cipher_list = (uint16_t *)mallocImpl(cipherCount); + if (!_cipher_list) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("list empty"), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; + } + memcpy_P(_cipher_list, cipherAry, cipherCount * sizeof(uint16_t)); + _cipher_cnt = cipherCount; + return true; +} + +bool BSSL_SSL_Client::setCiphers(const std::vector &list) +{ + return setCiphers(&list[0], list.size()); +} + +bool BSSL_SSL_Client::setCiphersLessSecure() +{ + return setCiphers(faster_suites_P, sizeof(faster_suites_P) / sizeof(faster_suites_P[0])); +} + +bool BSSL_SSL_Client::setSSLVersion(uint32_t min, uint32_t max) +{ + if (((min != BR_TLS10) && (min != BR_TLS11) && (min != BR_TLS12)) || + ((max != BR_TLS10) && (max != BR_TLS11) && (max != BR_TLS12)) || + (max < min)) + { + return false; // Invalid options + } + _tls_min = min; + _tls_max = max; + return true; +} + +// Checks for support of Maximum Frame Length Negotiation at the given +// blocksize. Note that, per spec, only 512, 1024, 2048, and 4096 are +// supported. Many servers today do not support this negotiation. + +// TODO - Allow for fragmentation...but not very critical as the ServerHello +// we use comes to < 80 bytes which has no reason to ever be fragmented. +// TODO - Check the type of returned extensions and that the MFL is the exact +// same one we sent. Not critical as only horribly broken servers would +// return changed or add their own extensions. +bool BSSL_SSL_Client::probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len) +{ + return mProbeMaxFragmentLength(nullptr, ip, port, len); +} + +bool BSSL_SSL_Client::probeMaxFragmentLength(const char *name, uint16_t port, uint16_t len) +{ + return mProbeMaxFragmentLength(name, IPAddress(), port, len); +} + +bool BSSL_SSL_Client::probeMaxFragmentLength(const String &host, uint16_t port, uint16_t len) +{ + return BSSL_SSL_Client::probeMaxFragmentLength(host.c_str(), port, len); +} + +size_t BSSL_SSL_Client::peekAvailable() +{ + return available(); +} + +// return a pointer to available data buffer (size = peekAvailable()) +// semantic forbids any kind of read() before calling peekConsume() +const char *BSSL_SSL_Client::peekBuffer() +{ + return (const char *)_recvapp_buf; +} + +// consume bytes after use (see peekBuffer) +void BSSL_SSL_Client::peekConsume(size_t consume) +{ + // according to BSSL_SSL_Client::read: + br_ssl_engine_recvapp_ack(_eng, consume); + _recvapp_buf = nullptr; + _recvapp_len = 0; +} + +void BSSL_SSL_Client::setCACert(const char *rootCA) +{ + if (_esp32_ta) + delete _esp32_ta; + _esp32_ta = new X509List(rootCA); +} + +void BSSL_SSL_Client::setCertificate(const char *client_ca) +{ + if (_esp32_chain) + delete _esp32_chain; + _esp32_chain = new X509List(client_ca); +} + +void BSSL_SSL_Client::setPrivateKey(const char *private_key) +{ + if (_esp32_sk) + delete _esp32_sk; + _esp32_sk = new PrivateKey(private_key); +} + +bool BSSL_SSL_Client::loadCACert(Stream &stream, size_t size) +{ + bool ret = false; + auto buff = (char *)mallocImpl(size); + if (size == stream.readBytes(buff, size)) + { + setCACert(buff); + ret = true; + } + freeImpl(&buff); + return ret; +} + +bool BSSL_SSL_Client::loadCertificate(Stream &stream, size_t size) +{ + bool ret = false; + auto buff = (char *)mallocImpl(size); + if (size == stream.readBytes(buff, size)) + { + setCertificate(buff); + ret = true; + } + freeImpl(&buff); + return ret; +} + +bool BSSL_SSL_Client::loadPrivateKey(Stream &stream, size_t size) +{ + bool ret = false; + auto buff = (char *)mallocImpl(size); + if (size == stream.readBytes(buff, size)) + { + setPrivateKey(buff); + ret = true; + } + freeImpl(&buff); + return ret; +} + +int BSSL_SSL_Client::connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) +{ + setSecure(rootCABuff, cli_cert, cli_key); + return connect(ip, port); +} + +int BSSL_SSL_Client::connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) +{ + setSecure(rootCABuff, cli_cert, cli_key); + return connect(host, port); +} + +BSSL_SSL_Client &BSSL_SSL_Client::operator=(const BSSL_SSL_Client &other) +{ + stop(); + setClient(other._basic_client); + _use_insecure = other._use_insecure; + _timeout = other._timeout; + _handshake_timeout = other._handshake_timeout; + return *this; +} + +bool BSSL_SSL_Client::operator==(const BSSL_SSL_Client &rhs) +{ + return _basic_client == rhs._basic_client; +} + +unsigned int BSSL_SSL_Client::getTimeout() const { return _timeout; } + +void BSSL_SSL_Client::setSecure(const char *rootCABuff, const char *cli_cert, const char *cli_key) +{ + if (_esp32_ta) + { + delete _esp32_ta; + _esp32_ta = nullptr; + } + if (_esp32_chain) + { + delete _esp32_chain; + _esp32_chain = nullptr; + } + if (_esp32_sk) + { + delete _esp32_sk; + _esp32_sk = nullptr; + } + if (rootCABuff) + { + setCertificate(rootCABuff); + } + if (cli_cert && cli_key) + { + setCertificate(cli_cert); + setPrivateKey(cli_key); + } +} + +////////////////////////////////////////////////////// +// Private access +////////////////////////////////////////////////////// + +bool BSSL_SSL_Client::mProbeMaxFragmentLength(Client *probe, uint16_t len) +{ + + // Hardcoded TLS 1.2 packets used throughout + static const uint8_t clientHelloHead_P[] PROGMEM = { + 0x16, 0x03, 0x03, 0x00, 0, // TLS header, change last 2 bytes to len + 0x01, 0x00, 0x00, 0, // Last 3 bytes == length + 0x03, 0x03, // Proto version TLS 1.2 + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Random (gmtime + rand[28]) + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x00, // Session ID + }; + // Followed by our cipher-suite, generated on-the-fly + // 0x00, 0x02, // cipher suite len + // 0xc0, 0x13, // BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + static const uint8_t clientHelloTail_P[] PROGMEM = { + 0x01, 0x00, // No compression + 0x00, 26 + 14 + 6 + 5, // Extension length + 0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x04, 0x03, 0x03, 0x03, 0x05, 0x03, + 0x06, 0x03, 0x02, 0x03, 0x04, 0x01, 0x03, 0x01, 0x05, 0x01, 0x06, + 0x01, 0x02, 0x01, // Supported signature algorithms + 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, + 0x00, 0x1d, // Supported groups + 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, // Supported EC formats + 0x00, 0x01, // Max Frag Len + 0x00, 0x01, // len of MaxFragLen + }; + // Followed by a 1-byte MFLN size requesst + // 0x04 // 2^12 = 4K + uint8_t mfl; + + switch (len) + { + case 512: + mfl = 1; + break; + case 1024: + mfl = 2; + break; + case 2048: + mfl = 3; + break; + case 4096: + mfl = 4; + break; + default: + return false; // Invalid size + } + int ttlLen = sizeof(clientHelloHead_P) + (2 + sizeof(suites_P)) + (sizeof(clientHelloTail_P) + 1); + uint8_t *clientHello = (uint8_t *)mallocImpl(ttlLen); + if (!clientHello) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("OOM error."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; + } + memcpy_P(clientHello, clientHelloHead_P, sizeof(clientHelloHead_P)); + clientHello[sizeof(clientHelloHead_P) + 0] = sizeof(suites_P) >> 8; // MSB byte len + clientHello[sizeof(clientHelloHead_P) + 1] = sizeof(suites_P) & 0xff; // LSB byte len + for (size_t i = 0; i < sizeof(suites_P) / sizeof(suites_P[0]); i++) + { + uint16_t flip = pgm_read_word(&suites_P[i]); + // Swap to network byte order + flip = ((flip >> 8) & 0xff) | ((flip & 0xff) << 8); + memcpy(clientHello + sizeof(clientHelloHead_P) + 2 + 2 * i, &flip, 2); + } + memcpy_P(clientHello + sizeof(clientHelloHead_P) + 2 + sizeof(suites_P), clientHelloTail_P, sizeof(clientHelloTail_P)); + clientHello[sizeof(clientHelloHead_P) + 2 + sizeof(suites_P) + sizeof(clientHelloTail_P)] = mfl; + + // Fix up TLS fragment length + clientHello[3] = (ttlLen - 5) >> 8; + clientHello[4] = (ttlLen - 5) & 0xff; + // Fix up ClientHello message length + clientHello[7] = (ttlLen - 5 - 4) >> 8; + clientHello[8] = (ttlLen - 5 - 4) & 0xff; + + int ret = probe->write(clientHello, ttlLen); + freeImpl(&clientHello); // We're done w/the hello message + if (!probe->connected() || (ret != ttlLen)) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Protocol error."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; + } + + bool supportsLen = false; + uint8_t fragResp[5]; + int fragLen; + uint8_t hand[4]; + int handLen; + uint8_t protoVer[2]; + uint8_t rand[32]; + uint8_t sessionLen; + uint8_t cipher[2]; + uint8_t comp; + uint8_t extBytes[2]; + uint16_t extLen; + + ret = probe->readBytes(fragResp, 5); + if (!probe->connected() || (ret != 5) || (fragResp[0] != 0x16) || (fragResp[1] != 0x03) || (fragResp[2] != 0x03)) + { + // Short read, not a HANDSHAKE or not TLS 1.2, so it's not supported + return send_abort(probe, supportsLen); + } + fragLen = (fragResp[3] << 8) | fragResp[4]; + if (fragLen < 4 + 2 + 32 + 1 + 2 + 1) + { + // Too short to have an extension + return send_abort(probe, supportsLen); + } + + ret = probe->readBytes(hand, 4); + fragLen -= ret; + if ((ret != 4) || (hand[0] != 2)) + { + // Short read or not server_hello + return send_abort(probe, supportsLen); + } + handLen = (hand[1] << 16) | (hand[2] << 8) | hand[3]; + if (handLen != fragLen) + { + // Got some weird mismatch, this is invalid + return send_abort(probe, supportsLen); + } + + ret = probe->readBytes(protoVer, 2); + handLen -= ret; + if ((ret != 2) || (protoVer[0] != 0x03) || (protoVer[1] != 0x03)) + { + // Short read or not tls 1.2, so can't do MFLN + return send_abort(probe, supportsLen); + } + + ret = probe->readBytes(rand, 32); + handLen -= ret; + if (ret != 32) + { + // short read of random data + return send_abort(probe, supportsLen); + } + + ret = probe->readBytes(&sessionLen, 1); + handLen -= ret; + if ((ret != 1) || (sessionLen > 32)) + { + // short read of session len or invalid size + return send_abort(probe, supportsLen); + } + if (sessionLen) + { + ret = probe->readBytes(rand, sessionLen); + handLen -= ret; + if (ret != sessionLen) + { + // short session id read + return send_abort(probe, supportsLen); + } + } + + ret = probe->readBytes(cipher, 2); + handLen -= ret; + if (ret != 2) + { + // Short read...we don't check the cipher here + return send_abort(probe, supportsLen); + } + + ret = probe->readBytes(&comp, 1); + handLen -= ret; + if ((ret != 1) || comp != 0) + { + // short read or invalid compression + return send_abort(probe, supportsLen); + } + + ret = probe->readBytes(extBytes, 2); + handLen -= ret; + extLen = extBytes[1] | (extBytes[0] << 8); + if ((extLen == 0) || (ret != 2)) + { + return send_abort(probe, supportsLen); + } + + while (handLen > 0) + { + // Parse each extension and look for MFLN + uint8_t typeBytes[2]; + ret = probe->readBytes(typeBytes, 2); + handLen -= 2; + if ((ret != 2) || (handLen <= 0)) + { + return send_abort(probe, supportsLen); + } + uint8_t lenBytes[2]; + ret = probe->readBytes(lenBytes, 2); + handLen -= 2; + uint16_t extLen = lenBytes[1] | (lenBytes[0] << 8); + if ((ret != 2) || (handLen <= 0) || (extLen > 32) || (extLen > handLen)) + { + return send_abort(probe, supportsLen); + } + if ((typeBytes[0] == 0x00) && (typeBytes[1] == 0x01)) + { // MFLN extension! + // If present and 1-byte in length, it's supported + return send_abort(probe, extLen == 1 ? true : false); + } + // Skip the extension, move to next one + uint8_t junk[32]; + ret = probe->readBytes(junk, extLen); + handLen -= extLen; + if (ret != extLen) + { + return send_abort(probe, supportsLen); + } + } + return send_abort(probe, supportsLen); +} + +bool BSSL_SSL_Client::mProbeMaxFragmentLength(const char *name, IPAddress ip, uint16_t port, uint16_t len) +{ + if (!mIsClientInitialized(false)) + return false; + + _basic_client->stop(); + + if (!(name ? _basic_client->connect(name, port) : _basic_client->connect(ip, port))) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Can't connect."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; + } + + bool ret = mProbeMaxFragmentLength(_basic_client, len); + _basic_client->stop(); + return ret; +} + +int BSSL_SSL_Client::mIsClientInitialized(bool notify) +{ + if (!_basic_client) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + if (notify) + esp_ssl_debug_print(PSTR("Basic client is not yet initialized."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return 0; + } + return 1; +} + +int BSSL_SSL_Client::mConnectBasicClient(const char *host, IPAddress ip, uint16_t port) +{ + + if (!mConnectionValidate(host, ip, port)) + return 0; + + if (!(host ? _basic_client->connect(host, port) : _basic_client->connect(ip, port))) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Failed to connect to server using basic client."), _debug_level, esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_connection_fail); + mFreeSSL(); + return 0; + } + + _secure = false; + _write_idx = 0; +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Basic client connected!"), _debug_level, esp_ssl_debug_info, __func__); +#endif + return 1; +} + +bool BSSL_SSL_Client::mSoftConnected(const char *func_name) +{ + // check if the socket is still open and such + if (getWriteError()) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Cannot operate if the write error is not reset."), _debug_level, esp_ssl_debug_error, func_name); + mPrintClientError(getWriteError(), esp_ssl_debug_error, func_name); +#endif + return false; + } + // check if the ssl engine is still open + if (!_is_connected || br_ssl_engine_current_state(_eng) == BR_SSL_CLOSED) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Cannot operate on a closed SSL connection."), _debug_level, esp_ssl_debug_error, func_name); + int error = br_ssl_engine_last_error(_eng); + if (error != BR_ERR_OK) + mPrintSSLError(error, esp_ssl_debug_error, func_name); +#endif + return false; + } + return true; +} + +int BSSL_SSL_Client::mConnectSSL(const char *host) +{ + +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Start connection."), _debug_level, esp_ssl_debug_info, __func__); +#endif + mFreeSSL(); + _oom_err = false; + +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + // BearSSL will reject all connections unless an authentication option is set, warn in DEBUG builds +#if defined(ESP_SSL_FS_SUPPORTED) +#define CRTSTORECOND &&!_certStore +#else +#define CRTSTORECOND +#endif + if (!_use_insecure && !_use_fingerprint && !_use_self_signed && !_knownkey CRTSTORECOND && !_ta) + { + esp_ssl_debug_print(PSTR("Connection *will* fail, no authentication method is setup."), _debug_level, esp_ssl_debug_warn, __func__); + } +#endif + + _sc = std::make_shared(); + _eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr + + _iobuf_in = (unsigned char *)mallocImpl(_iobuf_in_size); + _iobuf_out = (unsigned char *)mallocImpl(_iobuf_out_size); + + if (!_sc || !_iobuf_in || !_iobuf_out) + { + mFreeSSL(); // Frees _sc, _iobuf* + _oom_err = true; +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("OOM error."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return 0; + } + + // If no cipher list yet set, use defaults + if (!_cipher_list) + bssl::br_ssl_client_base_init(_sc.get(), suites_P, sizeof(suites_P) / sizeof(suites_P[0])); + else + bssl::br_ssl_client_base_init(_sc.get(), _cipher_list, _cipher_cnt); + + // Only failure possible in the installation is OOM + if (!mInstallClientX509Validator()) + { + mFreeSSL(); + _oom_err = true; +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Can't install x509 validator."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return 0; + } + + br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in, _iobuf_in_size, _iobuf_out, _iobuf_out_size); + br_ssl_engine_set_versions(_eng, _tls_min, _tls_max); + + // Apply any client certificates, if supplied. + if (_sk && _sk->isRSA()) + { + br_ssl_client_set_single_rsa(_sc.get(), _chain ? _chain->getX509Certs() : nullptr, _chain ? _chain->getCount() : 0, + _sk->getRSA(), br_rsa_pkcs1_sign_get_default()); + } + else if (_sk && _sk->isEC()) + { +#ifndef BEARSSL_SSL_BASIC + br_ssl_client_set_single_ec(_sc.get(), _chain ? _chain->getX509Certs() : nullptr, _chain ? _chain->getCount() : 0, + _sk->getEC(), _allowed_usages, + _cert_issuer_key_type, br_ec_get_default(), br_ecdsa_sign_asn1_get_default()); +#else + mFreeSSL(); +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Attempting to use EC cert in minimal cipher mode (no EC)."), _debug_level, esp_ssl_debug_error, __func__); +#endif + return 0; +#endif + } + else if (_esp32_sk && _esp32_chain) + { + br_ssl_client_set_single_rsa(_sc.get(), _esp32_chain->getX509Certs(), _esp32_chain->getCount(), + _esp32_sk->getRSA(), br_rsa_pkcs1_sign_get_default()); + } + + // clear the write error + setWriteError(esp_ssl_ok); + + // we want 128 bits to be safe, as recommended by the bearssl docs + uint8_t rng_seeds[16]; + + // prng + for (uint8_t i = 0; i < sizeof rng_seeds; i++) + rng_seeds[i] = static_cast(random(256)); + + br_ssl_engine_inject_entropy(_eng, rng_seeds, sizeof rng_seeds); + + // Restore session from the storage spot, if present + if (_session) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Set SSL session!"), _debug_level, esp_ssl_debug_info, __func__); +#endif + br_ssl_engine_set_session_parameters(_eng, _session->getSession()); + } + + if (!br_ssl_client_reset(_sc.get(), host, _session ? 1 : 0)) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Can't reset client."), _debug_level, esp_ssl_debug_error, __func__); + mPrintSSLError(br_ssl_engine_last_error(_eng), esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_connection_fail); + mFreeSSL(); + return 0; + } + +// SSL/TLS handshake +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Wait for SSL handshake."), _debug_level, esp_ssl_debug_info, __func__); +#endif + + if (mRunUntil(BR_SSL_SENDAPP, _handshake_timeout) < 0) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Failed to initlalize the SSL layer."), _debug_level, esp_ssl_debug_error, __func__); + mPrintSSLError(br_ssl_engine_last_error(_eng), esp_ssl_debug_error, __func__); +#endif + mFreeSSL(); + return 0; + } + +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Connection successful!"), _debug_level, esp_ssl_debug_info, __func__); +#endif + _handshake_done = true; + _is_connected = true; + _secure = true; + + // Save session + if (_session) + br_ssl_engine_get_session_parameters(_eng, _session->getSession()); + + // Session is already validated here, there is no need to keep following + _x509_minimal = nullptr; + _x509_insecure = nullptr; + _x509_knownkey = nullptr; + + return 1; +} + +bool BSSL_SSL_Client::mConnectionValidate(const char *host, IPAddress ip, uint16_t port) +{ + if (!mIsClientInitialized(true)) + return false; + + if (_basic_client && _basic_client->connected() && + host + ? (strcasecmp(host, _host.c_str()) != 0 || port != _port) + : (ip != _ip || port != _port)) + { + _basic_client->stop(); + } + + return true; +} + +int BSSL_SSL_Client::mRunUntil(const unsigned target, unsigned long timeout) +{ + unsigned lastState = 0; + size_t lastLen = 0; + const unsigned long start = millis(); + for (;;) + { + unsigned state = mUpdateEngine(); + // error check + if (state == BR_SSL_CLOSED || getWriteError() != esp_ssl_ok) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + if (state == BR_SSL_CLOSED) + esp_ssl_debug_print(PSTR("Terminating because the ssl engine closed."), _debug_level, esp_ssl_debug_warn, __func__); + else + esp_ssl_debug_print(PSTR("Terminating with write error."), _debug_level, esp_ssl_debug_warn, __func__); +#endif + return -1; + } + // timeout check + if (millis() - start > ((timeout > 0) ? timeout : getTimeout())) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("SSL internals timed out!"), _debug_level, esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_write_error); + stop(); + return -1; + } + // debug + if (state != lastState || lastState == 0) + { + lastState = state; +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("SSL state changed."), _debug_level, esp_ssl_debug_info, __func__); + mPrintSSLState(state, esp_ssl_debug_info, __func__); +#endif + } + if (state & BR_SSL_RECVREC) + { + size_t len; + br_ssl_engine_recvrec_buf(_eng, &len); + if (lastLen != len) + { + lastLen = len; +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + String s = PSTR("Expected bytes count: "); + s += len; + esp_ssl_debug_print(s.c_str(), _debug_level, esp_ssl_debug_info, __func__); +#endif + } + } + /* + * If we reached our target, then we are finished. + */ + if (state & target || (target == 0 && state == 0)) + return 0; + + /* + * If some application data must be read, and we did not + * exit, then this means that we are trying to write data, + * and that's not possible until the application data is + * read. This may happen if using a shared in/out buffer, + * and the underlying protocol is not strictly half-duplex. + * Normally this would be unrecoverable, however we can attempt + * to remedy the problem by telling the engine to discard + * the data. + */ + if (state & BR_SSL_RECVAPP) + { + _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len); + if (_recvapp_buf != nullptr) + { + // if application data is ready in buffer, don't ignore, just return. + + // _write_idx = 0; + // esp_ssl_debug_print(PSTR("Discarded unread data to favor a write operation."), _debug_level, esp_ssl_debug_warn, __func__); + // br_ssl_engine_recvapp_ack(_eng, len); + // continue; + return 0; + } + else + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("SSL engine state is RECVAPP, however the buffer was null! (This is a problem with BearSSL internals)."), _debug_level, esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_write_error); + stop(); + return -1; + } + } + + if (target & BR_SSL_SENDAPP) + { + // reset the write index + _write_idx = 0; + continue; + } + + /* + * We can reach that point if the target RECVAPP, and + * the state contains SENDAPP only. This may happen with + * a shared in/out buffer. In that case, we must flush + * the buffered data to "make room" for a new incoming + * record. + */ + if (state & BR_SSL_SENDAPP && target & BR_SSL_RECVAPP) + br_ssl_engine_flush(_eng, 0); + } +} + +unsigned BSSL_SSL_Client::mUpdateEngine() +{ + for (;;) + { + // get the state + unsigned state = br_ssl_engine_current_state(_eng); + // debug + if (_bssl_last_state == 0 || state != _bssl_last_state) + { + _bssl_last_state = state; +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + mPrintSSLState(state, esp_ssl_debug_info, __func__); +#endif + } + if (state & BR_SSL_CLOSED) + return state; + /* + * If there is some record data to send, do it. This takes + * precedence over everything else. + */ + if (state & BR_SSL_SENDREC) + { + unsigned char *buf; + size_t len; + int wlen; + + buf = br_ssl_engine_sendrec_buf(_eng, &len); + wlen = _basic_client->write(buf, len); + _basic_client->flush(); + if (wlen <= 0) + { + // if the arduino client encountered an error + if (_basic_client->getWriteError() || !_basic_client->connected()) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Error writing to basic client."), _debug_level, esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_write_error); + } + // else presumably the socket just closed itself, so just stop the engine + stop(); + return 0; + } + if (wlen > 0) + { + br_ssl_engine_sendrec_ack(_eng, wlen); + } + continue; + } + + /* + * If the client has specified there is client data to send, and + * the engine is ready to handle it, send it along. + */ + if (_write_idx > 0) + { + // if we've reached the point where BR_SSL_SENDAPP is off but + // data has been written to the io buffer, something is wrong + if (!(state & BR_SSL_SENDAPP)) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Error _write_idx > 0 but the ssl engine is not ready for data."), _debug_level, esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_write_error); + stop(); + return 0; + } + // else time to send the application data + else if (state & BR_SSL_SENDAPP) + { + size_t alen; + unsigned char *buf = br_ssl_engine_sendapp_buf(_eng, &alen); + // engine check + if (alen == 0 || buf == nullptr) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Engine set write flag but returned null buffer."), _debug_level, esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_write_error); + stop(); + return 0; + } + // sanity check + if (alen < _write_idx) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("Alen is less than _write_idx."), _debug_level, esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_internal_error); + stop(); + return 0; + } + // all good? lets send the data + // presumably the BSSL_SSL_Client::write function has already added + // data to *buf, so now we tell bearssl it's time for the + // encryption step. + // this will encrypt the data and presumably spit it out + // for BR_SSL_SENDREC to send over ethernet. + br_ssl_engine_sendapp_ack(_eng, _write_idx); + // reset the iobuffer index + _write_idx = 0; + // loop again! + continue; + } + } + + /* + * If there is some record data to recieve, check if we've + * recieved it so far. If we have, then we can update the state. + * else we can return that we're still waiting for the server. + */ + if (state & BR_SSL_RECVREC) + { + size_t len; + unsigned char *buf = br_ssl_engine_recvrec_buf(_eng, &len); + // do we have the record you're looking for? + const auto avail = _basic_client->available(); + if (avail > 0) + { + // I suppose so! + int rlen = _basic_client->read(buf, avail < (int)len ? avail : (int)len); + if (rlen <= 0) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + String s = PSTR("Error reading bytes from basic client. Write Error: "); + s += _basic_client->getWriteError(); + esp_ssl_debug_print(s.c_str(), _debug_level, esp_ssl_debug_error, __func__); +#endif + setWriteError(esp_ssl_write_error); + stop(); + return 0; + } + if (rlen > 0) + { + br_ssl_engine_recvrec_ack(_eng, rlen); + } + continue; + } + // guess not, tell the state we're waiting still + else + { + +#if defined __has_include +#if __has_include() + // Add a delay since spamming _basic_client->availible breaks the poor wiz chip + delay(10); +#endif +#endif + return state; + } + } + // if it's not any of the above states, then it must be waiting to send or recieve app data + // in which case we return + return state; + } +} + +void BSSL_SSL_Client::mPrintClientError(const int ssl_error, int level, const char *func_name) +{ +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + const char *msg = nullptr; + + switch (ssl_error) + { + case esp_ssl_ok: + msg = PSTR("SSL OK"); + break; + case esp_ssl_connection_fail: + msg = PSTR("SSL Connection fail"); + break; + case esp_ssl_write_error: + msg = PSTR("SSL Write error"); + break; + case esp_ssl_read_error: + msg = PSTR("SSL Read error"); + break; + case esp_ssl_out_of_memory: + msg = PSTR("SSL OOM error"); + break; + case esp_ssl_internal_error: + msg = PSTR("SSL Internal error"); + break; + } + + esp_ssl_debug_print(msg, _debug_level, level, func_name); +#endif +} + +void BSSL_SSL_Client::mPrintSSLError(const unsigned br_error_code, int level, const char *func_name) +{ +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + char dest[300]; + getLastSSLError(dest, 300); + esp_ssl_debug_print(dest, _debug_level, level, func_name); +#endif +} + +void BSSL_SSL_Client::mPrintSSLState(const unsigned state, int level, const char *func_name) +{ +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + const char *msg = nullptr; + + if (state == 0) + msg = PSTR("State Invalid"); + else if (state & BR_SSL_CLOSED) + msg = PSTR("State Connection close"); + else + { + if (state & BR_SSL_SENDREC) + msg = PSTR("State SENDREC"); + if (state & BR_SSL_RECVREC) + msg = PSTR("State RECVREC"); + if (state & BR_SSL_SENDAPP) + msg = PSTR("State SENDAPP"); + if (state & BR_SSL_RECVAPP) + msg = PSTR("State RECVAPP"); + } + + esp_ssl_debug_print(msg, _debug_level, level, func_name); +#endif +} + +bool BSSL_SSL_Client::mIsSecurePort(uint16_t port) +{ + int size = *(&_secure_ports + 1) - _secure_ports; + for (int i = 0; i < size; i++) + { + if (port == _secure_ports[i]) + return true; + } + + return false; +} + +void BSSL_SSL_Client::mBSSLX509InsecureInit(bssl::br_x509_insecure_context *ctx, int _use_fingerprint, const uint8_t _fingerprint[20], int _allow_self_signed) +{ + static const br_x509_class br_x509_insecure_vtable PROGMEM = { + sizeof(bssl::br_x509_insecure_context), + bssl::insecure_start_chain, + bssl::insecure_start_cert, + bssl::insecure_append, + bssl::insecure_end_cert, + bssl::insecure_end_chain, + bssl::insecure_get_pkey}; + + memset(ctx, 0, sizeof *ctx); + ctx->vtable = &br_x509_insecure_vtable; + ctx->done_cert = false; + ctx->match_fingerprint = _use_fingerprint ? _fingerprint : nullptr; + ctx->allow_self_signed = _allow_self_signed ? 1 : 0; +} + +void BSSL_SSL_Client::mClearAuthenticationSettings() +{ + _use_insecure = false; + _use_fingerprint = false; + _use_self_signed = false; + _knownkey = nullptr; + _ta = nullptr; + if (_esp32_ta) + { + delete _esp32_ta; + _esp32_ta = nullptr; + } +} + +void BSSL_SSL_Client::mClear() +{ + _timeout = 15000; + _sc = nullptr; + _eng = nullptr; + _x509_minimal = nullptr; + _x509_insecure = nullptr; + _x509_knownkey = nullptr; + + freeImpl(&_iobuf_in); + freeImpl(&_iobuf_out); + _now = 0; // You can override or ensure time() is correct w/configTime + _ta = nullptr; + setBufferSizes(16384, 512); // Minimum safe + _secure = false; + _recvapp_buf = nullptr; + _recvapp_len = 0; + _oom_err = false; + _session = nullptr; + freeImpl(&_cipher_list); + _cipher_cnt = 0; + _tls_min = BR_TLS10; + _tls_max = BR_TLS12; + if (_esp32_ta) + { + delete _esp32_ta; + _esp32_ta = nullptr; + } +} + +// X.509 validators differ from server to client +// Installs the appropriate X509 cert validation method for a client connection +bool BSSL_SSL_Client::mInstallClientX509Validator() +{ + + if (_use_insecure || _use_fingerprint || _use_self_signed) + { + // Use common insecure x509 authenticator + _x509_insecure = std::make_shared(); + if (!_x509_insecure) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("OOM for _x509_insecure"), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; + } + mBSSLX509InsecureInit(_x509_insecure.get(), _use_fingerprint, _fingerprint, _use_self_signed); + br_ssl_engine_set_x509(_eng, &_x509_insecure->vtable); + } + else if (_knownkey) + { + // Simple, pre-known public key authenticator, ignores cert completely. + _x509_knownkey = std::make_shared(); + if (!_x509_knownkey) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("OOM for _x509_knownkey"), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; + } + if (_knownkey->isRSA()) + { + br_x509_knownkey_init_rsa(_x509_knownkey.get(), _knownkey->getRSA(), _knownkey_usages); + } + else if (_knownkey->isEC()) + { +#ifndef BEARSSL_SSL_BASIC + br_x509_knownkey_init_ec(_x509_knownkey.get(), _knownkey->getEC(), _knownkey_usages); +#else + (void)_knownkey; + (void)_knownkey_usages; + esp_ssl_debug_print(PSTR("Attempting to use EC keys in minimal cipher mode (no EC)"), _debug_level, esp_ssl_debug_error, __func__); + return false; +#endif + } + br_ssl_engine_set_x509(_eng, &_x509_knownkey->vtable); + } + else + { + // X509 minimal validator. Checks dates, cert chain for trusted CA, etc. + _x509_minimal = std::make_shared(); + if (!_x509_minimal) + { +#if defined(ESP_SSLCLIENT_ENABLE_DEBUG) + esp_ssl_debug_print(PSTR("OOM for _x509_minimal"), _debug_level, esp_ssl_debug_error, __func__); +#endif + return false; + } + if (_esp32_ta) + { + br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _esp32_ta->getTrustAnchors(), _esp32_ta->getCount()); + } + else + { + br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _ta ? _ta->getTrustAnchors() : nullptr, _ta ? _ta->getCount() : 0); + } + br_x509_minimal_set_rsa(_x509_minimal.get(), br_ssl_engine_get_rsavrfy(_eng)); +#ifndef BEARSSL_SSL_BASIC + br_x509_minimal_set_ecdsa(_x509_minimal.get(), br_ssl_engine_get_ec(_eng), br_ssl_engine_get_ecdsa(_eng)); +#endif + bssl::br_x509_minimal_install_hashes(_x509_minimal.get()); + +#if (defined(ESP32) || defined(ESP8266) || defined(ARDUINO_ARCH_RP2040)) && !defined(ARDUINO_NANO_RP2040_CONNECT) + if (_now < ESP_SSLCLIENT_VALID_TIMESTAMP) + _now = time(nullptr); +#endif + if (_now) + { + // Magic constants convert to x509 times + br_x509_minimal_set_time(_x509_minimal.get(), ((uint32_t)_now) / 86400 + 719528, ((uint32_t)_now) % 86400); + } +#if defined(ESP_SSL_FS_SUPPORTED) + if (_certStore) + { + _certStore->installCertStore(_x509_minimal.get()); + } +#endif + br_ssl_engine_set_x509(_eng, &_x509_minimal->vtable); + } + return true; +} + +void BSSL_SSL_Client::mFreeSSL() +{ + // These are smart pointers and will free if refcnt==0 + _sc = nullptr; + _x509_minimal = nullptr; + _x509_insecure = nullptr; + _x509_knownkey = nullptr; + freeImpl(&_iobuf_in); + freeImpl(&_iobuf_out); + // Reset non-allocated ptrs (pointing to bits potentially free'd above) + _recvapp_buf = nullptr; + _recvapp_len = 0; + // This connection is toast + _handshake_done = false; + _timeout = 15000; + _secure = false; + _is_connected = false; +} + +uint8_t *BSSL_SSL_Client::mStreamLoad(Stream &stream, size_t size) +{ + uint8_t *dest = (uint8_t *)malloc(size + 1); + if (!dest) + { + return nullptr; + } + if (size != stream.readBytes(dest, size)) + { + free(dest); + dest = nullptr; + return nullptr; + } + dest[size] = '\0'; + return dest; +} + +// Allocate memory +void *BSSL_SSL_Client::mallocImpl(size_t len, bool clear) +{ + void *p; + size_t newLen = getReservedLen(len); +#if defined(BOARD_HAS_PSRAM) && defined(ESP_SSLCLIENT_USE_PSRAM) + + if (ESP.getPsramSize() > 0) + p = (void *)ps_malloc(newLen); + else + p = (void *)malloc(newLen); + + if (!p) + return NULL; + +#else + +#if defined(ESP_SSLCLIENT_ESP8266_USE_EXTERNAL_HEAP) + ESP.setExternalHeap(); +#endif + + p = (void *)malloc(newLen); + bool nn = p ? true : false; + +#if defined(ESP_SSLCLIENT_ESP8266_USE_EXTERNAL_HEAP) + ESP.resetHeap(); +#endif + + if (!nn) + return NULL; + +#endif + if (clear) + memset(p, 0, newLen); + return p; +} + +// Free reserved memory at pointer. +void BSSL_SSL_Client::freeImpl(void *ptr) +{ + void **p = (void **)ptr; + if (*p) + { + free(*p); + *p = 0; + } +} + +size_t BSSL_SSL_Client::getReservedLen(size_t len) +{ + int blen = len + 1; + + int newlen = (blen / 4) * 4; + + if (newlen < blen) + newlen += 4; + + return (size_t)newlen; +} + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_SSL_Client.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_SSL_Client.h new file mode 100644 index 000000000..98a42685d --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_SSL_Client.h @@ -0,0 +1,349 @@ +/** + * BSSL_SSL_Client library v1.0.11 for Arduino devices. + * + * Created August 27, 2003 + * + * This work contains codes based on WiFiClientSecure from Earle F. Philhower and SSLClient from OSU OPEnS Lab. + * + * Copyright (c) 2018 Earle F. Philhower, III + * + * Copyright 2019 OSU OPEnS Lab + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef BSSL_SSL_CLIENT_H +#define BSSL_SSL_CLIENT_H + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wvla" + +#include +#include "../ESP_SSLClient_FS.h" +#include "../ESP_SSLClient_Const.h" +#if defined(USE_LIB_SSL_ENGINE) || defined(USE_EMBED_SSL_ENGINE) + +#include +#include +#if defined __has_include +#if __has_include() +#include +#endif +#endif + +#if defined(USE_LIB_SSL_ENGINE) + +#include "BSSL_Helper.h" +#include "BSSL_CertStore.h" + +using namespace bssl; + +#elif defined(USE_EMBED_SSL_ENGINE) + +#include "BearSSLHelpers.h" +#include "BSSL_Helper.h" +#include "CertStoreBearSSL.h" + +using namespace BearSSL; + +#include + +#if defined(ESP8266) + +#include "PolledTimeout.h" +#if defined(ESP8266_CORE_SDK_V3_X_X) +#include +#endif + +#if __has_include() +#include +#endif + +#endif + +#endif + +class BSSL_SSL_Client : public Client +{ +public: + explicit BSSL_SSL_Client(Client *client = nullptr); + + ~BSSL_SSL_Client(); + + void setClient(Client *client, bool ssl = false); + + void setDebugLevel(int level); + + int connect(IPAddress ip, uint16_t port) override; + + int connect(const char *host, uint16_t port) override; + + uint8_t connected() override; + + void validate(const char *host, uint16_t port); + + void validate(IPAddress ip, uint16_t port); + + int available() override; + + int read() override; + + int read(uint8_t *buf, size_t size) override; + + size_t write(const uint8_t *buf, size_t size) override; + + size_t write(uint8_t b) override; + + size_t write_P(PGM_P buf, size_t size); + + size_t write(Stream &stream); + + int peek() override; + + size_t peekBytes(uint8_t *buffer, size_t length); + + void setInsecure(); + + void enableSSL(bool enable); + + int connectSSL(IPAddress ip, uint16_t port); + + int connectSSL(const char *host, uint16_t port); + + void stop() override; + + void setTimeout(unsigned int timeoutMs); + + void setHandshakeTimeout(unsigned int timeoutMs); + + void flush() override; + + void setBufferSizes(int recv, int xmit); + + operator bool() { return connected() > 0; } + + int availableForWrite(); + + void setSession(BearSSL_Session *session); + + void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN); + + bool setFingerprint(const uint8_t fingerprint[20]); + + bool setFingerprint(const char *fpStr); + + void allowSelfSignedCerts(); + + void setTrustAnchors(const X509List *ta); + + void setX509Time(time_t now); + + void setClientRSACert(const X509List *chain, const PrivateKey *sk); + + void setClientECCert(const X509List *chain, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type); + + int getMFLNStatus(); + + int getLastSSLError(char *dest, size_t len); +#if defined(ESP_SSL_FS_SUPPORTED) + void setCertStore(CertStoreBase *certStore); +#endif + bool setCiphers(const uint16_t *cipherAry, int cipherCount); + + bool setCiphers(const std::vector &list); + + bool setCiphersLessSecure(); + + bool setSSLVersion(uint32_t min, uint32_t max); + + bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len); + + bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len); + + bool probeMaxFragmentLength(const String &host, uint16_t port, uint16_t len); + + size_t peekAvailable(); + + const char *peekBuffer(); + + void peekConsume(size_t consume); + + void setCACert(const char *rootCA); + + void setCertificate(const char *client_ca); + + void setPrivateKey(const char *private_key); + + bool loadCACert(Stream &stream, size_t size); + + bool loadCertificate(Stream &stream, size_t size); + + bool loadPrivateKey(Stream &stream, size_t size); + + int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); + + int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); + + BSSL_SSL_Client &operator=(const BSSL_SSL_Client &other); + + bool operator==(const bool value) { return bool() == value; } + + bool operator!=(const bool value) { return bool() != value; } + + bool operator==(const BSSL_SSL_Client &); + + bool operator!=(const BSSL_SSL_Client &rhs) { return !this->operator==(rhs); }; + + unsigned int getTimeout() const; + + void setSecure(const char *rootCABuff, const char *cli_cert, const char *cli_key); + +private: + // Checks for support of Maximum Frame Length Negotiation at the given + // blocksize. Note that, per spec, only 512, 1024, 2048, and 4096 are + // supported. Many servers today do not support this negotiation. + + // TODO - Allow for fragmentation...but not very critical as the ServerHello + // we use comes to < 80 bytes which has no reason to ever be fragmented. + // TODO - Check the type of returned extensions and that the MFL is the exact + // same one we sent. Not critical as only horribly broken servers would + // return changed or add their own extensions. + bool mProbeMaxFragmentLength(Client *probe, uint16_t len); + + bool mProbeMaxFragmentLength(const char *name, IPAddress ip, uint16_t port, uint16_t len); + + int mIsClientInitialized(bool notify); + + int mConnectBasicClient(const char *host, IPAddress ip, uint16_t port); + // Returns whether or not the engine is connected, without polling the client over SPI or other (as opposed to connected()) + bool mSoftConnected(const char *func_name); + + int mConnectSSL(const char *host = nullptr); + + bool mConnectionValidate(const char *host, IPAddress ip, uint16_t port); + + int mRunUntil(const unsigned target, unsigned long timeout = 0); + + unsigned mUpdateEngine(); + + void mPrintClientError(const int ssl_error, int level, const char *func_name); + + void mPrintSSLError(const unsigned br_error_code, int level, const char *func_name); + + void mPrintSSLState(const unsigned br_state, int level, const char *func_name); + + bool mIsSecurePort(uint16_t port); + + void mBSSLX509InsecureInit(bssl::br_x509_insecure_context *ctx, int _use_fingerprint, const uint8_t _fingerprint[20], int _allow_self_signed); + + void mClearAuthenticationSettings(); + + void mClear(); + + bool mInstallClientX509Validator(); + + void mFreeSSL(); + + uint8_t *mStreamLoad(Stream &stream, size_t size); + + void *mallocImpl(size_t len, bool clear = true); + + void freeImpl(void *ptr); + + size_t getReservedLen(size_t len); + + // store whether to enable debug logging + int _debug_level = 0; + + bool _is_connected; + + // store the index of where we are writing in the buffer + // so we can send our records all at once to prevent + // weird timing issues + size_t _write_idx; + + // store the last BearSSL state so we can print changes to the console + unsigned _bssl_last_state; + + bool _secure = false; + + Client *_basic_client = nullptr; + + std::shared_ptr _sc; + br_ssl_engine_context *_eng = nullptr; // &_sc->eng, to allow for client or server contexts + std::shared_ptr _x509_minimal; + std::shared_ptr _x509_insecure; + std::shared_ptr _x509_knownkey; + + unsigned char *_iobuf_in = nullptr; + unsigned char *_iobuf_out = nullptr; + int _iobuf_in_size = 512; + int _iobuf_out_size = 512; + + time_t _now = 0; + const X509List *_ta = nullptr; +#if defined(ESP_SSL_FS_SUPPORTED) + CertStoreBase *_certStore = 0; +#endif + // Optional client certificate + const X509List *_chain = nullptr; + const PrivateKey *_sk = nullptr; + unsigned int _allowed_usages = 0; + unsigned int _cert_issuer_key_type = 0; + + // Optional storage space pointer for session parameters + // Will be used on connect and updated on close + BearSSL_Session *_session = nullptr; + + bool _use_insecure = false; + bool _use_fingerprint = false; + uint8_t _fingerprint[20]; + bool _use_self_signed = false; + const PublicKey *_knownkey; + unsigned int _knownkey_usages = 0; + + // Custom cipher list pointer or nullptr if default + uint16_t *_cipher_list = nullptr; + uint8_t _cipher_cnt = 0; + + // TLS ciphers allowed + uint32_t _tls_min = BR_TLS10; + uint32_t _tls_max = BR_TLS12; + + X509List *_esp32_ta = nullptr; + X509List *_esp32_chain = nullptr; + PrivateKey *_esp32_sk = nullptr; + + bool _handshake_done = false; + bool _oom_err = false; + unsigned char *_recvapp_buf = nullptr; + size_t _recvapp_len; + unsigned long _timeout = 15000; + unsigned long _handshake_timeout = 60000; + bool _isSSLEnabled = false; + String _host; + uint16_t _port = 0; + IPAddress _ip; +}; + +#endif + +#endif /** BSSL_SSL_Client_H */ diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_TCP_Client.cpp b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_TCP_Client.cpp new file mode 100644 index 000000000..f9f90075f --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_TCP_Client.cpp @@ -0,0 +1,461 @@ +/** + * BSSL_TCP_Client v2.0.12 for Arduino devices. + * + * Created August 27, 2023 + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + WiFiClientSecure.cpp - Client Secure class for ESP32 + Copyright (c) 2016 Hristo Gochkov All right reserved. + Additions Copyright (C) 2017 Evandro Luis Copercini. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef BSSL_TCP_CLIENT_CPP +#define BSSL_TCP_CLIENT_CPP + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wvla" + +#include +#include "../ESP_SSLClient_FS.h" +#include "../ESP_SSLClient_Const.h" +#if defined(USE_LIB_SSL_ENGINE) || defined(USE_EMBED_SSL_ENGINE) + +#include "BSSL_TCP_Client.h" +// #include +// #include +// #include + +#undef connect +#undef write +#undef read + +BSSL_TCP_Client::BSSL_TCP_Client() +{ + setClient(nullptr); + _ssl_client.setTimeout(120000); + _use_insecure = false; +} + +BSSL_TCP_Client::~BSSL_TCP_Client() +{ + stop(); + setClient(nullptr); +} + +void BSSL_TCP_Client::setClient(Client *client, bool enableSSL) +{ + _basic_client = client; + _ssl_client.setClient(_basic_client, enableSSL); +} + +void BSSL_TCP_Client::setDebugLevel(int level) +{ + _ssl_client.setDebugLevel(level); +} + +int BSSL_TCP_Client::connect(IPAddress ip, uint16_t port) +{ + return connect(ip, port, 0); +} + +int BSSL_TCP_Client::connect(IPAddress ip, uint16_t port, int32_t timeout) +{ + _port = port; + + if (timeout > 0) + { + _timeout = timeout; + if (_basic_client) + _basic_client->setTimeout(_timeout); + _ssl_client.setTimeout(_timeout); + } + + return _ssl_client.connect(ip, port); +} + +int BSSL_TCP_Client::connect(const char *host, uint16_t port) +{ + return connect(host, port, 0); +} + +int BSSL_TCP_Client::connect(const char *host, uint16_t port, int32_t timeout) +{ + + _host = host; + _port = port; + + if (timeout > 0) + { + _timeout = timeout; + if (_basic_client) + _basic_client->setTimeout(_timeout); + _ssl_client.setTimeout(_timeout); + } + + return _ssl_client.connect(host, port); +} + +uint8_t BSSL_TCP_Client::connected() +{ + return _ssl_client.connected(); +} + +void BSSL_TCP_Client::validate(const char *host, uint16_t port) +{ + _ssl_client.validate(host, port); +} + +void BSSL_TCP_Client::validate(IPAddress ip, uint16_t port) +{ + _ssl_client.validate(ip, port); +} + +int BSSL_TCP_Client::available() +{ + return _ssl_client.available(); +} + +int BSSL_TCP_Client::read() +{ + uint8_t data = -1; + int res = read(&data, 1); + if (res < 0) + return res; + return data; +} + +int BSSL_TCP_Client::read(uint8_t *buf, size_t size) +{ + if (!_ssl_client.connected()) + return 0; + return _ssl_client.read(buf, size); +} + +int BSSL_TCP_Client::send(const char *data) +{ + return write((uint8_t *)data, strlen(data)); +} + +int BSSL_TCP_Client::print(const char *data) +{ + return send(data); +} + +int BSSL_TCP_Client::print(const String &data) +{ + return print(data.c_str()); +} + +int BSSL_TCP_Client::print(int data) +{ + char buf[64]; + memset(buf, 0, 64); + sprintf(buf, (const char *)FPSTR("%d"), data); + int ret = send(buf); + return ret; +} + +int BSSL_TCP_Client::println(const char *data) +{ + int len = send(data); + if (len < 0) + return len; + int sz = send((const char *)FPSTR("\r\n")); + if (sz < 0) + return sz; + return len + sz; +} + +int BSSL_TCP_Client::println(const String &data) +{ + return println(data.c_str()); +} + +int BSSL_TCP_Client::println(int data) +{ + char buf[64]; + memset(buf, 0, 64); + sprintf(buf, (const char *)FPSTR("%d\r\n"), data); + int ret = send(buf); + return ret; +} + +size_t BSSL_TCP_Client::write(const uint8_t *buf, size_t size) +{ + if (!_ssl_client.connected()) + return 0; + return _ssl_client.write(buf, size); +} + +size_t BSSL_TCP_Client::write(uint8_t data) +{ + return write(&data, 1); +} + +size_t BSSL_TCP_Client::write_P(PGM_P buf, size_t size) { return _ssl_client.write_P(buf, size); } + +size_t BSSL_TCP_Client::write(const char *buf) { return write((const uint8_t *)buf, strlen(buf)); } + +size_t BSSL_TCP_Client::write(Stream &stream) { return _ssl_client.write(stream); } + +int BSSL_TCP_Client::peek() +{ + return _ssl_client.peek(); +} + +void BSSL_TCP_Client::setInsecure() +{ + _ssl_client.setInsecure(); + _use_insecure = true; +} + +void BSSL_TCP_Client::enableSSL(bool enable) +{ + _ssl_client.enableSSL(enable); +} + +bool BSSL_TCP_Client::connectSSL() +{ + if (!_ssl_client.connectSSL(_host.c_str(), _port)) + { + stop(); + return 0; + } + return 1; +} + +bool BSSL_TCP_Client::connectSSL(const String host, uint16_t port) { return connectSSL(); } + +void BSSL_TCP_Client::stop() +{ + _ssl_client.stop(); +} + +int BSSL_TCP_Client::setTimeout(uint32_t seconds) +{ + _timeout = seconds * 1000; + _ssl_client.setTimeout(_timeout); + return 1; +} + +int BSSL_TCP_Client::getTimeout() { return _ssl_client.getTimeout() / 1000; } + +void BSSL_TCP_Client::setHandshakeTimeout(unsigned long handshake_timeout) +{ + _handshake_timeout = handshake_timeout * 1000; + _ssl_client.setHandshakeTimeout(_handshake_timeout); +} + +void BSSL_TCP_Client::flush() +{ + if (!_basic_client) + return; + + while (available() > 0) + read(); +} + +void BSSL_TCP_Client::setBufferSizes(int recv, int xmit) +{ + _ssl_client.setBufferSizes(recv, xmit); +} + +int BSSL_TCP_Client::availableForWrite() { return _ssl_client.availableForWrite(); }; + +void BSSL_TCP_Client::setSession(BearSSL_Session *session) { _ssl_client.setSession(session); }; + +void BSSL_TCP_Client::setKnownKey(const PublicKey *pk, unsigned usages) +{ + _ssl_client.setKnownKey(pk, usages); +} + +bool BSSL_TCP_Client::setFingerprint(const uint8_t fingerprint[20]) +{ + return _ssl_client.setFingerprint(fingerprint); +} + +bool BSSL_TCP_Client::setFingerprint(const char *fpStr) +{ + return _ssl_client.setFingerprint(fpStr); +} + +void BSSL_TCP_Client::allowSelfSignedCerts() +{ + _ssl_client.allowSelfSignedCerts(); +} + +void BSSL_TCP_Client::setTrustAnchors(const X509List *ta) +{ + _ssl_client.setTrustAnchors(ta); +} + +void BSSL_TCP_Client::setX509Time(time_t now) +{ + _ssl_client.setX509Time(now); +} + +void BSSL_TCP_Client::setClientRSACert(const X509List *cert, const PrivateKey *sk) +{ + _ssl_client.setClientRSACert(cert, sk); +} + +void BSSL_TCP_Client::setClientECCert(const X509List *cert, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) +{ + _ssl_client.setClientECCert(cert, sk, allowed_usages, cert_issuer_key_type); +} + +int BSSL_TCP_Client::getMFLNStatus() { return _ssl_client.getMFLNStatus(); }; + +int BSSL_TCP_Client::getLastSSLError(char *dest, size_t len) +{ + return _ssl_client.getLastSSLError(dest, len); +} + +#if defined(ESP_SSL_FS_SUPPORTED) +void BSSL_TCP_Client::setCertStore(CertStoreBase *certStore) +{ + _ssl_client.setCertStore(certStore); +} +#endif + +bool BSSL_TCP_Client::setCiphers(const uint16_t *cipherAry, int cipherCount) +{ + return _ssl_client.setCiphers(cipherAry, cipherCount); +} + +bool BSSL_TCP_Client::setCiphers(const std::vector &list) +{ + return _ssl_client.setCiphers(list); +} + +bool BSSL_TCP_Client::setCiphersLessSecure() +{ + return _ssl_client.setCiphersLessSecure(); +} + +bool BSSL_TCP_Client::setSSLVersion(uint32_t min, uint32_t max) +{ + return _ssl_client.setSSLVersion(min, max); +} + +bool BSSL_TCP_Client::probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len) { return _ssl_client.probeMaxFragmentLength(ip, port, len); }; + +bool BSSL_TCP_Client::probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len) { return _ssl_client.probeMaxFragmentLength(hostname, port, len); }; + +bool BSSL_TCP_Client::probeMaxFragmentLength(const String &host, uint16_t port, uint16_t len) { return _ssl_client.probeMaxFragmentLength(host, port, len); }; + +// peek buffer API is present +bool BSSL_TCP_Client::hasPeekBufferAPI() const { return true; } + +// return number of byte accessible by peekBuffer() +size_t BSSL_TCP_Client::peekAvailable() { return _ssl_client.peekAvailable(); } + +// return a pointer to available data buffer (size = peekAvailable()) +// semantic forbids any kind of read() before calling peekConsume() +const char *BSSL_TCP_Client::peekBuffer() { return _ssl_client.peekBuffer(); } + +// consume bytes after use (see peekBuffer) +void BSSL_TCP_Client::peekConsume(size_t consume) { return _ssl_client.peekConsume(consume); } + +void BSSL_TCP_Client::setCACert(const char *rootCA) +{ + _ssl_client.setCACert(rootCA); +} + +void BSSL_TCP_Client::setCertificate(const char *client_ca) { return _ssl_client.setCertificate(client_ca); } + +void BSSL_TCP_Client::setPrivateKey(const char *private_key) { return _ssl_client.setPrivateKey(private_key); } + +bool BSSL_TCP_Client::loadCACert(Stream &stream, size_t size) +{ + char *dest = mStreamLoad(stream, size); + bool ret = false; + if (dest) + { + setCACert(dest); + ret = true; + } + return ret; +} + +bool BSSL_TCP_Client::loadCertificate(Stream &stream, size_t size) { return _ssl_client.loadCertificate(stream, size); } + +bool BSSL_TCP_Client::loadPrivateKey(Stream &stream, size_t size) { return _ssl_client.loadPrivateKey(stream, size); } + +int BSSL_TCP_Client::connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) { return _ssl_client.connect(ip, port, rootCABuff, cli_cert, cli_key); } + +int BSSL_TCP_Client::connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key) { return _ssl_client.connect(host, port, rootCABuff, cli_cert, cli_key); } + +BSSL_TCP_Client &BSSL_TCP_Client::operator=(const BSSL_TCP_Client &other) +{ + stop(); + setClient(other._basic_client); + _use_insecure = other._use_insecure; + _timeout = other._timeout; + _handshake_timeout = other._handshake_timeout; + _ssl_client.setTimeout(_timeout); + _ssl_client.setHandshakeTimeout(_handshake_timeout); + if (_use_insecure) + _ssl_client.setInsecure(); + return *this; +} + +char *BSSL_TCP_Client::mStreamLoad(Stream &stream, size_t size) +{ + char *dest = (char *)malloc(size + 1); + if (!dest) + { + return nullptr; + } + if (size != stream.readBytes(dest, size)) + { + free(dest); + dest = nullptr; + return nullptr; + } + dest[size] = '\0'; + return dest; +} + +bool BSSL_TCP_Client::operator==(const BSSL_TCP_Client &rhs) +{ + return _basic_client == rhs._basic_client && _port == rhs._port && _host == rhs._host; +} + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_TCP_Client.h b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_TCP_Client.h new file mode 100644 index 000000000..f70dbddfb --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/SSLClient/client/BSSL_TCP_Client.h @@ -0,0 +1,437 @@ +/** + * BSSL_TCP_Client v2.0.12 for Arduino devices. + * + * Created August 27, 2023 + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + WiFiClientSecure.h - Base class that provides Client SSL to ESP32 + Copyright (c) 2011 Adrian McEwen. All right reserved. + Additions Copyright (C) 2017 Evandro Luis Copercini. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef BSSL_TCP_CLIENT_H +#define BSSL_TCP_CLIENT_H + +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wvla" + +#include +#include "../ESP_SSLClient_FS.h" +#include "../ESP_SSLClient_Const.h" +#if defined(USE_LIB_SSL_ENGINE) || defined(USE_EMBED_SSL_ENGINE) + +#include "BSSL_SSL_Client.h" + +#include + +class BSSL_TCP_Client : public Client +{ + +protected: + bool _use_insecure; + +public: + BSSL_TCP_Client *next; + + // The default class constructor + BSSL_TCP_Client(); + + // The class deconstructor + ~BSSL_TCP_Client(); + + /** + * Set the client. + * @param client The pointer to Client interface. + * @param enableSSL The ssl option; true for enable, false for disable. + * + * Due to the client pointer is assigned, to avoid dangling pointer, + * client should be existed as long as it was used for transportation. + */ + void setClient(Client *client, bool enableSSL = true); + + /** + * Set debug level. + * @param level The debug level or esp_ssl_client_debug_level. + * esp_ssl_debug_none = 0 + * esp_ssl_debug_error = 1 + * esp_ssl_debug_warn = 2 + * esp_ssl_debug_info = 3 + * esp_ssl_debug_dump = 4 + */ + void setDebugLevel(int level); + + /** + * Connect to server. + * @param ip The server IP to connect. + * @param port The server port to connecte. + * @return 1 for success or 0 for error. + */ + int connect(IPAddress ip, uint16_t port) override; + + /** + * Connect to server. + * @param ip The server IP to connect. + * @param port The server port to connect. + * @param timeout The connection time out in miiliseconds. + * @return 1 for success or 0 for error. + */ + int connect(IPAddress ip, uint16_t port, int32_t timeout); + + /** + * Connect to server. + * @param host The server host name. + * @param port The server port to connect. + * @return 1 for success or 0 for error. + */ + int connect(const char *host, uint16_t port) override; + + /** + * Connect to server. + * @param host The server host name. + * @param port The server port to connect. + * @param timeout The connection time out in miiliseconds. + * @return 1 for success or 0 for error. + */ + int connect(const char *host, uint16_t port, int32_t timeout); + + /** + * Get TCP connection status. + * @return 1 for connected or 0 for not connected. + */ + uint8_t connected() override; + + /** + * Validate the last Client connection with these host and port. + * @param host The server host name. + * @param port The server port to connect. + * The Client connection will be closed when the provided host or port is not match with that of last connection. + */ + void validate(const char *host, uint16_t port); + + /** + * Validate the last Client connection with these IP and port. + * @param ip The server IP to connect. + * @param port The server port to connect. + * The Client connection will be closed when the provided IP or port is not match with that of last connection. + */ + void validate(IPAddress ip, uint16_t port); + + /** + * Get available data size to read. + * @return The avaiable data size. + * @note Get available data directly via lwIP for non-secure mode or via mbedTLS for secure mode. + */ + int available() override; + + /** + * The TCP data read function. + * @return A byte data that was successfully read or -1 for error. + * @note Get data directly via lwIP for non-secure mode or via mbedTLS to deccrypt data for secure mode. + */ + int read() override; + + /** + * The TCP data read function. + * @param buf The data buffer. + * @param size The length of data that read. + * @return The size of data that was successfully read or 0 for error. + * @note Get data directly via lwIP for non-secure mode or via mbedTLS to deccrypt data for secure mode. + */ + int read(uint8_t *buf, size_t size) override; + + /** + * The TCP data send function. + * @param data The data to send. + * @return The size of data that was successfully sent or 0 for error. + */ + int send(const char *data); + + /** + * The TCP data print function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int print(const char *data); + + /** + * The TCP data print function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int print(const String &data); + + /** + * The TCP data print function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int print(int data); + + /** + * The TCP data print with new line function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int println(const char *data); + + /** + * The TCP data print with new line function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int println(const String &data); + + /** + * The TCP data print with new line function. + * @param data The data to print. + * @return The size of data that was successfully print or 0 for error. + */ + int println(int data); + + /** + * The TCP data write function. + * @param buf The data to write. + * @param size The length of data to write. + * @return The size of data that was successfully written or 0 for error. + * @note Send data directly via lwIP for non-secure mode or via mbedTLS to encrypt for secure mode. + */ + size_t write(const uint8_t *buf, size_t size) override; + + /** + * The TCP data write function. + * @param data The byte of data to write. + * @return The size of data that was successfully written (1) or 0 for error. + * @note Send data directly via lwIP for non-secure mode or via mbedTLS to encrypt for secure mode. + */ + size_t write(uint8_t data) override; + + /** + * The TCP data write function. + * @param buf The PGM data to write. + * @param size The length of data to write. + * @return The size of data that was successfully written or 0 for error. + */ + size_t write_P(PGM_P buf, size_t size); + + /** + * The TCP data write function. + * @param buf The string data to write. + * @return The size of data that was successfully written or 0 for error. + */ + size_t write(const char *buf); + + /** + * The TCP data write function. + * @param stream The stream data to write. + * @return The size of data that was successfully written or 0 for error. + */ + size_t write(Stream &stream); + + /** + * Read one byte from Stream with time out. + * @return The byte of data that was successfully read or -1 for timed out. + */ + int peek() override; + + /** + * Disable certificate verification and ignore the authentication. + */ + void setInsecure(); // Don't validate the chain, just accept whatever is given. VERY INSECURE! + + /** + * Enable/disable the SSL layer transport. + * @param enable The enable option; true for enable, false to disable. + */ + void enableSSL(bool enable); + + /** + * Upgrade the current connection by setting up the SSL and perform the SSL handshake. + * + * @return operating result. + */ + bool connectSSL(); + + /** + * Upgrade the current connection by setting up the SSL and perform the SSL handshake. + * @param host The host to connect (unused). + * @param port The port to connect (unused). + * @return operating result. + */ + bool connectSSL(const String host, uint16_t port); + + /** + * Stop the TCP connection and release resources. + */ + void stop() override; + + /** + * Set the TCP timeout in seconds. + * @param seconds The TCP timeout in seconds. + */ + int setTimeout(uint32_t seconds); + + /** + * Get the TCP timeout in seconds. + * @return The TCP timeout in seconds. + */ + int getTimeout(); + + /** + * Set the SSL handshake timeout in seconds. + * @param handshake_timeout The SSL handshake timeout in seconds. + */ + void setHandshakeTimeout(unsigned long handshake_timeout); + + /** + * Wait for all receive buffer data read. + */ + void flush() override; + + /** + * Sets the requested buffer size for transmit and receive + * @param recv The receive buffer size. + * @param xmit The transmit buffer size. + */ + void setBufferSizes(int recv, int xmit); + + operator bool() { return connected(); } + + int availableForWrite(); + + void setSession(BearSSL_Session *session); + + void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN); + + /** + * Verify certificate's SHA256 fingerprint. + * + * @param fingerprint The certificate's SHA256 fingerprint data to compare with server certificate's SHA256 fingerprint. + * @return verification result. + */ + bool setFingerprint(const uint8_t fingerprint[20]); + + bool setFingerprint(const char *fpStr); + + void allowSelfSignedCerts(); + + void setTrustAnchors(const X509List *ta); + + void setX509Time(time_t now); + + void setClientRSACert(const X509List *cert, const PrivateKey *sk); + + void setClientECCert(const X509List *cert, const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type); + + int getMFLNStatus(); + + int getLastSSLError(char *dest = NULL, size_t len = 0); +#if defined(ESP_SSL_FS_SUPPORTED) + void setCertStore(CertStoreBase *certStore); +#endif + bool setCiphers(const uint16_t *cipherAry, int cipherCount); + + bool setCiphers(const std::vector &list); + + bool setCiphersLessSecure(); + + bool setSSLVersion(uint32_t min = BR_TLS10, uint32_t max = BR_TLS12); + + bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len); + + bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len); + + bool probeMaxFragmentLength(const String &host, uint16_t port, uint16_t len); + + bool hasPeekBufferAPI() const; + + size_t peekAvailable(); + + const char *peekBuffer(); + + void peekConsume(size_t consume); + + /** + * Set the Root CA or CA certificate. + * @param rootCA The Root CA or CA certificate. + */ + void setCACert(const char *rootCA); + + void setCertificate(const char *client_ca); + + void setPrivateKey(const char *private_key); + + /** + * Read and set CA cert from file (Stream). + * @param stream The Stream interface. + * @param size The size of data to read. + * @return The operating result. + */ + bool loadCACert(Stream &stream, size_t size); + + bool loadCertificate(Stream &stream, size_t size); + + bool loadPrivateKey(Stream &stream, size_t size); + + int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); + + int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); + + BSSL_TCP_Client &operator=(const BSSL_TCP_Client &other); + + bool operator==(const bool value) { return bool() == value; } + + bool operator!=(const bool value) { return bool() != value; } + + bool operator==(const BSSL_TCP_Client &); + + bool operator!=(const BSSL_TCP_Client &rhs) { return !this->operator==(rhs); }; + +private: + String _host; + uint16_t _port; + BSSL_SSL_Client _ssl_client; + Client *_basic_client = nullptr; + unsigned long _timeout = 15000; + unsigned long _handshake_timeout = 60000; + + char *mStreamLoad(Stream &stream, size_t size); +}; + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/Build_Options.h b/lib/libesp32/ESP-Mail-Client/src/extras/Build_Options.h new file mode 100644 index 000000000..a2251f896 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/Build_Options.h @@ -0,0 +1,52 @@ +#ifndef BUILD_OPTIONS_H +#define BUILD_OPTIONS_H + +#if defined(DISABLE_ALL_OPTIONS) +#undef ENABLE_NTP_TIME +#undef ENABLE_ERROR_STRING +#undef ENABLE_IMAP +#undef ENABLE_SMTP +#undef ESP_MAIL_USE_PSRAM +#undef ESP_MAIL_DEFAULT_SD_FS +#undef ESP_MAIL_CARD_TYPE_SD +#undef ESP_MAIL_CARD_TYPE_SD_MMC +#undef ESP_MAIL_DEFAULT_FLASH_FS +#undef ESP_MAIL_DEFAULT_DEBUG_PORT +#endif + +#if defined(DISABLE_NTP_TIME) +#undef ENABLE_NTP_TIME +#endif + +#if defined(DISABLE_ERROR_STRING) +#undef ENABLE_ERROR_STRING +#endif + +#if defined(DISABLE_IMAP) +#undef ENABLE_IMAP +#endif + +#if defined(DISABLE_SMTP) +#undef ENABLE_SMTP +#endif + +#if defined(DISABLE_PSRAM) +#undef ESP_MAIL_USE_PSRAM +#endif + +#if defined(DISABLE_SD) +#undef ESP_MAIL_DEFAULT_SD_FS +#undef ESP_MAIL_CARD_TYPE_SD_MMC +#undef ESP_MAIL_DEFAULT_FLASH_FS +#endif + +#if defined(DISABLE_FLASH) +#undef ESP_MAIL_DEFAULT_FLASH_FS +#undef ESP_MAIL_FORMAT_FLASH_IF_MOUNT_FAILED +#endif + +#if defined(ESP_MAIL_DEFAULT_DEBUG_PORT) +#undef ESP_MAIL_DEFAULT_DEBUG_PORT +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/ESP8266_Supports.h b/lib/libesp32/ESP-Mail-Client/src/extras/ESP8266_Supports.h new file mode 100644 index 000000000..5604690c6 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/ESP8266_Supports.h @@ -0,0 +1,52 @@ +#ifndef ESP8266_SUPPORTS_H +#define ESP8266_SUPPORTS_H +#include +#include "MB_MCU.h" +#if defined(ESP8266) || defined(MB_ARDUINO_PICO) + +#include + +//__GNUC__ +//__GNUC_MINOR__ +//__GNUC_PATCHLEVEL__ + +#ifdef __GNUC__ +#if __GNUC__ > 4 || __GNUC__ == 10 +#if defined(ARDUINO_ESP8266_GIT_VER) +#if ARDUINO_ESP8266_GIT_VER > 0 +#define ESP8266_CORE_SDK_V3_X_X +#endif +#endif +#endif +#endif + +#if defined __has_include + +#if __has_include() +#include +#endif + +#if __has_include()&& defined(ENABLE_ESP8266_ENC28J60_ETH) +#define INC_ENC28J60_LWIP +#include +#endif + +#if __has_include() && defined(ENABLE_ESP8266_W5100_ETH) +#define INC_W5100_LWIP +#include +#endif + +#if __has_include()&& defined(ENABLE_ESP8266_W5500_ETH) +#define INC_W5500_LWIP +#include +#endif + +#if defined(MB_ARDUINO_PICO) + +#endif + +#endif + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/MB_FS.h b/lib/libesp32/ESP-Mail-Client/src/extras/MB_FS.h new file mode 100644 index 000000000..96740627b --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/MB_FS.h @@ -0,0 +1,1137 @@ +/** + * The MB_FS, filesystems wrapper class v1.0.16 + * + * This wrapper class is for SD and Flash filesystems interface which supports SdFat (//https://github.com/greiman/SdFat) + * + * Created June 14, 2023 + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MBFS_CLASS_H +#define MBFS_CLASS_H + +#include +#include "MB_MCU.h" + +#define FS_NO_GLOBALS +#if defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO) +#if defined(MBFS_FLASH_FS) || defined(MBFS_SD_FS) +#include +#endif +#endif +#include "MB_FS_Interfaces.h" +#include MB_STRING_INCLUDE_CLASS + +#if defined(MBFS_FLASH_FS) || defined(MBFS_SD_FS) +#include "SPI.h" +#endif + +#if defined(ESP32) && __has_include() +#ifdef _LITTLEFS_H_ +#define MB_FS_USE_POSIX_STAT +#include +namespace mb_fs_ns +{ + inline bool exists(const char *mountPoint, const char *filename) + { + MB_String path = mountPoint; + path += filename; + struct stat st; + return stat(path.c_str(), &st) == 0; + } +}; +#endif +#endif + +using namespace mb_string; + +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) +#include +#endif + +#define MB_FS_ERROR_FILE_IO_ERROR -300 +#define MB_FS_ERROR_FILE_NOT_FOUND -301 +#define MB_FS_ERROR_FLASH_STORAGE_IS_NOT_READY -302 +#define MB_FS_ERROR_SD_STORAGE_IS_NOT_READY -303 +#define MB_FS_ERROR_FILE_STILL_OPENED -304 + +typedef enum +{ + mb_fs_mem_storage_type_undefined, + mb_fs_mem_storage_type_flash, + mb_fs_mem_storage_type_sd +} mb_fs_mem_storage_type; + +typedef enum +{ + mb_fs_open_mode_undefined = -1, + mb_fs_open_mode_read = 0, + mb_fs_open_mode_write, + mb_fs_open_mode_append +} mb_fs_open_mode; + +#define mbfs_file_type mb_fs_mem_storage_type +#define mbfs_flash mb_fs_mem_storage_type_flash +#define mbfs_sd mb_fs_mem_storage_type_sd +#define mbfs_undefined mb_fs_mem_storage_type_undefined + +#define mbfs_type (mbfs_file_type) + +#if defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) +#if !defined(MBFS_SDFAT_ENABLED) +struct mbfs_sd_config_info_t +{ + int ss = -1; +}; +#endif +#elif defined(ESP32) || defined(MBFS_SDFAT_ENABLED) + +#if defined(ESP32) +struct mbfs_sd_mmc_config_info_t +{ + const char *mountpoint = ""; + bool mode1bit = false; + bool format_if_mount_failed = false; +}; +#endif + +struct mbfs_sd_config_info_t +{ + int ss = -1; + int sck = -1; + int miso = -1; + int mosi = -1; + uint32_t frequency = 4000000; + +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + + SdSpiConfig *sdFatSPIConfig = nullptr; + SdioConfig *sdFatSDIOConfig = nullptr; + +#endif + +#if defined(ESP32) + +#if defined(MBFS_SD_FS) + SPIClass *spiConfig = nullptr; +#endif + mbfs_sd_mmc_config_info_t sdMMCConfig; +#endif + +#if defined(MBFS_SDFAT_ENABLED) + SPIClass *spiConfig = nullptr; +#endif +}; + +#elif defined(ESP8266) || defined(MB_ARDUINO_PICO) +struct mbfs_sd_config_info_t +{ + int ss = -1; +#if defined(MBFS_SD_FS) + SDFSConfig *sdFSConfig = nullptr; +#endif +}; +#else +struct mbfs_sd_config_info_t +{ + int ss = -1; +}; +#endif + +class MB_FS +{ + +public: + MB_FS() {} + ~MB_FS() {} + + struct mbfs_sd_config_info_t sd_config; + + // Assign the SD card interfaces with GPIO pins. + bool sdBegin(int ss = -1, int sck = -1, int miso = -1, int mosi = -1, uint32_t frequency = 4000000) + { + if (sd_rdy) + return true; + +#if defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD) + sd_config.ss = ss; +#if defined(ESP32) + sd_config.sck = sck; + sd_config.miso = miso; + sd_config.mosi = mosi; + SPI.begin(sck, miso, mosi, ss); + sd_config.frequency = frequency; + return sdSPIBegin(ss, &SPI, frequency); +#elif defined(ESP8266) || defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) + sd_rdy = MBFS_SD_FS.begin(ss); + return sd_rdy; +#elif defined(MB_ARDUINO_PICO) + SDFSConfig c; + c.setCSPin(ss); + c.setSPISpeed(frequency); + MBFS_SD_FS.setConfig(c); + sd_rdy = MBFS_SD_FS.begin(); + return sd_rdy; +#endif + +#endif + return false; + } + +#if defined(ESP32) && defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD) + + // Assign the SD card interfaces with SPIClass object pointer (ESP32 only). + bool sdSPIBegin(int ss, SPIClass *spiConfig, uint32_t frequency) + { + + if (sd_rdy) + return true; + + sd_config.frequency = frequency; + +#if defined(ESP32) + + sd_config.ss = ss; + + if (spiConfig) + sd_config.spiConfig = spiConfig; + else + sd_config.spiConfig = &SPI; + +#if !defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + if (ss > -1) + sd_rdy = MBFS_SD_FS.begin(ss, *sd_config.spiConfig, frequency); + else + sd_rdy = MBFS_SD_FS.begin(); +#endif + +#elif defined(ESP8266) || defined(MB_ARDUINO_PICO) + + cfg->_int.sd_config.sck = sck; + + if (ss > -1) + sd_rdy = MBFS_SD_FS.begin(ss); + else + sd_rdy = MBFS_SD_FS.begin(SD_CS_PIN); +#endif + + return sd_rdy; + } + +#endif + +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + + // Assign the SD card interfaces with SdSpiConfig object pointer and SPI pins assignment. + bool sdFatBegin(SdSpiConfig *sdFatSPIConfig, int ss, int sck, int miso, int mosi) + { + + if (sd_rdy) + return true; + + if (sdFatSPIConfig) + { + sd_config.sdFatSPIConfig = sdFatSPIConfig; + sd_config.spiConfig = &SPI; + sd_config.ss = ss; + +#if defined(ESP32) + if (ss > -1) + sd_config.spiConfig->begin(sck, miso, mosi, ss); +#endif + + sd_rdy = MBFS_SD_FS.begin(*sd_config.sdFatSPIConfig); + return sd_rdy; + } + + return false; + } + + // Assign the SD card interfaces with SdioConfig object pointer. + bool sdFatBegin(SdioConfig *sdFatSDIOConfig) + { + + if (sd_rdy) + return true; + +#if defined(HAS_SDIO_CLASS) // Default is 0 (no SDIO) in SdFatConfig.h + +#if HAS_SDIO_CLASS + + if (sdFatSDIOConfig) + { + sd_config.sdFatSDIOConfig = sdFatSDIOConfig; + + sd_rdy = MBFS_SD_FS.begin(*sd_config.sdFatSDIOConfig); + return sd_rdy; + } +#endif + +#endif + + return false; + } +#endif + +#if (defined(ESP8266) || defined(MB_ARDUINO_PICO)) && defined(MBFS_SD_FS) + // Assign the SD card interfaces with SDFSConfig object pointer (ESP8266 and Pico only). + bool sdFatBegin(SDFSConfig *sdFSConfig) + { + + if (sd_rdy) + return true; + + if (sdFSConfig) + { + sd_config.sdFSConfig = sdFSConfig; + SDFS.setConfig(*sd_config.sdFSConfig); + sd_rdy = SDFS.begin(); + return sd_rdy; + } + + return false; + } +#endif + + // Assign the SD_MMC card interfaces (ESP32 only). + bool sdMMCBegin(const char *mountpoint, bool mode1bit, bool format_if_mount_failed) + { + + if (sd_rdy) + return true; + +#if defined(ESP32) +#if defined(MBFS_CARD_TYPE_SD_MMC) + + sd_config.sdMMCConfig.mountpoint = mountpoint; + sd_config.sdMMCConfig.mode1bit = mode1bit; + sd_config.sdMMCConfig.format_if_mount_failed = format_if_mount_failed; + + sd_rdy = MBFS_SD_FS.begin(mountpoint, mode1bit, format_if_mount_failed); + return sd_rdy; +#endif +#endif + return false; + } + + // Check the mounting status of Flash storage. + bool flashReady() + { +#if defined MBFS_FLASH_FS + + if (flash_rdy) + return true; + +#if defined(ESP32) + +#if defined(MBFS_FORMAT_FLASH) + flash_rdy = MBFS_FLASH_FS.begin(true); +#else + flash_rdy = MBFS_FLASH_FS.begin(); +#endif + +#elif defined(ESP8266) || defined(MB_ARDUINO_PICO) + flash_rdy = MBFS_FLASH_FS.begin(); +#endif + +#endif + + return flash_rdy; + } + + // Check the mounting status of SD storage. + bool sdReady() + { + +#if defined(MBFS_SD_FS) + + if (sd_rdy) + return true; + +#if defined(ESP32) + +#if defined(MBFS_CARD_TYPE_SD) + + if (!sd_config.spiConfig) + { + if (sd_config.ss > -1) + SPI.begin(sd_config.sck, sd_config.miso, sd_config.mosi, sd_config.ss); + sd_config.spiConfig = &SPI; + } + +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + + if (!sd_rdy) + { + if (sd_config.sdFatSPIConfig) + sd_rdy = MBFS_SD_FS.begin(*sd_config.sdFatSPIConfig); + else if (sd_config.sdFatSDIOConfig) + sd_rdy = MBFS_SD_FS.begin(*sd_config.sdFatSDIOConfig); + } + +#else + if (!sd_rdy) + sd_rdy = sdSPIBegin(sd_config.ss, sd_config.spiConfig, sd_config.frequency); + +#endif + +#elif defined(MBFS_CARD_TYPE_SD_MMC) + if (!sd_rdy) + sd_rdy = sdMMCBegin(sd_config.sdMMCConfig.mountpoint, sd_config.sdMMCConfig.mode1bit, sd_config.sdMMCConfig.format_if_mount_failed); +#endif + +#elif defined(ESP8266) || defined(MB_ARDUINO_PICO) + if (!sd_rdy) + { + if (sd_config.sdFSConfig) + sd_rdy = sdFatBegin(sd_config.sdFSConfig); + else + sd_rdy = sdBegin(sd_config.ss); + } + +#elif defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) + if (!sd_rdy) + sd_rdy = sdBegin(sd_config.ss); +#endif + +#endif + + return sd_rdy; + } + + // Check the mounting status of Flash or SD storage with mb_fs_mem_storage_type. + bool checkStorageReady(mbfs_file_type type) + { + +#if defined(MBFS_USE_FILE_STORAGE) + if (type == mbfs_flash) + { + if (!flash_rdy) + flashReady(); + return flash_rdy; + } + else if (type == mbfs_sd) + { + if (!sd_rdy) + sdReady(); + return sd_rdy; + } +#endif + + return false; + } + + // Open file for read or write with file name, mb_fs_mem_storage_type and mb_fs_open_mode. + // return size of file (read) or 0 (write) or negative value for error + int open(const MB_String &filename, mbfs_file_type type, mb_fs_open_mode mode) + { + +#if defined(MBFS_USE_FILE_STORAGE) + + if (!checkStorageReady(type)) + { + if (type == mbfs_flash) + return MB_FS_ERROR_FLASH_STORAGE_IS_NOT_READY; + else if (type == mbfs_sd) + return MB_FS_ERROR_SD_STORAGE_IS_NOT_READY; + else + return MB_FS_ERROR_FILE_IO_ERROR; + } + + if (mode == mb_fs_open_mode_read) + { + if (!existed(filename.c_str(), type)) + return MB_FS_ERROR_FILE_NOT_FOUND; + } + + int ret = openFile(filename, type, mode); + + if (ret < 0) + return ret; + + if (ready(type)) + return ret; + +#endif + return MB_FS_ERROR_FILE_IO_ERROR; + } + + // Check if file is already open. + bool ready(mbfs_file_type type) + { +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + return true; +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs) + return true; +#endif + return false; + } + + // Get file for read/write with file name, mb_fs_mem_storage_type and mb_fs_open_mode. + int size(mbfs_file_type type) + { + int size = 0; + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + size = mb_flashFs.size(); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs) + size = mb_sdFs.size(); +#endif + return size; + } + + // Check if file is ready to read/write. + int available(mbfs_file_type type) + { + int available = 0; + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + available = mb_flashFs.available(); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs) + available = mb_sdFs.available(); +#endif + return available; + } + + // Read byte array. Return the number of bytes that completed read or negative value for error. + int read(mbfs_file_type type, uint8_t *buf, size_t len) + { + int read = 0; +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + read = mb_flashFs.read(buf, len); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs) + read = mb_sdFs.read(buf, len); +#endif + return read; + } + + // Print char array. Return the number of bytes that completed write or negative value for error. + int print(mbfs_file_type type, const char *str) + { + int write = 0; +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + write = mb_flashFs.print(str); +#endif +#if defined(MBFS_SD_FS) + + if (type == mbfs_sd && mb_sdFs) + write = mb_sdFs.print(str); +#endif + return write; + } + + // Print char array with new line. Return the number of bytes that completed write or negative value for error. + int println(mbfs_file_type type, const char *str) + { + int write = print(type, str); + if (write == (int)strlen(str)) + write += print(type, (const char *)MBSTRING_FLASH_MCR("\n")); + return write; + } + + // Print integer. Return the number of bytes that completed write or negative value for error. + int print(mbfs_file_type type, int v) + { + int write = 0; +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + write = mb_flashFs.print(v); +#endif +#if defined(MBFS_SD_FS) + + if (type == mbfs_sd && mb_sdFs) + write = mb_sdFs.print(v); +#endif + return write; + } + + // Print integer with newline. Return the number of bytes that completed write or negative value for error. + int println(mbfs_file_type type, int v) + { + int write = print(type, v); + if (write > 0) + write += print(type, (const char *)MBSTRING_FLASH_MCR("\n")); + return write; + } + + int print(mbfs_file_type type, unsigned int v) + { + int write = 0; +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + write = mb_flashFs.print(v); +#endif +#if defined(MBFS_SD_FS) + + if (type == mbfs_sd && mb_sdFs) + write = mb_sdFs.print(v); +#endif + return write; + } + + // Print integer with newline. Return the number of bytes that completed write or negative value for error. + int println(mbfs_file_type type, unsigned int v) + { + int write = print(type, v); + if (write > 0) + write += print(type, (const char *)MBSTRING_FLASH_MCR("\n")); + return write; + } + + // Write byte array. Return the number of bytes that completed write or negative value for error. + int write(mbfs_file_type type, uint8_t *buf, size_t len) + { + int write = 0; +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + write = mb_flashFs.write(buf, len); +#endif +#if defined(MBFS_SD_FS) + + if (type == mbfs_sd && mb_sdFs) + write = mb_sdFs.write(buf, len); +#endif + return write; + } + + // Close file. + void close(mbfs_file_type type) + { + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs && flash_opened) + { + mb_flashFs.close(); + flash_filename_crc = 0; + flash_opened = false; + flash_open_mode = mb_fs_open_mode_undefined; + } +#endif + +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs && sd_opened) + { + mb_sdFs.close(); + sd_filename_crc = 0; + sd_opened = false; + sd_open_mode = mb_fs_open_mode_undefined; + } +#endif + } + + // Check file existence. + bool existed(const MB_String &filename, mbfs_file_type type) + { + + if (!checkStorageReady(type)) + return false; + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash) + { + +// The workaround for ESP32 LittleFS when calling vfs_api.cpp open() issue. +// See https://github.com/espressif/arduino-esp32/issues/7615 +#if defined(MB_FS_USE_POSIX_STAT) + return mb_fs_ns::exists("/littlefs", filename.c_str()); +#else + return MBFS_FLASH_FS.exists(filename.c_str()); +#endif + } + +#endif + +#if defined(MBFS_SD_FS) + if (type == mbfs_sd) + { +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + MBFS_SD_FILE file; + bool ret = file.open(filename.c_str(), O_RDONLY); + file.close(); + return ret; +#else + return MBFS_SD_FS.exists(filename.c_str()); +#endif + } +#endif + + return false; + } + + // Seek to position in file. + bool seek(mbfs_file_type type, int pos) + { + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + return mb_flashFs.seek(pos); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs) + return mb_sdFs.seek(pos); +#endif + + return false; + } + + // Read byte. Return the 1 for completed read or negative value for error. + int read(mbfs_file_type type) + { +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + return mb_flashFs.read(); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs) + return mb_sdFs.read(); +#endif + return -1; + } + + // Write byte. Return the 1 for completed write or negative value for error. + int write(mbfs_file_type type, uint8_t v) + { +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + return mb_flashFs.write(v); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs) + return mb_sdFs.write(v); +#endif + return -1; + } + + bool remove(const MB_String &filename, mbfs_file_type type) + { + if (!checkStorageReady(type)) + return false; + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && !flashReady()) + return false; +#endif + +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && !sdReady()) + return false; +#endif + + if (!existed(filename, type)) + return true; + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash) + return MBFS_FLASH_FS.remove(filename.c_str()); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd) + { +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + if (mb_sdFs.open(filename.c_str(), O_RDWR | O_CREAT | O_APPEND)) + { + mb_sdFs.remove(); + mb_sdFs.close(); + return true; + } +#else + return MBFS_SD_FS.remove(filename.c_str()); +#endif + } + +#endif + return false; + } + +// Get the Flash file instance. +#if defined(MBFS_FLASH_FS) + fs::File &getFlashFile() + { + return mb_flashFs; + } +#endif + +// Get the SD file instance. +#if defined(MBFS_SD_FS) + MBFS_SD_FILE &getSDFile() + { + return mb_sdFs; + } +#endif + + // Get name of opened file. + const char *name(mbfs_file_type type) + { +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash && mb_flashFs) + return flash_file.c_str(); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd && mb_sdFs) + return sd_file.c_str(); +#endif + + return ""; + } + + // Calculate CRC16 of byte array. + uint16_t calCRC(const char *buf) + { + uint8_t x; + uint16_t crc = 0xFFFF; + + int length = (int)strlen(buf); + + while (length--) + { + x = crc >> 8 ^ *buf++; + x ^= x >> 4; + crc = (crc << 8) ^ ((uint16_t)(x << 12)) ^ ((uint16_t)(x << 5)) ^ ((uint16_t)x); + } + return crc; + } + + // Free reserved memory at pointer. + void delP(void *ptr) + { + void **p = (void **)ptr; + if (*p) + { + free(*p); + *p = 0; + } + } + + // Allocate memory + void *newP(size_t len, bool clear = true) + { + void *p; + size_t newLen = getReservedLen(len); +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + + if (ESP.getPsramSize() > 0) + p = (void *)ps_malloc(newLen); + else + p = (void *)malloc(newLen); + + if (!p) + return NULL; + +#else + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.setExternalHeap(); +#endif + + p = (void *)malloc(newLen); + bool nn = p ? true : false; + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.resetHeap(); +#endif + + if (!nn) + return NULL; + +#endif + if (clear) + memset(p, 0, newLen); + return p; + } + + size_t getReservedLen(size_t len) + { + int blen = len + 1; + + int newlen = (blen / 4) * 4; + + if (newlen < blen) + newlen += 4; + + return (size_t)newlen; + } + + void createDirs(MB_String dirs, mbfs_file_type type) + { + if (!longNameSupported()) + return; + + MB_String dir; + int count = 0; + int lastPos = 0; + for (size_t i = 0; i < dirs.length(); i++) + { + dir.append(1, dirs[i]); + count++; + if (dirs[i] == '/' && i > 0) + { + if (dir.length() > 0) + { + + lastPos = dir.length() - 1; + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash) + MBFS_FLASH_FS.mkdir(dir.substr(0, dir.length() - 1).c_str()); +#endif + +#if defined(MBFS_SD_FS) + if (type == mbfs_sd) + MBFS_SD_FS.mkdir(dir.substr(0, dir.length() - 1).c_str()); +#endif + } + count = 0; + } + } + + if (count > 0) + { + if (dir.find('.', lastPos) == MB_String::npos) + { +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash) + MBFS_FLASH_FS.mkdir(dir.c_str()); +#endif + +#if defined(MBFS_SD_FS) + if (type == mbfs_sd) + MBFS_SD_FS.mkdir(dir.c_str()); +#endif + } + } + + dir.clear(); + } + + bool longNameSupported() + { + +#if defined(MBFS_SDFAT_ENABLED) || defined(MBFS_FLASH_FS) + return true; +#endif + +#if defined(MBFS_SD_FS) && (defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO)) + return true; +#endif + + return false; + } + +private: + uint16_t flash_filename_crc = 0; + uint16_t sd_filename_crc = 0; + MB_String flash_file, sd_file; + mb_fs_open_mode flash_open_mode = mb_fs_open_mode_undefined; + mb_fs_open_mode sd_open_mode = mb_fs_open_mode_undefined; + bool flash_opened = false; + bool sd_opened = false; + bool sd_rdy = false; + bool flash_rdy = false; + uint16_t loopCount = 0; + +#if defined(MBFS_FLASH_FS) + fs::File mb_flashFs; +#endif +#if defined(MBFS_SD_FS) + MBFS_SD_FILE mb_sdFs; +#endif + + int openFile(const MB_String &filename, mb_fs_mem_storage_type type, mb_fs_open_mode mode) + { + +#if defined(MBFS_FLASH_FS) + if (type == mbfs_flash) + return openFlashFile(filename, mode); +#endif +#if defined(MBFS_SD_FS) + if (type == mbfs_sd) + return openSDFile(filename, mode); +#endif + return MB_FS_ERROR_FILE_IO_ERROR; + } + + int openSDFile(const MB_String &filename, mb_fs_open_mode mode) + { + int ret = MB_FS_ERROR_FILE_IO_ERROR; + +#if defined(MBFS_SD_FS) + + if (mode == mb_fs_open_mode_read || mode == mb_fs_open_mode_write || mode == mb_fs_open_mode_append) + { + uint16_t crc = calCRC(filename.c_str()); + + if (mode == sd_open_mode && flash_filename_crc == crc && sd_opened) // same sd file opened, leave it + return MB_FS_ERROR_FILE_STILL_OPENED; + + if (sd_opened) + close(mbfs_sd); // sd file opened, close it + + flash_filename_crc = crc; + } + +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + + if (mode == mb_fs_open_mode_read) + { + if (mb_sdFs.open(filename.c_str(), O_RDONLY)) + { + sd_file = filename; + sd_opened = true; + sd_open_mode = mode; + ret = mb_sdFs.size(); + } + } + else if (mode == mb_fs_open_mode_write || mode == mb_fs_open_mode_append) + { + if (mode == mb_fs_open_mode_write) + remove(filename, mb_fs_mem_storage_type_sd); + + createDirs(filename, mb_fs_mem_storage_type_sd); + if (mb_sdFs.open(filename.c_str(), O_RDWR | O_CREAT | O_APPEND)) + { + sd_file = filename; + sd_opened = true; + sd_open_mode = mode; + ret = 0; + } + } + +#else + + if (mode == mb_fs_open_mode_read) + { +#if defined(ESP32) || defined(ESP8266) + mb_sdFs = MBFS_SD_FS.open(filename.c_str(), FILE_READ); +#else + mb_sdFs = MBFS_SD_FS.open(filename.c_str(), "r"); +#endif + if (mb_sdFs) + { + sd_file = filename; + sd_opened = true; + sd_open_mode = mode; + ret = mb_sdFs.size(); + } + } + else if (mode == mb_fs_open_mode_write || mode == mb_fs_open_mode_append) + { + if (mode == mb_fs_open_mode_write) + remove(filename, mb_fs_mem_storage_type_sd); + + createDirs(filename, mb_fs_mem_storage_type_sd); +#if defined(ESP32) + if (mode == mb_fs_open_mode_write) + mb_sdFs = MBFS_SD_FS.open(filename.c_str(), FILE_WRITE); + else + mb_sdFs = MBFS_SD_FS.open(filename.c_str(), FILE_APPEND); +#elif defined(ESP8266) + mb_sdFs = MBFS_SD_FS.open(filename.c_str(), FILE_WRITE); +#else + if (mode == mb_fs_open_mode_write) + mb_sdFs = MBFS_SD_FS.open(filename.c_str(), "w"); + else + mb_sdFs = MBFS_SD_FS.open(filename.c_str(), "a"); +#endif + + if (mb_sdFs) + { + sd_file = filename; + sd_opened = true; + sd_open_mode = mode; + ret = 0; + } + } +#endif + +#endif + return ret; + } + + int openFlashFile(const MB_String &filename, mb_fs_open_mode mode) + { + int ret = MB_FS_ERROR_FILE_IO_ERROR; + +#if defined(MBFS_FLASH_FS) + + if (mode == mb_fs_open_mode_read || mode == mb_fs_open_mode_write || mode == mb_fs_open_mode_append) + { + uint16_t crc = calCRC(filename.c_str()); + if (mode == flash_open_mode && sd_filename_crc == crc && flash_opened) // same flash file opened, leave it + return MB_FS_ERROR_FILE_STILL_OPENED; + + if (flash_opened) + close(mbfs_flash); // flash file opened, close it + + sd_filename_crc = crc; + } + + if (mode == mb_fs_open_mode_read) + { + mb_flashFs = MBFS_FLASH_FS.open(filename.c_str(), "r"); + if (mb_flashFs) + { + flash_file = filename; + flash_opened = true; + flash_open_mode = mode; + ret = mb_flashFs.size(); + } + } + else if (mode == mb_fs_open_mode_write || mode == mb_fs_open_mode_append) + { + if (mode == mb_fs_open_mode_write) + remove(filename, mb_fs_mem_storage_type_flash); + + createDirs(filename, mb_fs_mem_storage_type_flash); + if (mode == mb_fs_open_mode_write) + mb_flashFs = MBFS_FLASH_FS.open(filename.c_str(), "w"); + else + mb_flashFs = MBFS_FLASH_FS.open(filename.c_str(), "a"); + + if (mb_flashFs) + { + flash_file = filename; + flash_opened = true; + flash_open_mode = mode; + ret = 0; + } + } + +#endif + return ret; + } +}; + +#endif diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/MB_FS_Interfaces.h b/lib/libesp32/ESP-Mail-Client/src/extras/MB_FS_Interfaces.h new file mode 100644 index 000000000..9bdc1e75d --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/MB_FS_Interfaces.h @@ -0,0 +1,94 @@ +#pragma once + +/* Convert specific definitions to MB_FS definitions */ +#ifndef MB_FS_INTERFACES_H +#define MB_FS_INTERFACES_H + +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +// include definitions file +#include "./ESP_Mail_FS.h" + +// 1. ESP_MAIL_DEFAULT_FLASH_FS -> MBFS_FLASH_FS +#if defined ESP_MAIL_DEFAULT_FLASH_FS +#define MBFS_FLASH_FS ESP_MAIL_DEFAULT_FLASH_FS +#endif + +// 2. ESP_MAIL_DEFAULT_SD_FS -> MBFS_SD_FS +#if defined ESP_MAIL_DEFAULT_SD_FS +#define MBFS_SD_FS ESP_MAIL_DEFAULT_SD_FS +#endif + +// 3. ESP_MAIL_CARD_TYPE_SD -> MBFS_CARD_TYPE_SD +#if defined(ESP_MAIL_CARD_TYPE_SD) +#define MBFS_CARD_TYPE_SD /* */ ESP_MAIL_CARD_TYPE_SD +#endif + +// 4. ESP_MAIL_CARD_TYPE_SD_MMC -> MBFS_CARD_TYPE_SD_MMC +#if defined(ESP_MAIL_CARD_TYPE_SD_MMC) +#define MBFS_CARD_TYPE_SD_MMC /* */ ESP_MAIL_CARD_TYPE_SD_MMC +#endif + +// 5. ESP_MAIL_FORMAT_FLASH_IF_MOUNT_FAILED -> MBFS_FORMAT_FLASH +#if defined(ESP_MAIL_FORMAT_FLASH_IF_MOUNT_FAILED) +#define MBFS_FORMAT_FLASH /* */ ESP_MAIL_FORMAT_FLASH_IF_MOUNT_FAILED +#endif + +#if defined(MBFS_SD_FS) || defined(MBFS_FLASH_FS) +#define MBFS_USE_FILE_STORAGE +#endif + +// Only SdFat library from Bill Greiman +#if defined(ESP32) && defined(SD_FAT_VERSION) && defined(SD_FAT_VERSION_STR) && defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD) +#define MBFS_ESP32_SDFAT_ENABLED +#ifndef ESP_MAIL_USE_SDFAT +#define ESP_MAIL_USE_SDFAT +#endif +#endif + +// Only SdFat library from Bill Greiman +#if !defined(ESP32) && !defined(ESP8266) && !defined(ARDUINO_ARCH_RP2040) && defined(SD_FAT_VERSION) && defined(SD_FAT_VERSION_STR) && defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD) +#define MBFS_SDFAT_ENABLED +#ifndef ESP_MAIL_USE_SDFAT +#define ESP_MAIL_USE_SDFAT +#endif +#endif + +// For MB_String +#if defined(ESP_MAIL_USE_PSRAM) +#define MB_STRING_USE_PSRAM +#endif + +#if defined(MBFS_SD_FS) + +#if !defined(ESP_MAIL_SD_FILE) + +#if defined(MBFS_ESP32_SDFAT_ENABLED) +#define MBFS_SD_FILE SdFile +#else +#if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_ARCH_RP2040) +#define MBFS_SD_FILE fs::File +#else +#define MBFS_SD_FILE File +#endif + +#endif + +#else + +#define MBFS_SD_FILE ESP_MAIL_SD_FILE + +#endif + +#endif + +#ifndef MB_STRING_INCLUDE_CLASS +#define MB_STRING_INCLUDE_CLASS "MB_String.h" +#endif + + + +#endif /* MB_FS_INTERFACES_H */ diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/MB_MCU.h b/lib/libesp32/ESP-Mail-Client/src/extras/MB_MCU.h new file mode 100644 index 000000000..3009e67bb --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/MB_MCU.h @@ -0,0 +1,67 @@ +#pragma once + +#ifndef MB_MCU_H +#define MB_MCU_H + + +#if defined(ESP8266) || defined(ESP32) +#ifndef MB_ARDUINO_ESP +#define MB_ARDUINO_ESP +#endif +#endif + +#if defined(__arm__) +#ifndef MB_ARDUINO_ARM +#define MB_ARDUINO_ARM +#endif +#endif + +// Renesas +#if defined(ARDUINO_PORTENTA_C33) + +#endif + +// Renesas +#if defined(ARDUINO_UNOWIFIR4) + +#endif + +// Renesas +#if defined(ARDUINO_MINIMA) + +#endif + +#if defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) || defined(ARDUINO_PORTENTA_X8) + +#endif + + +#if defined(ARDUINO_ARCH_SAMD) +#ifndef MB_ARDUINO_ARCH_SAMD +#define MB_ARDUINO_ARCH_SAMD +#endif +#endif + +#if defined(ARDUINO_ARCH_RP2040) + +#if defined(ARDUINO_NANO_RP2040_CONNECT) +#ifndef MB_ARDUINO_NANO_RP2040_CONNECT +#define MB_ARDUINO_NANO_RP2040_CONNECT +#endif +#else +#ifndef MB_ARDUINO_PICO +#define MB_ARDUINO_PICO +#endif +#endif + +#endif + + +#if defined(TEENSYDUINO) +#ifndef MB_ARDUINO_TEENSY +#define MB_ARDUINO_TEENSY +#endif +#endif + + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/MB_String.h b/lib/libesp32/ESP-Mail-Client/src/extras/MB_String.h new file mode 100644 index 000000000..775ade48d --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/MB_String.h @@ -0,0 +1,2075 @@ + +/** + * Mobizt's SRAM/PSRAM supported String, version 1.2.9 + * + * Created December 3, 2022 + * + * Changes Log + * + * v1.2.9 + * - substring optimization + * + * v1.2.8 + * - Add support StringSumHelper class in Arduino + * + * v1.2.7 + * - Fix string sub type checking issue + * + * v1.2.6 + * - Update trim() function + * + * v1.2.5 + * - Fixed double string issue and add support long double + * + * v1.2.4 + * - Check PSRAM availability before allocating the memory + * + * v1.2.3 + * - Fixed flash string F and PSTR handle + * + * v1.2.2 + * - Add supports more MCUs. + * + * v1.2.1 + * - Add flash string manipulation functions. + * + * v1.2.0 + * - Add supports bool, integer and float manipulation. + * + * v1.1.2 + * - Fix substring with zero length returns the original string issue. + * + * v1.1.1 + * - Fix possible ESP8266 code exit without resetting the external heap stack + * + * v1.1.0 + * - Add support ESP8266 external virtual RAM (SRAM or PSRAM) + * + * v1.0.1 + * - Add trim function + * - Add version enum + * + * v1.0.0 + * - Initial release + * + * The MIT License (MIT) + * Copyright (c) 2023 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MB_String_H +#define MB_String_H + +#include +#if !defined(__AVR__) +#include +#include +#include +#endif + +#define MB_STRING_MAJOR 1 +#define MB_STRING_MINOR 2 +#define MB_STRING_PATCH 5 + +#if defined(ESP8266) && defined(MMU_EXTERNAL_HEAP) && defined(MB_STRING_USE_PSRAM) +#include +#include +#define ESP8266_USE_EXTERNAL_HEAP +#endif + +#if defined(ESP8266) || defined(ESP32) +#define MBSTRING_FLASH_MCR FPSTR +#elif defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) +#define MBSTRING_FLASH_MCR PSTR +#else +#define MBSTRING_FLASH_MCR(s) (s) +#endif + +class MB_String; + +#define pgm2Str(p) (MB_String().appendP(p).c_str()) +#define num2Str(v, p) (MB_String().appendNum(v, p).c_str()) + +#if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4) +#define MB_IS_SAME std::is_same +#define MB_ENABLE_IF std::enable_if +#else +#define MB_IS_SAME is_same +#define MB_ENABLE_IF enable_if +#endif + +namespace mb_string +{ + enum mb_string_sub_type + { + mb_string_sub_type_none, + mb_string_sub_type_bool, + mb_string_sub_type_float, + mb_string_sub_type_double, + mb_string_sub_type_int8, + mb_string_sub_type_uint8, + mb_string_sub_type_int16, + mb_string_sub_type_uint16, + mb_string_sub_type_int32, + mb_string_sub_type_uint32, + mb_string_sub_type_int64, + mb_string_sub_type_uint64, + mb_string_sub_type_cstring, + mb_string_sub_type_chars, + mb_string_sub_type_mb_string, + mb_string_sub_type_arduino_string, + mb_string_sub_type_std_string, + mb_string_sub_type_fptr, + mb_string_sub_type_string_sum_helper + + }; + + typedef struct mb_string_ptr_t + { + + public: + mb_string_ptr_t(uint32_t addr = 0, mb_string_sub_type type = mb_string_sub_type_cstring, int precision = -1, const StringSumHelper *s = nullptr) + { + _addr = addr; + _type = type; + _precision = precision; + _ssh = s; + } + int precision() { return _precision; } + mb_string_sub_type type() { return _type; } + uint32_t address() { return _addr; } + const StringSumHelper *stringsumhelper() { return _ssh; } + + private: + mb_string_sub_type _type = mb_string_sub_type_none; + int _precision = -1; + uint32_t _addr = 0; + const StringSumHelper *_ssh = nullptr; + + } MB_StringPtr; + + template + struct enable_if + { + }; + template + struct enable_if + { + typedef T type; + }; + template + struct is_same + { + static bool const value = false; + }; + template + struct is_same + { + static bool const value = true; + }; + + template + struct is_num_int8 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_uint8 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_int16 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_uint16 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_int32 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value || + MB_IS_SAME::value || MB_IS_SAME::value || + MB_IS_SAME::value; + }; + + template + struct is_num_uint32 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value || + MB_IS_SAME::value; + }; + + template + struct is_num_int64 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_uint64 + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_num_neg_int + { + static bool const value = is_num_int8::value || is_num_int16::value || + is_num_int32::value || is_num_int64::value; + }; + + template + struct is_num_pos_int + { + static bool const value = is_num_uint8::value || is_num_uint16::value || + is_num_uint32::value || is_num_uint64::value; + }; + + template + struct is_num_int + { + static bool const value = is_num_pos_int::value || is_num_neg_int::value; + }; + + template + struct is_num_float + { + static bool const value = MB_IS_SAME::value || MB_IS_SAME::value || MB_IS_SAME::value; + }; + + template + struct is_bool + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct cs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct ccs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct as_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct cas_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct ss_t + { +#if !defined(__AVR__) + static bool const value = MB_IS_SAME::value; +#else + static bool const value = false; +#endif + }; + + template + struct css_t + { +#if !defined(__AVR__) + static bool const value = MB_IS_SAME::value; +#else + static bool const value = false; +#endif + }; + + template + struct ssh_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct fs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct mbs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct cmbs_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct pgm_t + { + static bool const value = MB_IS_SAME::value; + }; + + template + struct is_const_chars + { + static bool const value = cs_t::value || ccs_t::value; + }; + + template + struct is_arduino_string + { + static bool const value = as_t::value || cas_t::value; + }; + + template + struct is_std_string + { + static bool const value = ss_t::value || css_t::value; + }; + + template + struct is_mb_string + { + static bool const value = mbs_t::value || cmbs_t::value; + }; + + template + struct is_arduino_string_sum_helper + { + static bool const value = ssh_t::value; + }; + + template + struct is_arduino_flash_string_helper + { + static bool const value = fs_t::value; + }; + + template + struct is_string + { + static bool const value = is_const_chars::value || is_arduino_string::value || + is_arduino_string_sum_helper::value || is_arduino_flash_string_helper::value || + is_std_string::value || is_mb_string::value; + }; + + template + uint32_t toAddr(T &v) { return reinterpret_cast(&v); } + +#if defined(__AVR__) + template + T addrTo(int address) + { + return reinterpret_cast(address); + } +#else + template + auto addrTo(int address) -> typename MB_ENABLE_IF::value, T>::type + { + return reinterpret_cast(address); + } +#endif + + template + auto getSubType(T val) -> typename MB_ENABLE_IF::value || is_num_float::value || MB_IS_SAME::value || is_const_chars::value || is_arduino_flash_string_helper::value || is_arduino_string::value || is_std_string::value || is_mb_string::value || MB_IS_SAME::value, mb_string_sub_type>::type + { + if (is_num_uint64::value) + return mb_string_sub_type_uint64; + else if (is_num_int64::value) + return mb_string_sub_type_int64; + else if (is_num_uint32::value) + return mb_string_sub_type_uint32; + else if (is_num_int32::value) + return mb_string_sub_type_int32; + else if (is_num_uint16::value) + return mb_string_sub_type_uint16; + else if (is_num_int16::value) + return mb_string_sub_type_int16; + else if (is_num_uint8::value) + return mb_string_sub_type_uint8; + else if (is_num_int8::value) + return mb_string_sub_type_int8; + else if (MB_IS_SAME::value) + return mb_string_sub_type_bool; + else if (MB_IS_SAME::value) + return mb_string_sub_type_float; + else if (MB_IS_SAME::value) + return mb_string_sub_type_double; + else if (is_arduino_string::value) + return mb_string_sub_type_arduino_string; + else if (is_std_string::value) + return mb_string_sub_type_std_string; + else if (is_mb_string::value) + return mb_string_sub_type_mb_string; + else if (is_arduino_flash_string_helper::value) + return mb_string_sub_type_fptr; + else if (MB_IS_SAME::value) + return mb_string_sub_type_string_sum_helper; + else if (ccs_t::value) + return mb_string_sub_type_cstring; + else if (cs_t::value) + return mb_string_sub_type_chars; + + return mb_string_sub_type_int8; + } + + template + auto getSubType(T *val) -> typename MB_ENABLE_IF::value || is_num_float::value || MB_IS_SAME::value || is_const_chars::value || is_arduino_flash_string_helper::value || is_arduino_string::value || is_std_string::value || is_mb_string::value || MB_IS_SAME::value, mb_string_sub_type>::type + { + return getSubType(*val); + } + + template + auto toStringPtr(const T &val) -> typename MB_ENABLE_IF::value || is_arduino_string::value || is_mb_string::value, MB_StringPtr>::type + { + return MB_StringPtr(reinterpret_cast(&val), getSubType(val)); + } + + template + auto toStringPtr(const T &val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type + { +#if defined(ESP8266) + return MB_StringPtr(reinterpret_cast(&val), getSubType(val), -1); + +#else + return MB_StringPtr(reinterpret_cast(&val), getSubType(val), -1, &val); +#endif + } + + template + auto toStringPtr(T val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type { return MB_StringPtr(reinterpret_cast(val), getSubType(val)); } + + template + auto toStringPtr(T &val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type { return MB_StringPtr(reinterpret_cast(val), getSubType(val)); } + +#if !defined(__AVR__) + template + auto toStringPtr(T val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type + { + return MB_StringPtr(); + } +#endif + + template + auto toStringPtr(T val) -> typename MB_ENABLE_IF::value, MB_StringPtr>::type + { + return val; + } + + template + auto toStringPtr(T &val, int precision = -1) -> typename MB_ENABLE_IF::value || is_num_float::value || MB_IS_SAME::value, MB_StringPtr>::type { return MB_StringPtr(reinterpret_cast(&val), getSubType(val), precision); } +} + +using namespace mb_string; + +class MB_String +{ +public: + MB_String() + { +#if defined(ESP8266_USE_EXTERNAL_HEAP) + // reserve default 1 byte external heap to refer to its pointer later + reset(1); +#endif + }; + + ~MB_String() + { + allocate(0, false); + }; + + MB_String(const char *cstr) + { + if (cstr) + copy(cstr, strlen_P(cstr)); + } + + MB_String(const MB_String &value) + { + *this = value; + } + + MB_String(const __FlashStringHelper *str) + { + *this = str; + } + +#if !defined(ESP8266) + MB_String(StringSumHelper rval) + { + *this = rval; + } +#endif + + MB_String(MB_StringPtr value) + { + *this = value; + } + + MB_String(String value) + { + *this = value; + } + + MB_String(bool value) + { + appendNum(value); + } + + MB_String(unsigned char value, unsigned char base = 10) + { + int len = 1 + 8 * sizeof(unsigned char); + reserve(len); + + if (bufLen > 0) + utoa(value, buf, base); + } + + MB_String(int value, unsigned char base = 10) + { + int len = 2 + 8 * sizeof(int); + reserve(len); + + if (bufLen > 0) + { + if (base == 10) + sprintf(buf, (const char *)MBSTRING_FLASH_MCR("%d"), value); + else + itoa(value, buf, base); + } + } + + MB_String(unsigned int value, unsigned char base = 10) + { + int len = 1 + 8 * sizeof(unsigned int); + reserve(len); + + if (bufLen > 0) + utoa(value, buf, base); + } + + MB_String(long value, unsigned char base = 10) + { + int len = 2 + 8 * sizeof(long); + reserve(len); + + if (bufLen > 0) + { + if (base == 10) + sprintf(buf, (const char *)MBSTRING_FLASH_MCR("%ld"), value); + else + ltoa(value, buf, base); + } + } + + MB_String(unsigned long value, unsigned char base = 10) + { + int len = 1 + 8 * sizeof(unsigned long); + reserve(len); + + if (bufLen > 0) + ultoa(value, buf, base); + } + + MB_String(float value, unsigned char decimalPlaces = 2) + { + reserve(33); + if (bufLen > 0) + { + char *v = toFloatStr(value, 0, decimalPlaces); + if (v) + { + strcpy(buf, v); + delP(&v); + } + } + } + + MB_String(double value, unsigned char decimalPlaces = 3) + { + reserve(33); + + if (bufLen > 0) + { + char *v = toFloatStr(value, 1, decimalPlaces); + if (v) + { + strcpy(buf, v); + delP(&v); + } + } + } + + MB_String(long double value, unsigned char decimalPlaces = 3) + { + reserve(65); + if (bufLen > 0) + { + char *v = toFloatStr(value, 2, decimalPlaces); + if (v) + { + strcpy(buf, v); + delP(&v); + } + } + } + +#if !defined(__AVR__) + MB_String &operator=(const std::string &rhs) + { + if (rhs.length() > 0) + copy(rhs.c_str(), rhs.length()); + else + clear(); + + return *this; + } +#endif + MB_String &operator=(const String &rhs) + { + + if (rhs.length() > 0) + copy(rhs.c_str(), rhs.length()); + else + clear(); + + return *this; + } + + MB_String &operator=(const __FlashStringHelper *str) + { + if (str) + appendF(str, true); + + return *this; + } + +#if !defined(ESP8266) + MB_String &operator=(StringSumHelper rval) + { + String temp = rval; + *this = temp; + return *this; + } + + MB_String &operator+=(StringSumHelper rval) + { + String temp = rval; + *this += temp; + return *this; + } +#endif + + MB_String &operator+=(const __FlashStringHelper *str) + { + if (str) + appendF(str); + + return *this; + } + + unsigned char operator==(const MB_String &rhs) const + { + return equals(rhs); + } + + unsigned char operator==(const char *cstr) const + { + return equals(cstr); + } + + unsigned char operator!=(const MB_String &rhs) const + { + return !equals(rhs); + } + + unsigned char operator!=(const char *cstr) const + { + return !equals(cstr); + } +#if !defined(__AVR__) + MB_String &operator+=(const std::string &rhs) + { + concat(rhs.c_str()); + return (*this); + } +#endif + MB_String &operator+=(const String &rhs) + { + concat(rhs.c_str()); + return (*this); + } + + MB_String &operator=(const MB_String &rhs) + { + if (this == &rhs) + return *this; + + if (rhs.length() > 0) + copy(rhs.buf, rhs.length()); + else + clear(); + + return *this; + } + + MB_String &operator+=(const MB_String &rhs) + { + concat(rhs); + return (*this); + } + + MB_String &operator+=(const char *cstr) + { + size_t len = strlen_P(cstr); + size_t slen = length(); + + if (_reserve(slen + len, false)) + { + strcat_P(buf, (PGM_P)cstr); + *(buf + slen + len) = '\0'; + } + + return (*this); + } + + MB_String &operator+=(char cstr) + { + append(1, cstr); + return (*this); + } + + MB_String &operator+=(bool value) + { + appendNum(value); + return (*this); + } + + MB_String &operator=(MB_StringPtr ptr) + { + setPtr(ptr); + return (*this); + } + + MB_String &operator+=(MB_StringPtr ptr) + { + appendPtr(ptr); + return (*this); + } + + template + auto operator=(T value) -> typename MB_ENABLE_IF::value || is_num_float::value || is_bool::value, MB_String &>::type + { + clear(); + appendNum(value); + return (*this); + } + + template + auto operator+=(T value) -> typename MB_ENABLE_IF::value || is_num_float::value || is_bool::value, MB_String &>::type + { + appendNum(value); + return (*this); + } + + MB_String &appendP(PGM_P pgms, bool clear = false) + { + if (clear) + this->clear(); + + char *t = pgmStr(pgms); + if (t) + { + *this += t; + delP(&t); + } + + return (*this); + } + + MB_String &appendF(const __FlashStringHelper *pstr, bool clear = false) + { + if (clear) + this->clear(); + + int len = strlen_P((PGM_P)pstr); + if (len > 0) + { + unsigned int newlen = length() + len; + reserve(newlen); + + if (bufLen > 0) + memcpy_P(buf + length(), (PGM_P)pstr, len + 1); + } + + return (*this); + } + + MB_String &setPtr(MB_StringPtr src) + { + clear(); + appendPtr(src); + return (*this); + }; + + MB_String &appendPtr(MB_StringPtr src) + { + if (src.type() == mb_string_sub_type_fptr) + appendF(addrTo(src.address())); + else if (src.type() == mb_string_sub_type_cstring || src.type() == mb_string_sub_type_chars) + *this += addrTo(src.address()); + else if (src.type() == mb_string_sub_type_arduino_string) + *this += *addrTo(src.address()); + else if (src.type() == mb_string_sub_type_string_sum_helper) +#if !defined(ESP8266) + *this += *src.stringsumhelper(); +#else + *this += *addrTo(src.address()); +#endif +#if !defined(__AVR__) + else if (src.type() == mb_string_sub_type_std_string) + *this += *addrTo(src.address()); +#endif + else if (src.type() == mb_string_sub_type_mb_string) + *this += *addrTo(src.address()); + else if (src.type() == mb_string_sub_type_uint64) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_int64) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_uint32) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_int32) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_uint16) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_int16) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_uint8) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_int8) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_bool) + appendNum(*addrTo(src.address())); + else if (src.type() == mb_string_sub_type_float) + appendNum(*addrTo(src.address()), src.precision()); + else if (src.type() == mb_string_sub_type_double) + appendNum(*addrTo(src.address()), src.precision()); + + return (*this); + }; + + template + auto appendNum(T value, int precision = 0) -> typename MB_ENABLE_IF::value || is_bool::value, MB_String &>::type + { + char *s = NULL; + + if (is_bool::value) + s = boolStr(value); + else if (is_num_neg_int::value) + { +#if defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) + s = int32Str(value); +#else + s = int64Str(value); +#endif + } + else if (is_num_pos_int::value) + { +#if defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) + s = uint32Str(value); +#else + s = uint64Str(value); +#endif + } + + if (s) + { + *this += s; + delP(&s); + } + + return (*this); + } + + MB_String &appendNum(float value, int precision = 5) + { + if (precision < 0) + precision = 5; + + char *s = toFloatStr(value, 0, precision); + if (s) + { + *this += s; + delP(&s); + } + return (*this); + } + + MB_String &appendNum(double value, int precision = 9) + { + if (precision < 0) + precision = 9; + + char *s = toFloatStr(value, 1, precision); + if (s) + { + *this += s; + delP(&s); + } + return (*this); + } + + MB_String &appendNum(long double value, int precision = 9) + { + if (precision < 0) + precision = 9; + + char *s = toFloatStr(value, 2, precision); + if (s) + { + *this += s; + delP(&s); + } + return (*this); + } + + MB_String &operator=(const char *cstr) + { + if (cstr) + copy(cstr, strlen_P(cstr)); + else + clear(); + + return *this; + } + + MB_String &operator=(char c) + { + clear(); + if (_reserve(1, false)) + { + *(buf) = c; + *(buf + 1) = '\0'; + } + + return *this; + } + + void trim() + { + int p1 = 0, p2 = length() - 1; + while (p1 < (int)length()) + { + if (buf[p1] > 32) + break; + p1++; + } + + while (p2 >= 0) + { + if (buf[p2] > 32) + break; + p2--; + } + + if (p1 == (int)length() && p2 < 0) + { + clear(); + return; + } + + if (p2 >= p1 && p2 >= 0 && p1 < (int)length()) + { + memmove(buf, buf + p1, p2 - p1 + 1); + buf[p2 - p1 + 1] = '\0'; + _reserve(p2 - p1 + 1, true); + } + } + + void append(const char *cstr, size_t n) + { + if (!cstr) + return; + + size_t slen = length(); + + if (n > strlen(cstr)) + n = strlen(cstr); + + if (_reserve(slen + n, false)) + { + memmove(buf + slen, cstr, n); + *(buf + slen + n) = '\0'; + } + } + + void append(size_t n, char c) + { + size_t slen = length(); + + if (_reserve(slen + n, false)) + { + for (size_t i = 0; i < n; i++) + *(buf + slen + i) = c; + *(buf + slen + n) = '\0'; + } + } + + void prepend(char c) + { + size_t slen = length(); + size_t len = 1; + + if (maxLength() < slen + len) + _reserve(slen + len, false); + + memmove(buf + len, buf, slen); + buf[0] = c; + buf[len + slen] = '\0'; + } + + void prepend(const char *cstr) + { + size_t slen = length(); + size_t len = strlen(cstr); + + if (maxLength() < slen + len) + _reserve(slen + len, false); + + memmove(buf + len, buf, slen); + memmove(buf, cstr, len); + buf[len + slen] = '\0'; + } + + const char *c_str() const + { + if (!buf) + return ""; + return (const char *)buf; + } + + char operator[](size_t index) const + { + if (index >= bufLen || !buf) + return 0; + return buf[index]; + } + + char &operator[](size_t index) + { + static char c; + if (index >= bufLen || !buf) + { + c = '\0'; + return c; + } + return buf[index]; + } + + void swap(MB_String &rhs) + { + rhs.clear(); + } + + void shrink_to_fit() + { + size_t slen = length(); + _reserve(slen, true); + } + + void pop_back() + { + if (length() > 0) + { + size_t slen = length(); + if (slen > 0) + buf[slen - 1] = '\0'; + _reserve(slen, true); + } + } + + size_t size() const + { + return length(); + } + + size_t bufferLength() const + { + return bufLen; + } + + size_t find(const MB_String &s, size_t index = 0) const + { + if (!s.buf) + return -1; + return strpos(buf, s.buf, index); + } + + size_t find(const char *s, size_t index = 0) const + { + return strpos(buf, s, index); + } + + size_t find(char c, size_t index = 0) const + { + return strpos(buf, c, index); + } + + size_t rfind(const char *s, size_t index = npos) const + { + return rstrpos(buf, s, index); + } + + size_t rfind(char c, size_t index = npos) const + { + return rstrpos(buf, c, index); + } + + void erase(size_t index = 0, size_t len = npos) + { + + if (!buf || index >= length()) + return; + + if (index + len > length() || len == npos) + len = length() - index; + + int rightLen = length() - index - len; + + memmove(buf + index, buf + index + len, rightLen); + + buf[index + rightLen] = '\0'; + + _reserve(length(), true); + } + + size_t length() const + { + if (!buf) + return 0; + return strlen(buf); + } + + MB_String substr(size_t offset, size_t len = npos) const + { + MB_String out; + substr(out, offset, len); + return out; + } + + void substr(MB_String &out, size_t offset, size_t len = npos) const + { + if (len > 0 && length() > 0 && offset < length()) + { + if (len > length() - offset) + len = length() - offset; + out.copy(buf + offset, len); + } + } + + void clear() + { +#if defined(ESP8266_USE_EXTERNAL_HEAP) + reset(1); +#else + allocate(0, false); +#endif + } + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + void reset(size_t len) + { + if (len == 0) + len = 4; + ESP.setExternalHeap(); + if (buf) + buf = (char *)realloc(buf, len); + else + buf = (char *)malloc(len); + ESP.resetHeap(); + + if (buf) + { + bufLen = len; + memset(buf, 0, len); + } + } +#endif + + void resize(size_t len) + { + if (_reserve(len, true)) + buf[len] = '\0'; + } + + MB_String &replace(size_t pos, size_t len, const char *replace) + { + size_t repLen = strlen(replace); + + if (length() > 0 && length() > pos && repLen > 0) + { + if (pos + len > length()) + len = length() - pos; + + if (repLen > len) + { + size_t rightLen = length() - pos - len; + + if (maxLength() < length() + repLen - len) + _reserve(length() + repLen - len, false); + + memmove(buf + pos + repLen, buf + pos + len, rightLen); + buf[pos + repLen + rightLen] = '\0'; + } + + memmove(buf + pos, replace, repLen); + } + + return *this; + } + + MB_String &replace(size_t pos, size_t len, const MB_String &replace) + { + return this->replace(pos, len, replace.c_str()); + } + + MB_String &insert(size_t pos, size_t n, char c) + { + size_t slen = length(); + + size_t rightLen = slen - pos; + + if (maxLength() < slen + n) + _reserve(slen + n, false); + + if (maxLength() >= slen + n) + { + memmove(buf + pos + n, buf + pos, rightLen); + + for (size_t i = 0; i < n; i++) + *(buf + pos + i) = c; + + buf[pos + n + rightLen] = '\0'; + } + + return *this; + } + + MB_String &insert(size_t pos, const char *cstr) + { + size_t insLen = strlen(cstr); + + if (length() > 0 && length() > pos && insLen > 0) + { + + size_t rightLen = length() - pos; + + if (maxLength() < length() + insLen) + _reserve(length() + insLen, false); + + memmove(buf + pos + insLen, buf + pos, rightLen); + buf[pos + insLen + rightLen] = '\0'; + memmove(buf + pos, cstr, insLen); + } + + return *this; + } + + MB_String &insert(size_t pos, const MB_String &str) + { + return insert(pos, str.c_str()); + } + + MB_String &insert(size_t pos, char c) + { + char temp[2]{c, '\0'}; + return insert(pos, temp); + } + + size_t find_first_of(const char *cstr, size_t pos = 0) const + { + if (!cstr) + return -1; + + return strpos(buf, cstr, pos); + } + + size_t find_first_of(const MB_String &str, size_t pos = 0) const + { + if (length() == 0 || pos >= length()) + return -1; + + return find_first_of(str.buf, pos); + } + + size_t find_first_not_of(const char *cstr, size_t pos = 0) const + { + if (length() == 0 || pos >= length()) + return -1; + + int size = strcspn(buf + pos, cstr); + if (size == 0) + { + while (size == 0 && pos < length()) + { + size = strcspn(buf + pos, cstr); + pos++; + } + + if (pos > 0) + pos--; + } + + return pos; + } + + size_t find_first_not_of(const MB_String &str, size_t pos = 0) const + { + if (length() == 0 || pos >= length() || str.length() == 0) + return -1; + + return find_first_not_of(str.buf, pos); + } + + size_t find_last_of(const char *cstr, size_t pos = npos) const + { + if (!cstr) + return -1; + + return rstrpos(buf, cstr, pos); + } + + size_t find_last_of(const MB_String &str, size_t pos = npos) const + { + if (str.length() == 0) + return -1; + + return find_last_of(str.buf, pos); + } + + size_t find_last_not_of(const char *cstr, size_t pos = npos) const + { + if (length() == 0) + return -1; + + if (pos >= length()) + pos = length() - 1; + + int p = length() - 1; + int size = strcspn(buf + p, cstr); + if (size == 0) + { + while (size == 0 && p > 0) + { + size = strcspn(buf + p, cstr); + p--; + } + p++; + } + + return p; + } + + size_t find_last_not_of(const MB_String &str, size_t pos = npos) const + { + if (str.length() == 0) + return -1; + + return find_last_not_of(str.buf, pos); + } + + MB_String & replaceAll(const char *find, const char *replace) + { + if (length() == 0) + return *this;; + + int i, cnt = 0; + int repLen = strlen(replace); + int findLen = strlen(find); + + MB_String temp = buf; + char *s = temp.buf; + clear(); + + for (i = 0; s[i] != '\0'; i++) + { + if (strstr(&s[i], find) == &s[i]) + { + cnt++; + i += findLen - 1; + } + } + + if (_reserve(i + cnt * (repLen - findLen) + 1, false)) + { + i = 0; + while (*s) + { + if (strstr(s, find) == s) + { + strcpy(&buf[i], replace); + i += repLen; + s += findLen; + } + else + buf[i++] = *s++; + } + + buf[i] = '\0'; + } + + temp.clear(); + + return *this; + } + + void replaceAll(const MB_String &find, const MB_String &replace) + { + replaceAll(find.c_str(), replace.c_str()); + } + + bool empty() const + { + return length() == 0; + } + + void reserve(size_t len) + { + if (_reserve(len, false)) + buf[len] = '\0'; + } + + static const size_t npos = -1; + +private: +#if defined(ARDUINO_ARCH_SAMD) || defined(__AVR_ATmega4809__) || defined(ARDUINO_NANO_RP2040_CONNECT) + + char *int32Str(signed long value) + { + char *t = (char *)newP(64); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%ld"), value); + return t; + } + + char *uint32Str(unsigned long value) + { + char *t = (char *)newP(64); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%lu"), value); + return t; + } + +#endif + + char *int64Str(signed long long value) + { + char *t = (char *)newP(64); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%lld"), value); + return t; + } + + char *uint64Str(unsigned long long value) + { + char *t = (char *)newP(64); + sprintf(t, (const char *)MBSTRING_FLASH_MCR("%llu"), value); + return t; + } + + char *boolStr(bool value) + { + char *t = (char *)newP(8); + value ? strcpy(t, (const char *)MBSTRING_FLASH_MCR("true")) : strcpy(t, (const char *)MBSTRING_FLASH_MCR("false")); + return t; + } + + char *toFloatStr(long double value, int type, int precision) + { + int width = type == 0 ? 32 : 64; + + char *t = (char *)newP(width); + + if (t) + { + MB_String fmt = MBSTRING_FLASH_MCR("%."); + fmt += precision; + if (type == 2) + fmt += MBSTRING_FLASH_MCR("L"); + fmt += MBSTRING_FLASH_MCR("f"); + sprintf(t, fmt.c_str(), value); + trim(t); + } + + return t; + } + + char *nullStr() + { + char *t = (char *)newP(6); + strcpy(t, (const char *)MBSTRING_FLASH_MCR("null")); + return t; + } + + char *pgmStr(PGM_P p) + { + char *t = (char *)newP(strlen_P(p)); + strcpy_P(t, p); + return t; + } + + void trim(char *s) + { + if (!s) + return; + size_t i = strlen(s) - 1; + while (s[i] == '0' && i > 0) + { + if (s[i - 1] == '.') + { + i--; + break; + } + if (s[i - 1] != '0') + break; + i--; + } + if (i < strlen(s) - 1) + s[i] = '\0'; + } + + void *newP(size_t len) + { + void *p; + size_t newLen = getReservedLen(len); +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() > 0) + p = (void *)ps_malloc(newLen); + else + p = (void *)malloc(newLen); + if (!p) + return NULL; + +#else + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.setExternalHeap(); +#endif + + p = (void *)malloc(newLen); + bool nn = p ? true : false; + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.resetHeap(); +#endif + + if (!nn) + return NULL; + +#endif + memset(p, 0, newLen); + return p; + } + + void delP(void *ptr) + { + void **p = (void **)ptr; + if (*p) + { + free(*p); + *p = 0; + } + } + + size_t getReservedLen(size_t len) + { + int blen = len + 1; + + int newlen = (blen / 4) * 4; + + if (newlen < blen) + newlen += 4; + + return (size_t)newlen; + } + + size_t maxLength() const + { + if (bufferLength() == 0) + return 0; + return bufferLength() - 1; + } + + void concat(const MB_String &s) + { + if (s.length() == 0) + return; + + if (&s == this) + { + size_t slen = length(); + + if (2 * slen > maxLength()) + { + if (!_reserve(2 * slen, false)) + return; + } + + memmove(buf + slen, buf, slen); + buf[2 * slen] = '\0'; + } + else + { + concat(s.buf, s.length()); + } + } + + void concat(const char *cstr, size_t len) + { + if (!cstr) + return; + + size_t slen = length(); + + if (slen + len > maxLength()) + { + if (!_reserve(slen + len, false)) + return; + } + + memmove(buf + slen, cstr, len); + buf[slen + len] = '\0'; + } + + void concat(const char *cstr) + { + if (!cstr) + return; + + concat(cstr, strlen(cstr)); + } + + void move(MB_String &rhs) + { + if (buf) + { + if (bufLen >= rhs.bufLen) + { + strcpy(buf, rhs.buf); + bufLen = rhs.bufLen; + rhs.bufLen = 0; + return; + } + else + { + free(buf); + } + } + buf = rhs.buf; + bufLen = rhs.bufLen; + rhs.buf = NULL; + } + + void allocate(size_t len, bool shrink) + { + + if (len == 0) + { + if (buf) + free(buf); + buf = NULL; + bufLen = 0; + return; + } + + if (len > bufLen || shrink) + { + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.setExternalHeap(); +#endif + + if (shrink || (bufLen > 0 && buf)) + { + int slen = length(); + +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() > 0) + buf = (char *)ps_realloc(buf, len); + else + buf = (char *)realloc(buf, len); +#else + buf = (char *)realloc(buf, len); +#endif + if (buf) + { + buf[slen] = '\0'; + bufLen = len; + } + } + else + { +#if defined(BOARD_HAS_PSRAM) && defined(MB_STRING_USE_PSRAM) + if (ESP.getPsramSize() > 0) + buf = (char *)ps_malloc(len); + else + buf = (char *)malloc(len); +#else + buf = (char *)malloc(len); +#endif + if (buf) + { + buf[0] = '\0'; + bufLen = len; + } + } + +#if defined(ESP8266_USE_EXTERNAL_HEAP) + ESP.resetHeap(); +#endif + } + } + + MB_String ©(const char *cstr, size_t length) + { + + if (!_reserve(length, false)) + { + clear(); + return *this; + } + + memcpy_P(buf, (PGM_P)cstr, length); + buf[length] = '\0'; + + return *this; + } + + bool _reserve(size_t len, bool shrink) + { + + size_t newlen = getReservedLen(len); + if (shrink) + allocate(newlen, true); + else if (newlen > bufLen) + allocate(newlen, false); + + return newlen <= bufLen; + } + + int strpos(const char *haystack, const char *needle, int offset) const + { + if (!haystack || !needle) + return -1; + + int hlen = strlen(haystack); + int nlen = strlen(needle); + + if (hlen == 0 || nlen == 0) + return -1; + + int hidx = offset, nidx = 0; + while ((*(haystack + hidx) != '\0') && (*(needle + nidx) != '\0') && hidx < hlen) + { + if (*(needle + nidx) != *(haystack + hidx)) + { + hidx++; + nidx = 0; + } + else + { + nidx++; + hidx++; + if (nidx == nlen) + return hidx - nidx; + } + } + + return -1; + } + + int strpos(const char *haystack, char needle, int offset) const + { + if (!haystack || needle == 0) + return -1; + + int hlen = strlen(haystack); + + if (hlen == 0) + return -1; + + int hidx = offset; + while ((*(haystack + hidx) != '\0') && hidx < hlen) + { + if (needle == *(haystack + hidx)) + return hidx; + hidx++; + } + + return -1; + } + + int rstrpos(const char *haystack, const char *needle, int offset /* start search from this offset to the left string */) const + { + if (!haystack || !needle) + return -1; + + int hlen = strlen(haystack); + int nlen = strlen(needle); + + if (hlen == 0 || nlen == 0) + return -1; + + int hidx = offset; + + if (hidx >= hlen || (size_t)offset == npos) + hidx = hlen - 1; + + int nidx = nlen - 1; + + while (hidx >= 0) + { + if (*(needle + nidx) != *(haystack + hidx)) + { + hidx--; + nidx = nlen - 1; + } + else + { + if (nidx == 0) + return hidx + nidx; + nidx--; + hidx--; + } + } + + return -1; + } + + int rstrpos(const char *haystack, char needle, int offset /* start search from this offset to the left char */) const + { + if (!haystack || needle == 0) + return -1; + + int hlen = strlen(haystack); + + if (hlen == 0) + return -1; + + int hidx = offset; + + if (hidx >= hlen || (size_t)offset == npos) + hidx = hlen - 1; + + while (hidx >= 0) + { + if (needle == *(haystack + hidx)) + return hidx; + hidx--; + } + + return -1; + } + + int compareTo(const MB_String &s) const + { + if (!buf || !s.buf) + { + if (s.buf && s.length() > 0) + return 0 - *(unsigned char *)s.buf; + if (buf && length() > 0) + return *(unsigned char *)buf; + return 0; + } + return strcmp(buf, s.buf); + } + + unsigned char equals(const MB_String &s2) const + { + return (length() == s2.length() && compareTo(s2) == 0); + } + + unsigned char equals(const char *cstr) const + { + if (length() == 0) + return (cstr == NULL || *cstr == 0); + if (cstr == NULL) + return buf[0] == 0; + return strcmp(buf, cstr) == 0; + } + + char *ultoa(unsigned long value, char *str, int radix) + { + const char *format = NULL; + + switch (radix) + { + case 8: + format = "%o"; + break; + case 10: + format = "%ul"; + break; + case 16: + format = "%x"; + break; + } + + if (format == NULL) + return str; + + int size = sprintf(str, format, value); + return &str[size]; + } + +#if (!defined(ESP32) && !defined(ESP8266) && !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_SAMD)) || defined(ARDUINO_NANO_RP2040_CONNECT) + char *ltoa(long value, char *str, int radix) + { + const char *format = NULL; + + switch (radix) + { + case 8: + format = "%o"; + break; + case 10: + format = "%l"; + break; + case 16: + format = "%x"; + break; + } + + if (format == NULL) + return str; + + int size = sprintf(str, format, value); + return &str[size]; + } + + char *utoa(unsigned int value, char *str, int radix) + { + const char *format = NULL; + + switch (radix) + { + case 8: + format = "%o"; + break; + case 10: + format = "%u"; + break; + case 16: + format = "%x"; + break; + } + + if (format == NULL) + return str; + + int size = sprintf(str, format, value); + return &str[size]; + } + + char *itoa(int value, char *str, int radix) + { + const char *format = NULL; + + switch (radix) + { + case 8: + format = "%o"; + break; + case 10: + format = "%d"; + break; + case 16: + format = "%x"; + break; + } + + if (format == NULL) + return str; + + int size = sprintf(str, format, value); + return &str[size]; + } +#endif + + char *buf = NULL; + size_t bufLen = 0; +}; + +inline MB_String operator+(const MB_String &lhs, const MB_String &rhs) +{ + MB_String res; + res.reserve(lhs.length() + rhs.length()); + res += lhs; + res += rhs; + return res; +} + +#if !defined(__AVR__) + +inline MB_String operator+(MB_String &&lhs, const MB_String &rhs) +{ + lhs += rhs; + return std::move(lhs); +} + +inline MB_String operator+(MB_String &lhs, MB_String &&rhs) +{ + lhs += rhs; + return std::move(lhs); +} + +inline MB_String operator+(MB_String &lhs, char rhs) +{ + lhs += rhs; + return std::move(lhs); +} + +inline MB_String operator+(char lhs, MB_String &rhs) +{ + rhs.insert(0, lhs); + return rhs; +} + +inline MB_String operator+(MB_String &&lhs, char rhs) +{ + return std::move(lhs.insert(0, rhs)); +} + +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/MB_Time.h b/lib/libesp32/ESP-Mail-Client/src/extras/MB_Time.h new file mode 100644 index 000000000..73d84ac2b --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/MB_Time.h @@ -0,0 +1,435 @@ +#ifndef MB_Time_H +#define MB_Time_H + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +/* + * Time helper class v1.0.7 + * + * Created August 28, 2023 + * + * Do not remove or modify this file as it required for AVR, ARM, SAMD devices and external client to work. + * + * The MIT License (MIT) + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include "Networks_Provider.h" + +#define ESP_TIME_DEFAULT_TS 1577836800 +#define ESP_TIME_NON_TS -1000 + +#include +#include + +#if defined(ESP32) && !defined(ESP_ARDUINO_VERSION) /* ESP32 core < v2.0.x */ +#include +#else +#include +#endif + +#if defined(ESP_MAIL_USE_PSRAM) +#define MB_STRING_USE_PSRAM +#endif + +#include "MB_String.h" +#include "MB_MCU.h" + +#if defined(ESP8266) +#include "user_interface.h" +#endif + +#if defined(__AVR__) || defined(MB_ARDUINO_TEENSY) +#define MB_TIME_PGM_ATTR +#else +#define MB_TIME_PGM_ATTR PROGMEM +#endif + +#if !defined(MB_ARDUINO_ESP) +static const char *mb_months[12] MB_TIME_PGM_ATTR = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +#endif + +enum base_time_type_t +{ + base_time_type_undefined = -1, + base_time_type_unset = 0, + base_time_type_auto = 1, + base_time_type_user = 2 +}; + +class MB_Time +{ +public: + MB_Time() + { + } + + ~MB_Time() + { + clear(); + } + + void clear() + { +#if defined(ENABLE_NTP_TIME) + if (_sv1.length()) + { + _sv1.clear(); + _sv2.clear(); + _sv3.clear(); + } +#endif + } + + void readNTPTime(unsigned long waitMs, bool debugProgress) + { + if (!timeReady()) + { + if (WiFI_CONNECTED) + { + +#if defined(ENABLE_NTP_TIME) +#if (defined(ESP32) || defined(ESP8266)) + configTime(_gmt_offset * 3600, _daylight_offset * 60, _sv1.c_str(), _sv2.c_str(), _sv3.c_str()); +#elif defined(ARDUINO_RASPBERRY_PI_PICO_W) + NTP.begin(_sv1.c_str(), _sv2.c_str()); + NTP.waitSet(); +#endif +#endif + unsigned long ms = millis(); + +#if !defined(SILENT_MODE) + unsigned long pgms = 0; +#endif + do + { +#if defined(ESP_MAIL_HAS_WIFI_TIME) + _base_ts = WiFi.getTime() > ESP_TIME_DEFAULT_TS ? WiFi.getTime() : _base_ts; +#elif defined(ENABLE_NTP_TIME) + _base_ts = time(nullptr) > ESP_TIME_DEFAULT_TS ? time(nullptr) : _base_ts; +#else + break; +#endif + +#if !defined(SILENT_MODE) + if (debugProgress && millis() - pgms > 50) + { + pgms = millis(); + esp_mail_debug_print(".", false); + } +#endif + + yield_impl(); + } while (millis() - ms < waitMs && _base_ts < ESP_TIME_DEFAULT_TS); +#if !defined(SILENT_MODE) + if (debugProgress) + esp_mail_debug_print("", true); +#endif + } + } + } + + int setTimestamp(time_t ts, float gmtOffset) + { + _gmt_offset = gmtOffset; + _base_time_type = ts > ESP_TIME_DEFAULT_TS ? base_time_type_user : base_time_type_unset; +#if defined(MB_ARDUINO_ESP) + struct timeval tm; // sec, us + tm.tv_sec = ts; + tm.tv_usec = 0; + return settimeofday((const struct timeval *)&tm, 0); +#else + _ts_offset = ts - millis() / 1000; + return 1; +#endif + } + + /** Get the timestamp from the year, month, date, hour, minute, + * and second provided. + * + * @param year The year. + * @param mon The month from 1 to 12. + * @param date The dates. + * @param hour The hours. + * @param mins The minutes. + * @param sec The seconds. + * @return time_t The value of timestamp. + */ + time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec) + { + struct tm timeinfo; + timeinfo.tm_year = year - 1900; + timeinfo.tm_mon = mon - 1; + timeinfo.tm_mday = date; + timeinfo.tm_hour = hour; + timeinfo.tm_min = mins; + timeinfo.tm_sec = sec; + time_t ts = mktime(&timeinfo); + return ts; + } + + /** Get the timestamp from the RFC 2822 time string. + * e.g. Mon, 02 May 2022 00:30:00 +0000 or 02 May 2022 00:30:00 +0000 + * + * @param gmt Return the GMT time. + * @return timestamp of time string. + */ + time_t getTimestamp(const char *timeString, bool gmt = false) + { +#if defined(MB_ARDUINO_ESP) + struct tm timeinfo; + + if (strstr(timeString, ",") != NULL) + strptime(timeString, "%a, %d %b %Y %H:%M:%S %z", &timeinfo); + else + strptime(timeString, "%d %b %Y %H:%M:%S %z", &timeinfo); + + time_t ts = mktime(&timeinfo); + return ts; + +#else + + time_t ts = 0; + _vectorImpl tk; + MB_String s1 = timeString; + + splitToken(s1, tk, ' '); + int day = 0, mon = 0, year = 0, hr = 0, mins = 0, sec = 0, tz_h = 0, tz_m = 0; + + int tkindex = tk.size() == 5 ? -1 : 0; // No week days? + + // some response may include (UTC) and (ICT) + if (tk.size() >= 5) + { + day = atoi(tk[tkindex + 1].c_str()); + for (size_t i = 0; i < 12; i++) + { + if (strcmp_P(mb_months[i], tk[tkindex + 2].c_str()) == 0) + mon = i; + } + + // RFC 822 year to RFC 2822 + if (tk[tkindex + 3].length() == 2) + tk[tkindex + 3].prepend("20"); + + year = atoi(tk[tkindex + 3].c_str()); + + _vectorImpl tk2; + splitToken(tk[tkindex + 4], tk2, ':'); + if (tk2.size() == 3) + { + hr = atoi(tk2[0].c_str()); + mins = atoi(tk2[1].c_str()); + sec = atoi(tk2[2].c_str()); + } + + ts = getTimestamp(year, mon + 1, day, hr, mins, sec); + + if (tk[tkindex + 5].length() == 5 && gmt) + { + char tmp[6]; + memset(tmp, 0, 6); + strncpy(tmp, tk[tkindex + 5].c_str() + 1, 2); + tz_h = atoi(tmp); + + memset(tmp, 0, 6); + strncpy(tmp, tk[tkindex + 5].c_str() + 3, 2); + tz_m = atoi(tmp); + + time_t tz = tz_h * 60 * 60 + tz_m * 60; + if (tk[tkindex + 5][0] == '+') + ts -= tz; // remove time zone offset + else + ts += tz; + } + } + return ts; +#endif + } + + /** Get the current timestamp. + * + * @return uint64_t The value of current timestamp. + */ + uint64_t getCurrentTimestamp() + { + getBaseTime(); + return _base_ts; + } + + /** Get the current rfc822 date time string that valid for Email. + * @return String The current date time string. + */ + String getDateTimeString() + { + getBaseTime(); + + char tbuf[40]; + strftime(tbuf, 40, "%a, %d %b %Y %H:%M:%S %z", &_time_info); + MB_String tStr = tbuf, tzStr; + + int p = _gmt_offset < 0 ? -1 : 1; + float dif = (p * (_gmt_offset * 10 - (int)_gmt_offset * 10)) * 60.0 / 10; + tzStr = (_gmt_offset < 0) ? '-' : '+'; + + if ((int)_gmt_offset < 10) + tzStr += 0; + + tzStr += (int)_gmt_offset; + + if (dif < 10) + tzStr += 0; + + tzStr += (int)dif; + + // replace for valid timezone + tStr.replaceAll("+0000", tzStr); + return tStr.c_str(); + } + + String getDateTimeString(time_t ts, const char *format) + { + char tbuf[100]; + strftime(tbuf, 100, format, localtime(&ts)); + return tbuf; + } + + void begin(float gmtOffset, float daylightOffset, const char *servers) + { + if (timeReady() && _base_time_type == base_time_type_undefined) + _base_time_type = base_time_type_auto; + else if (_base_time_type == base_time_type_undefined) + _base_time_type = base_time_type_unset; + +#if defined(ENABLE_NTP_TIME) && (defined(ESP32) || defined(ESP8266) || defined(ARDUINO_RASPBERRY_PI_PICO_W)) + + _vectorImpl tk; + MB_String sv = servers; + + clear(); + + splitToken(sv, tk, ','); + + if (tk.size() > 0) + _sv1 = tk[0]; + if (tk.size() > 1) + _sv2 = tk[1]; + if (tk.size() > 2) + _sv3 = tk[2]; + +#endif + + if ((gmtOffset > ESP_TIME_NON_TS && _gmt_offset != gmtOffset) || (daylightOffset > ESP_TIME_NON_TS && _daylight_offset != daylightOffset)) + { + // Reset system timestamp when config changed + _base_ts = 0; + if (gmtOffset > ESP_TIME_NON_TS) + _gmt_offset = gmtOffset; + if (daylightOffset > ESP_TIME_NON_TS) + _daylight_offset = daylightOffset; + + if (_base_time_type == base_time_type_unset) + setTimestamp(millis(), _gmt_offset); + } + } + + /** get the clock ready state + */ + bool timeReady() + { + getBaseTime(); + return _time_ready; + } + +private: + time_t _base_ts = 0; + struct tm _time_info; + float _gmt_offset = ESP_TIME_NON_TS; + float _daylight_offset = ESP_TIME_NON_TS; + void splitToken(MB_String &str, _vectorImpl &tk, char delim) + { + size_t current, previous = 0; + current = str.find(delim, previous); + MB_String s; + while (current != MB_String::npos) + { + + s = str.substr(previous, current - previous); + s.trim(); + + if (s.length() > 0) + tk.push_back(s); + previous = current + 1; + current = str.find(delim, previous); + } + + s = str.substr(previous, current - previous); + + s.trim(); + + if (s.length() > 0) + tk.push_back(s); + + s.clear(); + } + + // 9Safe) Get base timestamp + void getBaseTime() + { + +#if defined(ESP32) || defined(ESP8266) || defined(MB_ARDUINO_PICO) + + if (_base_ts < time(nullptr) && time(nullptr) > ESP_TIME_DEFAULT_TS) + _base_ts = time(nullptr); + +#if defined(ESP32) + getLocalTime(&_time_info); +#elif defined(ESP8266) || defined(MB_ARDUINO_PICO) + localtime_r(&_base_ts, &_time_info); +#endif + +#elif defined(ESP_MAIL_HAS_WIFI_TIME) + if (WiFI_CONNECTED) + _base_ts = WiFi.getTime() > ESP_TIME_DEFAULT_TS ? WiFi.getTime() : _base_ts; +#else + _base_ts = _ts_offset + millis() / 1000; +#endif + + _time_ready = _base_ts > ESP_TIME_DEFAULT_TS; + if (_time_ready) + _ts_offset = _base_ts - millis() / 1000; + } + +#if defined(ENABLE_NTP_TIME) + // in ESP8266 these NTP sever strings should be existed during configuring time. + MB_String _sv1, _sv2, _sv3; +#endif + + uint32_t _ts_offset = 0; + bool _time_ready = false; + base_time_type_t _base_time_type = base_time_type_undefined; +}; + +#endif // MB_Time_H diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/Networks_Provider.h b/lib/libesp32/ESP-Mail-Client/src/extras/Networks_Provider.h new file mode 100644 index 000000000..fd523be67 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/Networks_Provider.h @@ -0,0 +1,131 @@ +#ifndef ESP_MAIL_NETWORKS_PROVIDER_H +#define ESP_MAIL_NETWORKS_PROVIDER_H + +#include "../ESP_Mail_FS.h" + +#include "../ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +#if __has_include() +#include +#endif + +#include "ESP8266_Supports.h" + +// Renesas devices +#if defined(ARDUINO_UNOWIFIR4) || defined(ARDUINO_MINIMA) || defined(ARDUINO_PORTENTA_C33) +#define ESP_MAIL_STRSEP strsepImpl +#define ESP_MAIL_USE_STRSEP_IMPL +#else +#define ESP_MAIL_STRSEP strsep +#endif + +#if defined(ESP32) || defined(ESP8266) || defined(ARDUINO_RASPBERRY_PI_PICO_W) || \ + defined(ARDUINO_UNOWIFIR4) || defined(ARDUINO_PORTENTA_C33) || \ + defined(ARDUINO_PORTENTA_H7_M7) || defined(ARDUINO_PORTENTA_H7_M4) || \ + __has_include() ||__has_include() + +#if !defined(ESP_MAIL_DISABLE_ONBOARD_WIFI) + +#define ESP_MAIL_WIFI_IS_AVAILABLE + +#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W) +#include +#elif defined(ESP8266) +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#elif __has_include() +#include +#endif + +#if !defined(ARDUINO_RASPBERRY_PI_PICO_W) && \ + !defined(MB_ARDUINO_ARCH_SAMD) && \ + !defined(MB_ARDUINO_MBED_PORTENTA) && \ + !defined(ARDUINO_UNOWIFIR4) && \ + !defined(ARDUINO_PORTENTA_C33) && \ + !defined(ARDUINO_NANO_RP2040_CONNECT) +#define ESP_MAIL_HAS_WIFI_DISCONNECT +#endif + +#if defined(ARDUINO_PORTENTA_C33) +#define CONST_STRING_CAST char * // C33 WiFi library SSID is char array +#else +#define CONST_STRING_CAST const char * +#endif + +// WiFiS3 getTime is currently return 0 (not implemented) +#if __has_include() || __has_include() +#define ESP_MAIL_HAS_WIFI_TIME +#endif + +#if defined(MB_ARDUINO_PICO) && __has_include() +#define ESP_MAIL_HAS_WIFIMULTI +#endif + +#endif + +#endif + +#if !defined(ESP_MAIL_DISABLE_NATIVE_ETHERNET) + +#if defined(ESP32) && __has_include() +#include +#define ESP_MAIL_ETH_IS_AVAILABLE +#elif defined(ESP8266) && defined(ESP8266_CORE_SDK_V3_X_X) +#if defined(INC_ENC28J60_LWIP) || defined(INC_W5100_LWIP) || defined(INC_W5500_LWIP) +#define ESP_MAIL_ETH_IS_AVAILABLE +#endif +#endif + +#endif + +#if defined(TINY_GSM_MODEM_SIM800) || \ + defined(TINY_GSM_MODEM_SIM808) || \ + defined(TINY_GSM_MODEM_SIM868) || \ + defined(TINY_GSM_MODEM_SIM900) || \ + defined(TINY_GSM_MODEM_SIM7000) || \ + defined(TINY_GSM_MODEM_SIM7000) || \ + defined(TINY_GSM_MODEM_SIM7000SSL) || \ + defined(TINY_GSM_MODEM_SIM7070) || \ + defined(TINY_GSM_MODEM_SIM7080) || \ + defined(TINY_GSM_MODEM_SIM7090) || \ + defined(TINY_GSM_MODEM_SIM5320) || \ + defined(TINY_GSM_MODEM_SIM5360) || \ + defined(TINY_GSM_MODEM_SIM5300) || \ + defined(TINY_GSM_MODEM_SIM7100) || \ + defined(TINY_GSM_MODEM_SIM7600) || \ + defined(TINY_GSM_MODEM_SIM7800) || \ + defined(TINY_GSM_MODEM_SIM7500) || \ + defined(TINY_GSM_MODEM_UBLOX) || \ + defined(TINY_GSM_MODEM_SARAR4) || \ + defined(TINY_GSM_MODEM_M95) || \ + defined(TINY_GSM_MODEM_BG96) || \ + defined(TINY_GSM_MODEM_A6) || \ + defined(TINY_GSM_MODEM_A7) || \ + defined(TINY_GSM_MODEM_M590) || \ + defined(TINY_GSM_MODEM_MC60) || \ + defined(TINY_GSM_MODEM_MC60E) || \ + defined(TINY_GSM_MODEM_XBEE) || \ + defined(TINY_GSM_MODEM_SEQUANS_MONARCH) +#define ESP_MAIL_TINYGSM_IS_AVAILABLE +#endif + +#if defined(ESP_MAIL_TINYGSM_IS_AVAILABLE) && __has_include() +#include +#define ESP_MAIL_GSM_MODEM_IS_AVAILABLE +#endif + +#if defined(ESP_MAIL_WIFI_IS_AVAILABLE) +#define WiFI_CONNECTED (WiFi.status() == WL_CONNECTED) +#else +#define WiFI_CONNECTED false +#endif + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/RFC2047.cpp b/lib/libesp32/ESP-Mail-Client/src/extras/RFC2047.cpp new file mode 100644 index 000000000..95e5ac140 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/RFC2047.cpp @@ -0,0 +1,192 @@ +#ifndef RFC2047_CPP +#define RFC2047_CPP + +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif + +#include "RFC2047.h" + +RFC2047_Decoder::RFC2047_Decoder() {} +RFC2047_Decoder::~RFC2047_Decoder() {} + +void RFC2047_Decoder::decode(MB_FS *mbfs, char *d, const char *s, size_t dlen) +{ + if (!mbfs) + return; + + this->mbfs = mbfs; + + const char *p, *q; + size_t n; + int found_encoded = 0; + + dlen--; /* save room for the terminal nul */ + + while (*s && dlen > 0) + { + if ((p = strstr(s, "=?")) == NULL || + (q = strchr(p + 2, '?')) == NULL || + (q = strchr(q + 1, '?')) == NULL || + (q = strstr(q + 1, "?=")) == NULL) + { + /* no encoded words */ + if (d != s) + strfcpy(d, s, dlen + 1); + return; + } + + if (p != s) + { + n = (size_t)(p - s); + /* ignore spaces between encoded words */ + if (!found_encoded || strspn(s, " \t\r\n") != n) + { + if (n > dlen) + n = dlen; + if (d != s) + memcpy(d, s, n); + d += n; + dlen -= n; + } + } + + rfc2047DecodeWord(d, p, dlen); + found_encoded = 1; + s = q + 2; + n = strlen(d); + dlen -= n; + d += n; + } + *d = 0; +} + +void RFC2047_Decoder::rfc2047DecodeWord(char *d, const char *s, size_t dlen) +{ + + if (!mbfs) + return; + + char *p = safe_strdup(s); + char *pp = p; + char *end = p; + char *pd = d; + size_t len = dlen; + int enc = 0, filter = 0, count = 0, c1, c2, c3, c4; + + while (pp != NULL) + { + // See RFC2047.h + ESP_MAIL_STRSEP(&end, "?"); + count++; + switch (count) + { + case 2: + if (strcasecmp(pp, Charset) != 0) + { + filter = 1; + } + break; + case 3: + if (toupper(*pp) == 'Q') + enc = ENCQUOTEDPRINTABLE; + else if (toupper(*pp) == 'B') + enc = ENCBASE64; + else + return; + break; + case 4: + if (enc == ENCQUOTEDPRINTABLE) + { + while (*pp && len > 0) + { + if (*pp == '_') + { + *pd++ = ' '; + len--; + } + else if (*pp == '=') + { + *pd++ = (hexval(pp[1]) << 4) | hexval(pp[2]); + len--; + pp += 2; + } + else + { + *pd++ = *pp; + len--; + } + pp++; + } + *pd = 0; + } + else if (enc == ENCBASE64) + { + while (*pp && len > 0) + { + c1 = base64val(pp[0]); + c2 = base64val(pp[1]); + *pd++ = (c1 << 2) | ((c2 >> 4) & 0x3); + if (--len == 0) + break; + + if (pp[2] == '=') + break; + + c3 = base64val(pp[2]); + *pd++ = ((c2 & 0xf) << 4) | ((c3 >> 2) & 0xf); + if (--len == 0) + break; + + if (pp[3] == '=') + break; + + c4 = base64val(pp[3]); + *pd++ = ((c3 & 0x3) << 6) | c4; + if (--len == 0) + break; + + pp += 4; + } + *pd = 0; + } + break; + } + + pp = end; + } + + mbfs->delP(&p); + + if (filter) + { + pd = d; + while (*pd) + { + if (!IsPrint(*pd)) + *pd = '?'; + pd++; + } + } + return; +} + +char *RFC2047_Decoder::safe_strdup(const char *s) +{ + + if (!mbfs) + return 0; + + char *p; + size_t l; + + if (!s || !*s) + return 0; + l = strlen(s) + 1; + p = (char *)mbfs->newP(l); + memcpy(p, s, l); + return (p); +} + +#endif // RFC2047_CPP \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/extras/RFC2047.h b/lib/libesp32/ESP-Mail-Client/src/extras/RFC2047.h similarity index 58% rename from lib/libesp32/lib_mail/src/extras/RFC2047.h rename to lib/libesp32/ESP-Mail-Client/src/extras/RFC2047.h index 1753a2119..baadaa672 100644 --- a/lib/libesp32/lib_mail/src/extras/RFC2047.h +++ b/lib/libesp32/ESP-Mail-Client/src/extras/RFC2047.h @@ -1,12 +1,43 @@ +#pragma once #ifndef RFC2047_H #define RFC2047_H +#include "ESP_Mail_Client_Version.h" +#if !VALID_VERSION_CHECK(30409) +#error "Mixed versions compilation." +#endif #include +#include "ESP_Mail_FS.h" +#include "MB_FS.h" +#include "Networks_Provider.h" +#if defined(ESP32) +#if defined(BOARD_HAS_PSRAM) && defined(ESP_Mail_USE_PSRAM) +#include +#endif +#endif -#define strfcpy(A,B,C) strncpy(A,B,C), *(A+(C)-1)=0 +#define strfcpy(A, B, C) strncpy(A, B, C), *(A + (C)-1) = 0 + +#if defined(ESP_MAIL_USE_STRSEP_IMPL) +// This is strsep implementation because strdup may not available in some platform. +static char *__attribute__((used)) strsepImpl(char **stringp, const char *delim) +{ + char *rv = *stringp; + if (rv) + { + *stringp += strcspn(*stringp, delim); + if (**stringp) + *(*stringp)++ = '\0'; + else + *stringp = 0; + } + return rv; +} + +#endif enum { @@ -41,29 +72,23 @@ __attribute__((used)) static int Index_64[128] = { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1}; #define IsPrint(c) (isprint((unsigned char)(c)) || \ - ((unsigned char)(c) >= 0xa0)) + ((unsigned char)(c) >= 0xa0)) #define hexval(c) Index_hex[(unsigned int)(c)] #define base64val(c) Index_64[(unsigned int)(c)] -class RFC2047_Decoder{ - - public: - RFC2047_Decoder(); - ~RFC2047_Decoder(); - void rfc2047Decode(char *d, const char *s, size_t dlen); - - - private: - void rfc2047DecodeWord(char *d, const char *s, size_t dlen); - void *safe_calloc (size_t nmemb, size_t size); - void *safe_malloc (unsigned int siz); - void safe_realloc (void **p, size_t siz); - void safe_free (void *ptr); - char *safe_strdup (const char *s); +class RFC2047_Decoder +{ +public: + RFC2047_Decoder(); + ~RFC2047_Decoder(); + void decode(MB_FS *mbfs, char *d, const char *s, size_t dlen); +private: + void rfc2047DecodeWord(char *d, const char *s, size_t dlen); + char *safe_strdup(const char *s); + MB_FS *mbfs = nullptr; }; - -#endif //RFC2047_H \ No newline at end of file +#endif // RFC2047_H \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/SDHelper.h b/lib/libesp32/ESP-Mail-Client/src/extras/SDHelper.h new file mode 100644 index 000000000..48490c473 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/SDHelper.h @@ -0,0 +1,163 @@ +#pragma once + +#ifndef SD_HELPER_H_ +#define SD_HELPER_H_ + +#include +#include + +// If SD Card used for storage, assign SD card type and FS used in src/ESP_Mail_FS.h and +// change the config for that card interfaces in this file (src/extras/SDHelper.h) + +#if defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD) + +#if defined(ESP32) + +#define SPI_CS_PIN 13 +#define SPI_SCK_PIN 14 +#define SPI_MISO_PIN 2 +#define SPI_MOSI_PIN 15 +#define SPI_CLOCK_IN_MHz 16 + +// #define SPI_CS_PIN 5 +// #define SPI_SCK_PIN 18 +// #define SPI_MISO_PIN 19 +// #define SPI_MOSI_PIN 23 +// #define SPI_CLOCK_IN_MHz 4 // may work on lower clock rate + +#elif defined(ESP8266) +#define SPI_CS_PIN 15 +#elif defined(MB_ARDUINO_PICO) +// Use SPI 1's SS (GPIO 13) port as CS for SPI +#define SPI_CS_PIN PIN_SPI1_SS +#elif defined(MB_ARDUINO_ARCH_SAMD) || defined(MB_ARDUINO_NANO_RP2040_CONNECT) || defined(MB_ARDUINO_TEENSY) + +#define SPI_CS_PIN 4 + +#if defined(MBFS_SDFAT_ENABLED) +#define SPI_SCK_PIN -1 +#define SPI_MISO_PIN -1 +#define SPI_MOSI_PIN -1 +#define SPI_CLOCK_IN_MHz 4 // works on lower clock rate +#endif + +#endif + +// if SdFat library installed and ESP_Mail_FS.h was set to use it (for ESP32 only) +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + +// https://github.com/greiman/SdFat +SdSpiConfig sdFatSPIConfig(SPI_CS_PIN, DEDICATED_SPI, SD_SCK_MHZ(SPI_CLOCK_IN_MHz)); + +#elif defined(ESP32) // if ESP32 and no SdFat library installed + +SPIClass spi; + +#elif defined(ESP8266) + +SDFSConfig sdFSConfig(SPI_CS_PIN, SPI_HALF_SPEED); + +#elif defined(MB_ARDUINO_PICO) + +/** Use Pico SPI 1 for SPI + * MISO GPIO 12 + * MOSI GPIO 15 + * SCK GPIO 14 + * SS GPIO 13 + */ +SDFSConfig sdFSConfig(SPI_CS_PIN, SPI_HALF_SPEED, SPI1); + +#endif + +#endif + +bool SD_Card_Mounting() +{ + +#if defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD) + +#if defined(MBFS_ESP32_SDFAT_ENABLED) || defined(MBFS_SDFAT_ENABLED) + + Serial.print("\nMounting SD Card... "); + + if (!MailClient.sdBegin(&sdFatSPIConfig, SPI_CS_PIN, SPI_SCK_PIN, SPI_MISO_PIN, SPI_MOSI_PIN)) // pointer to SdSpiConfig, SS, SCK,MISO, MOSI + { + Serial.println("failed\n"); + return false; + } + else + { + Serial.println("success\n"); + return true; + } + +#elif defined(ESP32) // if ESP32 and no SdFat library installed + + Serial.print("\nMounting SD Card... "); + + spi.begin(SPI_SCK_PIN, SPI_MISO_PIN, SPI_MOSI_PIN, SPI_CS_PIN); // SPI pins config -> SCK,MISO, MOSI, SS + if (!MailClient.sdBegin(SPI_CS_PIN, &spi)) // SS, pointer to SPIClass <- SPIClass object should defined as static or global + { + Serial.println("failed\n"); + return false; + } + else + { + Serial.println("success\n"); + return true; + } +#elif defined(ESP8266) + + Serial.print("\nMounting SD Card... "); + + if (!MailClient.sdBegin(SPI_CS_PIN)) // or Firebase.sdBegin(&sdFSConfig) + { + Serial.println("failed\n"); + return false; + } + else + { + Serial.println("success\n"); + return true; + } + +#elif defined(MB_ARDUINO_PICO) + + Serial.print("\nMounting SD Card... "); + + if (!MailClient.sdBegin(&sdFSConfig)) // We begin with the SDFSConfig to use SPI 1 port + { + Serial.println("failed\n"); + return false; + } + else + { + Serial.println("success\n"); + return true; + } + +#endif + +#endif + +#if defined(MBFS_SD_FS) && defined(MBFS_CARD_TYPE_SD_MMC) + + Serial.print("\nMounting SD_MMC Card... "); + + if (!MailClient.sdMMCBegin("/sdcard", false, true)) + { + Serial.println("failed\n"); + return false; + } + else + { + Serial.println("success\n"); + return true; + } +#endif + + Serial.println("\nSD filesystem was not setup yet."); + return false; +} + +#endif diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/WiFiClientImpl.h b/lib/libesp32/ESP-Mail-Client/src/extras/WiFiClientImpl.h new file mode 100644 index 000000000..99be542a3 --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/WiFiClientImpl.h @@ -0,0 +1,565 @@ +/** + * WiFiClientImpl v1.0.1 + * + * This library provides the base client in replacement of ESP32 WiFiClient. + * + * The WiFiClient in ESP32 cannot be used in multithreading environment as in FreeRTOS task + * which can (always) lead to the assetion error "pbuf_free: p->ref > 0". + * + * Created August 20, 2023 + * + * The MIT License (MIT) + * Copyright (c) 2022 K. Suwatchai (Mobizt) + * + * + * Permission is hereby granted, free of charge, to any person returning a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#if !defined(WIFICLIENT_IMPL_H) && defined(ESP32) +#define WIFICLIENT_IMPL_H + +#include +class WiFiClientImpl : public Client +{ +public: + WiFiClientImpl(){}; + virtual ~WiFiClientImpl() { tcpClose(); }; + int connect(IPAddress ip, uint16_t port) { return tcpConnect(ip, port, _timeout); } + int connect(IPAddress ip, uint16_t port, int32_t timeout_ms) { return tcpConnect(ip, port, timeout_ms); } + int connect(const char *host, uint16_t port) + { + IPAddress address((uint32_t)0); +#if defined(WIFI_HAS_HOST_BY_NAME) + if (!WiFiGenericClass::hostByName(host, address)) + return -1; +#endif + return tcpConnect(address, port, _timeout); + } + int connect(const char *host, uint16_t port, int32_t timeout_ms) + { + _timeout = timeout_ms; + return connect(host, port); + } + size_t write(uint8_t data) { return write(&data, 1); } + size_t write(const uint8_t *buf, size_t size) { return tcpWrite(buf, size); } + size_t write_P(PGM_P buf, size_t size) { return write(buf, size); } + size_t write(Stream &stream) + { + uint8_t *buf = (uint8_t *)malloc(1360); + if (!buf) + { + return 0; + } + size_t toRead = 0, toWrite = 0, written = 0; + size_t available = stream.available(); + while (available) + { + toRead = (available > 1360) ? 1360 : available; + toWrite = stream.readBytes(buf, toRead); + written += write(buf, toWrite); + available = stream.available(); + } + free(buf); + buf = nullptr; + return written; + } + int available() { return tcpAavailable(); } + int read() + { + uint8_t data = 0; + int res = read(&data, 1); + if (res < 0) + { + return res; + } + if (res == 0) + { // No data available. + return -1; + } + return data; + } + int read(uint8_t *buf, size_t size) { return tcpRead(buf, size); } + int peek() { return tcpPeek(); } + void flush() + { + if (r_available()) + fillRxBuffer(); + _fillPos = _fillSize; + } + + void stop() { tcpClose(); } + uint8_t connected() { return tcpConnected(); } + + operator bool() + { + return connected(); + } + WiFiClientImpl &operator=(const WiFiClientImpl &other); + bool operator==(const bool value) + { + return bool() == value; + } + bool operator!=(const bool value) + { + return bool() != value; + } + bool operator==(const WiFiClientImpl &); + bool operator!=(const WiFiClientImpl &rhs) + { + return !this->operator==(rhs); + }; + + virtual int fd() const { return _socket; } + + int setSocketOption(int option, char *value, size_t len) + { + return setSocketOption(SOL_SOCKET, option, (const void *)value, len); + } + int setSocketOption(int level, int option, const void *value, size_t len) + { + int res = setsockopt(_socket, level, option, value, len); + if (res < 0) + { + log_e("fail on %d, errno: %d, \"%s\"", _socket, errno, strerror(errno)); + } + return res; + } + int setOption(int option, int *value) + { + return setSocketOption(IPPROTO_TCP, option, (const void *)value, sizeof(int)); + } + int getOption(int option, int *value) + { + socklen_t size = sizeof(int); + int res = getsockopt(_socket, IPPROTO_TCP, option, (char *)value, &size); + if (res < 0) + { + log_e("fail on fd %d, errno: %d, \"%s\"", _socket, errno, strerror(errno)); + } + return res; + } + + int setTimeout(uint32_t seconds) + { + Client::setTimeout(seconds * 1000); // This should be here? + _timeout = seconds * 1000; + if (_socket >= 0) + { + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = 0; + if (setSocketOption(SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval)) < 0) + { + return -1; + } + return setSocketOption(SO_SNDTIMEO, (char *)&tv, sizeof(struct timeval)); + } + else + { + return 0; + } + } + + int setNoDelay(bool nodelay) + { + int flag = nodelay; + return setOption(TCP_NODELAY, &flag); + } + + bool getNoDelay() + { + int flag = 0; + getOption(TCP_NODELAY, &flag); + return flag; + } + + IPAddress remoteIP() const + { + return remoteIP(_socket); + } + + IPAddress remoteIP(int fd) const + { + struct sockaddr_storage addr; + socklen_t len = sizeof addr; + getpeername(fd, (struct sockaddr *)&addr, &len); + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + return IPAddress((uint32_t)(s->sin_addr.s_addr)); + } + + uint16_t remotePort() const + { + return remotePort(_socket); + } + + uint16_t remotePort(int fd) const + { + struct sockaddr_storage addr; + socklen_t len = sizeof addr; + getpeername(fd, (struct sockaddr *)&addr, &len); + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + return ntohs(s->sin_port); + } + + IPAddress localIP() const + { + return localIP(_socket); + } + + IPAddress localIP(int fd) const + { + struct sockaddr_storage addr; + socklen_t len = sizeof addr; + getsockname(fd, (struct sockaddr *)&addr, &len); + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + return IPAddress((uint32_t)(s->sin_addr.s_addr)); + } + + uint16_t localPort() const + { + return localPort(_socket); + } + + uint16_t localPort(int fd) const + { + struct sockaddr_storage addr; + socklen_t len = sizeof addr; + getsockname(fd, (struct sockaddr *)&addr, &len); + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + return ntohs(s->sin_port); + } + + // friend class WiFiServer; + using Print::write; + +private: + int _socket = -1; + int _timeout = 30000; + size_t _rxBuffSize = 2048; + uint8_t *_rxBuff = nullptr; + size_t _fillPos = 0; + size_t _fillSize = 0; + bool _failed = false; + bool _connected = false; + + size_t r_available() + { + if (_socket < 0) + { + return 0; + } + int count; +#ifdef ESP_IDF_VERSION_MAJOR + int res = lwip_ioctl(_socket, FIONREAD, &count); +#else + int res = lwip_ioctl_r(_socket, FIONREAD, &count); +#endif + if (res < 0) + { + _failed = true; + return 0; + } + return count; + } + + size_t fillRxBuffer() + { + if (!_rxBuff && !allocRxBuffer(_rxBuffSize)) + return 0; + + if (_fillSize && _fillPos == _fillSize) + { + _fillSize = 0; + _fillPos = 0; + } + + if (!_rxBuff || _rxBuffSize <= _fillSize || !r_available()) + { + return 0; + } + int res = recv(_socket, _rxBuff + _fillSize, _rxBuffSize - _fillSize, MSG_DONTWAIT); + if (res < 0) + { + if (errno != EWOULDBLOCK) + { + _failed = true; + } + return 0; + } + _fillSize += res; + return res; + } + + bool failed() + { + return _failed; + } + + int tcpConnect(const IPAddress &ip, uint32_t port, int timeout) + { + int enable = 1; + + log_v("Starting socket"); + + _socket = -1; + + _socket = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (_socket < 0) + { + return _socket; + } + + struct sockaddr_in serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = ip; + serv_addr.sin_port = htons(port); + + if (timeout <= 0) + timeout = 30000; // Milli seconds. + + fd_set fdset; + struct timeval tv; + FD_ZERO(&fdset); + FD_SET(_socket, &fdset); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + int res = lwip_connect(_socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + + if (res < 0 && errno != EINPROGRESS) + { + log_e("connect on fd %d, errno: %d, \"%s\"", _socket, errno, strerror(errno)); + tcpClose(); + return -1; + } + + res = select(_socket + 1, nullptr, &fdset, nullptr, timeout < 0 ? nullptr : &tv); + if (res < 0) + { + log_e("select on fd %d, errno: %d, \"%s\"", _socket, errno, strerror(errno)); + tcpClose(); + return -1; + } + else if (res == 0) + { + log_i("select returned due to timeout %d ms for fd %d", timeout, _socket); + tcpClose(); + return -1; + } + else + { + int sockerr; + socklen_t len = (socklen_t)sizeof(int); + res = getsockopt(_socket, SOL_SOCKET, SO_ERROR, &sockerr, &len); + + if (res < 0) + { + log_e("getsockopt on fd %d, errno: %d, \"%s\"", _socket, errno, strerror(errno)); + tcpClose(); + return -1; + } + + if (sockerr != 0) + { + log_e("socket error on fd %d, errno: %d, \"%s\"", _socket, sockerr, strerror(sockerr)); + tcpClose(); + return -1; + } + } + + lwip_setsockopt(_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + lwip_setsockopt(_socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + + lwip_setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)); + lwip_setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)); + + fcntl(_socket, F_SETFL, fcntl(_socket, F_GETFL, 0) | O_NONBLOCK); + + _connected = true; + + return 1; + } + + void tcpClose() + { + lwip_close(_socket); + _socket = -1; + _connected = false; + freeRxBuffer(); + } + + int tcpAavailable() + { + return _fillSize - _fillPos + r_available(); + } + + int tcpPeek() + { + if (!_rxBuff || _fillPos == _fillSize && !fillRxBuffer()) + { + return -1; + } + return _rxBuff[_fillPos]; + } + + size_t tcpWrite(const uint8_t *buf, size_t size) + { + if (!tcpConnected() || !size) + return 0; + + int res = 0; + int retry = 10; + int socketFileDescriptor = _socket; + size_t totalBytesSent = 0; + size_t bytesRemaining = size; + + while (retry) + { + // use select to make sure the socket is ready for writing + fd_set set; + struct timeval tv; + FD_ZERO(&set); // empties the set + FD_SET(socketFileDescriptor, &set); // adds FD to the set + tv.tv_sec = 0; + tv.tv_usec = 1000000; + retry--; + + if (select(socketFileDescriptor + 1, NULL, &set, NULL, &tv) < 0) + { + return 0; + } + + if (FD_ISSET(socketFileDescriptor, &set)) + { + res = send(socketFileDescriptor, (void *)buf, bytesRemaining, MSG_DONTWAIT); + if (res > 0) + { + totalBytesSent += res; + if (totalBytesSent >= size) + { + // completed successfully + retry = 0; + } + else + { + buf += res; + bytesRemaining -= res; + retry = 10; + } + } + else if (res < 0) + { + log_e("fail on fd %d, errno: %d, \"%s\"", _socket, errno, strerror(errno)); + if (errno != EAGAIN) + { + // if resource was busy, can try again, otherwise give up + res = 0; + retry = 0; + } + } + else + { + // Try again + } + } + } + return totalBytesSent; + + // return ssize_t or signed size_t for error + return lwip_write(_socket, buf, size); + } + + size_t tcpRead(uint8_t *dst, size_t len) + { + + if (!dst || !len || (_fillPos == _fillSize && !fillRxBuffer())) + { + return _failed ? -1 : 0; + } + + int remain = _fillSize - _fillPos; + if (len <= remain || ((len - remain) <= (_rxBuffSize - _fillSize) && fillRxBuffer() >= (len - remain))) + { + if (len == 1) + { + *dst = _rxBuff[_fillPos]; + } + else + { + memcpy(dst, _rxBuff + _fillPos, len); + } + _fillPos += len; + return len; + } + + size_t left = len; + size_t toRead = remain; + uint8_t *buf = dst; + memcpy(buf, _rxBuff + _fillPos, toRead); + _fillPos += toRead; + left -= toRead; + buf += toRead; + while (left) + { + if (!fillRxBuffer()) + { + return len - left; + } + remain = _fillSize - _fillPos; + toRead = (remain > left) ? left : remain; + memcpy(buf, _rxBuff + _fillPos, toRead); + _fillPos += toRead; + left -= toRead; + buf += toRead; + } + return len; + } + + int tcpConnected() + { + return _socket >= 0; + } + + bool allocRxBuffer(size_t size) + { + if (_rxBuff) + freeRxBuffer(); + + _rxBuff = (uint8_t *)malloc(size); + if (!_rxBuff) + { + + log_e("Not enough memory to allocate buffer"); + _failed = true; + return false; + } + + return true; + } + + void freeRxBuffer() + { + if (_rxBuff) + free(_rxBuff); + + _rxBuff = nullptr; + } +}; + +#endif /* WIFICLIENT_IMPL_H */ diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/mb_print/mb_print.c b/lib/libesp32/ESP-Mail-Client/src/extras/mb_print/mb_print.c new file mode 100644 index 000000000..1a595f4fc --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/mb_print/mb_print.c @@ -0,0 +1,1048 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. These routines are thread +// safe and reentrant! +// Use this instead of the bloated standard/newlib printf cause these use +// malloc for printf (and may not be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MB_PRINT_C +#define MB_PRINT_C + +#include +#include + +#include "mb_print.h" + +// define this globally (e.g. gcc -DMB_PRINT_INCLUDE_CONFIG_H ...) to include the +// printf_config.h header file +// default: undefined +#ifdef MB_PRINT_INCLUDE_CONFIG_H +#include "printf_config.h" +#endif + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef MB_PRINT_NTOA_BUFFER_SIZE +#define MB_PRINT_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef MB_PRINT_FTOA_BUFFER_SIZE +#define MB_PRINT_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef MB_PRINT_DISABLE_SUPPORT_FLOAT +#define MB_PRINT_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef MB_PRINT_DISABLE_SUPPORT_EXPONENTIAL +#define MB_PRINT_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 6 digits +#ifndef MB_PRINT_DEFAULT_FLOAT_PRECISION +#define MB_PRINT_DEFAULT_FLOAT_PRECISION 6U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef MB_PRINT_MAX_FLOAT +#define MB_PRINT_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef MB_PRINT_DISABLE_SUPPORT_LONG_LONG +#define MB_PRINT_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef MB_PRINT_DISABLE_SUPPORT_PTRDIFF_T +#define MB_PRINT_SUPPORT_PTRDIFF_T +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define MB_PRINT_FLAGS_ZEROPAD (1U << 0U) +#define MB_PRINT_FLAGS_LEFT (1U << 1U) +#define MB_PRINT_FLAGS_PLUS (1U << 2U) +#define MB_PRINT_FLAGS_SPACE (1U << 3U) +#define MB_PRINT_FLAGS_HASH (1U << 4U) +#define MB_PRINT_FLAGS_UPPERCASE (1U << 5U) +#define MB_PRINT_FLAGS_CHAR (1U << 6U) +#define MB_PRINT_FLAGS_SHORT (1U << 7U) +#define MB_PRINT_FLAGS_LONG (1U << 8U) +#define MB_PRINT_FLAGS_LONG_LONG (1U << 9U) +#define MB_PRINT_FLAGS_PRECISION (1U << 10U) +#define MB_PRINT_FLAGS_ADAPT_EXP (1U << 11U) + +// import float.h for DBL_MAX +#if defined(MB_PRINT_SUPPORT_FLOAT) +#include +#endif + +// output function type +typedef void (*mb_print_out_fn_type)(char character, void *buffer, size_t idx, size_t maxlen); + +// wrapper (used as buffer) for output function type +typedef struct +{ + void (*fct)(char character, void *arg); + void *arg; +} mb_print_out_fn_wrap_type; + +// internal buffer output +static inline void mb_print_out_buffer(char character, void *buffer, size_t idx, size_t maxlen) +{ + if (idx < maxlen) + { + ((char *)buffer)[idx] = character; + } +} + +// internal null output +static inline void mb_print_out_null(char character, void *buffer, size_t idx, size_t maxlen) +{ + (void)character; + (void)buffer; + (void)idx; + (void)maxlen; +} + +// internal _putchar wrapper +static inline void mb_print_out_char(char character, void *buffer, size_t idx, size_t maxlen) +{ + (void)buffer; + (void)idx; + (void)maxlen; + if (character) + { + mb_print_putchar(character); + } +} + +// internal output function wrapper +static inline void mb_print_out_fn(char character, void *buffer, size_t idx, size_t maxlen) +{ + (void)idx; + (void)maxlen; + if (character) + { + // buffer is the output fct pointer + ((mb_print_out_fn_wrap_type *)buffer)->fct(character, ((mb_print_out_fn_wrap_type *)buffer)->arg); + } +} + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by 'maxsize' +static inline unsigned int mb_print_strlen(const char *str, size_t maxsize) +{ + const char *s; + for (s = str; *s && maxsize--; ++s) + ; + return (unsigned int)(s - str); +} + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool mb_print_is_digit(char ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +// internal ASCII string to unsigned int conversion +static unsigned int mb_print_atoi(const char **str) +{ + unsigned int i = 0U; + while (mb_print_is_digit(**str)) + { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + +// output the specified string in reverse, taking care of any zero-padding +static size_t mb_print_out_rev(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, const char *buf, size_t len, unsigned int width, unsigned int flags) +{ + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & MB_PRINT_FLAGS_LEFT) && !(flags & MB_PRINT_FLAGS_ZEROPAD)) + { + for (size_t i = len; i < width; i++) + { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) + { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & MB_PRINT_FLAGS_LEFT) + { + while (idx - start_idx < width) + { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + +// internal itoa format +static size_t mb_print_itoa_format(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, char *buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) +{ + // pad leading zeros + if (!(flags & MB_PRINT_FLAGS_LEFT)) + { + if (width && (flags & MB_PRINT_FLAGS_ZEROPAD) && (negative || (flags & (MB_PRINT_FLAGS_PLUS | MB_PRINT_FLAGS_SPACE)))) + { + width--; + } + while ((len < prec) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = '0'; + } + while ((flags & MB_PRINT_FLAGS_ZEROPAD) && (len < width) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & MB_PRINT_FLAGS_HASH) + { + if (!(flags & MB_PRINT_FLAGS_PRECISION) && len && ((len == prec) || (len == width))) + { + len--; + if (len && (base == 16U)) + { + len--; + } + } + if ((base == 16U) && !(flags & MB_PRINT_FLAGS_UPPERCASE) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = 'x'; + } + else if ((base == 16U) && (flags & MB_PRINT_FLAGS_UPPERCASE) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = 'X'; + } + else if ((base == 2U) && (len < MB_PRINT_NTOA_BUFFER_SIZE)) + { + buf[len++] = 'b'; + } + if (len < MB_PRINT_NTOA_BUFFER_SIZE) + { + buf[len++] = '0'; + } + } + + if (len < MB_PRINT_NTOA_BUFFER_SIZE) + { + if (negative) + { + buf[len++] = '-'; + } + else if (flags & MB_PRINT_FLAGS_PLUS) + { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & MB_PRINT_FLAGS_SPACE) + { + buf[len++] = ' '; + } + } + + return mb_print_out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +// internal itoa for 'long' type +static size_t mb_print_itoa_long(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[MB_PRINT_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) + { + flags &= ~MB_PRINT_FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & MB_PRINT_FLAGS_PRECISION) || value) + { + do + { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & MB_PRINT_FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < MB_PRINT_NTOA_BUFFER_SIZE)); + } + + return mb_print_itoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} + +// internal itoa for 'long long' type +#if defined(MB_PRINT_SUPPORT_LONG_LONG) +static size_t mb_print_itoa_long_long(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[MB_PRINT_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) + { + flags &= ~MB_PRINT_FLAGS_HASH; + } + + // write if precision != 0 and value is != 0 + if (!(flags & MB_PRINT_FLAGS_PRECISION) || value) + { + do + { + const char digit = (char)(value % base); + buf[len++] = digit < 10 ? '0' + digit : (flags & MB_PRINT_FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < MB_PRINT_NTOA_BUFFER_SIZE)); + } + + return mb_print_itoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); +} +#endif // MB_PRINT_SUPPORT_LONG_LONG + +#if defined(MB_PRINT_SUPPORT_FLOAT) + +#if defined(MB_PRINT_SUPPORT_EXPONENTIAL) +// forward declaration so that mb_print_ftoa can switch to exp notation for values > MB_PRINT_MAX_FLOAT +static size_t mb_print_ftoa_exp(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); +#endif + +// internal ftoa for fixed decimal floating point +static size_t mb_print_ftoa(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + char buf[MB_PRINT_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; + + // test for special values + if (value != value) + return mb_print_out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return mb_print_out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return mb_print_out_rev(out, buffer, idx, maxlen, (flags & MB_PRINT_FLAGS_PLUS) ? "fni+" : "fni", (flags & MB_PRINT_FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad + if ((value > MB_PRINT_MAX_FLOAT) || (value < -MB_PRINT_MAX_FLOAT)) + { +#if defined(MB_PRINT_SUPPORT_EXPONENTIAL) + return mb_print_ftoa_exp(out, buffer, idx, maxlen, value, prec, width, flags); +#else + return 0U; +#endif + } + + // test for negative + bool negative = false; + if (value < 0) + { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & MB_PRINT_FLAGS_PRECISION)) + { + prec = MB_PRINT_DEFAULT_FLOAT_PRECISION; + } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < MB_PRINT_FTOA_BUFFER_SIZE) && (prec > 9U)) + { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) + { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) + { + frac = 0; + ++whole; + } + } + else if (diff < 0.5) + { + } + else if ((frac == 0U) || (frac & 1U)) + { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) + { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) + { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } + else + { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < MB_PRINT_FTOA_BUFFER_SIZE) + { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) + { + break; + } + } + // add extra 0s + while ((len < MB_PRINT_FTOA_BUFFER_SIZE) && (count-- > 0U)) + { + buf[len++] = '0'; + } + if (len < MB_PRINT_FTOA_BUFFER_SIZE) + { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < MB_PRINT_FTOA_BUFFER_SIZE) + { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) + { + break; + } + } + + // pad leading zeros + if (!(flags & MB_PRINT_FLAGS_LEFT) && (flags & MB_PRINT_FLAGS_ZEROPAD)) + { + if (width && (negative || (flags & (MB_PRINT_FLAGS_PLUS | MB_PRINT_FLAGS_SPACE)))) + { + width--; + } + while ((len < width) && (len < MB_PRINT_FTOA_BUFFER_SIZE)) + { + buf[len++] = '0'; + } + } + + if (len < MB_PRINT_FTOA_BUFFER_SIZE) + { + if (negative) + { + buf[len++] = '-'; + } + else if (flags & MB_PRINT_FLAGS_PLUS) + { + buf[len++] = '+'; // ignore the space if the '+' exists + } + else if (flags & MB_PRINT_FLAGS_SPACE) + { + buf[len++] = ' '; + } + } + + return mb_print_out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +#if defined(MB_PRINT_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse +static size_t mb_print_ftoa_exp(mb_print_out_fn_type out, char *buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) +{ + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) + { + return mb_print_ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) + { + value = -value; + } + + // default precision + if (!(flags & MB_PRINT_FLAGS_PRECISION)) + { + prec = MB_PRINT_DEFAULT_FLOAT_PRECISION; + } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union + { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) + { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & MB_PRINT_FLAGS_ADAPT_EXP) + { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) + { + if ((int)prec > expval) + { + prec = (unsigned)((int)prec - expval - 1); + } + else + { + prec = 0; + } + flags |= MB_PRINT_FLAGS_PRECISION; // make sure mb_print_ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } + else + { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & MB_PRINT_FLAGS_PRECISION)) + { + --prec; + } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) + { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } + else + { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & MB_PRINT_FLAGS_LEFT) && minwidth) + { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) + { + value /= conv.F; + } + + // output the floating part + const size_t start_idx = idx; + idx = mb_print_ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~MB_PRINT_FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) + { + // output the exponential symbol + out((flags & MB_PRINT_FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = mb_print_itoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth - 1, MB_PRINT_FLAGS_ZEROPAD | MB_PRINT_FLAGS_PLUS); + // might need to right-pad spaces + if (flags & MB_PRINT_FLAGS_LEFT) + { + while (idx - start_idx < width) + out(' ', buffer, idx++, maxlen); + } + } + return idx; +} +#endif // MB_PRINT_SUPPORT_EXPONENTIAL +#endif // MB_PRINT_SUPPORT_FLOAT + +// internal vsnprintf +static int mb_print_vsnprintf_int(mb_print_out_fn_type out, char *buffer, const size_t maxlen, const char *format, va_list va) +{ + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) + { + // use null output function + out = mb_print_out_null; + } + + while (*format) + { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') + { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } + else + { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do + { + switch (*format) + { + case '0': + flags |= MB_PRINT_FLAGS_ZEROPAD; + format++; + n = 1U; + break; + case '-': + flags |= MB_PRINT_FLAGS_LEFT; + format++; + n = 1U; + break; + case '+': + flags |= MB_PRINT_FLAGS_PLUS; + format++; + n = 1U; + break; + case ' ': + flags |= MB_PRINT_FLAGS_SPACE; + format++; + n = 1U; + break; + case '#': + flags |= MB_PRINT_FLAGS_HASH; + format++; + n = 1U; + break; + default: + n = 0U; + break; + } + } while (n); + + // evaluate width field + width = 0U; + if (mb_print_is_digit(*format)) + { + width = mb_print_atoi(&format); + } + else if (*format == '*') + { + const int w = va_arg(va, int); + if (w < 0) + { + flags |= MB_PRINT_FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } + else + { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') + { + flags |= MB_PRINT_FLAGS_PRECISION; + format++; + if (mb_print_is_digit(*format)) + { + precision = mb_print_atoi(&format); + } + else if (*format == '*') + { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) + { + case 'l': + flags |= MB_PRINT_FLAGS_LONG; + format++; + if (*format == 'l') + { + flags |= MB_PRINT_FLAGS_LONG_LONG; + format++; + } + break; + case 'h': + flags |= MB_PRINT_FLAGS_SHORT; + format++; + if (*format == 'h') + { + flags |= MB_PRINT_FLAGS_CHAR; + format++; + } + break; +#if defined(MB_PRINT_SUPPORT_PTRDIFF_T) + case 't': + flags |= (sizeof(ptrdiff_t) == sizeof(long) ? MB_PRINT_FLAGS_LONG : MB_PRINT_FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j': + flags |= (sizeof(intmax_t) == sizeof(long) ? MB_PRINT_FLAGS_LONG : MB_PRINT_FLAGS_LONG_LONG); + format++; + break; + case 'z': + flags |= (sizeof(size_t) == sizeof(long) ? MB_PRINT_FLAGS_LONG : MB_PRINT_FLAGS_LONG_LONG); + format++; + break; + default: + break; + } + + // evaluate specifier + switch (*format) + { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'b': + { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') + { + base = 16U; + } + else if (*format == 'o') + { + base = 8U; + } + else if (*format == 'b') + { + base = 2U; + } + else + { + base = 10U; + flags &= ~MB_PRINT_FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') + { + flags |= MB_PRINT_FLAGS_UPPERCASE; + } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) + { + flags &= ~(MB_PRINT_FLAGS_PLUS | MB_PRINT_FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & MB_PRINT_FLAGS_PRECISION) + { + flags &= ~MB_PRINT_FLAGS_ZEROPAD; + } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) + { + // signed + if (flags & MB_PRINT_FLAGS_LONG_LONG) + { +#if defined(MB_PRINT_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = mb_print_itoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); +#endif + } + else if (flags & MB_PRINT_FLAGS_LONG) + { + const long value = va_arg(va, long); + idx = mb_print_itoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + else + { + const int value = (flags & MB_PRINT_FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & MB_PRINT_FLAGS_SHORT) ? (short int)va_arg(va, int) + : va_arg(va, int); + idx = mb_print_itoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); + } + } + else + { + // unsigned + if (flags & MB_PRINT_FLAGS_LONG_LONG) + { +#if defined(MB_PRINT_SUPPORT_LONG_LONG) + idx = mb_print_itoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); +#endif + } + else if (flags & MB_PRINT_FLAGS_LONG) + { + idx = mb_print_itoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); + } + else + { + const unsigned int value = (flags & MB_PRINT_FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & MB_PRINT_FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) + : va_arg(va, unsigned int); + idx = mb_print_itoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); + } + } + format++; + break; + } +#if defined(MB_PRINT_SUPPORT_FLOAT) + case 'f': + case 'F': + if (*format == 'F') + flags |= MB_PRINT_FLAGS_UPPERCASE; + idx = mb_print_ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#if defined(MB_PRINT_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g') || (*format == 'G')) + flags |= MB_PRINT_FLAGS_ADAPT_EXP; + if ((*format == 'E') || (*format == 'G')) + flags |= MB_PRINT_FLAGS_UPPERCASE; + idx = mb_print_ftoa_exp(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); + format++; + break; +#endif // MB_PRINT_SUPPORT_EXPONENTIAL +#endif // MB_PRINT_SUPPORT_FLOAT + case 'c': + { + unsigned int l = 1U; + // pre padding + if (!(flags & MB_PRINT_FLAGS_LEFT)) + { + while (l++ < width) + { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & MB_PRINT_FLAGS_LEFT) + { + while (l++ < width) + { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's': + { + const char *p = va_arg(va, char *); + unsigned int l = mb_print_strlen(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & MB_PRINT_FLAGS_PRECISION) + { + l = (l < precision ? l : precision); + } + if (!(flags & MB_PRINT_FLAGS_LEFT)) + { + while (l++ < width) + { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & MB_PRINT_FLAGS_PRECISION) || precision--)) + { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & MB_PRINT_FLAGS_LEFT) + { + while (l++ < width) + { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p': + { + width = sizeof(void *) * 2U; + flags |= MB_PRINT_FLAGS_ZEROPAD | MB_PRINT_FLAGS_UPPERCASE; +#if defined(MB_PRINT_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) + { + idx = mb_print_itoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void *), false, 16U, precision, width, flags); + } + else + { +#endif + idx = mb_print_itoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void *)), false, 16U, precision, width, flags); +#if defined(MB_PRINT_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%': + out('%', buffer, idx++, maxlen); + format++; + break; + + default: + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + +/////////////////////////////////////////////////////////////////////////////// + +int mb_print_printf(const char *format, ...) +{ + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = mb_print_vsnprintf_int(mb_print_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int mb_print_sprintf(char *buffer, const char *format, ...) +{ + va_list va; + va_start(va, format); + const int ret = mb_print_vsnprintf_int(mb_print_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int mb_print_snprintf_(char *buffer, size_t count, const char *format, ...) +{ + va_list va; + va_start(va, format); + const int ret = mb_print_vsnprintf_int(mb_print_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + +int mb_print_vprintf(const char *format, va_list va) +{ + char buffer[1]; + return mb_print_vsnprintf_int(mb_print_out_char, buffer, (size_t)-1, format, va); +} + +int mb_print_vsnprintf_(char *buffer, size_t count, const char *format, va_list va) +{ + return mb_print_vsnprintf_int(mb_print_out_buffer, buffer, count, format, va); +} + +int mb_print_fnprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...) +{ + va_list va; + va_start(va, format); + const mb_print_out_fn_wrap_type out_fct_wrap = {out, arg}; + const int ret = mb_print_vsnprintf_int(mb_print_out_fn, (char *)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); + va_end(va); + return ret; +} + +#endif \ No newline at end of file diff --git a/lib/libesp32/ESP-Mail-Client/src/extras/mb_print/mb_print.h b/lib/libesp32/ESP-Mail-Client/src/extras/mb_print/mb_print.h new file mode 100644 index 000000000..5ec3727bd --- /dev/null +++ b/lib/libesp32/ESP-Mail-Client/src/extras/mb_print/mb_print.h @@ -0,0 +1,108 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant. +// +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#ifndef _PRINTF_H_ +#define _PRINTF_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + /** + * Output a character to a custom device like UART, used by the printf() function + * This function is declared here only. You have to write your custom implementation somewhere + * \param character Character to output + */ + void mb_print_putchar(char character) __attribute__((used)); + + /** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro defines + * and internal underscore-appended functions like printf_() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not counting the terminating null character + */ + int mb_print_printf(const char *format, ...) __attribute__((used)); + + /** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! + * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! + * \param format A string that specifies the format of the output + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ + int mb_print_sprintf(char *buffer, const char *format, ...) __attribute__((used)); + + /** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, including a terminating null character + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that COULD have been written into the buffer, not counting the terminating + * null character. A value equal or larger than count indicates truncation. Only when the returned value + * is non-negative and less than count, the string has been completely written. + */ +#define mb_print_snprintf mb_print_snprintf_ +#define mb_print_vsnprintf mb_print_vsnprintf_ + int mb_print_snprintf_(char *buffer, size_t count, const char *format, ...) __attribute__((used)); + int mb_print_vsnprintf_(char *buffer, size_t count, const char *format, va_list va) __attribute__((used)); + + /** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character + */ + int mb_print_vprintf(const char *format, va_list va) __attribute__((used)); + + /** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() output + * \param out An output function which takes one character and an argument pointer + * \param arg An argument pointer for user data passed to output function + * \param format A string that specifies the format of the output + * \return The number of characters that are sent to the output function, not counting the terminating null character + */ + int mb_print_fnprintf(void (*out)(char character, void *arg), void *arg, const char *format, ...) __attribute__((used)); + +#ifdef __cplusplus +} +#endif + +#endif // _PRINTF_H_ \ No newline at end of file diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp index c886a666d..d31aaed2b 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.cpp @@ -48,16 +48,14 @@ enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_D // replicated from `tasmota.h` -#if defined(CONFIG_IDF_TARGET_ESP32) - const uint8_t MAX_PWMS = 16; // ESP32: 16 ledc PWM channels in total - TODO for now -#elif defined(CONFIG_IDF_TARGET_ESP32S2) - const uint8_t MAX_PWMS = 8; // ESP32S2: 8 ledc PWM channels in total -#elif defined(CONFIG_IDF_TARGET_ESP32S3) - const uint8_t MAX_PWMS = 8; // ESP32S2: 8 ledc PWM channels in total -#elif defined(CONFIG_IDF_TARGET_ESP32C3) - const uint8_t MAX_PWMS = 6; // ESP32C3: 6 ledc PWM channels in total +#if CONFIG_IDF_TARGET_ESP32 +const uint8_t MAX_PWMS = 16; // ESP32: 16 ledc PWM channels in total - TODO for now +#elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 +const uint8_t MAX_PWMS = 8; // ESP32S2/S3: 8 ledc PWM channels in total +#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6 +const uint8_t MAX_PWMS = 6; // ESP32C2/C3/C6: 6 ledc PWM channels in total #else - const uint8_t MAX_PWMS = 5; // Unknown - revert to 5 PWM max +const uint8_t MAX_PWMS = 5; // Unknown - revert to 5 PWM max #endif // current configuration of timers: frequency and resolution diff --git a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h index 07bc9c2d5..8cae8d499 100644 --- a/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h +++ b/lib/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h @@ -126,7 +126,12 @@ uint32_t analogGetTimerFrequency(uint8_t timer); #define ESPhttpUpdate httpUpdate +#if ESP_IDF_VERSION_MAJOR >= 5 +#include "rom/ets_sys.h" +#else #define os_delay_us ets_delay_us +#endif + // Serial minimal type to hold the config typedef int SerConfu8; //typedef int SerialConfig; // Will be replaced enum in esp32_hal-uart.h (#7926) diff --git a/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp b/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp index 3b66ca539..62eea2ea8 100644 --- a/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp +++ b/lib/libesp32/HttpClientLight/src/HttpClientLight.cpp @@ -32,7 +32,6 @@ #ifdef HTTPCLIENT_1_1_COMPATIBLE #include -#include #endif #include diff --git a/lib/libesp32/HttpClientLight/src/HttpClientLight.h b/lib/libesp32/HttpClientLight/src/HttpClientLight.h index 59f532d08..f18a9a232 100644 --- a/lib/libesp32/HttpClientLight/src/HttpClientLight.h +++ b/lib/libesp32/HttpClientLight/src/HttpClientLight.h @@ -32,7 +32,6 @@ #include #include #include -#include #include // import definitions from the original code @@ -274,4 +273,4 @@ protected: -#endif /* HTTPClient_Light_H_ */ \ No newline at end of file +#endif /* HTTPClient_Light_H_ */ diff --git a/lib/libesp32/HttpClientLight/src/TasUpdater.cpp b/lib/libesp32/HttpClientLight/src/TasUpdater.cpp index e359ff96f..d69463515 100644 --- a/lib/libesp32/HttpClientLight/src/TasUpdater.cpp +++ b/lib/libesp32/HttpClientLight/src/TasUpdater.cpp @@ -1,6 +1,10 @@ #include "TasUpdate.h" #include "Arduino.h" +#if ESP_IDF_VERSION_MAJOR >= 5 +#include "spi_flash_mmap.h" +#else #include "esp_spi_flash.h" +#endif #include "esp_ota_ops.h" #include "esp_image_format.h" diff --git a/lib/libesp32/berry/default/be_modtab.c b/lib/libesp32/berry/default/be_modtab.c index c4f548031..121ccff49 100644 --- a/lib/libesp32/berry/default/be_modtab.c +++ b/lib/libesp32/berry/default/be_modtab.c @@ -208,7 +208,6 @@ be_extern_native_class(OneWire); be_extern_native_class(Leds_ntv); be_extern_native_class(Leds); be_extern_native_class(Leds_animator); -be_extern_native_class(AudioOutput); be_extern_native_class(AudioGenerator); be_extern_native_class(AudioFileSource); be_extern_native_class(AudioOutputI2S); @@ -216,6 +215,7 @@ be_extern_native_class(AudioGeneratorWAV); be_extern_native_class(AudioGeneratorMP3); be_extern_native_class(AudioFileSourceFS); be_extern_native_class(AudioOpusDecoder); +be_extern_native_class(AudioInputI2S); be_extern_native_class(md5); be_extern_native_class(udp); be_extern_native_class(webclient); @@ -295,8 +295,7 @@ BERRY_LOCAL bclass_array be_class_table = { &be_native_class(lv_clock_icon), #endif // USE_LVGL -#ifdef USE_I2S_AUDIO_BERRY - &be_native_class(AudioOutput), +#if defined(USE_I2S_AUDIO_BERRY) && (ESP_IDF_VERSION_MAJOR >= 5) &be_native_class(AudioGenerator), &be_native_class(AudioFileSource), &be_native_class(AudioOutputI2S), @@ -306,7 +305,8 @@ BERRY_LOCAL bclass_array be_class_table = { &be_native_class(AudioFileSourceFS), #endif // USE_UFILESYS &be_native_class(AudioOpusDecoder), -#endif // USE_I2S_AUDIO_BERRY + &be_native_class(AudioInputI2S), +#endif // defined(USE_I2S_AUDIO_BERRY) && (ESP_IDF_VERSION_MAJOR >= 5) #if defined(USE_BERRY_INT64) || defined(USE_MATTER_DEVICE) &be_native_class(int64), #endif diff --git a/lib/libesp32/berry/library.json b/lib/libesp32/berry/library.json index 38df6e3fc..e5b08a1de 100644 --- a/lib/libesp32/berry/library.json +++ b/lib/libesp32/berry/library.json @@ -27,6 +27,6 @@ "+<*.cpp>", "+<*.h>" ], - "flags": [ "-I$PROJECT_DIR/tasmota", "-DCOMPILE_BERRY_LIB" ] + "flags": [ "-I$PROJECT_DIR/tasmota", "-DCOMPILE_BERRY_LIB", "-includeesp_idf_version.h" ] } } diff --git a/lib/libesp32/berry/src/be_code.c b/lib/libesp32/berry/src/be_code.c index ac4208a01..147036948 100644 --- a/lib/libesp32/berry/src/be_code.c +++ b/lib/libesp32/berry/src/be_code.c @@ -358,7 +358,7 @@ static int suffix_destreg(bfuncinfo *finfo, bexpdesc *e1, int dst, bbool no_reg_ /* both are ETREG, we keep the lowest and discard the other */ if (reg1 != reg2) { cand_dst = min(reg1, reg2); - be_code_freeregs(finfo, 1); /* and free the other one */ + be_code_freeregs(finfo, finfo->freereg - cand_dst); /* and free the other one */ } else { cand_dst = reg1; /* both ETREG are equal, we return its value */ } @@ -726,8 +726,8 @@ int be_code_setvar(bfuncinfo *finfo, bexpdesc *e1, bexpdesc *e2, bbool keep_reg) /* if local or const, allocate a new register and copy value */ int be_code_nextreg(bfuncinfo *finfo, bexpdesc *e) { - int dst = finfo->freereg; int src = exp2anyreg(finfo, e); /* get variable register index */ + int dst = finfo->freereg; if ((e->type != ETREG) || (src < dst - 1)) { /* move local and const to new register, don't move if already top of stack */ code_move(finfo, dst, src); be_code_allocregs(finfo, 1); @@ -832,8 +832,8 @@ void be_code_ret(bfuncinfo *finfo, bexpdesc *e) /* Both expdesc are materialized in kregs */ static void package_suffix(bfuncinfo *finfo, bexpdesc *c, bexpdesc *k) { - int key = exp2anyreg(finfo, k); c->v.ss.obj = exp2anyreg(finfo, c); + int key = exp2anyreg(finfo, k); c->v.ss.tt = c->type; c->v.ss.idx = key; } diff --git a/lib/libesp32/berry/tests/compiler.be b/lib/libesp32/berry/tests/compiler.be index 90303734f..3741095a2 100644 --- a/lib/libesp32/berry/tests/compiler.be +++ b/lib/libesp32/berry/tests/compiler.be @@ -26,3 +26,34 @@ assert(s == "foo") b.ok() assert(s == "foo") + +# detect a wrong compilation when accessing index +# Berry compilation problem: +# +# ```berry +# def f(self) print(self.a[128]) end +# ``` +# +# Compilation assigns unwanted registers: +# ``` +# 0x60040001, // 0000 GETGBL R1 G1 +# 0x540A007F, // 0001 LDINT R2 128 +# 0x880C0100, // 0002 GETMBR R3 R0 K0 +# 0x94080602, // 0003 GETIDX R2 R3 R2 +# 0x5C100400, // 0004 MOVE R4 R2 <- PROBLEM +# 0x7C040200, // 0005 CALL R1 1 +# 0x80000000, // 0006 RET 0 +# ``` +# +# With the fix, the integer is retrieved in second place, and erroneous register is not allocated: +# ``` +# 0x60040001, // 0000 GETGBL R1 G1 +# 0x88080100, // 0001 GETMBR R2 R0 K0 +# 0x540E007F, // 0002 LDINT R3 128 +# 0x94080403, // 0003 GETIDX R2 R2 R3 +# 0x7C040200, // 0004 CALL R1 1 +# 0x80000000, // 0005 RET 0 +# ``` +def f(a,b) return b end +l = [1,2,3,4] +assert(f(l[-1],l[-2]) == 3) diff --git a/lib/libesp32/berry/tools/coc/block_builder.py b/lib/libesp32/berry/tools/coc/block_builder.py index 2d76465df..6535fd40b 100644 --- a/lib/libesp32/berry/tools/coc/block_builder.py +++ b/lib/libesp32/berry/tools/coc/block_builder.py @@ -159,7 +159,7 @@ class block_builder: def writefile(self, filename, text): otext = "#include \"be_constobj.h\"\n\n" + text - with open(filename, "w") as f: + with open(filename, "w", encoding='utf-8') as f: f.write(otext) def dumpfile(self, path): diff --git a/lib/libesp32/berry/tools/coc/coc b/lib/libesp32/berry/tools/coc/coc index 2111b1ea2..1a12c01e6 100755 --- a/lib/libesp32/berry/tools/coc/coc +++ b/lib/libesp32/berry/tools/coc/coc @@ -34,7 +34,7 @@ class builder: if re.search(r"\.(h|c|cc|cpp)$", filename): # print(f"> parse {filename}") text = "" - with open(filename) as f: + with open(filename, encoding='utf-8') as f: text = f.read() # print(f"> len(text)={len(text)}") parser = coc_parser(text) diff --git a/lib/libesp32/berry/tools/coc/macro_table.py b/lib/libesp32/berry/tools/coc/macro_table.py index 8b4518ddc..de741040e 100644 --- a/lib/libesp32/berry/tools/coc/macro_table.py +++ b/lib/libesp32/berry/tools/coc/macro_table.py @@ -22,7 +22,7 @@ class macro_table: def scan_file(self, filename): str = "" - with open(filename) as f: + with open(filename, encoding='utf-8') as f: str = f.read() r = macro_table.pat.findall(str) for it in r: diff --git a/lib/libesp32/berry_mapping/src/be_class_wrapper.c b/lib/libesp32/berry_mapping/src/be_class_wrapper.c index 71c29eff9..94cbb9f51 100644 --- a/lib/libesp32/berry_mapping/src/be_class_wrapper.c +++ b/lib/libesp32/berry_mapping/src/be_class_wrapper.c @@ -360,7 +360,7 @@ int be_check_arg_type(bvm *vm, int arg_start, int argc, const char * arg_type, i } } // berry_log_C(">> be_call_c_func arg %i, type %s", i, arg_type_check ? type_short_name : ""); - p[p_idx] = be_convert_single_elt(vm, i + arg_start, arg_type_check ? type_short_name : NULL, &buf_len); + p[p_idx] = be_convert_single_elt(vm, i + arg_start, arg_type_check ? type_short_name : NULL, (int*)&buf_len); // berry_log_C("< ret[%i]=%i", p_idx, p[p_idx]); p_idx++; diff --git a/lib/libesp32/berry_matter/solidify_all.be b/lib/libesp32/berry_matter/solidify_all.be index 54a1d197e..cf19458aa 100755 --- a/lib/libesp32/berry_matter/solidify_all.be +++ b/lib/libesp32/berry_matter/solidify_all.be @@ -25,6 +25,20 @@ end var prefix_dir = "src/embedded/" var prefix_out = "src/solidify/" +def sort(l) + # insertion sort + for i:1..size(l)-1 + var k = l[i] + var j = i + while (j > 0) && (l[j-1] > k) + l[j] = l[j-1] + j -= 1 + end + l[j] = k + end + return l +end + def clean_directory(dir) var file_list = os.listdir(dir) for f : file_list @@ -78,6 +92,7 @@ end clean_directory(prefix_out) var src_file_list = os.listdir(prefix_dir) +src_file_list = sort(src_file_list) for src_file : src_file_list if src_file[0] == '.' continue end parse_file(src_file, prefix_out) diff --git a/lib/libesp32/berry_matter/src/be_matter_module.c b/lib/libesp32/berry_matter/src/be_matter_module.c index 9c28d4014..f5a97b7ae 100644 --- a/lib/libesp32/berry_matter/src/be_matter_module.c +++ b/lib/libesp32/berry_matter/src/be_matter_module.c @@ -177,8 +177,9 @@ BE_FUNC_CTYPE_DECLARE(matter_get_command_name, "s", "ii") extern const void* matter_get_ip_bytes(const char* ip_str, size_t* ret_len); BE_FUNC_CTYPE_DECLARE(matter_get_ip_bytes, "&", "s") +extern int matter_publish_command(bvm *vm); -#include "solidify/solidified_Matter_inspect.h" +#include "solidify/solidified_Matter_0_Inspect.h" extern const bclass be_class_Matter_TLV; // need to declare it upfront because of circular reference #include "solidify/solidified_Matter_Path.h" @@ -200,7 +201,7 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because #include "solidify/solidified_Matter_IM_Subscription.h" #include "solidify/solidified_Matter_IM.h" #include "solidify/solidified_Matter_Control_Message.h" -#include "solidify/solidified_Matter_Plugin.h" +#include "solidify/solidified_Matter_Plugin_0.h" #include "solidify/solidified_Matter_Base38.h" #include "solidify/solidified_Matter_UI.h" #include "solidify/solidified_Matter_Device.h" @@ -208,37 +209,47 @@ extern const bclass be_class_Matter_TLV; // need to declare it upfront because #include "../generate/be_matter_certs.h" -#include "solidify/solidified_Matter_Plugin_Root.h" -#include "solidify/solidified_Matter_Plugin_Aggregator.h" -#include "solidify/solidified_Matter_Plugin_Device.h" -#include "solidify/solidified_Matter_Plugin_OnOff.h" -#include "solidify/solidified_Matter_Plugin_Light0.h" -#include "solidify/solidified_Matter_Plugin_Light1.h" -#include "solidify/solidified_Matter_Plugin_Light2.h" -#include "solidify/solidified_Matter_Plugin_Light3.h" -#include "solidify/solidified_Matter_Plugin_Shutter.h" -#include "solidify/solidified_Matter_Plugin_ShutterTilt.h" -#include "solidify/solidified_Matter_Plugin_Sensor.h" -#include "solidify/solidified_Matter_Plugin_Sensor_Pressure.h" -#include "solidify/solidified_Matter_Plugin_Sensor_Temp.h" -#include "solidify/solidified_Matter_Plugin_Sensor_Illuminance.h" -#include "solidify/solidified_Matter_Plugin_Sensor_Humidity.h" -#include "solidify/solidified_Matter_Plugin_Sensor_Occupancy.h" -#include "solidify/solidified_Matter_Plugin_Sensor_OnOff.h" -#include "solidify/solidified_Matter_Plugin_Sensor_Contact.h" -#include "solidify/solidified_Matter_Plugin_Bridge_HTTP.h" -#include "solidify/solidified_Matter_Plugin_Bridge_OnOff.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Light0.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Light1.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Light2.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Light3.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Sensor.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Sensor_Pressure.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Sensor_Temp.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Sensor_Illuminance.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Sensor_Humidity.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Sensor_Occupancy.h" -#include "solidify/solidified_Matter_Plugin_Bridge_Sensor_Contact.h" +#include "solidify/solidified_Matter_Plugin_1_Root.h" +#include "solidify/solidified_Matter_Plugin_2_Aggregator.h" +#include "solidify/solidified_Matter_Plugin_1_Device.h" +#include "solidify/solidified_Matter_Plugin_2_OnOff.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_OnOff.h" +#include "solidify/solidified_Matter_Plugin_2_Light0.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Light0.h" +#include "solidify/solidified_Matter_Plugin_3_Light1.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Light1.h" +#include "solidify/solidified_Matter_Plugin_4_Light2.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Light2.h" +#include "solidify/solidified_Matter_Plugin_4_Light3.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Light3.h" +#include "solidify/solidified_Matter_Plugin_2_Shutter.h" +#include "solidify/solidified_Matter_Plugin_3_ShutterTilt.h" +#include "solidify/solidified_Matter_Plugin_2_Sensor.h" +#include "solidify/solidified_Matter_Plugin_3_Sensor_Pressure.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Pressure.h" +#include "solidify/solidified_Matter_Plugin_3_Sensor_Temp.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Temp.h" +#include "solidify/solidified_Matter_Plugin_3_Sensor_Illuminance.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Illuminance.h" +#include "solidify/solidified_Matter_Plugin_3_Sensor_Humidity.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Humidity.h" +#include "solidify/solidified_Matter_Plugin_3_Sensor_Occupancy.h" +#include "solidify/solidified_Matter_Plugin_3_Sensor_OnOff.h" +#include "solidify/solidified_Matter_Plugin_3_Sensor_Contact.h" +#include "solidify/solidified_Matter_Plugin_9_Virt_Sensor_Contact.h" +#include "solidify/solidified_Matter_Plugin_2_Bridge_HTTP.h" +#include "solidify/solidified_Matter_Plugin_4_Bridge_OnOff.h" +#include "solidify/solidified_Matter_Plugin_3_Bridge_Light0.h" +#include "solidify/solidified_Matter_Plugin_4_Bridge_Light1.h" +#include "solidify/solidified_Matter_Plugin_5_Bridge_Light2.h" +#include "solidify/solidified_Matter_Plugin_5_Bridge_Light3.h" +#include "solidify/solidified_Matter_Plugin_3_Bridge_Sensor.h" +#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Pressure.h" +#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Temp.h" +#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Illuminance.h" +#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Humidity.h" +#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Occupancy.h" +#include "solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Contact.h" /*********************************************************************************************\ * Get a bytes() object of the certificate DAC/PAI_Cert @@ -276,6 +287,7 @@ module matter (scope: global, strings: weak) { setmember, closure(matter_setmember_closure) member, closure(matter_member_closure) get_ip_bytes, ctype_func(matter_get_ip_bytes) + publish_command, func(matter_publish_command) get_vendor_name, ctype_func(matter_get_vendor_name) get_cluster_name, ctype_func(matter_get_cluster_name) @@ -288,6 +300,8 @@ module matter (scope: global, strings: weak) { sort, closure(matter_sort_closure) jitter, closure(matter_jitter_closure) inspect, closure(matter_inspect_closure) + consolidate_clusters, closure(matter_consolidate_clusters_closure) + UC_LIST, closure(matter_UC_LIST_closure) Profiler, class(be_class_Matter_Profiler) // Status codes @@ -420,20 +434,30 @@ module matter (scope: global, strings: weak) { Plugin_Aggregator, class(be_class_Matter_Plugin_Aggregator) // Aggregator Plugin_Device, class(be_class_Matter_Plugin_Device) // Generic device (abstract) Plugin_OnOff, class(be_class_Matter_Plugin_OnOff) // Relay/Light behavior (OnOff) + Plugin_Virt_OnOff, class(be_class_Matter_Plugin_Virt_OnOff) // Relay/Light virtual (OnOff) Plugin_Light0, class(be_class_Matter_Plugin_Light0) // OnOff Light + Plugin_Virt_Light0, class(be_class_Matter_Plugin_Virt_Light0) // OnOff Light Virtual Plugin_Light1, class(be_class_Matter_Plugin_Light1) // Dimmable Light + Plugin_Virt_Light1, class(be_class_Matter_Plugin_Virt_Light1) // Dimmable Light Virtual Plugin_Light2, class(be_class_Matter_Plugin_Light2) // Color Temperature Light + Plugin_Virt_Light2, class(be_class_Matter_Plugin_Virt_Light2) // Color Temperature Light Virtual Plugin_Light3, class(be_class_Matter_Plugin_Light3) // Extended Color Light + Plugin_Virt_Light3, class(be_class_Matter_Plugin_Virt_Light3) // Extended Color Light Virtual Plugin_Shutter, class(be_class_Matter_Plugin_Shutter) // Shutter Plugin_ShutterTilt, class(be_class_Matter_Plugin_ShutterTilt) // Shutter + Tilt Plugin_Sensor, class(be_class_Matter_Plugin_Sensor) // Generic Sensor Plugin_Sensor_Pressure, class(be_class_Matter_Plugin_Sensor_Pressure) // Pressure Sensor + Plugin_Sensor_Virt_Pressure, class(be_class_Matter_Plugin_Virt_Sensor_Pressure) // Pressure Virtual Sensor Plugin_Sensor_Temp, class(be_class_Matter_Plugin_Sensor_Temp) // Temperature Sensor + Plugin_Virt_Sensor_Temp, class(be_class_Matter_Plugin_Virt_Sensor_Temp) // Temperature Sensor Plugin_Sensor_Illuminance, class(be_class_Matter_Plugin_Sensor_Illuminance) // Illuminance Sensor + Plugin_Virt_Sensor_Illuminance, class(be_class_Matter_Plugin_Virt_Sensor_Illuminance) // Illuminance Virtual Sensor Plugin_Sensor_Humidity, class(be_class_Matter_Plugin_Sensor_Humidity) // Humidity Sensor + Plugin_Sensor_Virt_Humidity, class(be_class_Matter_Plugin_Virt_Sensor_Humidity) // Humidity Virtual Sensor Plugin_Sensor_Occupancy, class(be_class_Matter_Plugin_Sensor_Occupancy) // Occupancy Sensor Plugin_Sensor_OnOff, class(be_class_Matter_Plugin_Sensor_OnOff) // Simple OnOff Sensor Plugin_Sensor_Contact, class(be_class_Matter_Plugin_Sensor_Contact) // Contact Sensor + Plugin_Virt_Sensor_Contact, class(be_class_Matter_Plugin_Virt_Sensor_Contact) // Virtual Contact Sensor Plugin_Bridge_HTTP, class(be_class_Matter_Plugin_Bridge_HTTP) // HTTP bridge superclass Plugin_Bridge_OnOff, class(be_class_Matter_Plugin_Bridge_OnOff) // HTTP Relay/Light behavior (OnOff) Plugin_Bridge_Light0, class(be_class_Matter_Plugin_Bridge_Light0) // HTTP OnOff Light diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_inspect.be b/lib/libesp32/berry_matter/src/embedded/Matter_0_Inspect.be similarity index 67% rename from lib/libesp32/berry_matter/src/embedded/Matter_inspect.be rename to lib/libesp32/berry_matter/src/embedded/Matter_0_Inspect.be index 832046b0a..5d6f31de0 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_inspect.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_0_Inspect.be @@ -74,3 +74,42 @@ def inspect(p) end end matter.inspect = inspect + + +############################################################# +# consolidate_clusters +# +# Build a consolidated map of all the `CLUSTERS` static vars +# from the inheritance hierarchy +#@ solidify:matter.consolidate_clusters,weak +def consolidate_clusters(cl, m) + var cl_parent = super(cl).CLUSTERS + var ret = {} + # clone cl_parent + for k: cl_parent.keys() + # print(f"{k=} {cl_parent[k]=}") + ret[k] = cl_parent[k].copy() + end + # add all keys from m + # print("--- step 2") + for k: m.keys() + # print(f"{k=} {ret.find(k)=} {m[k]=}") + var l = ret.find(k) + if l == nil l = [] end + ret[k] = l + m[k] + end + # print(ret) + return ret +end +matter.consolidate_clusters = consolidate_clusters + +############################################################# +# consolidate_update_commands_list +# +# Build a consolidated list and remove duplicates +#@ solidify:matter.UC_LIST,weak +def UC_LIST(cl, *l) + var uc_parent = super(cl).UPDATE_COMMANDS + return uc_parent + l +end +matter.UC_LIST = UC_LIST diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be index db7bc669e..d2427a2ce 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Commissioning.be @@ -294,7 +294,7 @@ class Matter_Commisioning_Context end for fabric : self.device.sessions.fabrics if fabric.noc == nil || fabric.fabric_id == nil || fabric.device_id == nil continue end - # compute candidateDestinationId, Section 4.13.2.4.1, “Destination Identifier” + # compute candidateDestinationId, Section 4.13.2.4.1, "Destination Identifier" var destinationMessage = initiatorRandom + fabric.get_ca_pub() + fabric.fabric_id + fabric.device_id var key = fabric.get_ipk_group_key() # tasmota.log("MTR: SIGMA1: destinationMessage=" + destinationMessage.tohex(), 4) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be index d272c4061..64915824a 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Device.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Device.be @@ -664,6 +664,23 @@ class Matter_Device return nil end + ############################################################# + # Find plugin by endpoint + def find_plugin_by_friendly_name(name) + if (name == nil) || (size(name) == 0) return nil end # invalid name + + var idx = 0 + while idx < size(self.plugins) + var pl = self.plugins[idx] + var pl_name = pl.get_name() + if (pl_name != nil) && (size(pl_name) > 0) && (pl_name == name) + return pl + end + idx += 1 + end + return nil + end + ############################################################# # Persistance of Matter Device parameters # @@ -886,7 +903,7 @@ class Matter_Device # Add Hostname (based on MAC) with IPv4/IPv6 addresses var eth = tasmota.eth() self.hostname_eth = string.replace(eth.find("mac"), ':', '') - if !self.ipv4only + if !self.ipv4only || !eth.contains('ip6local') # tasmota.log(format("MTR: calling mdns.add_hostname(%s, %s, %s)", self.hostname_eth, eth.find('ip6local',''), eth.find('ip','')), 4) mdns.add_hostname(self.hostname_eth, eth.find('ip6local',''), eth.find('ip',''), eth.find('ip6','')) else @@ -896,11 +913,11 @@ class Matter_Device else var wifi = tasmota.wifi() self.hostname_wifi = string.replace(wifi.find("mac"), ':', '') - if !self.ipv4only + if !self.ipv4only || !wifi.contains('ip6local') # tasmota.log(format("MTR: calling mdns.add_hostname(%s, %s, %s)", self.hostname_wifi, wifi.find('ip6local',''), wifi.find('ip','')), 4) mdns.add_hostname(self.hostname_wifi, wifi.find('ip6local',''), wifi.find('ip',''), wifi.find('ip6','')) else - tasmota.log(format("MTR: calling mdns.add_hostname(%s, %s)", self.hostname_eth, wifi.find('ip','')), 3) + tasmota.log(format("MTR: calling mdns.add_hostname(%s, %s)", self.hostname_wifi, wifi.find('ip','')), 3) mdns.add_hostname(self.hostname_wifi, wifi.find('ip','')) end end @@ -1271,7 +1288,7 @@ class Matter_Device # get a class name light "light0" and return displayname def get_plugin_class_displayname(name) var cl = self.plugins_classes.find(name) - return cl ? cl.NAME : "" + return cl ? cl.DISPLAY_NAME : "" end ############################################################# @@ -1514,6 +1531,8 @@ class Matter_Device # def register_commands() tasmota.add_cmd("MtrJoin", /cmd_found, idx, payload, payload_json -> self.MtrJoin(cmd_found, idx, payload, payload_json)) + tasmota.add_cmd("MtrUpdate", /cmd_found, idx, payload, payload_json -> self.MtrUpdate(cmd_found, idx, payload, payload_json)) + tasmota.add_cmd("MtrInfo", /cmd_found, idx, payload, payload_json -> self.MtrInfo(cmd_found, idx, payload, payload_json)) end ##################################################################### @@ -1531,6 +1550,114 @@ class Matter_Device tasmota.resp_cmnd_done() end + ##################################################################### + # `MtrUpdate` + # + # MtrUpdate {"ep":1, "Power":1} + # MtrUpdate {"name":"ep1", "power":1} + # MtrUpdate {"Name":"Light0", "Power":0} + # MtrUpdate {"Name":"Light0", "Power":1} + # MtrUpdate {"Name":"Light1", "Power":0} + # MtrUpdate {"Name":"Light1", "Power":1,"Bri":55} + # MtrUpdate {"Name":"Light2", "Power":0} + # MtrUpdate {"Name":"Light2", "Power":1, "CT":400, "Bri":20} + # MtrUpdate {"Name":"Light3", "Power":0} + # MtrUpdate {"Name":"Light3", "Power":1, "Bri":20, "Hue":85, "Sat":200} + # + def MtrUpdate(cmd_found, idx, payload, payload_json) + if payload_json == nil return tasmota.resp_cmnd_str("Invalid JSON") end + + var key_ep = tasmota.find_key_i(payload_json, 'Ep') + var key_name = tasmota.find_key_i(payload_json, 'Name') + if key_ep || key_name + var pl = nil # plugin instance + + if key_ep + var ep = int(payload_json[key_ep]) + if ep <= 0 return tasmota.resp_cmnd_str("Invalid 'Ep' attribute") end + pl = self.find_plugin_by_endpoint(ep) + payload_json.remove(key_ep) + end + + if key_name + if pl == nil + pl = self.find_plugin_by_friendly_name(payload_json[key_name]) + end + payload_json.remove(key_name) + end + + if (pl == nil) return tasmota.resp_cmnd_str("Invalid Device") end + if (!pl.VIRTUAL) return tasmota.resp_cmnd_str("Device is not virtual") end + # filter parameter accedpted by plugin, and rename with canonical + # Ex: {"power":1,"HUE":2} becomes {"Power":1,"Hue":2} + var uc = pl.consolidate_update_commands() + # check that all commands are in the list of supported commands + var cmd_cleaned = {} + for k: payload_json.keys() + var cleaned_command_idx = tasmota.find_list_i(uc, k) + if (cleaned_command_idx == nil) + tasmota.resp_cmnd_str(f"Invalid attribute '{k}'") + return + end + cmd_cleaned[uc[cleaned_command_idx]] = payload_json[k] + end + # call plug-in + pl.update_virtual(cmd_cleaned) + var state_json = pl.state_json() + if state_json + var cmnd_status = f'{{"{cmd_found}":{state_json}}}' + return tasmota.resp_cmnd(cmnd_status) + else + return tasmota.resp_cmnd_done() + end + end + + tasmota.resp_cmnd_str("Missing 'Device' attribute") + end + + ##################################################################### + # `MtrInfo` + # + # MtrInfo 9 + def MtrInfo(cmd_found, idx, payload, payload_json) + if payload == "" + # dump all devices + end + + if payload == "" + # dump all + for pl: self.plugins + self.MtrInfo_one(pl.endpoint) + end + + elif type(payload_json) == 'int' + # try ep number + self.MtrInfo_one(payload_json) + + else + # try by name + var pl = self.find_plugin_by_friendly_name(payload) + if pl != nil + self.MtrInfo_one(pl.endpoint) + end + end + + tasmota.resp_cmnd_done() + end + + # output for a single endpoint + def MtrInfo_one(ep) + var pl = self.find_plugin_by_endpoint(ep) + if pl == nil return end # abort + + var state_json = pl.state_json() + if state_json + var mtr_info = f'{{"' 'MtrInfo"' ':{state_json}}}' + # publish + # tasmota.publish_rule(mtr_info) + tasmota.publish_result(mtr_info, "") + end + end end matter.Device = Matter_Device diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be index 016115fc8..9f4c8613d 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_IM.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_IM.be @@ -866,7 +866,7 @@ class Matter_IM var res = self.device.invoke_request(msg.session, q.command_fields, ctx) matter.profiler.log("COMMAND DONE") var params_log = (ctx.log != nil) ? "(" + str(ctx.log) + ") " : "" - tasmota.log(format("MTR: >Command (%6i) %s %s %s", msg.session.local_session_id, ctx_str, cmd_name ? cmd_name : "", params_log), ctx.endpoint != 0 ? 2 : 3 #- don't log for endpoint 0 -# ) + tasmota.log(format("MTR: >Command (%6i) %s %s %s", msg.session.local_session_id, ctx_str, cmd_name ? cmd_name : "", params_log), 3) # tasmota.log("MTR: Perf/Command = " + str(debug.counters()), 4) ctx.log = nil var raw = bytes(32) @@ -927,9 +927,8 @@ class Matter_IM var res = self.device.invoke_request(msg.session, ctx.command_fields, ctx) matter.profiler.log("COMMAND DONE") var params_log = (ctx.log != nil) ? "(" + str(ctx.log) + ") " : "" - var cmd_log_level = ctx.endpoint != 0 ? 2 : 3 #- don't log for endpoint 0 -# - if tasmota.loglevel(cmd_log_level) - tasmota.log(format("MTR: >Command1 (%6i) %s %s %s", msg.session.local_session_id, ctx_str, cmd_name ? cmd_name : "", params_log), cmd_log_level) + if tasmota.loglevel(3) + tasmota.log(format("MTR: >Command1 (%6i) %s %s %s", msg.session.local_session_id, ctx_str, cmd_name ? cmd_name : "", params_log), 3) end # tasmota.log("MTR: Perf/Command = " + str(debug.counters()), 4) ctx.log = nil diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_0.be similarity index 78% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_0.be index 9a52fa6cc..3e7bb9e42 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_0.be @@ -27,22 +27,26 @@ import matter class Matter_Plugin # Global type system for plugins static var TYPE = "" # name of the plug-in in json - static var NAME = "" # display name of the plug-in + static var DISPLAY_NAME = "" # display name of the plug-in static var ARG = "" # additional argument name (or empty if none) static var ARG_TYPE = / x -> str(x) # function to convert argument to the right type static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') # Behavior of the plugin, frequency at which `update_shadow()` is called static var UPDATE_TIME = 5000 # default is every 5 seconds + static var VIRTUAL = false # set to true only for virtual devices var update_next # next timestamp for update # Configuration of the plugin: clusters and type static var CLUSTERS = { 0x001D: [0,1,2,3,0xFFFC,0xFFFD], # Descriptor Cluster 9.5 p.453 0x0039: [0x11], # Bridged Device Basic Information 9.13 p.485 } + # Accepted Update commands for virtual devices + static var UPDATE_COMMANDS = [] var device # reference to the `device` global object var endpoint # current endpoint var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy var tick # tick value when it was last updated + var node_label # name of the endpoint, used only in bridge mode, "" if none ############################################################# # MVC Model @@ -61,6 +65,7 @@ class Matter_Plugin self.endpoint = endpoint self.clusters = self.consolidate_clusters() self.parse_configuration(config) + self.node_label = config.find("name", "") end # proxy for the same method in IM @@ -126,24 +131,49 @@ class Matter_Plugin # Build a consolidated map of all the `CLUSTERS` static vars # from the inheritance hierarchy def consolidate_clusters() - def real_super(o) return super(o) end # enclose `super()` in a static function to disable special behavior for super in instances - var ret = {} - var o = self # start with self - while o != nil # when we rich highest class, `super()` returns `nil` - var CL = o.CLUSTERS - for k: CL.keys() - # check if key already exists - if !ret.contains(k) ret[k] = [] end - for attr: CL[k] # iterate on values - if ret[k].find(attr) == nil - ret[k].push(attr) - end - end - end + return self.CLUSTERS + # def real_super(o) return super(o) end # enclose `super()` in a static function to disable special behavior for super in instances + # var ret = {} + # var o = self # start with self + # while o != nil # when we rich highest class, `super()` returns `nil` + # var CL = o.CLUSTERS + # for k: CL.keys() + # # check if key already exists + # if !ret.contains(k) ret[k] = [] end + # for attr: CL[k] # iterate on values + # if ret[k].find(attr) == nil + # ret[k].push(attr) + # end + # end + # end - o = real_super(o) + # o = real_super(o) + # end + # return ret + end + + ############################################################# + # consolidate_update_commands + # + # Return consolidated "update commands" for this class + def consolidate_update_commands() + return self.UPDATE_COMMANDS + end + + ############################################################# + # Publish to MQTT a command received from controller + # + # we limit to 3 commands (to we need more?) + def publish_command(key1, value1, key2, value2, key3, value3) + import json + var payload = f"{json.dump(key1)}:{json.dump(value1)}" + if key2 != nil + payload = f"{payload},{json.dump(key2)}:{json.dump(value2)}" end - return ret + if key3 != nil + payload = f"{payload},{json.dump(key3)}:{json.dump(value3)}" + end + matter.publish_command('MtrReceived', self.endpoint, self.node_label, payload) end ############################################################# @@ -184,6 +214,14 @@ class Matter_Plugin return self.clusters.contains(cluster) && self.endpoints.find(endpoint) != nil end + def set_name(n) + if n != self.node_label + self.attribute_updated(0x0039, 0x0005) + end + self.node_label = n + end + def get_name() return self.node_label end + ############################################################# # MVC Model # @@ -343,6 +381,41 @@ class Matter_Plugin return conf end + ############################################################# + # append_state_json + # + # Output the current state in JSON + # Takes the JSON string prefix + # New values need to be appended with `,"key":value` (including prefix comma) + def append_state_json() + return "" + end + + # This is to be called by matter_device to get the full state JSON + # including "Ep":,"Name"=" int(x) # function to convert argument to the right type static var ARG_HINT = "Relay number" static var UPDATE_TIME = 250 # update every 250ms - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 # 0x0005: inherited # Scenes 1.4 p.30 - no writable 0x0006: [0,0xFFFC,0xFFFD], # On/Off 1.5 p.48 - } + }) + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Power") static var TYPES = { 0x010A: 2 } # On/Off Plug-in Unit - var tasmota_relay_index # Relay number in Tasmota (zero based) - var shadow_onoff # fake status for now # TODO + # Inherited + # var device # reference to the `device` global object + # var endpoint # current endpoint + # var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy + # var tick # tick value when it was last updated + # var node_label # name of the endpoint, used only in bridge mode, "" if none + var shadow_onoff # (bool) status of the light power on/off + var tasmota_relay_index # Relay number in Tasmota (zero based) ############################################################# # Constructor @@ -65,12 +69,14 @@ class Matter_Plugin_OnOff : Matter_Plugin_Device # Update shadow # def update_shadow() - var state = tasmota.get_power(self.tasmota_relay_index - 1) - if state != nil - if self.shadow_onoff != nil && self.shadow_onoff != bool(state) - self.attribute_updated(0x0006, 0x0000) + if !self.VIRTUAL + var pow = tasmota.get_power(self.tasmota_relay_index - 1) + if pow != nil + if self.shadow_onoff != bool(pow) + self.attribute_updated(0x0006, 0x0000) + end + self.shadow_onoff = pow end - self.shadow_onoff = state end super(self).update_shadow() end @@ -78,9 +84,16 @@ class Matter_Plugin_OnOff : Matter_Plugin_Device ############################################################# # Model # - def set_onoff(v) - tasmota.set_power(self.tasmota_relay_index - 1, bool(v)) - self.update_shadow() + def set_onoff(pow) + if !self.VIRTUAL + tasmota.set_power(self.tasmota_relay_index - 1, bool(pow)) + self.update_shadow() + else + if pow != self.shadow_onoff + self.attribute_updated(0x0006, 0x0000) + self.shadow_onoff = pow + end + end end ############################################################# @@ -122,20 +135,32 @@ class Matter_Plugin_OnOff : Matter_Plugin_Device self.update_shadow_lazy() if command == 0x0000 # ---------- Off ---------- self.set_onoff(false) - self.update_shadow() + self.publish_command('Power', 0) return true elif command == 0x0001 # ---------- On ---------- self.set_onoff(true) - self.update_shadow() + self.publish_command('Power', 1) return true elif command == 0x0002 # ---------- Toggle ---------- self.set_onoff(!self.shadow_onoff) - self.update_shadow() + self.publish_command('Power', self.shadow_onoff ? 1 : 0) return true end end end + ############################################################# + # update_virtual + # + # Update internal state for virtual devices + def update_virtual(payload_json) + var val_onoff = payload_json.find("Power") + if val_onoff != nil + self.set_onoff(bool(val_onoff)) + end + super(self).update_virtual(payload_json) + end + end matter.Plugin_OnOff = Matter_Plugin_OnOff diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_2_Sensor.be similarity index 74% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_2_Sensor.be index 91d3a81a8..bb44c91aa 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_2_Sensor.be @@ -21,15 +21,13 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Device end - #@ solidify:Matter_Plugin_Sensor,weak class Matter_Plugin_Sensor : Matter_Plugin_Device static var ARG = "filter" # additional argument name (or empty if none) static var ARG_HINT = "Filter pattern" static var UPDATE_TIME = 5000 # update sensor every 5s + static var JSON_NAME = "" # Name of the sensor attribute in JSON payloads var tasmota_sensor_filter # Rule-type filter to the value, like "ESP32#Temperature" var tasmota_sensor_matcher # Actual matcher object var shadow_value # Last known value @@ -55,9 +53,9 @@ class Matter_Plugin_Sensor : Matter_Plugin_Device var val = self.pre_value(real(self.tasmota_sensor_matcher.match(payload))) if val != nil if val != self.shadow_value - self.value_changed(val) + self.value_changed() + self.shadow_value = val end - self.shadow_value = val end end end @@ -67,7 +65,7 @@ class Matter_Plugin_Sensor : Matter_Plugin_Device # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() # self.attribute_updated(0x0402, 0x0000) end @@ -80,5 +78,32 @@ class Matter_Plugin_Sensor : Matter_Plugin_Device return val end + ############################################################# + # update_virtual + # + # Update internal state for virtual devices + def update_virtual(payload_json) + var val = payload_json.find(self.JSON_NAME) + if val != nil + if type(val) == 'bool' val = int(val) end + + if self.shadow_value != val + self.value_changed() + self.shadow_value = val + end + end + super(self).update_virtual(payload_json) + end + + ############################################################# + # append_state_json + # + # Output the current state in JSON + # New values need to be appended with `,"key":value` (including prefix comma) + def append_state_json() + var val = (self.shadow_value != nil) ? self.shadow_value : "null" + return f',"{self.JSON_NAME}":{val}' + end + end matter.Plugin_Sensor = Matter_Plugin_Sensor diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Shutter.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_2_Shutter.be similarity index 97% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Shutter.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_2_Shutter.be index e3285b36f..54e832f85 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Shutter.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_2_Shutter.be @@ -21,30 +21,26 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Device end - #@ solidify:Matter_Plugin_Shutter,weak class Matter_Plugin_Shutter : Matter_Plugin_Device static var TYPE = "shutter" # name of the plug-in in json - static var NAME = "Shutter" # display name of the plug-in + static var DISPLAY_NAME = "Shutter" # display name of the plug-in static var ARG = "shutter" # additional argument name (or empty if none) static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type static var ARG_HINT = "Relay number" - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 # 0x0005: inherited # Scenes 1.4 p.30 - no writable 0x0102: [0,5,7,0xA,0xB,0xD,0xE,0x17,0xFFFC,0xFFFD], # Window Covering 5.3 p.289 - } + }) static var TYPES = { 0x0202: 2 } # New data model format and notation var tasmota_shutter_index # Shutter number in Tasmota (zero based) var shadow_shutter_pos var shadow_shutter_target - var shadow_shutter_tilt var shadow_shutter_direction # 1=opening -1=closing 0=not moving TODO var shadow_shutter_inverted # 1=same as matter 0=matter must invert diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light0.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Bridge_Light0.be similarity index 95% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light0.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Bridge_Light0.be index c92eff4db..fe0bc8a81 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light0.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Bridge_Light0.be @@ -21,26 +21,23 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_HTTP end - #@ solidify:Matter_Plugin_Bridge_Light0,weak class Matter_Plugin_Bridge_Light0 : Matter_Plugin_Bridge_HTTP static var TYPE = "http_light0" # name of the plug-in in json - static var NAME = "Light 0 On" # display name of the plug-in + static var DISPLAY_NAME = "Light 0 On" # display name of the plug-in static var ARG = "relay" # additional argument name (or empty if none) static var ARG_HINT = "Power number" static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type # static var UPDATE_TIME = 3000 # update every 3s # static var UPDATE_CMD = "Status 11" # command to send for updates - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 # 0x0005: inherited # Scenes 1.4 p.30 - no writable 0x0006: [0,0xFFFC,0xFFFD], # On/Off 1.5 p.48 - } + }) static var TYPES = { 0x0100: 2 } # OnOff Light, but not actually used because Relay is managed by OnOff var tasmota_relay_index # Relay number in Tasmota (one based) @@ -125,12 +122,15 @@ class Matter_Plugin_Bridge_Light0 : Matter_Plugin_Bridge_HTTP if cluster == 0x0006 # ========== On/Off 1.5 p.48 ========== if command == 0x0000 # ---------- Off ---------- self.set_onoff(false) + self.publish_command('Power', 0) return true elif command == 0x0001 # ---------- On ---------- self.set_onoff(true) + self.publish_command('Power', 1) return true elif command == 0x0002 # ---------- Toggle ---------- self.set_onoff(!self.shadow_onoff) + self.publish_command('Power', self.shadow_onoff ? 1 : 0) return true end end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Bridge_Sensor.be similarity index 94% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Bridge_Sensor.be index ba8589eae..301c1c02a 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Bridge_Sensor.be @@ -21,14 +21,11 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_HTTP end - #@ solidify:Matter_Plugin_Bridge_Sensor,weak class Matter_Plugin_Bridge_Sensor : Matter_Plugin_Bridge_HTTP # static var TYPE = "" # name of the plug-in in json - # static var NAME = "" # display name of the plug-in + # static var DISPLAY_NAME = "" # display name of the plug-in static var ARG = "filter" # additional argument name (or empty if none) static var ARG_HTTP = "url" # domain name static var ARG_HINT = "Filter pattern" @@ -76,9 +73,9 @@ class Matter_Plugin_Bridge_Sensor : Matter_Plugin_Bridge_HTTP var val = self.pre_value(real(self.tasmota_sensor_matcher.match(data))) if val != nil if val != self.shadow_value - self.value_changed(val) + self.value_changed() + self.shadow_value = val end - self.shadow_value = val end end end @@ -89,7 +86,7 @@ class Matter_Plugin_Bridge_Sensor : Matter_Plugin_Bridge_HTTP # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() # self.attribute_updated(0x0402, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light1.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Light1.be similarity index 61% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light1.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Light1.be index d488f00fd..03a55b1c7 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light1.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Light1.be @@ -21,26 +21,30 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Light0 end - #@ solidify:Matter_Plugin_Light1,weak class Matter_Plugin_Light1 : Matter_Plugin_Light0 static var TYPE = "light1" # name of the plug-in in json - static var NAME = "Light 1 Dimmer" # display name of the plug-in - static var CLUSTERS = { + static var DISPLAY_NAME = "Light 1 Dimmer" # display name of the plug-in + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 # 0x0005: inherited # Scenes 1.4 p.30 - no writable # 0x0006: inherited # On/Off 1.5 p.48 0x0008: [0,2,3,0x0F,0x11,0xFFFC,0xFFFD], # Level Control 1.6 p.57 - } + }) + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Bri") static var TYPES = { 0x0101: 2 } # Dimmable Light - var shadow_bri - # var shadow_onoff # inherited + # Inherited + # var device # reference to the `device` global object + # var endpoint # current endpoint + # var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy + # var tick # tick value when it was last updated + # var node_label # name of the endpoint, used only in bridge mode, "" if none + # var shadow_onoff # (bool) status of the light power on/off + var shadow_bri # (int 0..254) brightness before Gamma correction - as per Matter 255 is not allowed ############################################################# # Constructor @@ -53,21 +57,53 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0 # Update shadow # def update_shadow() - import light - var light_status = light.get() - if light_status != nil - var bri = light_status.find('bri', nil) - if bri != nil - bri = tasmota.scale_uint(bri, 0, 255, 0, 254) - if bri != self.shadow_bri - self.attribute_updated(0x0008, 0x0000) - self.shadow_bri = bri + if !self.VIRTUAL + import light + var light_status = light.get() + if light_status != nil + var bri = light_status.find('bri', nil) + if bri != nil + bri = tasmota.scale_uint(bri, 0, 255, 0, 254) + if bri != self.shadow_bri + self.attribute_updated(0x0008, 0x0000) + self.shadow_bri = bri + end end end end super(self).update_shadow() # superclass manages 'power' end + ############################################################# + # Set Bri + # + # `bri` is in range 0.255 and not 0..254 like in Matter + # `pow` can be bool on `nil` if no change + def set_bri(bri_254, pow) + if (bri_254 < 0) bri_254 = 0 end + if (bri_254 > 254) bri_254 = 254 end + pow = (pow != nil) ? bool(pow) : nil # nil or bool + if !self.VIRTUAL + import light + var bri_255 = tasmota.scale_uint(bri_254, 0, 254, 0, 255) + if pow == nil + light.set({'bri': bri_255}) + else + light.set({'bri': bri_255, 'power': pow}) + end + self.update_shadow() + else + if (pow != nil) && (pow != self.shadow_onoff) + self.attribute_updated(0x0006, 0x0000) + self.shadow_onoff = pow + end + if bri_254 != self.shadow_bri + self.attribute_updated(0x0008, 0x0000) + self.shadow_bri = bri_254 + end + end + end + ############################################################# # read an attribute # @@ -115,11 +151,10 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0 if cluster == 0x0008 # ========== Level Control 1.6 p.57 ========== self.update_shadow_lazy() if command == 0x0000 # ---------- MoveToLevel ---------- - var bri_in = val.findsubval(0) # Hue 0..254 - var bri = tasmota.scale_uint(bri_in, 0, 254, 0, 255) - light.set({'bri': bri}) - self.update_shadow() - ctx.log = "bri:"+str(bri_in) + var bri_254 = val.findsubval(0) # Hue 0..254 + self.set_bri(bri_254) + ctx.log = "bri:"+str(bri_254) + self.publish_command('Bri', bri_254, 'Dimmer', tasmota.scale_uint(bri_254, 0, 254, 0, 100)) return true elif command == 0x0001 # ---------- Move ---------- # TODO, we don't really support it @@ -131,12 +166,11 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0 # TODO, we don't really support it return true elif command == 0x0004 # ---------- MoveToLevelWithOnOff ---------- - var bri_in = val.findsubval(0) # Hue 0..254 - var bri = tasmota.scale_uint(bri_in, 0, 254, 0, 255) - var onoff = bri > 0 - light.set({'bri': bri, 'power': onoff}) - self.update_shadow() - ctx.log = "bri:"+str(bri_in) + var bri_254 = val.findsubval(0) # Hue 0..254 + var onoff = bri_254 > 0 + self.set_bri(bri_254, onoff) + ctx.log = "bri:"+str(bri_254) + self.publish_command('Bri', bri_254, 'Dimmer', tasmota.scale_uint(bri_254, 0, 254, 0, 100), 'Power', onoff ? 1 : 0) return true elif command == 0x0005 # ---------- MoveWithOnOff ---------- # TODO, we don't really support it @@ -154,5 +188,19 @@ class Matter_Plugin_Light1 : Matter_Plugin_Light0 end end + ############################################################# + # update_virtual + # + # Update internal state for virtual devices + def update_virtual(payload_json) + var val_onoff = payload_json.find("Power") + var val_bri = payload_json.find("Bri") + if val_bri != nil + self.set_bri(int(val_bri), val_onoff) + return # don't call super() because we already handeld 'Power' + end + super(self).update_virtual(payload_json) + end + end matter.Plugin_Light1 = Matter_Plugin_Light1 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Contact.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Contact.be similarity index 73% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Contact.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Contact.be index 7b5fbf6fa..e4c847ead 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Contact.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Contact.be @@ -21,26 +21,31 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Device end - #@ solidify:Matter_Plugin_Sensor_Contact,weak class Matter_Plugin_Sensor_Contact : Matter_Plugin_Device static var TYPE = "contact" # name of the plug-in in json - static var NAME = "Contact" # display name of the plug-in + static var DISPLAY_NAME = "Contact" # display name of the plug-in static var ARG = "switch" # additional argument name (or empty if none) static var ARG_HINT = "Switch number" static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type static var UPDATE_TIME = 750 # update every 750ms - static var CLUSTERS = { + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Contact") + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0045: [0,0xFFFC,0xFFFD], # Boolean State p.70 - no writable - } + }) static var TYPES = { 0x0015: 1 } # Contact Sensor, rev 1 var tasmota_switch_index # Switch number in Tasmota (one based) var shadow_contact + ############################################################# + # Constructor + def init(device, endpoint, config) + super(self).init(device, endpoint, config) + self.shadow_contact = false + end + ############################################################# # parse_configuration # @@ -64,10 +69,10 @@ class Matter_Plugin_Sensor_Contact : Matter_Plugin_Device var state = false state = (j.find("Switch" + str(self.tasmota_switch_index)) == "ON") - if self.shadow_contact != nil && self.shadow_contact != bool(state) + if self.shadow_contact != state self.attribute_updated(0x0045, 0x0000) + self.shadow_contact = state end - self.shadow_contact = state end end end @@ -99,5 +104,30 @@ class Matter_Plugin_Sensor_Contact : Matter_Plugin_Device end end + ############################################################# + # update_virtual + # + # Update internal state for virtual devices + def update_virtual(payload_json) + var val_onoff = payload_json.find("Contact") + if val_onoff != nil + val_onoff = bool(val_onoff) + if self.shadow_contact != val_onoff + self.attribute_updated(0x0045, 0x0000) + self.shadow_contact = val_onoff + end + end + super(self).update_virtual(payload_json) + end + + ############################################################# + # append_state_json + # + # Output the current state in JSON + # New values need to be appended with `,"key":value` (including prefix comma) + def append_state_json() + return f',"Contact":{int(self.shadow_contact)}' + end + end matter.Plugin_Sensor_Contact = Matter_Plugin_Sensor_Contact diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Humidity.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Humidity.be similarity index 90% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Humidity.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Humidity.be index 3786eaa47..e3ff44184 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Humidity.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Humidity.be @@ -21,17 +21,16 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Sensor end - #@ solidify:Matter_Plugin_Sensor_Humidity,weak class Matter_Plugin_Sensor_Humidity : Matter_Plugin_Sensor static var TYPE = "humidity" # name of the plug-in in json - static var NAME = "Humidity" # display name of the plug-in - static var CLUSTERS = { + static var DISPLAY_NAME = "Humidity" # display name of the plug-in + static var JSON_NAME = "Humidity" # Name of the sensor attribute in JSON payloads + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Humidity") + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0405: [0,1,2,0xFFFC,0xFFFD], # Humidity Measurement p.102 - no writable - } + }) static var TYPES = { 0x0307: 2 } # Humidity Sensor, rev 2 ############################################################# @@ -48,7 +47,7 @@ class Matter_Plugin_Sensor_Humidity : Matter_Plugin_Sensor # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() self.attribute_updated(0x0405, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Illuminance.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Illuminance.be similarity index 91% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Illuminance.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Illuminance.be index f5602b1ad..e49de236d 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Illuminance.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Illuminance.be @@ -21,17 +21,16 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Sensor end - #@ solidify:Matter_Plugin_Sensor_Illuminance,weak class Matter_Plugin_Sensor_Illuminance : Matter_Plugin_Sensor static var TYPE = "illuminance" # name of the plug-in in json - static var NAME = "Illuminance" # display name of the plug-in - static var CLUSTERS = { + static var DISPLAY_NAME = "Illuminance" # display name of the plug-in + static var JSON_NAME = "Illuminance" # Name of the sensor attribute in JSON payloads + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Illuminance") + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0400: [0,1,2,0xFFFC,0xFFFD], # Illuminance Measurement p.95 - no writable - } + }) static var TYPES = { 0x0106: 2 } # Illuminance Sensor, rev 2 ############################################################# @@ -55,7 +54,7 @@ class Matter_Plugin_Sensor_Illuminance : Matter_Plugin_Sensor # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() self.attribute_updated(0x0400, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Occupancy.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Occupancy.be similarity index 76% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Occupancy.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Occupancy.be index 6d2106849..5d9d4f18c 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Occupancy.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Occupancy.be @@ -21,26 +21,31 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Device end - #@ solidify:Matter_Plugin_Sensor_Occupancy,weak class Matter_Plugin_Sensor_Occupancy : Matter_Plugin_Device static var TYPE = "occupancy" # name of the plug-in in json - static var NAME = "Occupancy" # display name of the plug-in + static var DISPLAY_NAME = "Occupancy" # display name of the plug-in static var ARG = "switch" # additional argument name (or empty if none) static var ARG_HINT = "Switch number" static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type static var UPDATE_TIME = 750 # update every 750ms - static var CLUSTERS = { + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Occupancy") + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0406: [0,1,2,0xFFFC,0xFFFD], # Occupancy Sensing p.105 - no writable - } + }) static var TYPES = { 0x0107: 2 } # Occupancy Sensor, rev 2 var tasmota_switch_index # Switch number in Tasmota (one based) var shadow_occupancy + ############################################################# + # Constructor + def init(device, endpoint, config) + super(self).init(device, endpoint, config) + self.shadow_occupancy = false + end + ############################################################# # parse_configuration # @@ -100,5 +105,30 @@ class Matter_Plugin_Sensor_Occupancy : Matter_Plugin_Device end end + ############################################################# + # update_virtual + # + # Update internal state for virtual devices + def update_virtual(payload_json) + var val_onoff = payload_json.find("Occupancy") + if val_onoff != nil + val_onoff = bool(val_onoff) + if self.shadow_occupancy != val_onoff + self.attribute_updated(0x0406, 0x0000) + self.shadow_occupancy = val_onoff + end + end + super(self).update_virtual(payload_json) + end + + ############################################################# + # append_state_json + # + # Output the current state in JSON + # New values need to be appended with `,"key":value` (including prefix comma) + def append_state_json() + return f',"Occupancy":{int(self.shadow_occupancy)}' + end + end matter.Plugin_Sensor_Occupancy = Matter_Plugin_Sensor_Occupancy diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_OnOff.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_OnOff.be similarity index 88% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_OnOff.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_OnOff.be index 0746ee49f..79eb51c62 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_OnOff.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_OnOff.be @@ -19,21 +19,18 @@ # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Device end - #@ solidify:Matter_Plugin_Sensor_OnOff,weak class Matter_Plugin_Sensor_OnOff : Matter_Plugin_Device static var TYPE = "onoff" # name of the plug-in in json - static var NAME = "OnOff Sensor" # display name of the plug-in + static var DISPLAY_NAME = "OnOff Sensor" # display name of the plug-in static var ARG = "switch" # additional argument name (or empty if none) static var ARG_HINT = "Switch number" static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type static var UPDATE_TIME = 750 # update every 750ms - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0006: [0,0xFFFC,0xFFFD], # On/Off 1.5 p.48 - } + }) static var TYPES = { 0x0850: 2 } # OnOff Sensor, rev 2 var tasmota_switch_index # Switch number in Tasmota (one based) @@ -91,5 +88,14 @@ class Matter_Plugin_Sensor_OnOff : Matter_Plugin_Device end end + ############################################################# + # append_state_json + # + # Output the current state in JSON + # New values need to be appended with `,"key":value` (including prefix comma) + def append_state_json() + return f',"OnOff":{int(self.shadow_onoff)}' + end + end matter.Plugin_Sensor_OnOff = Matter_Plugin_Sensor_OnOff diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Pressure.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Pressure.be similarity index 90% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Pressure.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Pressure.be index ae4c6ef3c..54a0b7627 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Pressure.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Pressure.be @@ -21,17 +21,16 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Sensor end - #@ solidify:Matter_Plugin_Sensor_Pressure,weak class Matter_Plugin_Sensor_Pressure : Matter_Plugin_Sensor static var TYPE = "pressure" # name of the plug-in in json - static var NAME = "Pressure" # display name of the plug-in - static var CLUSTERS = { + static var DISPLAY_NAME = "Pressure" # display name of the plug-in + static var JSON_NAME = "Pressure" # Name of the sensor attribute in JSON payloads + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Pressure") + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0403: [0,1,2,0xFFFC,0xFFFD], # Pressure Measurement - } + }) static var TYPES = { 0x0305: 2 } # Pressure Sensor, rev 2 ############################################################# @@ -48,7 +47,7 @@ class Matter_Plugin_Sensor_Pressure : Matter_Plugin_Sensor # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() self.attribute_updated(0x0403, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Temp.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Temp.be similarity index 91% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Temp.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Temp.be index 33dec8d13..2b6ac22f7 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Sensor_Temp.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_Sensor_Temp.be @@ -21,17 +21,16 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Sensor end - #@ solidify:Matter_Plugin_Sensor_Temp,weak class Matter_Plugin_Sensor_Temp : Matter_Plugin_Sensor static var TYPE = "temperature" # name of the plug-in in json - static var NAME = "Temperature" # display name of the plug-in - static var CLUSTERS = { + static var DISPLAY_NAME = "Temperature" # display name of the plug-in + static var JSON_NAME = "Temperature" # Name of the sensor attribute in JSON payloads + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Temperature") + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0402: [0,1,2,0xFFFC,0xFFFD], # Temperature Measurement p.97 - no writable - } + }) static var TYPES = { 0x0302: 2 } # Temperature Sensor, rev 2 ############################################################# @@ -51,7 +50,7 @@ class Matter_Plugin_Sensor_Temp : Matter_Plugin_Sensor # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() self.attribute_updated(0x0402, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_ShutterTilt.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_ShutterTilt.be similarity index 96% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_ShutterTilt.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_ShutterTilt.be index 0849f3418..f73548f69 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_ShutterTilt.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_3_ShutterTilt.be @@ -21,23 +21,20 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Shutter end - #@ solidify:Matter_Plugin_ShutterTilt,weak class Matter_Plugin_ShutterTilt : Matter_Plugin_Shutter static var TYPE = "shutter+tilt" # name of the plug-in in json - static var NAME = "Shutter + Tilt" # display name of the plug-in + static var DISPLAY_NAME = "Shutter + Tilt" # display name of the plug-in # inherited static var ARG = "shutter" # additional argument name (or empty if none) # inherited static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 # 0x0005: inherited # Scenes 1.4 p.30 - no writable 0x0102: [7,0xC,0xF,0xFFFC], # Window Covering 5.3 p.289 - } + }) # inherited static var TYPES = { 0x0202: 2 } # New data model format and notation # below is inherited @@ -46,6 +43,7 @@ class Matter_Plugin_ShutterTilt : Matter_Plugin_Shutter # var shadow_shutter_target # var shadow_shutter_tilt # var shadow_shutter_direction # 1=opening -1=closing 0=not moving TODO + var shadow_shutter_tilt var tilt_min, tilt_max ############################################################# @@ -167,8 +165,5 @@ class Matter_Plugin_ShutterTilt : Matter_Plugin_Shutter end - ############################################################# - # parse sensor inherited - end matter.Plugin_ShutterTilt = Matter_Plugin_ShutterTilt diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light1.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Light1.be similarity index 93% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light1.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Light1.be index da53e225e..b20d27ff4 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light1.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Light1.be @@ -21,24 +21,21 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_Light0 end - #@ solidify:Matter_Plugin_Bridge_Light1,weak class Matter_Plugin_Bridge_Light1 : Matter_Plugin_Bridge_Light0 static var TYPE = "http_light1" # name of the plug-in in json - static var NAME = "Light 1 Dimmer" # display name of the plug-in + static var DISPLAY_NAME = "Light 1 Dimmer" # display name of the plug-in # static var ARG = "relay" # additional argument name (or empty if none) # static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 # 0x0005: inherited # Scenes 1.4 p.30 - no writable # 0x0006: inherited # On/Off 1.5 p.48 0x0008: [0,2,3,0x0F,0x11,0xFFFC,0xFFFD], # Level Control 1.6 p.57 - } + }) static var TYPES = { 0x0101: 2 } # Dimmable Light var shadow_bri @@ -131,6 +128,8 @@ class Matter_Plugin_Bridge_Light1 : Matter_Plugin_Bridge_Light0 var bri_in = val.findsubval(0) # Hue 0..254 self.set_bri(bri_in) ctx.log = "bri:"+str(bri_in) + self.publish_command('Bri', tasmota.scale_uint(bri_in, 0, 254, 0, 255), + 'Dimmer', tasmota.scale_uint(bri_in, 0, 254, 0, 100)) return true elif command == 0x0001 # ---------- Move ---------- # TODO, we don't really support it @@ -147,6 +146,9 @@ class Matter_Plugin_Bridge_Light1 : Matter_Plugin_Bridge_Light0 var onoff = bri_in > 0 self.set_onoff(onoff) ctx.log = "bri:"+str(bri_in) + self.publish_command('Bri', tasmota.scale_uint(bri_in, 0, 254, 0, 255), + 'Dimmer', tasmota.scale_uint(bri_in, 0, 254, 0, 100), + 'Power', onoff ? 1 : 0) return true elif command == 0x0005 # ---------- MoveWithOnOff ---------- # TODO, we don't really support it diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_OnOff.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_OnOff.be similarity index 91% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_OnOff.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_OnOff.be index 4b8cb0e12..a2c3f388f 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_OnOff.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_OnOff.be @@ -21,14 +21,11 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_Light0 end - #@ solidify:Matter_Plugin_Bridge_OnOff,weak class Matter_Plugin_Bridge_OnOff : Matter_Plugin_Bridge_Light0 static var TYPE = "http_relay" # name of the plug-in in json - static var NAME = "Relay" # display name of the plug-in + static var DISPLAY_NAME = "Relay" # display name of the plug-in static var ARG_HINT = "Relay number" static var TYPES = { 0x010A: 2 } # On/Off Plug-in Unit diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Contact.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Contact.be similarity index 95% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Contact.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Contact.be index 09411b809..d4f738e26 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Contact.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Contact.be @@ -21,23 +21,20 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_HTTP end - #@ solidify:Matter_Plugin_Bridge_Sensor_Contact,weak class Matter_Plugin_Bridge_Sensor_Contact : Matter_Plugin_Bridge_HTTP static var TYPE = "http_contact" # name of the plug-in in json - static var NAME = "Contact" # display name of the plug-in + static var DISPLAY_NAME = "Contact" # display name of the plug-in static var ARG = "switch" # additional argument name (or empty if none) static var ARG_HINT = "Switch number" static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type static var UPDATE_TIME = 5000 # update every 5s static var UPDATE_CMD = "Status 8" # command to send for updates - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0045: [0,0xFFFC,0xFFFD], # Boolean State p.70 - no writable - } + }) static var TYPES = { 0x0015: 1 } # Contact Sensor, rev 1 var tasmota_switch_index # Switch number in Tasmota (one based) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Humidity.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Humidity.be similarity index 94% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Humidity.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Humidity.be index ebd83502a..7e8b62342 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Humidity.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Humidity.be @@ -21,18 +21,15 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_Sensor end - #@ solidify:Matter_Plugin_Bridge_Sensor_Humidity,weak class Matter_Plugin_Bridge_Sensor_Humidity : Matter_Plugin_Bridge_Sensor static var TYPE = "http_humidity" # name of the plug-in in json - static var NAME = "Humidity" # display name of the plug-in + static var DISPLAY_NAME = "Humidity" # display name of the plug-in - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0405: [0,1,2,0xFFFC,0xFFFD], # Humidity Measurement p.102 - no writable - } + }) static var TYPES = { 0x0307: 2 } # Humidity Sensor, rev 2 ############################################################# @@ -40,7 +37,7 @@ class Matter_Plugin_Bridge_Sensor_Humidity : Matter_Plugin_Bridge_Sensor # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() self.attribute_updated(0x0405, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Illuminance.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Illuminance.be similarity index 94% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Illuminance.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Illuminance.be index b3904bda6..48e0bf8de 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Illuminance.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Illuminance.be @@ -21,18 +21,15 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_Sensor end - #@ solidify:Matter_Plugin_Bridge_Sensor_Illuminance,weak class Matter_Plugin_Bridge_Sensor_Illuminance : Matter_Plugin_Bridge_Sensor static var TYPE = "http_illuminance" # name of the plug-in in json - static var NAME = "Illuminance" # display name of the plug-in + static var DISPLAY_NAME = "Illuminance" # display name of the plug-in - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0400: [0,1,2,0xFFFC,0xFFFD], # Illuminance Measurement p.95 - no writable - } + }) static var TYPES = { 0x0106: 2 } # Illuminance Sensor, rev 2 ############################################################# @@ -40,7 +37,7 @@ class Matter_Plugin_Bridge_Sensor_Illuminance : Matter_Plugin_Bridge_Sensor # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() self.attribute_updated(0x0400, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Occupancy.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Occupancy.be similarity index 96% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Occupancy.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Occupancy.be index 3e312259f..8279a6088 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Occupancy.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Occupancy.be @@ -21,23 +21,20 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_HTTP end - #@ solidify:Matter_Plugin_Bridge_Sensor_Occupancy,weak class Matter_Plugin_Bridge_Sensor_Occupancy : Matter_Plugin_Bridge_HTTP static var TYPE = "http_occupancy" # name of the plug-in in json - static var NAME = "Occupancy" # display name of the plug-in + static var DISPLAY_NAME = "Occupancy" # display name of the plug-in static var ARG = "switch" # additional argument name (or empty if none) static var ARG_HINT = "Switch number" static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type static var UPDATE_TIME = 5000 # update every 5s static var UPDATE_CMD = "Status 8" # command to send for updates - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0406: [0,1,2,0xFFFC,0xFFFD], # Occupancy Sensing p.105 - no writable - } + }) static var TYPES = { 0x0107: 2 } # Occupancy Sensor, rev 2 var tasmota_switch_index # Switch number in Tasmota (one based) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Pressure.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Pressure.be similarity index 94% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Pressure.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Pressure.be index b519fed3d..86dec0081 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Pressure.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Pressure.be @@ -21,18 +21,15 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_Sensor end - #@ solidify:Matter_Plugin_Bridge_Sensor_Pressure,weak class Matter_Plugin_Bridge_Sensor_Pressure : Matter_Plugin_Bridge_Sensor static var TYPE = "http_pressure" # name of the plug-in in json - static var NAME = "Pressure" # display name of the plug-in + static var DISPLAY_NAME = "Pressure" # display name of the plug-in - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0403: [0,1,2,0xFFFC,0xFFFD], # Pressure Measurement - } + }) static var TYPES = { 0x0305: 2 } # Temperature Sensor, rev 2 ############################################################# @@ -40,7 +37,7 @@ class Matter_Plugin_Bridge_Sensor_Pressure : Matter_Plugin_Bridge_Sensor # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() self.attribute_updated(0x0403, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Temp.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Temp.be similarity index 94% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Temp.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Temp.be index 7980044c3..771c6eb7d 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Sensor_Temp.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Bridge_Sensor_Temp.be @@ -21,18 +21,15 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_Sensor end - #@ solidify:Matter_Plugin_Bridge_Sensor_Temp,weak class Matter_Plugin_Bridge_Sensor_Temp : Matter_Plugin_Bridge_Sensor static var TYPE = "http_temperature" # name of the plug-in in json - static var NAME = "Temperature" # display name of the plug-in + static var DISPLAY_NAME = "Temperature" # display name of the plug-in - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { 0x0402: [0,1,2,0xFFFC,0xFFFD], # Temperature Measurement p.97 - no writable - } + }) static var TYPES = { 0x0302: 2 } # Temperature Sensor, rev 2 ############################################################# @@ -40,7 +37,7 @@ class Matter_Plugin_Bridge_Sensor_Temp : Matter_Plugin_Bridge_Sensor # # This must be overriden. # This is where you call `self.attribute_updated(, )` - def value_changed(val) + def value_changed() self.attribute_updated(0x0402, 0x0000) end diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light2.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Light2.be similarity index 69% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light2.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Light2.be index 27d9657d4..c4d4f9317 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light2.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Light2.be @@ -21,15 +21,12 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Light1 end - #@ solidify:Matter_Plugin_Light2,weak class Matter_Plugin_Light2 : Matter_Plugin_Light1 static var TYPE = "light2" # name of the plug-in in json - static var NAME = "Light 2 CT" # display name of the plug-in - static var CLUSTERS = { + static var DISPLAY_NAME = "Light 2 CT" # display name of the plug-in + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 @@ -37,18 +34,27 @@ class Matter_Plugin_Light2 : Matter_Plugin_Light1 # 0x0006: inherited # On/Off 1.5 p.48 # 0x0008: inherited # Level Control 1.6 p.57 0x0300: [7,8,0xF,0x400B,0x400C,0xFFFC,0xFFFD], # Color Control 3.2 p.111 - } + }) + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "CT") static var TYPES = { 0x010C: 2 } # Color Temperature Light - var shadow_ct - var ct_min, ct_max + # Inherited + # var device # reference to the `device` global object + # var endpoint # current endpoint + # var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy + # var tick # tick value when it was last updated + # var node_label # name of the endpoint, used only in bridge mode, "" if none + # var shadow_onoff # (bool) status of the light power on/off + # var shadow_bri # (int 0..254) brightness before Gamma correction - as per Matter 255 is not allowed + var shadow_ct # (int 153..500, default 325) Color Temperatur in mireds + var ct_min, ct_max # min and max value allowed for CT, Alexa emulation requires to have a narrower range 200..380 ############################################################# # Constructor def init(device, endpoint, arguments) super(self).init(device, endpoint, arguments) self.shadow_ct = 325 - self.update_ct_minmax() + self.update_ct_minmax() # read SetOption to adjust ct min/max end ############################################################# @@ -62,19 +68,42 @@ class Matter_Plugin_Light2 : Matter_Plugin_Light1 if light_status != nil var ct = light_status.find('ct', nil) if ct == nil ct = self.shadow_ct end - if ct != self.shadow_ct self.attribute_updated(0x0300, 0x0007) self.shadow_ct = ct end + if ct != self.shadow_ct + self.attribute_updated(0x0300, 0x0007) + self.shadow_ct = ct + end end end ############################################################# # Update ct_min/max # + # Standard range is 153..500 but Alexa emulation reduces range to 200..380 + # Depending on `SetOption82` def update_ct_minmax() var ct_alexa_mode = tasmota.get_option(82) # if set, range is 200..380 instead of 153...500 self.ct_min = ct_alexa_mode ? 200 : 153 self.ct_max = ct_alexa_mode ? 380 : 500 end + ############################################################# + # set_ct + # + def set_ct(ct) + if ct < self.ct_min ct = self.ct_min end + if ct > self.ct_max ct = self.ct_max end + if !self.VIRTUAL + import light + light.set({'ct': ct}) + self.update_shadow() + else + if ct != self.shadow_ct + self.attribute_updated(0x0300, 0x0007) + self.shadow_ct = ct + end + end + end + ############################################################# # read an attribute # @@ -124,11 +153,9 @@ class Matter_Plugin_Light2 : Matter_Plugin_Light1 self.update_shadow_lazy() if command == 0x000A # ---------- MoveToColorTemperature ---------- var ct_in = val.findsubval(0) # CT - if ct_in < self.ct_min ct_in = self.ct_min end - if ct_in > self.ct_max ct_in = self.ct_max end - light.set({'ct': ct_in}) - self.update_shadow() + self.set_ct(ct_in) ctx.log = "ct:"+str(ct_in) + self.publish_command('CT', ct_in) return true elif command == 0x0047 # ---------- StopMoveStep ---------- # TODO, we don't really support it @@ -147,5 +174,17 @@ class Matter_Plugin_Light2 : Matter_Plugin_Light1 end + ############################################################# + # update_virtual + # + # Update internal state for virtual devices + def update_virtual(payload_json) + var val_ct = int(payload_json.find("CT")) # int or nil + if (val_ct != nil) + self.set_ct(val_ct) + end + super(self).update_virtual(payload_json) + end + end matter.Plugin_Light2 = Matter_Plugin_Light2 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light3.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Light3.be similarity index 60% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light3.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Light3.be index 41981fcbd..8f7dd46fd 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Light3.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_4_Light3.be @@ -21,15 +21,12 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Light1 end - #@ solidify:Matter_Plugin_Light3,weak class Matter_Plugin_Light3 : Matter_Plugin_Light1 static var TYPE = "light3" # name of the plug-in in json - static var NAME = "Light 3 RGB" # display name of the plug-in - static var CLUSTERS = { + static var DISPLAY_NAME = "Light 3 RGB" # display name of the plug-in + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 @@ -37,10 +34,21 @@ class Matter_Plugin_Light3 : Matter_Plugin_Light1 # 0x0006: inherited # On/Off 1.5 p.48 # 0x0008: inherited # Level Control 1.6 p.57 0x0300: [0,1,7,8,0xF,0x4001,0x400A,0xFFFC,0xFFFD],# Color Control 3.2 p.111 - } + }) + static var UPDATE_COMMANDS = matter.UC_LIST(_class, "Hue", "Sat") static var TYPES = { 0x010D: 2 } # Extended Color Light - var shadow_hue, shadow_sat + # Inherited + # var device # reference to the `device` global object + # var endpoint # current endpoint + # var clusters # map from cluster to list of attributes, typically constructed from CLUSTERS hierachy + # var tick # tick value when it was last updated + # var node_label # name of the endpoint, used only in bridge mode, "" if none + # var virtual # (bool) is the device pure virtual (i.e. not related to a device implementation by Tasmota) + # var shadow_onoff # (bool) status of the light power on/off + # var shadow_bri # (int 0..254) brightness before Gamma correction - as per Matter 255 is not allowed + var shadow_hue # (int 0..254) hue of color, may need to be extended to 0..360 for value in degrees + var shadow_sat # (int 0..254) saturation of color ############################################################# # Constructor @@ -54,16 +62,56 @@ class Matter_Plugin_Light3 : Matter_Plugin_Light1 # Update shadow # def update_shadow() - import light super(self).update_shadow() - var light_status = light.get() - if light_status != nil - var hue = light_status.find('hue', nil) - var sat = light_status.find('sat', nil) - if hue != nil hue = tasmota.scale_uint(hue, 0, 360, 0, 254) else hue = self.shadow_hue end - if sat != nil sat = tasmota.scale_uint(sat, 0, 255, 0, 254) else sat = self.shadow_sat end - if hue != self.shadow_hue self.attribute_updated(0x0300, 0x0000) self.shadow_hue = hue end - if sat != self.shadow_sat self.attribute_updated(0x0300, 0x0001) self.shadow_sat = sat end + if !self.VIRTUAL + import light + var light_status = light.get() + if light_status != nil + var hue = light_status.find('hue', nil) + var sat = light_status.find('sat', nil) + if hue != nil hue = tasmota.scale_uint(hue, 0, 360, 0, 254) else hue = self.shadow_hue end + if sat != nil sat = tasmota.scale_uint(sat, 0, 255, 0, 254) else sat = self.shadow_sat end + if hue != self.shadow_hue self.attribute_updated(0x0300, 0x0000) self.shadow_hue = hue end + if sat != self.shadow_sat self.attribute_updated(0x0300, 0x0001) self.shadow_sat = sat end + end + end + end + + ############################################################# + # set_hue_sat + # + # `hue` 0..254 or `nil` + # `sat` 0..255 or `nil` + def set_hue_sat(hue_254, sat_254) + # sanity checks on values + if hue_254 != nil + if hue_254 < 0 hue_254 = 0 end + if hue_254 > 254 hue_254 = 254 end + end + if sat_254 != nil + if sat_254 < 0 sat_254 = 0 end + if sat_254 > 254 sat_254 = 254 end + end + + if !self.VIRTUAL + var hue_360 = (hue_254 != nil) ? tasmota.scale_uint(hue_254, 0, 254, 0, 360) : nil + var sat_255 = (sat_254 != nil) ? tasmota.scale_uint(sat_254, 0, 254, 0, 255) : nil + + if (hue_360 != nil) && (sat_255 != nil) + light.set({'hue': hue_360, 'sat': sat_255}) + elif (hue_360 != nil) + light.set({'hue': hue_360}) + else + light.set({'sat': sat_255}) + end + self.update_shadow() + else + if hue_254 != nil + if hue_254 != self.shadow_hue self.attribute_updated(0x0300, 0x0000) self.shadow_hue = hue_254 end + end + if sat_254 != nil + if sat_254 != self.shadow_sat self.attribute_updated(0x0300, 0x0001) self.shadow_sat = sat_254 end + end end end @@ -124,10 +172,9 @@ class Matter_Plugin_Light3 : Matter_Plugin_Light1 self.update_shadow_lazy() if command == 0x0000 # ---------- MoveToHue ---------- var hue_in = val.findsubval(0) # Hue 0..254 - var hue = tasmota.scale_uint(hue_in, 0, 254, 0, 360) - light.set({'hue': hue}) - self.update_shadow() + self.set_hue_sat(hue_in, nil) ctx.log = "hue:"+str(hue_in) + self.publish_command('Hue', hue_in) return true elif command == 0x0001 # ---------- MoveHue ---------- # TODO, we don't really support it @@ -137,10 +184,9 @@ class Matter_Plugin_Light3 : Matter_Plugin_Light1 return true elif command == 0x0003 # ---------- MoveToSaturation ---------- var sat_in = val.findsubval(0) # Sat 0..254 - var sat = tasmota.scale_uint(sat_in, 0, 254, 0, 255) - light.set({'sat': sat}) - self.update_shadow() + self.set_hue_sat(nil, sat_in) ctx.log = "sat:"+str(sat_in) + self.publish_command('Sat', sat_in) return true elif command == 0x0004 # ---------- MoveSaturation ---------- # TODO, we don't really support it @@ -150,12 +196,10 @@ class Matter_Plugin_Light3 : Matter_Plugin_Light1 return true elif command == 0x0006 # ---------- MoveToHueAndSaturation ---------- var hue_in = val.findsubval(0) # Hue 0..254 - var hue = tasmota.scale_uint(hue_in, 0, 254, 0, 360) var sat_in = val.findsubval(1) # Sat 0..254 - var sat = tasmota.scale_uint(sat_in, 0, 254, 0, 255) - light.set({'hue': hue, 'sat': sat}) - self.update_shadow() + self.set_hue_sat(hue_in, sat_in) ctx.log = "hue:"+str(hue_in)+" sat:"+str(sat_in) + self.publish_command('Hue', hue_in, 'Sat', sat_in) return true elif command == 0x0047 # ---------- StopMoveStep ---------- # TODO, we don't really support it @@ -168,5 +212,18 @@ class Matter_Plugin_Light3 : Matter_Plugin_Light1 end + ############################################################# + # update_virtual + # + # Update internal state for virtual devices + def update_virtual(payload_json) + var val_hue = int(payload_json.find("Hue")) # int or nil + var val_sat = int(payload_json.find("Sat")) # int or nil + if (val_hue != nil) || (val_sat != nil) + self.set_hue_sat(val_hue, val_sat) + end + super(self).update_virtual(payload_json) + end + end matter.Plugin_Light3 = Matter_Plugin_Light3 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light2.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_5_Bridge_Light2.be similarity index 97% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light2.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_5_Bridge_Light2.be index 596790042..56d1d9de6 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light2.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_5_Bridge_Light2.be @@ -21,17 +21,14 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_Light1 end - #@ solidify:Matter_Plugin_Bridge_Light2,weak class Matter_Plugin_Bridge_Light2 : Matter_Plugin_Bridge_Light1 static var TYPE = "http_light2" # name of the plug-in in json - static var NAME = "Light 2 CT" # display name of the plug-in + static var DISPLAY_NAME = "Light 2 CT" # display name of the plug-in # static var ARG = "relay" # additional argument name (or empty if none) # static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 @@ -39,7 +36,7 @@ class Matter_Plugin_Bridge_Light2 : Matter_Plugin_Bridge_Light1 # 0x0006: inherited # On/Off 1.5 p.48 # 0x0008: inherited # Level Control 1.6 p.57 0x0300: [7,8,0xF,0x400A,0x400B,0x400C,0xFFFC,0xFFFD], # Color Control 3.2 p.111 - } + }) static var TYPES = { 0x010C: 2 } # Dimmable Light var shadow_ct @@ -149,6 +146,7 @@ class Matter_Plugin_Bridge_Light2 : Matter_Plugin_Bridge_Light1 if ct_in > self.ct_max ct_in = self.ct_max end self.set_ct(ct_in) ctx.log = "ct:"+str(ct_in) + self.publish_command('CT', ct_in) return true elif command == 0x0047 # ---------- StopMoveStep ---------- # TODO, we don't really support it diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light3.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_5_Bridge_Light3.be similarity index 96% rename from lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light3.be rename to lib/libesp32/berry_matter/src/embedded/Matter_Plugin_5_Bridge_Light3.be index 9898cfbb4..abb4e9672 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_Bridge_Light3.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_5_Bridge_Light3.be @@ -21,17 +21,14 @@ import matter # Matter plug-in for core behavior -# dummy declaration for solidification -class Matter_Plugin_Bridge_Light1 end - #@ solidify:Matter_Plugin_Bridge_Light3,weak class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1 static var TYPE = "http_light3" # name of the plug-in in json - static var NAME = "Light 3 RGB" # display name of the plug-in + static var DISPLAY_NAME = "Light 3 RGB" # display name of the plug-in # static var ARG = "relay" # additional argument name (or empty if none) # static var ARG_TYPE = / x -> int(x) # function to convert argument to the right type - static var CLUSTERS = { + static var CLUSTERS = matter.consolidate_clusters(_class, { # 0x001D: inherited # Descriptor Cluster 9.5 p.453 # 0x0003: inherited # Identify 1.2 p.16 # 0x0004: inherited # Groups 1.3 p.21 @@ -39,7 +36,7 @@ class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1 # 0x0006: inherited # On/Off 1.5 p.48 # 0x0008: inherited # Level Control 1.6 p.57 0x0300: [0,1,7,8,0xF,0x4001,0x400A,0xFFFC,0xFFFD],# Color Control 3.2 p.111 - } + }) static var TYPES = { 0x010D: 2 } # Extended Color Light var shadow_hue, shadow_sat # 0..254 @@ -157,6 +154,7 @@ class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1 var hue_in = val.findsubval(0) # Hue 0..254 self.set_hue(hue_in) ctx.log = "hue:"+str(hue_in) + self.publish_command('Hue', hue_in) return true elif command == 0x0001 # ---------- MoveHue ---------- # TODO, we don't really support it @@ -168,6 +166,7 @@ class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1 var sat_in = val.findsubval(0) # Sat 0..254 self.set_sat(sat_in) ctx.log = "sat:"+str(sat_in) + self.publish_command('Sat', sat_in) return true elif command == 0x0004 # ---------- MoveSaturation ---------- # TODO, we don't really support it @@ -181,6 +180,7 @@ class Matter_Plugin_Bridge_Light3 : Matter_Plugin_Bridge_Light1 self.set_hue(hue_in) self.set_sat(sat_in) ctx.log = "hue:"+str(hue_in)+" sat:"+str(sat_in) + self.publish_command('Hue', hue_in, 'Sat', sat_in) return true elif command == 0x0047 # ---------- StopMoveStep ---------- # TODO, we don't really support it diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light0.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light0.be new file mode 100644 index 000000000..cbe90af7d --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light0.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_Virt_Light0.be - implements the behavior for a virtual Light (OnOff only) +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Light0,weak + +class Matter_Plugin_Virt_Light0 : Matter_Plugin_Light0 + static var TYPE = "v_light0" # name of the plug-in in json + static var DISPLAY_NAME = "v.Light 0 On" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Light0 = Matter_Plugin_Virt_Light0 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light1.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light1.be new file mode 100644 index 000000000..8697bf2df --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light1.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_Virt_Light1.be - implements the behavior for a virtual Light 1 channel (Dimmer) +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Light1,weak + +class Matter_Plugin_Virt_Light1 : Matter_Plugin_Light1 + static var TYPE = "v_light1" # name of the plug-in in json + static var DISPLAY_NAME = "v.Light 1 Dimmer" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Light1 = Matter_Plugin_Virt_Light1 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light2.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light2.be new file mode 100644 index 000000000..20876b842 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light2.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_Virt_Light2.be - implements the behavior for a virtual Light with 2 channel (CT) +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Light2,weak + +class Matter_Plugin_Virt_Light2 : Matter_Plugin_Light2 + static var TYPE = "v_light2" # name of the plug-in in json + static var DISPLAY_NAME = "v.Light 2 CT" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Light2 = Matter_Plugin_Virt_Light2 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light3.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light3.be new file mode 100644 index 000000000..15e7e2ae1 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Light3.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_Virt_Light3.be - implements the behavior for a virtual Light with 3 channels (RGB) +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Light3,weak + +class Matter_Plugin_Virt_Light3 : Matter_Plugin_Light3 + static var TYPE = "v_light3" # name of the plug-in in json + static var DISPLAY_NAME = "v.Light 3 RGB" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Light3 = Matter_Plugin_Virt_Light3 diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_OnOff.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_OnOff.be new file mode 100644 index 000000000..d9bb5403b --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_OnOff.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_Virt_OnOff.be - implements the behavior for a Virtual Relay +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_OnOff,weak + +class Matter_Plugin_Virt_OnOff : Matter_Plugin_OnOff + static var TYPE = "v_relay" # name of the plug-in in json + static var DISPLAY_NAME = "v.Relay" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_OnOff = Matter_Plugin_Virt_OnOff diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Contact.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Contact.be new file mode 100644 index 000000000..0cf722866 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Contact.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_9_Virt_Sensor_Contact.be - implements the behavior for a Virtual Contact Sensor +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Sensor_Contact,weak + +class Matter_Plugin_Virt_Sensor_Contact : Matter_Plugin_Sensor_Contact + static var TYPE = "v_contact" # name of the plug-in in json + static var DISPLAY_NAME = "v.Contact" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Sensor_Contact = Matter_Plugin_Virt_Sensor_Contact diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Humidity.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Humidity.be new file mode 100644 index 000000000..0fb033a55 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Humidity.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_9_Virt_Sensor_Humidity.be - implements the behavior for a Virtual Humidity Sensor +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Sensor_Humidity,weak + +class Matter_Plugin_Virt_Sensor_Humidity : Matter_Plugin_Sensor_Humidity + static var TYPE = "v_humidity" # name of the plug-in in json + static var DISPLAY_NAME = "v.Humidity" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Sensor_Humidity = Matter_Plugin_Virt_Sensor_Humidity diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Illuminance.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Illuminance.be new file mode 100644 index 000000000..76090f41a --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Illuminance.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_9_Virt_Sensor_Illuminance.be - implements the behavior for a Virtual Illuminance Sensor +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Sensor_Illuminance,weak + +class Matter_Plugin_Virt_Sensor_Illuminance : Matter_Plugin_Sensor_Illuminance + static var TYPE = "v_illuminance" # name of the plug-in in json + static var DISPLAY_NAME = "v.Illuminance" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Sensor_Illuminance = Matter_Plugin_Virt_Sensor_Illuminance diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Pressure.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Pressure.be new file mode 100644 index 000000000..c661b2b0d --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Pressure.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_9_Virt_Sensor_Pressure.be - implements the behavior for a Virtual Temperature Sensor +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Sensor_Pressure,weak + +class Matter_Plugin_Virt_Sensor_Pressure : Matter_Plugin_Sensor_Pressure + static var TYPE = "v_pressure" # name of the plug-in in json + static var DISPLAY_NAME = "v.Pressure" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Sensor_Pressure = Matter_Plugin_Virt_Sensor_Pressure diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Temp.be b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Temp.be new file mode 100644 index 000000000..8ad2b11e3 --- /dev/null +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Plugin_9_Virt_Sensor_Temp.be @@ -0,0 +1,34 @@ +# +# Matter_Plugin_9_Virt_Sensor_Temp.be - implements the behavior for a Virtual Temperature Sensor +# +# Copyright (C) 2023 Stephan Hadinger & Theo Arends +# +# 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 . +# + +import matter + +# Matter plug-in for core behavior + +#@ solidify:Matter_Plugin_Virt_Sensor_Temp,weak + +class Matter_Plugin_Virt_Sensor_Temp : Matter_Plugin_Sensor_Temp + static var TYPE = "v_temp" # name of the plug-in in json + static var DISPLAY_NAME = "v.Temperature" # display name of the plug-in + static var ARG = "" # no arg for virtual device + static var ARG_HINT = "_Not used_" # Hint for entering the Argument (inside 'placeholder') + static var VIRTUAL = true # virtual device + +end +matter.Plugin_Virt_Sensor_Temp = Matter_Plugin_Virt_Sensor_Temp diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be index dd17a0df0..2696d753a 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_Session.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_Session.be @@ -256,10 +256,10 @@ class Matter_Session : Matter_Expirable def get_fabric_id() return self._fabric.fabric_id end def get_fabric_index() return self._fabric ? self._fabric.fabric_index : nil end def get_device_id() return self._fabric ? self._fabric.device_id : nil end - def get_fabric_compressed() return self._fabric.fabric_compressed end - def get_fabric_label() return self._fabric.fabric_label end - def get_admin_subject() return self._fabric.admin_subject end - def get_admin_vendor() return self._fabric.admin_vendor end + def get_fabric_compressed() return self._fabric ? self._fabric.fabric_compressed : nil end + def get_fabric_label() return self._fabric ? self._fabric.fabric_label : nil end + def get_admin_subject() return self._fabric ? self._fabric.admin_subject : nil end + def get_admin_vendor() return self._fabric ? self._fabric.admin_vendor : nil end ############################################################# # Get operational key pair (private key) diff --git a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be index c4701e957..278d8c250 100644 --- a/lib/libesp32/berry_matter/src/embedded/Matter_UI.be +++ b/lib/libesp32/berry_matter/src/embedded/Matter_UI.be @@ -34,6 +34,8 @@ import matter class Matter_UI static var _CLASSES_TYPES = "|relay|light0|light1|light2|light3|shutter|shutter+tilt" "|temperature|pressure|illuminance|humidity|occupancy|onoff|contact" + "|-virtual|v_relay|v_light0|v_light1|v_light2|v_light3" + "|v_temp|v_pressure|v_illuminance|v_humidity|v_contact" # static var _CLASSES_HTTP = "-http" static var _CLASSES_TYPES2= "|http_relay|http_light0|http_light1|http_light2|http_light3" "|http_temperature|http_pressure|http_illuminance|http_humidity" @@ -496,8 +498,8 @@ class Matter_UI var typ = class_types[i] if typ == '' webserver.content_send("") - elif typ == '-http' - webserver.content_send("") + elif typ == '-virtual' + webserver.content_send("") else var nam = self.device.get_plugin_class_displayname(typ) webserver.content_send(format("", typ, (typ == cur) ? " selected" : "", nam)) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_inspect.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_0_Inspect.h similarity index 68% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_inspect.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_0_Inspect.h index 65b17a3ec..079f5e775 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_inspect.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_0_Inspect.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_inspect.h */ +/* Solidification of Matter_0_Inspect.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -227,5 +227,110 @@ be_local_closure(matter_inspect, /* name */ ); /*******************************************************************/ + +/******************************************************************** +** Solidified function: consolidate_clusters +********************************************************************/ +be_local_closure(matter_consolidate_clusters, /* name */ + be_nested_proto( + 9, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(CLUSTERS), + /* K1 */ be_nested_str_weak(keys), + /* K2 */ be_nested_str_weak(copy), + /* K3 */ be_nested_str_weak(stop_iteration), + /* K4 */ be_nested_str_weak(find), + }), + be_str_weak(consolidate_clusters), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x88080500, // 0003 GETMBR R2 R2 K0 + 0x600C0013, // 0004 GETGBL R3 G19 + 0x7C0C0000, // 0005 CALL R3 0 + 0x60100010, // 0006 GETGBL R4 G16 + 0x8C140501, // 0007 GETMET R5 R2 K1 + 0x7C140200, // 0008 CALL R5 1 + 0x7C100200, // 0009 CALL R4 1 + 0xA8020006, // 000A EXBLK 0 #0012 + 0x5C140800, // 000B MOVE R5 R4 + 0x7C140000, // 000C CALL R5 0 + 0x94180405, // 000D GETIDX R6 R2 R5 + 0x8C180D02, // 000E GETMET R6 R6 K2 + 0x7C180200, // 000F CALL R6 1 + 0x980C0A06, // 0010 SETIDX R3 R5 R6 + 0x7001FFF8, // 0011 JMP #000B + 0x58100003, // 0012 LDCONST R4 K3 + 0xAC100200, // 0013 CATCH R4 1 0 + 0xB0080000, // 0014 RAISE 2 R0 R0 + 0x60100010, // 0015 GETGBL R4 G16 + 0x8C140301, // 0016 GETMET R5 R1 K1 + 0x7C140200, // 0017 CALL R5 1 + 0x7C100200, // 0018 CALL R4 1 + 0xA802000E, // 0019 EXBLK 0 #0029 + 0x5C140800, // 001A MOVE R5 R4 + 0x7C140000, // 001B CALL R5 0 + 0x8C180704, // 001C GETMET R6 R3 K4 + 0x5C200A00, // 001D MOVE R8 R5 + 0x7C180400, // 001E CALL R6 2 + 0x4C1C0000, // 001F LDNIL R7 + 0x1C1C0C07, // 0020 EQ R7 R6 R7 + 0x781E0002, // 0021 JMPF R7 #0025 + 0x601C0012, // 0022 GETGBL R7 G18 + 0x7C1C0000, // 0023 CALL R7 0 + 0x5C180E00, // 0024 MOVE R6 R7 + 0x941C0205, // 0025 GETIDX R7 R1 R5 + 0x001C0C07, // 0026 ADD R7 R6 R7 + 0x980C0A07, // 0027 SETIDX R3 R5 R7 + 0x7001FFF0, // 0028 JMP #001A + 0x58100003, // 0029 LDCONST R4 K3 + 0xAC100200, // 002A CATCH R4 1 0 + 0xB0080000, // 002B RAISE 2 R0 R0 + 0x80040600, // 002C RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: UC_LIST +********************************************************************/ +be_local_closure(matter_UC_LIST, /* name */ + be_nested_proto( + 4, /* nstack */ + 2, /* argc */ + 1, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(UPDATE_COMMANDS), + }), + be_str_weak(UC_LIST), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x60080003, // 0000 GETGBL R2 G3 + 0x5C0C0000, // 0001 MOVE R3 R0 + 0x7C080200, // 0002 CALL R2 1 + 0x88080500, // 0003 GETMBR R2 R2 K0 + 0x000C0401, // 0004 ADD R3 R2 R1 + 0x80040600, // 0005 RET 1 R3 + }) + ) +); +/*******************************************************************/ + /********************************************************************/ /* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h index 32377c2c9..64b35f2bb 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Device.h @@ -7,203 +7,11 @@ extern const bclass be_class_Matter_Device; /******************************************************************** -** Solidified function: clean_remotes +** Solidified function: get_plugin_class_displayname ********************************************************************/ -be_local_closure(Matter_Device_clean_remotes, /* name */ +be_local_closure(Matter_Device_get_plugin_class_displayname, /* name */ be_nested_proto( - 10, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[18]) { /* constants */ - /* K0 */ be_nested_str_weak(introspect), - /* K1 */ be_nested_str_weak(http_remotes), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(stop_iteration), - /* K4 */ be_nested_str_weak(plugins), - /* K5 */ be_nested_str_weak(get), - /* K6 */ be_nested_str_weak(http_remote), - /* K7 */ be_nested_str_weak(find), - /* K8 */ be_const_int(1), - /* K9 */ be_nested_str_weak(keys), - /* K10 */ be_nested_str_weak(push), - /* K11 */ be_nested_str_weak(tasmota), - /* K12 */ be_nested_str_weak(log), - /* K13 */ be_nested_str_weak(MTR_X3A_X20remove_X20unused_X20remote_X3A_X20), - /* K14 */ be_nested_str_weak(addr), - /* K15 */ be_const_int(3), - /* K16 */ be_nested_str_weak(close), - /* K17 */ be_nested_str_weak(remove), - }), - be_str_weak(clean_remotes), - &be_const_str_solidified, - ( &(const binstruction[81]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x88080101, // 0001 GETMBR R2 R0 K1 - 0x780A004C, // 0002 JMPF R2 #0050 - 0x60080013, // 0003 GETGBL R2 G19 - 0x7C080000, // 0004 CALL R2 0 - 0x600C0010, // 0005 GETGBL R3 G16 - 0x88100101, // 0006 GETMBR R4 R0 K1 - 0x7C0C0200, // 0007 CALL R3 1 - 0xA8020003, // 0008 EXBLK 0 #000D - 0x5C100600, // 0009 MOVE R4 R3 - 0x7C100000, // 000A CALL R4 0 - 0x98080902, // 000B SETIDX R2 R4 K2 - 0x7001FFFB, // 000C JMP #0009 - 0x580C0003, // 000D LDCONST R3 K3 - 0xAC0C0200, // 000E CATCH R3 1 0 - 0xB0080000, // 000F RAISE 2 R0 R0 - 0x600C0010, // 0010 GETGBL R3 G16 - 0x88100104, // 0011 GETMBR R4 R0 K4 - 0x7C0C0200, // 0012 CALL R3 1 - 0xA802000F, // 0013 EXBLK 0 #0024 - 0x5C100600, // 0014 MOVE R4 R3 - 0x7C100000, // 0015 CALL R4 0 - 0x8C140305, // 0016 GETMET R5 R1 K5 - 0x5C1C0800, // 0017 MOVE R7 R4 - 0x58200006, // 0018 LDCONST R8 K6 - 0x7C140600, // 0019 CALL R5 3 - 0x4C180000, // 001A LDNIL R6 - 0x20180A06, // 001B NE R6 R5 R6 - 0x781A0005, // 001C JMPF R6 #0023 - 0x8C180507, // 001D GETMET R6 R2 K7 - 0x5C200A00, // 001E MOVE R8 R5 - 0x58240002, // 001F LDCONST R9 K2 - 0x7C180600, // 0020 CALL R6 3 - 0x00180D08, // 0021 ADD R6 R6 K8 - 0x98080A06, // 0022 SETIDX R2 R5 R6 - 0x7001FFEF, // 0023 JMP #0014 - 0x580C0003, // 0024 LDCONST R3 K3 - 0xAC0C0200, // 0025 CATCH R3 1 0 - 0xB0080000, // 0026 RAISE 2 R0 R0 - 0x600C0012, // 0027 GETGBL R3 G18 - 0x7C0C0000, // 0028 CALL R3 0 - 0x60100010, // 0029 GETGBL R4 G16 - 0x8C140509, // 002A GETMET R5 R2 K9 - 0x7C140200, // 002B CALL R5 1 - 0x7C100200, // 002C CALL R4 1 - 0xA8020008, // 002D EXBLK 0 #0037 - 0x5C140800, // 002E MOVE R5 R4 - 0x7C140000, // 002F CALL R5 0 - 0x94180405, // 0030 GETIDX R6 R2 R5 - 0x1C180D02, // 0031 EQ R6 R6 K2 - 0x781A0002, // 0032 JMPF R6 #0036 - 0x8C18070A, // 0033 GETMET R6 R3 K10 - 0x5C200A00, // 0034 MOVE R8 R5 - 0x7C180400, // 0035 CALL R6 2 - 0x7001FFF6, // 0036 JMP #002E - 0x58100003, // 0037 LDCONST R4 K3 - 0xAC100200, // 0038 CATCH R4 1 0 - 0xB0080000, // 0039 RAISE 2 R0 R0 - 0x60100010, // 003A GETGBL R4 G16 - 0x5C140600, // 003B MOVE R5 R3 - 0x7C100200, // 003C CALL R4 1 - 0xA802000E, // 003D EXBLK 0 #004D - 0x5C140800, // 003E MOVE R5 R4 - 0x7C140000, // 003F CALL R5 0 - 0xB81A1600, // 0040 GETNGBL R6 K11 - 0x8C180D0C, // 0041 GETMET R6 R6 K12 - 0x88200B0E, // 0042 GETMBR R8 R5 K14 - 0x00221A08, // 0043 ADD R8 K13 R8 - 0x5824000F, // 0044 LDCONST R9 K15 - 0x7C180600, // 0045 CALL R6 3 - 0x8C180B10, // 0046 GETMET R6 R5 K16 - 0x7C180200, // 0047 CALL R6 1 - 0x88180101, // 0048 GETMBR R6 R0 K1 - 0x8C180D11, // 0049 GETMET R6 R6 K17 - 0x88200B0E, // 004A GETMBR R8 R5 K14 - 0x7C180400, // 004B CALL R6 2 - 0x7001FFF0, // 004C JMP #003E - 0x58100003, // 004D LDCONST R4 K3 - 0xAC100200, // 004E CATCH R4 1 0 - 0xB0080000, // 004F RAISE 2 R0 R0 - 0x80000000, // 0050 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: save_before_restart -********************************************************************/ -be_local_closure(Matter_Device_save_before_restart, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(stop_basic_commissioning), - /* K1 */ be_nested_str_weak(mdns_remove_op_discovery_all_fabrics), - }), - be_str_weak(save_before_restart), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x8C040101, // 0002 GETMET R1 R0 K1 - 0x7C040200, // 0003 CALL R1 1 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: stop -********************************************************************/ -be_local_closure(Matter_Device_stop, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(remove_driver), - /* K2 */ be_nested_str_weak(udp_server), - /* K3 */ be_nested_str_weak(stop), - }), - be_str_weak(stop), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x5C0C0000, // 0002 MOVE R3 R0 - 0x7C040400, // 0003 CALL R1 2 - 0x88040102, // 0004 GETMBR R1 R0 K2 - 0x78060002, // 0005 JMPF R1 #0009 - 0x88040102, // 0006 GETMBR R1 R0 K2 - 0x8C040303, // 0007 GETMET R1 R1 K3 - 0x7C040200, // 0008 CALL R1 1 - 0x80000000, // 0009 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: process_attribute_read_solo -********************************************************************/ -be_local_closure(Matter_Device_process_attribute_read_solo, /* name */ - be_nested_proto( - 10, /* nstack */ + 5, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -211,119 +19,24 @@ be_local_closure(Matter_Device_process_attribute_read_solo, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_nested_str_weak(endpoint), - /* K1 */ be_nested_str_weak(cluster), - /* K2 */ be_nested_str_weak(attribute), - /* K3 */ be_nested_str_weak(find_plugin_by_endpoint), - /* K4 */ be_nested_str_weak(status), - /* K5 */ be_nested_str_weak(matter), - /* K6 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), - /* K7 */ be_nested_str_weak(contains_cluster), - /* K8 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), - /* K9 */ be_nested_str_weak(contains_attribute), - /* K10 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(plugins_classes), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(DISPLAY_NAME), + /* K3 */ be_nested_str_weak(), }), - be_str_weak(process_attribute_read_solo), + be_str_weak(get_plugin_class_displayname), &be_const_str_solidified, - ( &(const binstruction[45]) { /* code */ - 0x88080300, // 0000 GETMBR R2 R1 K0 - 0x880C0301, // 0001 GETMBR R3 R1 K1 - 0x88100302, // 0002 GETMBR R4 R1 K2 - 0x4C140000, // 0003 LDNIL R5 - 0x1C140405, // 0004 EQ R5 R2 R5 - 0x74160005, // 0005 JMPT R5 #000C - 0x4C140000, // 0006 LDNIL R5 - 0x1C140605, // 0007 EQ R5 R3 R5 - 0x74160002, // 0008 JMPT R5 #000C - 0x4C140000, // 0009 LDNIL R5 - 0x1C140805, // 000A EQ R5 R4 R5 - 0x78160001, // 000B JMPF R5 #000E - 0x4C140000, // 000C LDNIL R5 - 0x80040A00, // 000D RET 1 R5 - 0x8C140103, // 000E GETMET R5 R0 K3 - 0x5C1C0400, // 000F MOVE R7 R2 - 0x7C140400, // 0010 CALL R5 2 - 0x4C180000, // 0011 LDNIL R6 - 0x1C180A06, // 0012 EQ R6 R5 R6 - 0x781A0004, // 0013 JMPF R6 #0019 - 0xB81A0A00, // 0014 GETNGBL R6 K5 - 0x88180D06, // 0015 GETMBR R6 R6 K6 - 0x90060806, // 0016 SETMBR R1 K4 R6 - 0x4C180000, // 0017 LDNIL R6 - 0x80040C00, // 0018 RET 1 R6 - 0x8C180B07, // 0019 GETMET R6 R5 K7 - 0x5C200600, // 001A MOVE R8 R3 - 0x7C180400, // 001B CALL R6 2 - 0x741A0004, // 001C JMPT R6 #0022 - 0xB81A0A00, // 001D GETNGBL R6 K5 - 0x88180D08, // 001E GETMBR R6 R6 K8 - 0x90060806, // 001F SETMBR R1 K4 R6 - 0x4C180000, // 0020 LDNIL R6 - 0x80040C00, // 0021 RET 1 R6 - 0x8C180B09, // 0022 GETMET R6 R5 K9 - 0x5C200600, // 0023 MOVE R8 R3 - 0x5C240800, // 0024 MOVE R9 R4 - 0x7C180600, // 0025 CALL R6 3 - 0x741A0004, // 0026 JMPT R6 #002C - 0xB81A0A00, // 0027 GETNGBL R6 K5 - 0x88180D0A, // 0028 GETMBR R6 R6 K10 - 0x90060806, // 0029 SETMBR R1 K4 R6 - 0x4C180000, // 002A LDNIL R6 - 0x80040C00, // 002B RET 1 R6 - 0x80040A00, // 002C RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: mdns_announce_op_discovery_all_fabrics -********************************************************************/ -be_local_closure(Matter_Device_mdns_announce_op_discovery_all_fabrics, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(active_fabrics), - /* K2 */ be_nested_str_weak(get_device_id), - /* K3 */ be_nested_str_weak(get_fabric_id), - /* K4 */ be_nested_str_weak(mdns_announce_op_discovery), - /* K5 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(mdns_announce_op_discovery_all_fabrics), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x8C080501, // 0002 GETMET R2 R2 K1 - 0x7C080200, // 0003 CALL R2 1 - 0x7C040200, // 0004 CALL R1 1 - 0xA802000B, // 0005 EXBLK 0 #0012 - 0x5C080200, // 0006 MOVE R2 R1 - 0x7C080000, // 0007 CALL R2 0 - 0x8C0C0502, // 0008 GETMET R3 R2 K2 - 0x7C0C0200, // 0009 CALL R3 1 - 0x780E0005, // 000A JMPF R3 #0011 - 0x8C0C0503, // 000B GETMET R3 R2 K3 - 0x7C0C0200, // 000C CALL R3 1 - 0x780E0002, // 000D JMPF R3 #0011 - 0x8C0C0104, // 000E GETMET R3 R0 K4 - 0x5C140400, // 000F MOVE R5 R2 - 0x7C0C0400, // 0010 CALL R3 2 - 0x7001FFF3, // 0011 JMP #0006 - 0x58040005, // 0012 LDCONST R1 K5 - 0xAC040200, // 0013 CATCH R1 1 0 - 0xB0080000, // 0014 RAISE 2 R0 R0 - 0x80000000, // 0015 RET 0 + ( &(const binstruction[ 9]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x780A0001, // 0004 JMPF R2 #0007 + 0x880C0502, // 0005 GETMBR R3 R2 K2 + 0x70020000, // 0006 JMP #0008 + 0x580C0003, // 0007 LDCONST R3 K3 + 0x80040600, // 0008 RET 1 R3 }) ) ); @@ -456,6 +169,1673 @@ be_local_closure(Matter_Device_mdns_remove_PASE, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: compute_qrcode_content +********************************************************************/ +be_local_closure(Matter_Device_compute_qrcode_content, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(resize), + /* K1 */ be_nested_str_weak(setbits), + /* K2 */ be_const_int(3), + /* K3 */ be_nested_str_weak(vendorid), + /* K4 */ be_nested_str_weak(productid), + /* K5 */ be_nested_str_weak(root_discriminator), + /* K6 */ be_nested_str_weak(root_passcode), + /* K7 */ be_const_int(134217727), + /* K8 */ be_nested_str_weak(MT_X3A), + /* K9 */ be_nested_str_weak(matter), + /* K10 */ be_nested_str_weak(Base38), + /* K11 */ be_nested_str_weak(encode), + }), + be_str_weak(compute_qrcode_content), + &be_const_str_solidified, + ( &(const binstruction[40]) { /* code */ + 0x60040015, // 0000 GETGBL R1 G21 + 0x7C040000, // 0001 CALL R1 0 + 0x8C040300, // 0002 GETMET R1 R1 K0 + 0x540E000A, // 0003 LDINT R3 11 + 0x7C040400, // 0004 CALL R1 2 + 0x8C080301, // 0005 GETMET R2 R1 K1 + 0x58100002, // 0006 LDCONST R4 K2 + 0x5416000F, // 0007 LDINT R5 16 + 0x88180103, // 0008 GETMBR R6 R0 K3 + 0x7C080800, // 0009 CALL R2 4 + 0x8C080301, // 000A GETMET R2 R1 K1 + 0x54120012, // 000B LDINT R4 19 + 0x5416000F, // 000C LDINT R5 16 + 0x88180104, // 000D GETMBR R6 R0 K4 + 0x7C080800, // 000E CALL R2 4 + 0x8C080301, // 000F GETMET R2 R1 K1 + 0x54120024, // 0010 LDINT R4 37 + 0x54160007, // 0011 LDINT R5 8 + 0x541A0003, // 0012 LDINT R6 4 + 0x7C080800, // 0013 CALL R2 4 + 0x8C080301, // 0014 GETMET R2 R1 K1 + 0x5412002C, // 0015 LDINT R4 45 + 0x5416000B, // 0016 LDINT R5 12 + 0x88180105, // 0017 GETMBR R6 R0 K5 + 0x541E0FFE, // 0018 LDINT R7 4095 + 0x2C180C07, // 0019 AND R6 R6 R7 + 0x7C080800, // 001A CALL R2 4 + 0x8C080301, // 001B GETMET R2 R1 K1 + 0x54120038, // 001C LDINT R4 57 + 0x5416001A, // 001D LDINT R5 27 + 0x88180106, // 001E GETMBR R6 R0 K6 + 0x2C180D07, // 001F AND R6 R6 K7 + 0x7C080800, // 0020 CALL R2 4 + 0xB80A1200, // 0021 GETNGBL R2 K9 + 0x8808050A, // 0022 GETMBR R2 R2 K10 + 0x8C08050B, // 0023 GETMET R2 R2 K11 + 0x5C100200, // 0024 MOVE R4 R1 + 0x7C080400, // 0025 CALL R2 2 + 0x000A1002, // 0026 ADD R2 K8 R2 + 0x80040400, // 0027 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _init_basic_commissioning +********************************************************************/ +be_local_closure(Matter_Device__init_basic_commissioning, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(count_active_fabrics), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(start_root_basic_commissioning), + }), + be_str_weak(_init_basic_commissioning), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x1C040302, // 0003 EQ R1 R1 K2 + 0x78060001, // 0004 JMPF R1 #0007 + 0x8C040103, // 0005 GETMET R1 R0 K3 + 0x7C040200, // 0006 CALL R1 1 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: compute_manual_pairing_code +********************************************************************/ +be_local_closure(Matter_Device_compute_manual_pairing_code, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(root_discriminator), + /* K1 */ be_nested_str_weak(root_passcode), + /* K2 */ be_nested_str_weak(_X251i_X2505i_X2504i), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(Verhoeff), + /* K5 */ be_nested_str_weak(checksum), + }), + be_str_weak(compute_manual_pairing_code), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x540A0FFE, // 0001 LDINT R2 4095 + 0x2C040202, // 0002 AND R1 R1 R2 + 0x540A0009, // 0003 LDINT R2 10 + 0x3C040202, // 0004 SHR R1 R1 R2 + 0x88080100, // 0005 GETMBR R2 R0 K0 + 0x540E02FF, // 0006 LDINT R3 768 + 0x2C080403, // 0007 AND R2 R2 R3 + 0x540E0005, // 0008 LDINT R3 6 + 0x38080403, // 0009 SHL R2 R2 R3 + 0x880C0101, // 000A GETMBR R3 R0 K1 + 0x54123FFE, // 000B LDINT R4 16383 + 0x2C0C0604, // 000C AND R3 R3 R4 + 0x30080403, // 000D OR R2 R2 R3 + 0x880C0101, // 000E GETMBR R3 R0 K1 + 0x5412000D, // 000F LDINT R4 14 + 0x3C0C0604, // 0010 SHR R3 R3 R4 + 0x60100018, // 0011 GETGBL R4 G24 + 0x58140002, // 0012 LDCONST R5 K2 + 0x5C180200, // 0013 MOVE R6 R1 + 0x5C1C0400, // 0014 MOVE R7 R2 + 0x5C200600, // 0015 MOVE R8 R3 + 0x7C100800, // 0016 CALL R4 4 + 0xB8160600, // 0017 GETNGBL R5 K3 + 0x88140B04, // 0018 GETMBR R5 R5 K4 + 0x8C140B05, // 0019 GETMET R5 R5 K5 + 0x5C1C0800, // 001A MOVE R7 R4 + 0x7C140400, // 001B CALL R5 2 + 0x00100805, // 001C ADD R4 R4 R5 + 0x80040800, // 001D RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Device_invoke_request, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(endpoint), + /* K2 */ be_nested_str_weak(plugins), + /* K3 */ be_nested_str_weak(invoke_request), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(status), + /* K6 */ be_nested_str_weak(matter), + /* K7 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x58100000, // 0000 LDCONST R4 K0 + 0x88140701, // 0001 GETMBR R5 R3 K1 + 0x6018000C, // 0002 GETGBL R6 G12 + 0x881C0102, // 0003 GETMBR R7 R0 K2 + 0x7C180200, // 0004 CALL R6 1 + 0x14180806, // 0005 LT R6 R4 R6 + 0x781A000C, // 0006 JMPF R6 #0014 + 0x88180102, // 0007 GETMBR R6 R0 K2 + 0x94180C04, // 0008 GETIDX R6 R6 R4 + 0x881C0D01, // 0009 GETMBR R7 R6 K1 + 0x1C1C0E05, // 000A EQ R7 R7 R5 + 0x781E0005, // 000B JMPF R7 #0012 + 0x8C1C0D03, // 000C GETMET R7 R6 K3 + 0x5C240200, // 000D MOVE R9 R1 + 0x5C280400, // 000E MOVE R10 R2 + 0x5C2C0600, // 000F MOVE R11 R3 + 0x7C1C0800, // 0010 CALL R7 4 + 0x80040E00, // 0011 RET 1 R7 + 0x00100904, // 0012 ADD R4 R4 K4 + 0x7001FFED, // 0013 JMP #0002 + 0xB81A0C00, // 0014 GETNGBL R6 K6 + 0x88180D07, // 0015 GETMBR R6 R6 K7 + 0x900E0A06, // 0016 SETMBR R3 K5 R6 + 0x80000000, // 0017 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: stop +********************************************************************/ +be_local_closure(Matter_Device_stop, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(remove_driver), + /* K2 */ be_nested_str_weak(udp_server), + /* K3 */ be_nested_str_weak(stop), + }), + be_str_weak(stop), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x5C0C0000, // 0002 MOVE R3 R0 + 0x7C040400, // 0003 CALL R1 2 + 0x88040102, // 0004 GETMBR R1 R0 K2 + 0x78060002, // 0005 JMPF R1 #0009 + 0x88040102, // 0006 GETMBR R1 R0 K2 + 0x8C040303, // 0007 GETMET R1 R1 K3 + 0x7C040200, // 0008 CALL R1 1 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: bridge_add_endpoint +********************************************************************/ +be_local_closure(Matter_Device_bridge_add_endpoint, /* name */ + be_nested_proto( + 17, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_nested_str_weak(plugins_classes), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(log), + /* K4 */ be_nested_str_weak(MTR_X3A_X20unknown_X20class_X20name_X20_X27), + /* K5 */ be_nested_str_weak(_X27_X20skipping), + /* K6 */ be_const_int(3), + /* K7 */ be_nested_str_weak(next_ep), + /* K8 */ be_nested_str_weak(plugins), + /* K9 */ be_nested_str_weak(push), + /* K10 */ be_nested_str_weak(type), + /* K11 */ be_nested_str_weak(keys), + /* K12 */ be_nested_str_weak(stop_iteration), + /* K13 */ be_nested_str_weak(MTR_X3A_X20adding_X20endpoint_X20_X3D_X20_X25i_X20type_X3A_X25s_X25s), + /* K14 */ be_nested_str_weak(conf_to_log), + /* K15 */ be_const_int(2), + /* K16 */ be_nested_str_weak(plugins_config), + /* K17 */ be_nested_str_weak(plugins_persist), + /* K18 */ be_const_int(1), + /* K19 */ be_nested_str_weak(save_param), + /* K20 */ be_nested_str_weak(signal_endpoints_changed), + }), + be_str_weak(bridge_add_endpoint), + &be_const_str_solidified, + ( &(const binstruction[70]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x4C100000, // 0004 LDNIL R4 + 0x1C100604, // 0005 EQ R4 R3 R4 + 0x78120009, // 0006 JMPF R4 #0011 + 0xB8120400, // 0007 GETNGBL R4 K2 + 0x8C100903, // 0008 GETMET R4 R4 K3 + 0x60180008, // 0009 GETGBL R6 G8 + 0x5C1C0200, // 000A MOVE R7 R1 + 0x7C180200, // 000B CALL R6 1 + 0x001A0806, // 000C ADD R6 K4 R6 + 0x00180D05, // 000D ADD R6 R6 K5 + 0x581C0006, // 000E LDCONST R7 K6 + 0x7C100600, // 000F CALL R4 3 + 0x80000800, // 0010 RET 0 + 0x88100107, // 0011 GETMBR R4 R0 K7 + 0x60140008, // 0012 GETGBL R5 G8 + 0x5C180800, // 0013 MOVE R6 R4 + 0x7C140200, // 0014 CALL R5 1 + 0x5C180600, // 0015 MOVE R6 R3 + 0x5C1C0000, // 0016 MOVE R7 R0 + 0x5C200800, // 0017 MOVE R8 R4 + 0x5C240400, // 0018 MOVE R9 R2 + 0x7C180600, // 0019 CALL R6 3 + 0x881C0108, // 001A GETMBR R7 R0 K8 + 0x8C1C0F09, // 001B GETMET R7 R7 K9 + 0x5C240C00, // 001C MOVE R9 R6 + 0x7C1C0400, // 001D CALL R7 2 + 0x601C0013, // 001E GETGBL R7 G19 + 0x7C1C0000, // 001F CALL R7 0 + 0x981E1401, // 0020 SETIDX R7 K10 R1 + 0x60200010, // 0021 GETGBL R8 G16 + 0x8C24050B, // 0022 GETMET R9 R2 K11 + 0x7C240200, // 0023 CALL R9 1 + 0x7C200200, // 0024 CALL R8 1 + 0xA8020004, // 0025 EXBLK 0 #002B + 0x5C241000, // 0026 MOVE R9 R8 + 0x7C240000, // 0027 CALL R9 0 + 0x94280409, // 0028 GETIDX R10 R2 R9 + 0x981C120A, // 0029 SETIDX R7 R9 R10 + 0x7001FFFA, // 002A JMP #0026 + 0x5820000C, // 002B LDCONST R8 K12 + 0xAC200200, // 002C CATCH R8 1 0 + 0xB0080000, // 002D RAISE 2 R0 R0 + 0xB8220400, // 002E GETNGBL R8 K2 + 0x8C201103, // 002F GETMET R8 R8 K3 + 0x60280018, // 0030 GETGBL R10 G24 + 0x582C000D, // 0031 LDCONST R11 K13 + 0x5C300800, // 0032 MOVE R12 R4 + 0x5C340200, // 0033 MOVE R13 R1 + 0x8C38010E, // 0034 GETMET R14 R0 K14 + 0x5C400400, // 0035 MOVE R16 R2 + 0x7C380400, // 0036 CALL R14 2 + 0x7C280800, // 0037 CALL R10 4 + 0x582C000F, // 0038 LDCONST R11 K15 + 0x7C200600, // 0039 CALL R8 3 + 0x88200110, // 003A GETMBR R8 R0 K16 + 0x98200A07, // 003B SETIDX R8 R5 R7 + 0x50200200, // 003C LDBOOL R8 1 0 + 0x90022208, // 003D SETMBR R0 K17 R8 + 0x88200107, // 003E GETMBR R8 R0 K7 + 0x00201112, // 003F ADD R8 R8 K18 + 0x90020E08, // 0040 SETMBR R0 K7 R8 + 0x8C200113, // 0041 GETMET R8 R0 K19 + 0x7C200200, // 0042 CALL R8 1 + 0x8C200114, // 0043 GETMET R8 R0 K20 + 0x7C200200, // 0044 CALL R8 1 + 0x80040800, // 0045 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: mdns_remove_op_discovery +********************************************************************/ +be_local_closure(Matter_Device_mdns_remove_op_discovery, /* name */ + be_nested_proto( + 12, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[23]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns), + /* K1 */ be_nested_str_weak(get_device_id), + /* K2 */ be_nested_str_weak(copy), + /* K3 */ be_nested_str_weak(reverse), + /* K4 */ be_nested_str_weak(get_fabric_compressed), + /* K5 */ be_nested_str_weak(tohex), + /* K6 */ be_nested_str_weak(_X2D), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(eth), + /* K9 */ be_nested_str_weak(find), + /* K10 */ be_nested_str_weak(up), + /* K11 */ be_nested_str_weak(log), + /* K12 */ be_nested_str_weak(MTR_X3A_X20remove_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27), + /* K13 */ be_const_int(3), + /* K14 */ be_nested_str_weak(remove_service), + /* K15 */ be_nested_str_weak(_matter), + /* K16 */ be_nested_str_weak(_tcp), + /* K17 */ be_nested_str_weak(hostname_eth), + /* K18 */ be_nested_str_weak(wifi), + /* K19 */ be_nested_str_weak(hostname_wifi), + /* K20 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K21 */ be_nested_str_weak(_X7C), + /* K22 */ be_const_int(2), + }), + be_str_weak(mdns_remove_op_discovery), + &be_const_str_solidified, + ( &(const binstruction[80]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA802003B, // 0001 EXBLK 0 #003E + 0x8C0C0301, // 0002 GETMET R3 R1 K1 + 0x7C0C0200, // 0003 CALL R3 1 + 0x8C0C0702, // 0004 GETMET R3 R3 K2 + 0x7C0C0200, // 0005 CALL R3 1 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x7C0C0200, // 0007 CALL R3 1 + 0x8C100304, // 0008 GETMET R4 R1 K4 + 0x7C100200, // 0009 CALL R4 1 + 0x8C140905, // 000A GETMET R5 R4 K5 + 0x7C140200, // 000B CALL R5 1 + 0x00140B06, // 000C ADD R5 R5 K6 + 0x8C180705, // 000D GETMET R6 R3 K5 + 0x7C180200, // 000E CALL R6 1 + 0x00140A06, // 000F ADD R5 R5 R6 + 0xB81A0E00, // 0010 GETNGBL R6 K7 + 0x8C180D08, // 0011 GETMET R6 R6 K8 + 0x7C180200, // 0012 CALL R6 1 + 0x8C180D09, // 0013 GETMET R6 R6 K9 + 0x5820000A, // 0014 LDCONST R8 K10 + 0x7C180400, // 0015 CALL R6 2 + 0x781A000E, // 0016 JMPF R6 #0026 + 0xB81A0E00, // 0017 GETNGBL R6 K7 + 0x8C180D0B, // 0018 GETMET R6 R6 K11 + 0x60200018, // 0019 GETGBL R8 G24 + 0x5824000C, // 001A LDCONST R9 K12 + 0x58280008, // 001B LDCONST R10 K8 + 0x5C2C0A00, // 001C MOVE R11 R5 + 0x7C200600, // 001D CALL R8 3 + 0x5824000D, // 001E LDCONST R9 K13 + 0x7C180600, // 001F CALL R6 3 + 0x8C18050E, // 0020 GETMET R6 R2 K14 + 0x5820000F, // 0021 LDCONST R8 K15 + 0x58240010, // 0022 LDCONST R9 K16 + 0x5C280A00, // 0023 MOVE R10 R5 + 0x882C0111, // 0024 GETMBR R11 R0 K17 + 0x7C180A00, // 0025 CALL R6 5 + 0xB81A0E00, // 0026 GETNGBL R6 K7 + 0x8C180D12, // 0027 GETMET R6 R6 K18 + 0x7C180200, // 0028 CALL R6 1 + 0x8C180D09, // 0029 GETMET R6 R6 K9 + 0x5820000A, // 002A LDCONST R8 K10 + 0x7C180400, // 002B CALL R6 2 + 0x781A000E, // 002C JMPF R6 #003C + 0xB81A0E00, // 002D GETNGBL R6 K7 + 0x8C180D0B, // 002E GETMET R6 R6 K11 + 0x60200018, // 002F GETGBL R8 G24 + 0x5824000C, // 0030 LDCONST R9 K12 + 0x58280012, // 0031 LDCONST R10 K18 + 0x5C2C0A00, // 0032 MOVE R11 R5 + 0x7C200600, // 0033 CALL R8 3 + 0x5824000D, // 0034 LDCONST R9 K13 + 0x7C180600, // 0035 CALL R6 3 + 0x8C18050E, // 0036 GETMET R6 R2 K14 + 0x5820000F, // 0037 LDCONST R8 K15 + 0x58240010, // 0038 LDCONST R9 K16 + 0x5C280A00, // 0039 MOVE R10 R5 + 0x882C0113, // 003A GETMBR R11 R0 K19 + 0x7C180A00, // 003B CALL R6 5 + 0xA8040001, // 003C EXBLK 1 1 + 0x70020010, // 003D JMP #004F + 0xAC0C0002, // 003E CATCH R3 0 2 + 0x7002000D, // 003F JMP #004E + 0xB8160E00, // 0040 GETNGBL R5 K7 + 0x8C140B0B, // 0041 GETMET R5 R5 K11 + 0x601C0008, // 0042 GETGBL R7 G8 + 0x5C200600, // 0043 MOVE R8 R3 + 0x7C1C0200, // 0044 CALL R7 1 + 0x001E2807, // 0045 ADD R7 K20 R7 + 0x001C0F15, // 0046 ADD R7 R7 K21 + 0x60200008, // 0047 GETGBL R8 G8 + 0x5C240800, // 0048 MOVE R9 R4 + 0x7C200200, // 0049 CALL R8 1 + 0x001C0E08, // 004A ADD R7 R7 R8 + 0x58200016, // 004B LDCONST R8 K22 + 0x7C140600, // 004C CALL R5 3 + 0x70020000, // 004D JMP #004F + 0xB0080000, // 004E RAISE 2 R0 R0 + 0x80000000, // 004F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_plugin_remote_info +********************************************************************/ +be_local_closure(Matter_Device_get_plugin_remote_info, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(plugins_config_remotes), + /* K1 */ be_nested_str_weak(find), + }), + be_str_weak(get_plugin_remote_info), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x60140013, // 0003 GETGBL R5 G19 + 0x7C140000, // 0004 CALL R5 0 + 0x7C080600, // 0005 CALL R2 3 + 0x80040400, // 0006 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: autoconf_device_map +********************************************************************/ +be_local_closure(Matter_Device_autoconf_device_map, /* name */ + be_nested_proto( + 20, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[36]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_const_int(1), + /* K2 */ be_nested_str_weak(light), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_nested_str_weak(find), + /* K5 */ be_nested_str_weak(channels), + /* K6 */ be_nested_str_weak(), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(type), + /* K9 */ be_nested_str_weak(light1), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(light2), + /* K12 */ be_nested_str_weak(light3), + /* K13 */ be_nested_str_weak(tasmota), + /* K14 */ be_nested_str_weak(cmd), + /* K15 */ be_nested_str_weak(Status_X2013), + /* K16 */ be_nested_str_weak(log), + /* K17 */ be_nested_str_weak(MTR_X3A_X20Status_X2013_X20_X3D_X20), + /* K18 */ be_const_int(3), + /* K19 */ be_nested_str_weak(contains), + /* K20 */ be_nested_str_weak(StatusSHT), + /* K21 */ be_nested_str_weak(SHT), + /* K22 */ be_nested_str_weak(MTR_X3A_X20_X27_X25s_X27_X20_X3D_X20_X25s), + /* K23 */ be_nested_str_weak(Relay1), + /* K24 */ be_nested_str_weak(Relay2), + /* K25 */ be_nested_str_weak(push), + /* K26 */ be_nested_str_weak(MTR_X3A_X20relay1_X3D_X25s_X20relay2_X3D_X25s), + /* K27 */ be_nested_str_weak(TiltConfig), + /* K28 */ be_nested_str_weak(shutter_X2Btilt), + /* K29 */ be_nested_str_weak(shutter), + /* K30 */ be_nested_str_weak(get_power), + /* K31 */ be_nested_str_weak(relay), + /* K32 */ be_nested_str_weak(load), + /* K33 */ be_nested_str_weak(read_sensors), + /* K34 */ be_nested_str_weak(autoconf_sensors_list), + /* K35 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(autoconf_device_map), + &be_const_str_solidified, + ( &(const binstruction[198]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x60080013, // 0001 GETGBL R2 G19 + 0x7C080000, // 0002 CALL R2 0 + 0x580C0001, // 0003 LDCONST R3 K1 + 0x50100000, // 0004 LDBOOL R4 0 0 + 0xA4160400, // 0005 IMPORT R5 K2 + 0x8C180B03, // 0006 GETMET R6 R5 K3 + 0x7C180200, // 0007 CALL R6 1 + 0x4C1C0000, // 0008 LDNIL R7 + 0x201C0C07, // 0009 NE R7 R6 R7 + 0x781E0024, // 000A JMPF R7 #0030 + 0x601C000C, // 000B GETGBL R7 G12 + 0x8C200D04, // 000C GETMET R8 R6 K4 + 0x58280005, // 000D LDCONST R10 K5 + 0x582C0006, // 000E LDCONST R11 K6 + 0x7C200600, // 000F CALL R8 3 + 0x7C1C0200, // 0010 CALL R7 1 + 0x24200F07, // 0011 GT R8 R7 K7 + 0x7822001C, // 0012 JMPF R8 #0030 + 0x1C200F01, // 0013 EQ R8 R7 K1 + 0x78220007, // 0014 JMPF R8 #001D + 0x60200008, // 0015 GETGBL R8 G8 + 0x5C240600, // 0016 MOVE R9 R3 + 0x7C200200, // 0017 CALL R8 1 + 0x60240013, // 0018 GETGBL R9 G19 + 0x7C240000, // 0019 CALL R9 0 + 0x98261109, // 001A SETIDX R9 K8 K9 + 0x98081009, // 001B SETIDX R2 R8 R9 + 0x70020010, // 001C JMP #002E + 0x1C200F0A, // 001D EQ R8 R7 K10 + 0x78220007, // 001E JMPF R8 #0027 + 0x60200008, // 001F GETGBL R8 G8 + 0x5C240600, // 0020 MOVE R9 R3 + 0x7C200200, // 0021 CALL R8 1 + 0x60240013, // 0022 GETGBL R9 G19 + 0x7C240000, // 0023 CALL R9 0 + 0x9826110B, // 0024 SETIDX R9 K8 K11 + 0x98081009, // 0025 SETIDX R2 R8 R9 + 0x70020006, // 0026 JMP #002E + 0x60200008, // 0027 GETGBL R8 G8 + 0x5C240600, // 0028 MOVE R9 R3 + 0x7C200200, // 0029 CALL R8 1 + 0x60240013, // 002A GETGBL R9 G19 + 0x7C240000, // 002B CALL R9 0 + 0x9826110C, // 002C SETIDX R9 K8 K12 + 0x98081009, // 002D SETIDX R2 R8 R9 + 0x50100200, // 002E LDBOOL R4 1 0 + 0x000C0701, // 002F ADD R3 R3 K1 + 0xB81E1A00, // 0030 GETNGBL R7 K13 + 0x8C1C0F0E, // 0031 GETMET R7 R7 K14 + 0x5824000F, // 0032 LDCONST R9 K15 + 0x50280200, // 0033 LDBOOL R10 1 0 + 0x7C1C0600, // 0034 CALL R7 3 + 0x60200012, // 0035 GETGBL R8 G18 + 0x7C200000, // 0036 CALL R8 0 + 0xB8261A00, // 0037 GETNGBL R9 K13 + 0x8C241310, // 0038 GETMET R9 R9 K16 + 0x602C0008, // 0039 GETGBL R11 G8 + 0x5C300E00, // 003A MOVE R12 R7 + 0x7C2C0200, // 003B CALL R11 1 + 0x002E220B, // 003C ADD R11 K17 R11 + 0x58300012, // 003D LDCONST R12 K18 + 0x7C240600, // 003E CALL R9 3 + 0x4C240000, // 003F LDNIL R9 + 0x20240E09, // 0040 NE R9 R7 R9 + 0x7826004F, // 0041 JMPF R9 #0092 + 0x8C240F13, // 0042 GETMET R9 R7 K19 + 0x582C0014, // 0043 LDCONST R11 K20 + 0x7C240400, // 0044 CALL R9 2 + 0x7826004B, // 0045 JMPF R9 #0092 + 0x941C0F14, // 0046 GETIDX R7 R7 K20 + 0x58240007, // 0047 LDCONST R9 K7 + 0x50280200, // 0048 LDBOOL R10 1 0 + 0x782A0047, // 0049 JMPF R10 #0092 + 0x60280008, // 004A GETGBL R10 G8 + 0x5C2C1200, // 004B MOVE R11 R9 + 0x7C280200, // 004C CALL R10 1 + 0x002A2A0A, // 004D ADD R10 K21 R10 + 0x8C2C0F13, // 004E GETMET R11 R7 K19 + 0x5C341400, // 004F MOVE R13 R10 + 0x7C2C0400, // 0050 CALL R11 2 + 0x742E0000, // 0051 JMPT R11 #0053 + 0x7002003E, // 0052 JMP #0092 + 0x942C0E0A, // 0053 GETIDX R11 R7 R10 + 0xB8321A00, // 0054 GETNGBL R12 K13 + 0x8C301910, // 0055 GETMET R12 R12 K16 + 0x60380018, // 0056 GETGBL R14 G24 + 0x583C0016, // 0057 LDCONST R15 K22 + 0x5C401400, // 0058 MOVE R16 R10 + 0x60440008, // 0059 GETGBL R17 G8 + 0x5C481600, // 005A MOVE R18 R11 + 0x7C440200, // 005B CALL R17 1 + 0x7C380600, // 005C CALL R14 3 + 0x583C0012, // 005D LDCONST R15 K18 + 0x7C300600, // 005E CALL R12 3 + 0x8C301704, // 005F GETMET R12 R11 K4 + 0x58380017, // 0060 LDCONST R14 K23 + 0x543DFFFE, // 0061 LDINT R15 -1 + 0x7C300600, // 0062 CALL R12 3 + 0x8C341704, // 0063 GETMET R13 R11 K4 + 0x583C0018, // 0064 LDCONST R15 K24 + 0x5441FFFE, // 0065 LDINT R16 -1 + 0x7C340600, // 0066 CALL R13 3 + 0x24381907, // 0067 GT R14 R12 K7 + 0x783A0002, // 0068 JMPF R14 #006C + 0x8C381119, // 0069 GETMET R14 R8 K25 + 0x04401901, // 006A SUB R16 R12 K1 + 0x7C380400, // 006B CALL R14 2 + 0x24381B07, // 006C GT R14 R13 K7 + 0x783A0002, // 006D JMPF R14 #0071 + 0x8C381119, // 006E GETMET R14 R8 K25 + 0x04401B01, // 006F SUB R16 R13 K1 + 0x7C380400, // 0070 CALL R14 2 + 0xB83A1A00, // 0071 GETNGBL R14 K13 + 0x8C381D10, // 0072 GETMET R14 R14 K16 + 0x60400018, // 0073 GETGBL R16 G24 + 0x5844001A, // 0074 LDCONST R17 K26 + 0x5C481800, // 0075 MOVE R18 R12 + 0x5C4C1A00, // 0076 MOVE R19 R13 + 0x7C400600, // 0077 CALL R16 3 + 0x58440012, // 0078 LDCONST R17 K18 + 0x7C380600, // 0079 CALL R14 3 + 0x8C381704, // 007A GETMET R14 R11 K4 + 0x5840001B, // 007B LDCONST R16 K27 + 0x7C380400, // 007C CALL R14 2 + 0x783A0002, // 007D JMPF R14 #0081 + 0x943C1D0A, // 007E GETIDX R15 R14 K10 + 0x243C1F07, // 007F GT R15 R15 K7 + 0x743E0000, // 0080 JMPT R15 #0082 + 0x503C0001, // 0081 LDBOOL R15 0 1 + 0x503C0200, // 0082 LDBOOL R15 1 0 + 0x60400008, // 0083 GETGBL R16 G8 + 0x5C440600, // 0084 MOVE R17 R3 + 0x7C400200, // 0085 CALL R16 1 + 0x60440013, // 0086 GETGBL R17 G19 + 0x7C440000, // 0087 CALL R17 0 + 0x783E0001, // 0088 JMPF R15 #008B + 0x5848001C, // 0089 LDCONST R18 K28 + 0x70020000, // 008A JMP #008C + 0x5848001D, // 008B LDCONST R18 K29 + 0x98461012, // 008C SETIDX R17 K8 R18 + 0x98463A09, // 008D SETIDX R17 K29 R9 + 0x98082011, // 008E SETIDX R2 R16 R17 + 0x000C0701, // 008F ADD R3 R3 K1 + 0x00241301, // 0090 ADD R9 R9 K1 + 0x7001FFB5, // 0091 JMP #0048 + 0x6024000C, // 0092 GETGBL R9 G12 + 0xB82A1A00, // 0093 GETNGBL R10 K13 + 0x8C28151E, // 0094 GETMET R10 R10 K30 + 0x7C280200, // 0095 CALL R10 1 + 0x7C240200, // 0096 CALL R9 1 + 0x58280007, // 0097 LDCONST R10 K7 + 0x78120000, // 0098 JMPF R4 #009A + 0x04241301, // 0099 SUB R9 R9 K1 + 0x142C1409, // 009A LT R11 R10 R9 + 0x782E0011, // 009B JMPF R11 #00AE + 0x8C2C1104, // 009C GETMET R11 R8 K4 + 0x5C341400, // 009D MOVE R13 R10 + 0x7C2C0400, // 009E CALL R11 2 + 0x4C300000, // 009F LDNIL R12 + 0x1C2C160C, // 00A0 EQ R11 R11 R12 + 0x782E0009, // 00A1 JMPF R11 #00AC + 0x602C0008, // 00A2 GETGBL R11 G8 + 0x5C300600, // 00A3 MOVE R12 R3 + 0x7C2C0200, // 00A4 CALL R11 1 + 0x60300013, // 00A5 GETGBL R12 G19 + 0x7C300000, // 00A6 CALL R12 0 + 0x9832111F, // 00A7 SETIDX R12 K8 K31 + 0x00341501, // 00A8 ADD R13 R10 K1 + 0x98323E0D, // 00A9 SETIDX R12 K31 R13 + 0x9808160C, // 00AA SETIDX R2 R11 R12 + 0x000C0701, // 00AB ADD R3 R3 K1 + 0x00281501, // 00AC ADD R10 R10 K1 + 0x7001FFEB, // 00AD JMP #009A + 0x8C2C0320, // 00AE GETMET R11 R1 K32 + 0xB8361A00, // 00AF GETNGBL R13 K13 + 0x8C341B21, // 00B0 GETMET R13 R13 K33 + 0x7C340200, // 00B1 CALL R13 1 + 0x7C2C0400, // 00B2 CALL R11 2 + 0x8C300122, // 00B3 GETMET R12 R0 K34 + 0x5C381600, // 00B4 MOVE R14 R11 + 0x7C300400, // 00B5 CALL R12 2 + 0x60340010, // 00B6 GETGBL R13 G16 + 0x5C381800, // 00B7 MOVE R14 R12 + 0x7C340200, // 00B8 CALL R13 1 + 0xA8020007, // 00B9 EXBLK 0 #00C2 + 0x5C381A00, // 00BA MOVE R14 R13 + 0x7C380000, // 00BB CALL R14 0 + 0x603C0008, // 00BC GETGBL R15 G8 + 0x5C400600, // 00BD MOVE R16 R3 + 0x7C3C0200, // 00BE CALL R15 1 + 0x98081E0E, // 00BF SETIDX R2 R15 R14 + 0x000C0701, // 00C0 ADD R3 R3 K1 + 0x7001FFF7, // 00C1 JMP #00BA + 0x58340023, // 00C2 LDCONST R13 K35 + 0xAC340200, // 00C3 CATCH R13 1 0 + 0xB0080000, // 00C4 RAISE 2 R0 R0 + 0x80040400, // 00C5 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: clean_remotes +********************************************************************/ +be_local_closure(Matter_Device_clean_remotes, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_nested_str_weak(introspect), + /* K1 */ be_nested_str_weak(http_remotes), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(stop_iteration), + /* K4 */ be_nested_str_weak(plugins), + /* K5 */ be_nested_str_weak(get), + /* K6 */ be_nested_str_weak(http_remote), + /* K7 */ be_nested_str_weak(find), + /* K8 */ be_const_int(1), + /* K9 */ be_nested_str_weak(keys), + /* K10 */ be_nested_str_weak(push), + /* K11 */ be_nested_str_weak(tasmota), + /* K12 */ be_nested_str_weak(log), + /* K13 */ be_nested_str_weak(MTR_X3A_X20remove_X20unused_X20remote_X3A_X20), + /* K14 */ be_nested_str_weak(addr), + /* K15 */ be_const_int(3), + /* K16 */ be_nested_str_weak(close), + /* K17 */ be_nested_str_weak(remove), + }), + be_str_weak(clean_remotes), + &be_const_str_solidified, + ( &(const binstruction[81]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x780A004C, // 0002 JMPF R2 #0050 + 0x60080013, // 0003 GETGBL R2 G19 + 0x7C080000, // 0004 CALL R2 0 + 0x600C0010, // 0005 GETGBL R3 G16 + 0x88100101, // 0006 GETMBR R4 R0 K1 + 0x7C0C0200, // 0007 CALL R3 1 + 0xA8020003, // 0008 EXBLK 0 #000D + 0x5C100600, // 0009 MOVE R4 R3 + 0x7C100000, // 000A CALL R4 0 + 0x98080902, // 000B SETIDX R2 R4 K2 + 0x7001FFFB, // 000C JMP #0009 + 0x580C0003, // 000D LDCONST R3 K3 + 0xAC0C0200, // 000E CATCH R3 1 0 + 0xB0080000, // 000F RAISE 2 R0 R0 + 0x600C0010, // 0010 GETGBL R3 G16 + 0x88100104, // 0011 GETMBR R4 R0 K4 + 0x7C0C0200, // 0012 CALL R3 1 + 0xA802000F, // 0013 EXBLK 0 #0024 + 0x5C100600, // 0014 MOVE R4 R3 + 0x7C100000, // 0015 CALL R4 0 + 0x8C140305, // 0016 GETMET R5 R1 K5 + 0x5C1C0800, // 0017 MOVE R7 R4 + 0x58200006, // 0018 LDCONST R8 K6 + 0x7C140600, // 0019 CALL R5 3 + 0x4C180000, // 001A LDNIL R6 + 0x20180A06, // 001B NE R6 R5 R6 + 0x781A0005, // 001C JMPF R6 #0023 + 0x8C180507, // 001D GETMET R6 R2 K7 + 0x5C200A00, // 001E MOVE R8 R5 + 0x58240002, // 001F LDCONST R9 K2 + 0x7C180600, // 0020 CALL R6 3 + 0x00180D08, // 0021 ADD R6 R6 K8 + 0x98080A06, // 0022 SETIDX R2 R5 R6 + 0x7001FFEF, // 0023 JMP #0014 + 0x580C0003, // 0024 LDCONST R3 K3 + 0xAC0C0200, // 0025 CATCH R3 1 0 + 0xB0080000, // 0026 RAISE 2 R0 R0 + 0x600C0012, // 0027 GETGBL R3 G18 + 0x7C0C0000, // 0028 CALL R3 0 + 0x60100010, // 0029 GETGBL R4 G16 + 0x8C140509, // 002A GETMET R5 R2 K9 + 0x7C140200, // 002B CALL R5 1 + 0x7C100200, // 002C CALL R4 1 + 0xA8020008, // 002D EXBLK 0 #0037 + 0x5C140800, // 002E MOVE R5 R4 + 0x7C140000, // 002F CALL R5 0 + 0x94180405, // 0030 GETIDX R6 R2 R5 + 0x1C180D02, // 0031 EQ R6 R6 K2 + 0x781A0002, // 0032 JMPF R6 #0036 + 0x8C18070A, // 0033 GETMET R6 R3 K10 + 0x5C200A00, // 0034 MOVE R8 R5 + 0x7C180400, // 0035 CALL R6 2 + 0x7001FFF6, // 0036 JMP #002E + 0x58100003, // 0037 LDCONST R4 K3 + 0xAC100200, // 0038 CATCH R4 1 0 + 0xB0080000, // 0039 RAISE 2 R0 R0 + 0x60100010, // 003A GETGBL R4 G16 + 0x5C140600, // 003B MOVE R5 R3 + 0x7C100200, // 003C CALL R4 1 + 0xA802000E, // 003D EXBLK 0 #004D + 0x5C140800, // 003E MOVE R5 R4 + 0x7C140000, // 003F CALL R5 0 + 0xB81A1600, // 0040 GETNGBL R6 K11 + 0x8C180D0C, // 0041 GETMET R6 R6 K12 + 0x88200B0E, // 0042 GETMBR R8 R5 K14 + 0x00221A08, // 0043 ADD R8 K13 R8 + 0x5824000F, // 0044 LDCONST R9 K15 + 0x7C180600, // 0045 CALL R6 3 + 0x8C180B10, // 0046 GETMET R6 R5 K16 + 0x7C180200, // 0047 CALL R6 1 + 0x88180101, // 0048 GETMBR R6 R0 K1 + 0x8C180D11, // 0049 GETMET R6 R6 K17 + 0x88200B0E, // 004A GETMBR R8 R5 K14 + 0x7C180400, // 004B CALL R6 2 + 0x7001FFF0, // 004C JMP #003E + 0x58100003, // 004D LDCONST R4 K3 + 0xAC100200, // 004E CATCH R4 1 0 + 0xB0080000, // 004F RAISE 2 R0 R0 + 0x80000000, // 0050 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_fabric +********************************************************************/ +be_local_closure(Matter_Device_remove_fabric, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[16]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(log), + /* K2 */ be_nested_str_weak(MTR_X3A_X20removing_X20fabric_X20), + /* K3 */ be_nested_str_weak(get_fabric_id), + /* K4 */ be_nested_str_weak(copy), + /* K5 */ be_nested_str_weak(reverse), + /* K6 */ be_nested_str_weak(tohex), + /* K7 */ be_const_int(2), + /* K8 */ be_nested_str_weak(message_handler), + /* K9 */ be_nested_str_weak(im), + /* K10 */ be_nested_str_weak(subs_shop), + /* K11 */ be_nested_str_weak(remove_by_fabric), + /* K12 */ be_nested_str_weak(mdns_remove_op_discovery), + /* K13 */ be_nested_str_weak(sessions), + /* K14 */ be_nested_str_weak(remove_fabric), + /* K15 */ be_nested_str_weak(save_fabrics), + }), + be_str_weak(remove_fabric), + &be_const_str_solidified, + ( &(const binstruction[33]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x20080202, // 0001 NE R2 R1 R2 + 0x780A0019, // 0002 JMPF R2 #001D + 0xB80A0000, // 0003 GETNGBL R2 K0 + 0x8C080501, // 0004 GETMET R2 R2 K1 + 0x8C100303, // 0005 GETMET R4 R1 K3 + 0x7C100200, // 0006 CALL R4 1 + 0x8C100904, // 0007 GETMET R4 R4 K4 + 0x7C100200, // 0008 CALL R4 1 + 0x8C100905, // 0009 GETMET R4 R4 K5 + 0x7C100200, // 000A CALL R4 1 + 0x8C100906, // 000B GETMET R4 R4 K6 + 0x7C100200, // 000C CALL R4 1 + 0x00120404, // 000D ADD R4 K2 R4 + 0x58140007, // 000E LDCONST R5 K7 + 0x7C080600, // 000F CALL R2 3 + 0x88080108, // 0010 GETMBR R2 R0 K8 + 0x88080509, // 0011 GETMBR R2 R2 K9 + 0x8808050A, // 0012 GETMBR R2 R2 K10 + 0x8C08050B, // 0013 GETMET R2 R2 K11 + 0x5C100200, // 0014 MOVE R4 R1 + 0x7C080400, // 0015 CALL R2 2 + 0x8C08010C, // 0016 GETMET R2 R0 K12 + 0x5C100200, // 0017 MOVE R4 R1 + 0x7C080400, // 0018 CALL R2 2 + 0x8808010D, // 0019 GETMBR R2 R0 K13 + 0x8C08050E, // 001A GETMET R2 R2 K14 + 0x5C100200, // 001B MOVE R4 R1 + 0x7C080400, // 001C CALL R2 2 + 0x8808010D, // 001D GETMBR R2 R0 K13 + 0x8C08050F, // 001E GETMET R2 R2 K15 + 0x7C080200, // 001F CALL R2 1 + 0x80000000, // 0020 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _mdns_announce_hostname +********************************************************************/ +be_local_closure(Matter_Device__mdns_announce_hostname, /* name */ + be_nested_proto( + 14, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[27]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(start), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(eth), + /* K5 */ be_nested_str_weak(hostname_eth), + /* K6 */ be_nested_str_weak(replace), + /* K7 */ be_nested_str_weak(find), + /* K8 */ be_nested_str_weak(mac), + /* K9 */ be_nested_str_weak(_X3A), + /* K10 */ be_nested_str_weak(), + /* K11 */ be_nested_str_weak(ipv4only), + /* K12 */ be_nested_str_weak(contains), + /* K13 */ be_nested_str_weak(ip6local), + /* K14 */ be_nested_str_weak(add_hostname), + /* K15 */ be_nested_str_weak(ip), + /* K16 */ be_nested_str_weak(ip6), + /* K17 */ be_nested_str_weak(log), + /* K18 */ be_nested_str_weak(MTR_X3A_X20calling_X20mdns_X2Eadd_hostname_X28_X25s_X2C_X20_X25s_X29), + /* K19 */ be_const_int(3), + /* K20 */ be_nested_str_weak(wifi), + /* K21 */ be_nested_str_weak(hostname_wifi), + /* K22 */ be_nested_str_weak(MTR_X3A_X20start_X20mDNS_X20on_X20_X25s_X20host_X20_X27_X25s_X2Elocal_X27), + /* K23 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K24 */ be_nested_str_weak(_X7C), + /* K25 */ be_const_int(2), + /* K26 */ be_nested_str_weak(mdns_announce_op_discovery_all_fabrics), + }), + be_str_weak(_mdns_announce_hostname), + &be_const_str_solidified, + ( &(const binstruction[148]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x8C100502, // 0002 GETMET R4 R2 K2 + 0x7C100200, // 0003 CALL R4 1 + 0xA802007A, // 0004 EXBLK 0 #0080 + 0x78060034, // 0005 JMPF R1 #003B + 0xB8120600, // 0006 GETNGBL R4 K3 + 0x8C100904, // 0007 GETMET R4 R4 K4 + 0x7C100200, // 0008 CALL R4 1 + 0x8C140706, // 0009 GETMET R5 R3 K6 + 0x8C1C0907, // 000A GETMET R7 R4 K7 + 0x58240008, // 000B LDCONST R9 K8 + 0x7C1C0400, // 000C CALL R7 2 + 0x58200009, // 000D LDCONST R8 K9 + 0x5824000A, // 000E LDCONST R9 K10 + 0x7C140800, // 000F CALL R5 4 + 0x90020A05, // 0010 SETMBR R0 K5 R5 + 0x8814010B, // 0011 GETMBR R5 R0 K11 + 0x78160003, // 0012 JMPF R5 #0017 + 0x8C14090C, // 0013 GETMET R5 R4 K12 + 0x581C000D, // 0014 LDCONST R7 K13 + 0x7C140400, // 0015 CALL R5 2 + 0x7416000F, // 0016 JMPT R5 #0027 + 0x8C14050E, // 0017 GETMET R5 R2 K14 + 0x881C0105, // 0018 GETMBR R7 R0 K5 + 0x8C200907, // 0019 GETMET R8 R4 K7 + 0x5828000D, // 001A LDCONST R10 K13 + 0x582C000A, // 001B LDCONST R11 K10 + 0x7C200600, // 001C CALL R8 3 + 0x8C240907, // 001D GETMET R9 R4 K7 + 0x582C000F, // 001E LDCONST R11 K15 + 0x5830000A, // 001F LDCONST R12 K10 + 0x7C240600, // 0020 CALL R9 3 + 0x8C280907, // 0021 GETMET R10 R4 K7 + 0x58300010, // 0022 LDCONST R12 K16 + 0x5834000A, // 0023 LDCONST R13 K10 + 0x7C280600, // 0024 CALL R10 3 + 0x7C140A00, // 0025 CALL R5 5 + 0x70020012, // 0026 JMP #003A + 0xB8160600, // 0027 GETNGBL R5 K3 + 0x8C140B11, // 0028 GETMET R5 R5 K17 + 0x601C0018, // 0029 GETGBL R7 G24 + 0x58200012, // 002A LDCONST R8 K18 + 0x88240105, // 002B GETMBR R9 R0 K5 + 0x8C280907, // 002C GETMET R10 R4 K7 + 0x5830000F, // 002D LDCONST R12 K15 + 0x5834000A, // 002E LDCONST R13 K10 + 0x7C280600, // 002F CALL R10 3 + 0x7C1C0600, // 0030 CALL R7 3 + 0x58200013, // 0031 LDCONST R8 K19 + 0x7C140600, // 0032 CALL R5 3 + 0x8C14050E, // 0033 GETMET R5 R2 K14 + 0x881C0105, // 0034 GETMBR R7 R0 K5 + 0x8C200907, // 0035 GETMET R8 R4 K7 + 0x5828000F, // 0036 LDCONST R10 K15 + 0x582C000A, // 0037 LDCONST R11 K10 + 0x7C200600, // 0038 CALL R8 3 + 0x7C140600, // 0039 CALL R5 3 + 0x70020033, // 003A JMP #006F + 0xB8120600, // 003B GETNGBL R4 K3 + 0x8C100914, // 003C GETMET R4 R4 K20 + 0x7C100200, // 003D CALL R4 1 + 0x8C140706, // 003E GETMET R5 R3 K6 + 0x8C1C0907, // 003F GETMET R7 R4 K7 + 0x58240008, // 0040 LDCONST R9 K8 + 0x7C1C0400, // 0041 CALL R7 2 + 0x58200009, // 0042 LDCONST R8 K9 + 0x5824000A, // 0043 LDCONST R9 K10 + 0x7C140800, // 0044 CALL R5 4 + 0x90022A05, // 0045 SETMBR R0 K21 R5 + 0x8814010B, // 0046 GETMBR R5 R0 K11 + 0x78160003, // 0047 JMPF R5 #004C + 0x8C14090C, // 0048 GETMET R5 R4 K12 + 0x581C000D, // 0049 LDCONST R7 K13 + 0x7C140400, // 004A CALL R5 2 + 0x7416000F, // 004B JMPT R5 #005C + 0x8C14050E, // 004C GETMET R5 R2 K14 + 0x881C0115, // 004D GETMBR R7 R0 K21 + 0x8C200907, // 004E GETMET R8 R4 K7 + 0x5828000D, // 004F LDCONST R10 K13 + 0x582C000A, // 0050 LDCONST R11 K10 + 0x7C200600, // 0051 CALL R8 3 + 0x8C240907, // 0052 GETMET R9 R4 K7 + 0x582C000F, // 0053 LDCONST R11 K15 + 0x5830000A, // 0054 LDCONST R12 K10 + 0x7C240600, // 0055 CALL R9 3 + 0x8C280907, // 0056 GETMET R10 R4 K7 + 0x58300010, // 0057 LDCONST R12 K16 + 0x5834000A, // 0058 LDCONST R13 K10 + 0x7C280600, // 0059 CALL R10 3 + 0x7C140A00, // 005A CALL R5 5 + 0x70020012, // 005B JMP #006F + 0xB8160600, // 005C GETNGBL R5 K3 + 0x8C140B11, // 005D GETMET R5 R5 K17 + 0x601C0018, // 005E GETGBL R7 G24 + 0x58200012, // 005F LDCONST R8 K18 + 0x88240115, // 0060 GETMBR R9 R0 K21 + 0x8C280907, // 0061 GETMET R10 R4 K7 + 0x5830000F, // 0062 LDCONST R12 K15 + 0x5834000A, // 0063 LDCONST R13 K10 + 0x7C280600, // 0064 CALL R10 3 + 0x7C1C0600, // 0065 CALL R7 3 + 0x58200013, // 0066 LDCONST R8 K19 + 0x7C140600, // 0067 CALL R5 3 + 0x8C14050E, // 0068 GETMET R5 R2 K14 + 0x881C0115, // 0069 GETMBR R7 R0 K21 + 0x8C200907, // 006A GETMET R8 R4 K7 + 0x5828000F, // 006B LDCONST R10 K15 + 0x582C000A, // 006C LDCONST R11 K10 + 0x7C200600, // 006D CALL R8 3 + 0x7C140600, // 006E CALL R5 3 + 0xB8120600, // 006F GETNGBL R4 K3 + 0x8C100911, // 0070 GETMET R4 R4 K17 + 0x60180018, // 0071 GETGBL R6 G24 + 0x581C0016, // 0072 LDCONST R7 K22 + 0x78060001, // 0073 JMPF R1 #0076 + 0x58200004, // 0074 LDCONST R8 K4 + 0x70020000, // 0075 JMP #0077 + 0x58200014, // 0076 LDCONST R8 K20 + 0x78060001, // 0077 JMPF R1 #007A + 0x88240105, // 0078 GETMBR R9 R0 K5 + 0x70020000, // 0079 JMP #007B + 0x88240115, // 007A GETMBR R9 R0 K21 + 0x7C180600, // 007B CALL R6 3 + 0x581C0013, // 007C LDCONST R7 K19 + 0x7C100600, // 007D CALL R4 3 + 0xA8040001, // 007E EXBLK 1 1 + 0x70020010, // 007F JMP #0091 + 0xAC100002, // 0080 CATCH R4 0 2 + 0x7002000D, // 0081 JMP #0090 + 0xB81A0600, // 0082 GETNGBL R6 K3 + 0x8C180D11, // 0083 GETMET R6 R6 K17 + 0x60200008, // 0084 GETGBL R8 G8 + 0x5C240800, // 0085 MOVE R9 R4 + 0x7C200200, // 0086 CALL R8 1 + 0x00222E08, // 0087 ADD R8 K23 R8 + 0x00201118, // 0088 ADD R8 R8 K24 + 0x60240008, // 0089 GETGBL R9 G8 + 0x5C280A00, // 008A MOVE R10 R5 + 0x7C240200, // 008B CALL R9 1 + 0x00201009, // 008C ADD R8 R8 R9 + 0x58240019, // 008D LDCONST R9 K25 + 0x7C180600, // 008E CALL R6 3 + 0x70020000, // 008F JMP #0091 + 0xB0080000, // 0090 RAISE 2 R0 R0 + 0x8C10011A, // 0091 GETMET R4 R0 K26 + 0x7C100200, // 0092 CALL R4 1 + 0x80000000, // 0093 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: register_native_classes +********************************************************************/ +be_local_closure(Matter_Device_register_native_classes, /* name */ + be_nested_proto( + 12, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(introspect), + /* K1 */ be_nested_str_weak(string), + /* K2 */ be_nested_str_weak(members), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(get), + /* K5 */ be_nested_str_weak(class), + /* K6 */ be_nested_str_weak(find), + /* K7 */ be_nested_str_weak(Plugin_), + /* K8 */ be_const_int(0), + /* K9 */ be_nested_str_weak(register_plugin_class), + /* K10 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(register_native_classes), + &be_const_str_solidified, + ( &(const binstruction[33]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0xA4120200, // 0001 IMPORT R4 K1 + 0x60140010, // 0002 GETGBL R5 G16 + 0x8C180702, // 0003 GETMET R6 R3 K2 + 0xB8220600, // 0004 GETNGBL R8 K3 + 0x7C180400, // 0005 CALL R6 2 + 0x7C140200, // 0006 CALL R5 1 + 0xA8020014, // 0007 EXBLK 0 #001D + 0x5C180A00, // 0008 MOVE R6 R5 + 0x7C180000, // 0009 CALL R6 0 + 0x8C1C0704, // 000A GETMET R7 R3 K4 + 0xB8260600, // 000B GETNGBL R9 K3 + 0x5C280C00, // 000C MOVE R10 R6 + 0x7C1C0600, // 000D CALL R7 3 + 0x60200004, // 000E GETGBL R8 G4 + 0x5C240E00, // 000F MOVE R9 R7 + 0x7C200200, // 0010 CALL R8 1 + 0x1C201105, // 0011 EQ R8 R8 K5 + 0x78220008, // 0012 JMPF R8 #001C + 0x8C200906, // 0013 GETMET R8 R4 K6 + 0x5C280C00, // 0014 MOVE R10 R6 + 0x582C0007, // 0015 LDCONST R11 K7 + 0x7C200600, // 0016 CALL R8 3 + 0x1C201108, // 0017 EQ R8 R8 K8 + 0x78220002, // 0018 JMPF R8 #001C + 0x8C200109, // 0019 GETMET R8 R0 K9 + 0x5C280E00, // 001A MOVE R10 R7 + 0x7C200400, // 001B CALL R8 2 + 0x7001FFEA, // 001C JMP #0008 + 0x5814000A, // 001D LDCONST R5 K10 + 0xAC140200, // 001E CATCH R5 1 0 + 0xB0080000, // 001F RAISE 2 R0 R0 + 0x80000000, // 0020 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: mdns_remove_op_discovery_all_fabrics +********************************************************************/ +be_local_closure(Matter_Device_mdns_remove_op_discovery_all_fabrics, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(active_fabrics), + /* K2 */ be_nested_str_weak(get_device_id), + /* K3 */ be_nested_str_weak(get_fabric_id), + /* K4 */ be_nested_str_weak(mdns_remove_op_discovery), + /* K5 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(mdns_remove_op_discovery_all_fabrics), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x8C080501, // 0002 GETMET R2 R2 K1 + 0x7C080200, // 0003 CALL R2 1 + 0x7C040200, // 0004 CALL R1 1 + 0xA802000B, // 0005 EXBLK 0 #0012 + 0x5C080200, // 0006 MOVE R2 R1 + 0x7C080000, // 0007 CALL R2 0 + 0x8C0C0502, // 0008 GETMET R3 R2 K2 + 0x7C0C0200, // 0009 CALL R3 1 + 0x780E0005, // 000A JMPF R3 #0011 + 0x8C0C0503, // 000B GETMET R3 R2 K3 + 0x7C0C0200, // 000C CALL R3 1 + 0x780E0002, // 000D JMPF R3 #0011 + 0x8C0C0104, // 000E GETMET R3 R0 K4 + 0x5C140400, // 000F MOVE R5 R2 + 0x7C0C0400, // 0010 CALL R3 2 + 0x7001FFF3, // 0011 JMP #0006 + 0x58040005, // 0012 LDCONST R1 K5 + 0xAC040200, // 0013 CATCH R1 1 0 + 0xB0080000, // 0014 RAISE 2 R0 R0 + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: is_root_commissioning_open +********************************************************************/ +be_local_closure(Matter_Device_is_root_commissioning_open, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(commissioning_open), + /* K1 */ be_nested_str_weak(commissioning_admin_fabric), + }), + be_str_weak(is_root_commissioning_open), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x20040202, // 0002 NE R1 R1 R2 + 0x78060003, // 0003 JMPF R1 #0008 + 0x88040101, // 0004 GETMBR R1 R0 K1 + 0x4C080000, // 0005 LDNIL R2 + 0x1C040202, // 0006 EQ R1 R1 R2 + 0x74060000, // 0007 JMPT R1 #0009 + 0x50040001, // 0008 LDBOOL R1 0 1 + 0x50040200, // 0009 LDBOOL R1 1 0 + 0x80040200, // 000A RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: msg_send +********************************************************************/ +be_local_closure(Matter_Device_msg_send, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(send_UDP), + }), + be_str_weak(msg_send), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: process_attribute_read_solo +********************************************************************/ +be_local_closure(Matter_Device_process_attribute_read_solo, /* name */ + be_nested_proto( + 10, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(endpoint), + /* K1 */ be_nested_str_weak(cluster), + /* K2 */ be_nested_str_weak(attribute), + /* K3 */ be_nested_str_weak(find_plugin_by_endpoint), + /* K4 */ be_nested_str_weak(status), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), + /* K7 */ be_nested_str_weak(contains_cluster), + /* K8 */ be_nested_str_weak(UNSUPPORTED_CLUSTER), + /* K9 */ be_nested_str_weak(contains_attribute), + /* K10 */ be_nested_str_weak(UNSUPPORTED_ATTRIBUTE), + }), + be_str_weak(process_attribute_read_solo), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0x88080300, // 0000 GETMBR R2 R1 K0 + 0x880C0301, // 0001 GETMBR R3 R1 K1 + 0x88100302, // 0002 GETMBR R4 R1 K2 + 0x4C140000, // 0003 LDNIL R5 + 0x1C140405, // 0004 EQ R5 R2 R5 + 0x74160005, // 0005 JMPT R5 #000C + 0x4C140000, // 0006 LDNIL R5 + 0x1C140605, // 0007 EQ R5 R3 R5 + 0x74160002, // 0008 JMPT R5 #000C + 0x4C140000, // 0009 LDNIL R5 + 0x1C140805, // 000A EQ R5 R4 R5 + 0x78160001, // 000B JMPF R5 #000E + 0x4C140000, // 000C LDNIL R5 + 0x80040A00, // 000D RET 1 R5 + 0x8C140103, // 000E GETMET R5 R0 K3 + 0x5C1C0400, // 000F MOVE R7 R2 + 0x7C140400, // 0010 CALL R5 2 + 0x4C180000, // 0011 LDNIL R6 + 0x1C180A06, // 0012 EQ R6 R5 R6 + 0x781A0004, // 0013 JMPF R6 #0019 + 0xB81A0A00, // 0014 GETNGBL R6 K5 + 0x88180D06, // 0015 GETMBR R6 R6 K6 + 0x90060806, // 0016 SETMBR R1 K4 R6 + 0x4C180000, // 0017 LDNIL R6 + 0x80040C00, // 0018 RET 1 R6 + 0x8C180B07, // 0019 GETMET R6 R5 K7 + 0x5C200600, // 001A MOVE R8 R3 + 0x7C180400, // 001B CALL R6 2 + 0x741A0004, // 001C JMPT R6 #0022 + 0xB81A0A00, // 001D GETNGBL R6 K5 + 0x88180D08, // 001E GETMBR R6 R6 K8 + 0x90060806, // 001F SETMBR R1 K4 R6 + 0x4C180000, // 0020 LDNIL R6 + 0x80040C00, // 0021 RET 1 R6 + 0x8C180B09, // 0022 GETMET R6 R5 K9 + 0x5C200600, // 0023 MOVE R8 R3 + 0x5C240800, // 0024 MOVE R9 R4 + 0x7C180600, // 0025 CALL R6 3 + 0x741A0004, // 0026 JMPT R6 #002C + 0xB81A0A00, // 0027 GETNGBL R6 K5 + 0x88180D0A, // 0028 GETMBR R6 R6 K10 + 0x90060806, // 0029 SETMBR R1 K4 R6 + 0x4C180000, // 002A LDNIL R6 + 0x80040C00, // 002B RET 1 R6 + 0x80040A00, // 002C RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: autoconf_device +********************************************************************/ +be_local_closure(Matter_Device_autoconf_device, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[16]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(plugins), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(plugins_persist), + /* K4 */ be_nested_str_weak(plugins_config), + /* K5 */ be_nested_str_weak(autoconf_device_map), + /* K6 */ be_nested_str_weak(plugins_config_remotes), + /* K7 */ be_nested_str_weak(adjust_next_ep), + /* K8 */ be_nested_str_weak(tasmota), + /* K9 */ be_nested_str_weak(log), + /* K10 */ be_nested_str_weak(MTR_X3A_X20autoconfig_X20_X3D_X20), + /* K11 */ be_const_int(3), + /* K12 */ be_nested_str_weak(_instantiate_plugins_from_config), + /* K13 */ be_nested_str_weak(sessions), + /* K14 */ be_nested_str_weak(count_active_fabrics), + /* K15 */ be_nested_str_weak(save_param), + }), + be_str_weak(autoconf_device), + &be_const_str_solidified, + ( &(const binstruction[40]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x6008000C, // 0001 GETGBL R2 G12 + 0x880C0101, // 0002 GETMBR R3 R0 K1 + 0x7C080200, // 0003 CALL R2 1 + 0x24080502, // 0004 GT R2 R2 K2 + 0x780A0000, // 0005 JMPF R2 #0007 + 0x80000400, // 0006 RET 0 + 0x88080103, // 0007 GETMBR R2 R0 K3 + 0x740A000F, // 0008 JMPT R2 #0019 + 0x8C080105, // 0009 GETMET R2 R0 K5 + 0x7C080200, // 000A CALL R2 1 + 0x90020802, // 000B SETMBR R0 K4 R2 + 0x60080013, // 000C GETGBL R2 G19 + 0x7C080000, // 000D CALL R2 0 + 0x90020C02, // 000E SETMBR R0 K6 R2 + 0x8C080107, // 000F GETMET R2 R0 K7 + 0x7C080200, // 0010 CALL R2 1 + 0xB80A1000, // 0011 GETNGBL R2 K8 + 0x8C080509, // 0012 GETMET R2 R2 K9 + 0x60100008, // 0013 GETGBL R4 G8 + 0x88140104, // 0014 GETMBR R5 R0 K4 + 0x7C100200, // 0015 CALL R4 1 + 0x00121404, // 0016 ADD R4 K10 R4 + 0x5814000B, // 0017 LDCONST R5 K11 + 0x7C080600, // 0018 CALL R2 3 + 0x8C08010C, // 0019 GETMET R2 R0 K12 + 0x88100104, // 001A GETMBR R4 R0 K4 + 0x7C080400, // 001B CALL R2 2 + 0x88080103, // 001C GETMBR R2 R0 K3 + 0x740A0008, // 001D JMPT R2 #0027 + 0x8808010D, // 001E GETMBR R2 R0 K13 + 0x8C08050E, // 001F GETMET R2 R2 K14 + 0x7C080200, // 0020 CALL R2 1 + 0x24080502, // 0021 GT R2 R2 K2 + 0x780A0003, // 0022 JMPF R2 #0027 + 0x50080200, // 0023 LDBOOL R2 1 0 + 0x90020602, // 0024 SETMBR R0 K3 R2 + 0x8C08010F, // 0025 GETMET R2 R0 K15 + 0x7C080200, // 0026 CALL R2 1 + 0x80000000, // 0027 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: register_http_remote +********************************************************************/ +be_local_closure(Matter_Device_register_http_remote, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(http_remotes), + /* K1 */ be_nested_str_weak(contains), + /* K2 */ be_nested_str_weak(get_timeout), + /* K3 */ be_nested_str_weak(set_timeout), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(HTTP_remote), + /* K6 */ be_nested_str_weak(plugins_config_remotes), + /* K7 */ be_nested_str_weak(set_info), + }), + be_str_weak(register_http_remote), + &be_const_str_solidified, + ( &(const binstruction[42]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x4C100000, // 0001 LDNIL R4 + 0x1C0C0604, // 0002 EQ R3 R3 R4 + 0x780E0002, // 0003 JMPF R3 #0007 + 0x600C0013, // 0004 GETGBL R3 G19 + 0x7C0C0000, // 0005 CALL R3 0 + 0x90020003, // 0006 SETMBR R0 K0 R3 + 0x4C0C0000, // 0007 LDNIL R3 + 0x88100100, // 0008 GETMBR R4 R0 K0 + 0x8C100901, // 0009 GETMET R4 R4 K1 + 0x5C180200, // 000A MOVE R6 R1 + 0x7C100400, // 000B CALL R4 2 + 0x78120009, // 000C JMPF R4 #0017 + 0x88100100, // 000D GETMBR R4 R0 K0 + 0x940C0801, // 000E GETIDX R3 R4 R1 + 0x8C140702, // 000F GETMET R5 R3 K2 + 0x7C140200, // 0010 CALL R5 1 + 0x14140405, // 0011 LT R5 R2 R5 + 0x78160002, // 0012 JMPF R5 #0016 + 0x8C140703, // 0013 GETMET R5 R3 K3 + 0x5C1C0400, // 0014 MOVE R7 R2 + 0x7C140400, // 0015 CALL R5 2 + 0x70020011, // 0016 JMP #0029 + 0xB8120800, // 0017 GETNGBL R4 K4 + 0x8C100905, // 0018 GETMET R4 R4 K5 + 0x5C180000, // 0019 MOVE R6 R0 + 0x5C1C0200, // 001A MOVE R7 R1 + 0x5C200400, // 001B MOVE R8 R2 + 0x7C100800, // 001C CALL R4 4 + 0x5C0C0800, // 001D MOVE R3 R4 + 0x88100106, // 001E GETMBR R4 R0 K6 + 0x8C100901, // 001F GETMET R4 R4 K1 + 0x5C180200, // 0020 MOVE R6 R1 + 0x7C100400, // 0021 CALL R4 2 + 0x78120003, // 0022 JMPF R4 #0027 + 0x8C100707, // 0023 GETMET R4 R3 K7 + 0x88180106, // 0024 GETMBR R6 R0 K6 + 0x94180C01, // 0025 GETIDX R6 R6 R1 + 0x7C100400, // 0026 CALL R4 2 + 0x88100100, // 0027 GETMBR R4 R0 K0 + 0x98100203, // 0028 SETIDX R4 R1 R3 + 0x80040600, // 0029 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: attribute_updated +********************************************************************/ +be_local_closure(Matter_Device_attribute_updated, /* name */ + be_nested_proto( + 10, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(Path), + /* K2 */ be_nested_str_weak(endpoint), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(attribute), + /* K5 */ be_nested_str_weak(message_handler), + /* K6 */ be_nested_str_weak(im), + /* K7 */ be_nested_str_weak(subs_shop), + /* K8 */ be_nested_str_weak(attribute_updated_ctx), + }), + be_str_weak(attribute_updated), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x1C140805, // 0001 EQ R5 R4 R5 + 0x78160000, // 0002 JMPF R5 #0004 + 0x50100000, // 0003 LDBOOL R4 0 0 + 0xB8160000, // 0004 GETNGBL R5 K0 + 0x8C140B01, // 0005 GETMET R5 R5 K1 + 0x7C140200, // 0006 CALL R5 1 + 0x90160401, // 0007 SETMBR R5 K2 R1 + 0x90160602, // 0008 SETMBR R5 K3 R2 + 0x90160803, // 0009 SETMBR R5 K4 R3 + 0x88180105, // 000A GETMBR R6 R0 K5 + 0x88180D06, // 000B GETMBR R6 R6 K6 + 0x88180D07, // 000C GETMBR R6 R6 K7 + 0x8C180D08, // 000D GETMET R6 R6 K8 + 0x5C200A00, // 000E MOVE R8 R5 + 0x5C240800, // 000F MOVE R9 R4 + 0x7C180600, // 0010 CALL R6 3 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: every_250ms ********************************************************************/ @@ -501,6 +1881,472 @@ be_local_closure(Matter_Device_every_250ms, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: get_active_endpoints +********************************************************************/ +be_local_closure(Matter_Device_get_active_endpoints, /* name */ + be_nested_proto( + 9, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(plugins), + /* K1 */ be_nested_str_weak(get_endpoint), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(find), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(get_active_endpoints), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0x60080012, // 0000 GETGBL R2 G18 + 0x7C080000, // 0001 CALL R2 0 + 0x600C0010, // 0002 GETGBL R3 G16 + 0x88100100, // 0003 GETMBR R4 R0 K0 + 0x7C0C0200, // 0004 CALL R3 1 + 0xA8020011, // 0005 EXBLK 0 #0018 + 0x5C100600, // 0006 MOVE R4 R3 + 0x7C100000, // 0007 CALL R4 0 + 0x8C140901, // 0008 GETMET R5 R4 K1 + 0x7C140200, // 0009 CALL R5 1 + 0x78060002, // 000A JMPF R1 #000E + 0x1C180B02, // 000B EQ R6 R5 K2 + 0x781A0000, // 000C JMPF R6 #000E + 0x7001FFF7, // 000D JMP #0006 + 0x8C180503, // 000E GETMET R6 R2 K3 + 0x5C200A00, // 000F MOVE R8 R5 + 0x7C180400, // 0010 CALL R6 2 + 0x4C1C0000, // 0011 LDNIL R7 + 0x1C180C07, // 0012 EQ R6 R6 R7 + 0x781A0002, // 0013 JMPF R6 #0017 + 0x8C180504, // 0014 GETMET R6 R2 K4 + 0x5C200A00, // 0015 MOVE R8 R5 + 0x7C180400, // 0016 CALL R6 2 + 0x7001FFED, // 0017 JMP #0006 + 0x580C0005, // 0018 LDCONST R3 K5 + 0xAC0C0200, // 0019 CATCH R3 1 0 + 0xB0080000, // 001A RAISE 2 R0 R0 + 0x80040400, // 001B RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _start_udp +********************************************************************/ +be_local_closure(Matter_Device__start_udp, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(msg_received), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x680C0000, // 0000 GETUPV R3 U0 + 0x8C0C0700, // 0001 GETMET R3 R3 K0 + 0x5C140000, // 0002 MOVE R5 R0 + 0x5C180200, // 0003 MOVE R6 R1 + 0x5C1C0400, // 0004 MOVE R7 R2 + 0x7C0C0800, // 0005 CALL R3 4 + 0x80040600, // 0006 RET 1 R3 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(log), + /* K3 */ be_nested_str_weak(MTR_X3A_X20Starting_X20UDP_X20server_X20on_X20port_X3A_X20), + /* K4 */ be_const_int(2), + /* K5 */ be_nested_str_weak(matter), + /* K6 */ be_nested_str_weak(UDPServer), + /* K7 */ be_nested_str_weak(), + /* K8 */ be_nested_str_weak(start), + }), + be_str_weak(_start_udp), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A0000, // 0001 JMPF R2 #0003 + 0x80000400, // 0002 RET 0 + 0x4C080000, // 0003 LDNIL R2 + 0x1C080202, // 0004 EQ R2 R1 R2 + 0x780A0000, // 0005 JMPF R2 #0007 + 0x540615A3, // 0006 LDINT R1 5540 + 0xB80A0200, // 0007 GETNGBL R2 K1 + 0x8C080502, // 0008 GETMET R2 R2 K2 + 0x60100008, // 0009 GETGBL R4 G8 + 0x5C140200, // 000A MOVE R5 R1 + 0x7C100200, // 000B CALL R4 1 + 0x00120604, // 000C ADD R4 K3 R4 + 0x58140004, // 000D LDCONST R5 K4 + 0x7C080600, // 000E CALL R2 3 + 0xB80A0A00, // 000F GETNGBL R2 K5 + 0x8C080506, // 0010 GETMET R2 R2 K6 + 0x5C100000, // 0011 MOVE R4 R0 + 0x58140007, // 0012 LDCONST R5 K7 + 0x5C180200, // 0013 MOVE R6 R1 + 0x7C080800, // 0014 CALL R2 4 + 0x90020002, // 0015 SETMBR R0 K0 R2 + 0x88080100, // 0016 GETMBR R2 R0 K0 + 0x8C080508, // 0017 GETMET R2 R2 K8 + 0x84100000, // 0018 CLOSURE R4 P0 + 0x7C080400, // 0019 CALL R2 2 + 0xA0000000, // 001A CLOSE R0 + 0x80000000, // 001B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_basic_commissioning +********************************************************************/ +be_local_closure(Matter_Device_start_basic_commissioning, /* name */ + be_nested_proto( + 13, /* nstack */ + 8, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns_announce_PASE), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(remove_rule), + /* K3 */ be_nested_str_weak(Wifi_X23Connected), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x7C000200, // 0002 CALL R0 1 + 0xB8020200, // 0003 GETNGBL R0 K1 + 0x8C000102, // 0004 GETMET R0 R0 K2 + 0x58080003, // 0005 LDCONST R2 K3 + 0x580C0000, // 0006 LDCONST R3 K0 + 0x7C000600, // 0007 CALL R0 3 + 0x80000000, // 0008 RET 0 + }) + ), + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns_announce_PASE), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(remove_rule), + /* K3 */ be_nested_str_weak(Eth_X23Connected), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x7C000200, // 0002 CALL R0 1 + 0xB8020200, // 0003 GETNGBL R0 K1 + 0x8C000102, // 0004 GETMET R0 R0 K2 + 0x58080003, // 0005 LDCONST R2 K3 + 0x580C0000, // 0006 LDCONST R3 K0 + 0x7C000600, // 0007 CALL R0 3 + 0x80000000, // 0008 RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[16]) { /* constants */ + /* K0 */ be_nested_str_weak(commissioning_open), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(millis), + /* K3 */ be_nested_str_weak(commissioning_iterations), + /* K4 */ be_nested_str_weak(commissioning_discriminator), + /* K5 */ be_nested_str_weak(commissioning_salt), + /* K6 */ be_nested_str_weak(commissioning_w0), + /* K7 */ be_nested_str_weak(commissioning_L), + /* K8 */ be_nested_str_weak(commissioning_admin_fabric), + /* K9 */ be_nested_str_weak(wifi), + /* K10 */ be_nested_str_weak(up), + /* K11 */ be_nested_str_weak(eth), + /* K12 */ be_nested_str_weak(mdns_announce_PASE), + /* K13 */ be_nested_str_weak(add_rule), + /* K14 */ be_nested_str_weak(Wifi_X23Connected), + /* K15 */ be_nested_str_weak(Eth_X23Connected), + }), + be_str_weak(start_basic_commissioning), + &be_const_str_solidified, + ( &(const binstruction[40]) { /* code */ + 0xB8220200, // 0000 GETNGBL R8 K1 + 0x8C201102, // 0001 GETMET R8 R8 K2 + 0x7C200200, // 0002 CALL R8 1 + 0x542603E7, // 0003 LDINT R9 1000 + 0x08240209, // 0004 MUL R9 R1 R9 + 0x00201009, // 0005 ADD R8 R8 R9 + 0x90020008, // 0006 SETMBR R0 K0 R8 + 0x90020602, // 0007 SETMBR R0 K3 R2 + 0x90020803, // 0008 SETMBR R0 K4 R3 + 0x90020A04, // 0009 SETMBR R0 K5 R4 + 0x90020C05, // 000A SETMBR R0 K6 R5 + 0x90020E06, // 000B SETMBR R0 K7 R6 + 0x90021007, // 000C SETMBR R0 K8 R7 + 0xB8220200, // 000D GETNGBL R8 K1 + 0x8C201109, // 000E GETMET R8 R8 K9 + 0x7C200200, // 000F CALL R8 1 + 0x9420110A, // 0010 GETIDX R8 R8 K10 + 0x74220004, // 0011 JMPT R8 #0017 + 0xB8220200, // 0012 GETNGBL R8 K1 + 0x8C20110B, // 0013 GETMET R8 R8 K11 + 0x7C200200, // 0014 CALL R8 1 + 0x9420110A, // 0015 GETIDX R8 R8 K10 + 0x78220002, // 0016 JMPF R8 #001A + 0x8C20010C, // 0017 GETMET R8 R0 K12 + 0x7C200200, // 0018 CALL R8 1 + 0x7002000B, // 0019 JMP #0026 + 0xB8220200, // 001A GETNGBL R8 K1 + 0x8C20110D, // 001B GETMET R8 R8 K13 + 0x5828000E, // 001C LDCONST R10 K14 + 0x842C0000, // 001D CLOSURE R11 P0 + 0x5830000C, // 001E LDCONST R12 K12 + 0x7C200800, // 001F CALL R8 4 + 0xB8220200, // 0020 GETNGBL R8 K1 + 0x8C20110D, // 0021 GETMET R8 R8 K13 + 0x5828000F, // 0022 LDCONST R10 K15 + 0x842C0001, // 0023 CLOSURE R11 P1 + 0x5830000C, // 0024 LDCONST R12 K12 + 0x7C200800, // 0025 CALL R8 4 + 0xA0000000, // 0026 CLOSE R0 + 0x80000000, // 0027 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: bridge_remove_endpoint +********************************************************************/ +be_local_closure(Matter_Device_bridge_remove_endpoint, /* name */ + be_nested_proto( + 11, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(plugins_config), + /* K2 */ be_nested_str_weak(contains), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(log), + /* K5 */ be_nested_str_weak(MTR_X3A_X20Cannot_X20remove_X20an_X20enpoint_X20not_X20configured_X3A_X20), + /* K6 */ be_const_int(3), + /* K7 */ be_nested_str_weak(MTR_X3A_X20deleting_X20endpoint_X20_X3D_X20_X25i), + /* K8 */ be_const_int(2), + /* K9 */ be_nested_str_weak(remove), + /* K10 */ be_nested_str_weak(plugins_persist), + /* K11 */ be_const_int(0), + /* K12 */ be_nested_str_weak(plugins), + /* K13 */ be_nested_str_weak(get_endpoint), + /* K14 */ be_const_int(1), + /* K15 */ be_nested_str_weak(clean_remotes), + /* K16 */ be_nested_str_weak(save_param), + /* K17 */ be_nested_str_weak(signal_endpoints_changed), + }), + be_str_weak(bridge_remove_endpoint), + &be_const_str_solidified, + ( &(const binstruction[58]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x600C0008, // 0001 GETGBL R3 G8 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C0C0200, // 0003 CALL R3 1 + 0x4C100000, // 0004 LDNIL R4 + 0x4C140000, // 0005 LDNIL R5 + 0x88180101, // 0006 GETMBR R6 R0 K1 + 0x8C180D02, // 0007 GETMET R6 R6 K2 + 0x5C200600, // 0008 MOVE R8 R3 + 0x7C180400, // 0009 CALL R6 2 + 0x741A0005, // 000A JMPT R6 #0011 + 0xB81A0600, // 000B GETNGBL R6 K3 + 0x8C180D04, // 000C GETMET R6 R6 K4 + 0x00220A03, // 000D ADD R8 K5 R3 + 0x58240006, // 000E LDCONST R9 K6 + 0x7C180600, // 000F CALL R6 3 + 0x80000C00, // 0010 RET 0 + 0xB81A0600, // 0011 GETNGBL R6 K3 + 0x8C180D04, // 0012 GETMET R6 R6 K4 + 0x60200018, // 0013 GETGBL R8 G24 + 0x58240007, // 0014 LDCONST R9 K7 + 0x5C280200, // 0015 MOVE R10 R1 + 0x7C200400, // 0016 CALL R8 2 + 0x58240008, // 0017 LDCONST R9 K8 + 0x7C180600, // 0018 CALL R6 3 + 0x88180101, // 0019 GETMBR R6 R0 K1 + 0x8C180D09, // 001A GETMET R6 R6 K9 + 0x5C200600, // 001B MOVE R8 R3 + 0x7C180400, // 001C CALL R6 2 + 0x50180200, // 001D LDBOOL R6 1 0 + 0x90021406, // 001E SETMBR R0 K10 R6 + 0x5818000B, // 001F LDCONST R6 K11 + 0x601C000C, // 0020 GETGBL R7 G12 + 0x8820010C, // 0021 GETMBR R8 R0 K12 + 0x7C1C0200, // 0022 CALL R7 1 + 0x141C0C07, // 0023 LT R7 R6 R7 + 0x781E000D, // 0024 JMPF R7 #0033 + 0x881C010C, // 0025 GETMBR R7 R0 K12 + 0x941C0E06, // 0026 GETIDX R7 R7 R6 + 0x8C1C0F0D, // 0027 GETMET R7 R7 K13 + 0x7C1C0200, // 0028 CALL R7 1 + 0x1C1C0207, // 0029 EQ R7 R1 R7 + 0x781E0005, // 002A JMPF R7 #0031 + 0x881C010C, // 002B GETMBR R7 R0 K12 + 0x8C1C0F09, // 002C GETMET R7 R7 K9 + 0x5C240C00, // 002D MOVE R9 R6 + 0x7C1C0400, // 002E CALL R7 2 + 0x70020002, // 002F JMP #0033 + 0x70020000, // 0030 JMP #0032 + 0x00180D0E, // 0031 ADD R6 R6 K14 + 0x7001FFEC, // 0032 JMP #0020 + 0x8C1C010F, // 0033 GETMET R7 R0 K15 + 0x7C1C0200, // 0034 CALL R7 1 + 0x8C1C0110, // 0035 GETMET R7 R0 K16 + 0x7C1C0200, // 0036 CALL R7 1 + 0x8C1C0111, // 0037 GETMET R7 R0 K17 + 0x7C1C0200, // 0038 CALL R7 1 + 0x80000000, // 0039 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start +********************************************************************/ +be_local_closure(Matter_Device_start, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 2, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(_trigger_read_sensors), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x7C000200, // 0002 CALL R0 1 + 0x80000000, // 0003 RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(started), + /* K1 */ be_nested_str_weak(autoconf_device), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(add_cron), + /* K4 */ be_nested_str_weak(_X2A_X2F30_X20_X2A_X20_X2A_X20_X2A_X20_X2A_X20_X2A), + /* K5 */ be_nested_str_weak(matter_sensors_30s), + /* K6 */ be_nested_str_weak(_start_udp), + /* K7 */ be_nested_str_weak(UDP_PORT), + /* K8 */ be_nested_str_weak(start_mdns_announce_hostnames), + }), + be_str_weak(start), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060000, // 0001 JMPF R1 #0003 + 0x80000200, // 0002 RET 0 + 0x8C040101, // 0003 GETMET R1 R0 K1 + 0x7C040200, // 0004 CALL R1 1 + 0xB8060400, // 0005 GETNGBL R1 K2 + 0x8C040303, // 0006 GETMET R1 R1 K3 + 0x580C0004, // 0007 LDCONST R3 K4 + 0x84100000, // 0008 CLOSURE R4 P0 + 0x58140005, // 0009 LDCONST R5 K5 + 0x7C040800, // 000A CALL R1 4 + 0x8C040106, // 000B GETMET R1 R0 K6 + 0x880C0107, // 000C GETMBR R3 R0 K7 + 0x7C040400, // 000D CALL R1 2 + 0x8C040108, // 000E GETMET R1 R0 K8 + 0x7C040200, // 000F CALL R1 1 + 0x50040200, // 0010 LDBOOL R1 1 0 + 0x90020001, // 0011 SETMBR R0 K0 R1 + 0xA0000000, // 0012 CLOSE R0 + 0x80000000, // 0013 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: stop_basic_commissioning ********************************************************************/ @@ -564,58 +2410,246 @@ be_local_closure(Matter_Device_stop_basic_commissioning, /* name */ /******************************************************************** -** Solidified function: start_commissioning_complete +** Solidified function: init ********************************************************************/ -be_local_closure(Matter_Device_start_commissioning_complete, /* name */ +be_local_closure(Matter_Device_init, /* name */ be_nested_proto( - 11, /* nstack */ - 2, /* argc */ + 7, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_nested_str_weak(get_fabric), - /* K1 */ be_nested_str_weak(get_fabric_id), - /* K2 */ be_nested_str_weak(copy), - /* K3 */ be_nested_str_weak(reverse), - /* K4 */ be_nested_str_weak(tohex), - /* K5 */ be_nested_str_weak(get_admin_vendor_name), - /* K6 */ be_nested_str_weak(tasmota), - /* K7 */ be_nested_str_weak(log), - /* K8 */ be_nested_str_weak(MTR_X3A_X20_X2D_X2D_X2D_X20Commissioning_X20complete_X20for_X20Fabric_X20_X27_X25s_X27_X20_X28Vendor_X20_X25s_X29_X20_X2D_X2D_X2D), - /* K9 */ be_const_int(2), - /* K10 */ be_nested_str_weak(stop_basic_commissioning), + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(start), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(remove_rule), + /* K3 */ be_nested_str_weak(Wifi_X23Connected), + /* K4 */ be_nested_str_weak(matter_start), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x7C000200, // 0002 CALL R0 1 + 0xB8020200, // 0003 GETNGBL R0 K1 + 0x8C000102, // 0004 GETMET R0 R0 K2 + 0x58080003, // 0005 LDCONST R2 K3 + 0x580C0004, // 0006 LDCONST R3 K4 + 0x7C000600, // 0007 CALL R0 3 + 0x80000000, // 0008 RET 0 + }) + ), + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(start), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(remove_rule), + /* K3 */ be_nested_str_weak(Eth_X23Connected), + /* K4 */ be_nested_str_weak(matter_start), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x7C000200, // 0002 CALL R0 1 + 0xB8020200, // 0003 GETNGBL R0 K1 + 0x8C000102, // 0004 GETMET R0 R0 K2 + 0x58080003, // 0005 LDCONST R2 K3 + 0x580C0004, // 0006 LDCONST R3 K4 + 0x7C000600, // 0007 CALL R0 3 + 0x80000000, // 0008 RET 0 + }) + ), }), - be_str_weak(start_commissioning_complete), + 1, /* has constants */ + ( &(const bvalue[46]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(get_option), + /* K3 */ be_nested_str_weak(matter), + /* K4 */ be_nested_str_weak(MATTER_OPTION), + /* K5 */ be_nested_str_weak(UI), + /* K6 */ be_nested_str_weak(profiler), + /* K7 */ be_nested_str_weak(Profiler), + /* K8 */ be_nested_str_weak(started), + /* K9 */ be_nested_str_weak(tick), + /* K10 */ be_const_int(0), + /* K11 */ be_nested_str_weak(plugins), + /* K12 */ be_nested_str_weak(plugins_persist), + /* K13 */ be_nested_str_weak(plugins_classes), + /* K14 */ be_nested_str_weak(plugins_config_remotes), + /* K15 */ be_nested_str_weak(register_native_classes), + /* K16 */ be_nested_str_weak(vendorid), + /* K17 */ be_nested_str_weak(VENDOR_ID), + /* K18 */ be_nested_str_weak(productid), + /* K19 */ be_nested_str_weak(PRODUCT_ID), + /* K20 */ be_nested_str_weak(root_iterations), + /* K21 */ be_nested_str_weak(PBKDF_ITERATIONS), + /* K22 */ be_nested_str_weak(next_ep), + /* K23 */ be_const_int(1), + /* K24 */ be_nested_str_weak(root_salt), + /* K25 */ be_nested_str_weak(random), + /* K26 */ be_nested_str_weak(ipv4only), + /* K27 */ be_nested_str_weak(disable_bridge_mode), + /* K28 */ be_nested_str_weak(load_param), + /* K29 */ be_nested_str_weak(sessions), + /* K30 */ be_nested_str_weak(Session_Store), + /* K31 */ be_nested_str_weak(load_fabrics), + /* K32 */ be_nested_str_weak(message_handler), + /* K33 */ be_nested_str_weak(MessageHandler), + /* K34 */ be_nested_str_weak(ui), + /* K35 */ be_nested_str_weak(wifi), + /* K36 */ be_nested_str_weak(up), + /* K37 */ be_nested_str_weak(eth), + /* K38 */ be_nested_str_weak(start), + /* K39 */ be_nested_str_weak(add_rule), + /* K40 */ be_nested_str_weak(Wifi_X23Connected), + /* K41 */ be_nested_str_weak(matter_start), + /* K42 */ be_nested_str_weak(Eth_X23Connected), + /* K43 */ be_nested_str_weak(_init_basic_commissioning), + /* K44 */ be_nested_str_weak(add_driver), + /* K45 */ be_nested_str_weak(register_commands), + }), + be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[24]) { /* code */ - 0x8C080300, // 0000 GETMET R2 R1 K0 - 0x7C080200, // 0001 CALL R2 1 - 0x8C0C0501, // 0002 GETMET R3 R2 K1 - 0x7C0C0200, // 0003 CALL R3 1 - 0x8C0C0702, // 0004 GETMET R3 R3 K2 - 0x7C0C0200, // 0005 CALL R3 1 - 0x8C0C0703, // 0006 GETMET R3 R3 K3 - 0x7C0C0200, // 0007 CALL R3 1 - 0x8C0C0704, // 0008 GETMET R3 R3 K4 - 0x7C0C0200, // 0009 CALL R3 1 - 0x8C100505, // 000A GETMET R4 R2 K5 - 0x7C100200, // 000B CALL R4 1 - 0xB8160C00, // 000C GETNGBL R5 K6 - 0x8C140B07, // 000D GETMET R5 R5 K7 - 0x601C0018, // 000E GETGBL R7 G24 - 0x58200008, // 000F LDCONST R8 K8 - 0x5C240600, // 0010 MOVE R9 R3 - 0x5C280800, // 0011 MOVE R10 R4 - 0x7C1C0600, // 0012 CALL R7 3 - 0x58200009, // 0013 LDCONST R8 K9 - 0x7C140600, // 0014 CALL R5 3 - 0x8C14010A, // 0015 GETMET R5 R0 K10 - 0x7C140200, // 0016 CALL R5 1 - 0x80000000, // 0017 RET 0 + ( &(const binstruction[112]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xB80A0200, // 0001 GETNGBL R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0xB8120600, // 0003 GETNGBL R4 K3 + 0x88100904, // 0004 GETMBR R4 R4 K4 + 0x7C080400, // 0005 CALL R2 2 + 0x740A0004, // 0006 JMPT R2 #000C + 0xB80A0600, // 0007 GETNGBL R2 K3 + 0x8C080505, // 0008 GETMET R2 R2 K5 + 0x5C100000, // 0009 MOVE R4 R0 + 0x7C080400, // 000A CALL R2 2 + 0x80000400, // 000B RET 0 + 0xB80A0600, // 000C GETNGBL R2 K3 + 0xB80E0600, // 000D GETNGBL R3 K3 + 0x8C0C0707, // 000E GETMET R3 R3 K7 + 0x7C0C0200, // 000F CALL R3 1 + 0x900A0C03, // 0010 SETMBR R2 K6 R3 + 0x50080000, // 0011 LDBOOL R2 0 0 + 0x90021002, // 0012 SETMBR R0 K8 R2 + 0x9002130A, // 0013 SETMBR R0 K9 K10 + 0x60080012, // 0014 GETGBL R2 G18 + 0x7C080000, // 0015 CALL R2 0 + 0x90021602, // 0016 SETMBR R0 K11 R2 + 0x50080000, // 0017 LDBOOL R2 0 0 + 0x90021802, // 0018 SETMBR R0 K12 R2 + 0x60080013, // 0019 GETGBL R2 G19 + 0x7C080000, // 001A CALL R2 0 + 0x90021A02, // 001B SETMBR R0 K13 R2 + 0x60080013, // 001C GETGBL R2 G19 + 0x7C080000, // 001D CALL R2 0 + 0x90021C02, // 001E SETMBR R0 K14 R2 + 0x8C08010F, // 001F GETMET R2 R0 K15 + 0x7C080200, // 0020 CALL R2 1 + 0x88080111, // 0021 GETMBR R2 R0 K17 + 0x90022002, // 0022 SETMBR R0 K16 R2 + 0x88080113, // 0023 GETMBR R2 R0 K19 + 0x90022402, // 0024 SETMBR R0 K18 R2 + 0x88080115, // 0025 GETMBR R2 R0 K21 + 0x90022802, // 0026 SETMBR R0 K20 R2 + 0x90022D17, // 0027 SETMBR R0 K22 K23 + 0x8C080319, // 0028 GETMET R2 R1 K25 + 0x5412000F, // 0029 LDINT R4 16 + 0x7C080400, // 002A CALL R2 2 + 0x90023002, // 002B SETMBR R0 K24 R2 + 0x50080000, // 002C LDBOOL R2 0 0 + 0x90023402, // 002D SETMBR R0 K26 R2 + 0x50080000, // 002E LDBOOL R2 0 0 + 0x90023602, // 002F SETMBR R0 K27 R2 + 0x8C08011C, // 0030 GETMET R2 R0 K28 + 0x7C080200, // 0031 CALL R2 1 + 0xB80A0600, // 0032 GETNGBL R2 K3 + 0x8C08051E, // 0033 GETMET R2 R2 K30 + 0x5C100000, // 0034 MOVE R4 R0 + 0x7C080400, // 0035 CALL R2 2 + 0x90023A02, // 0036 SETMBR R0 K29 R2 + 0x8808011D, // 0037 GETMBR R2 R0 K29 + 0x8C08051F, // 0038 GETMET R2 R2 K31 + 0x7C080200, // 0039 CALL R2 1 + 0xB80A0600, // 003A GETNGBL R2 K3 + 0x8C080521, // 003B GETMET R2 R2 K33 + 0x5C100000, // 003C MOVE R4 R0 + 0x7C080400, // 003D CALL R2 2 + 0x90024002, // 003E SETMBR R0 K32 R2 + 0xB80A0600, // 003F GETNGBL R2 K3 + 0x8C080505, // 0040 GETMET R2 R2 K5 + 0x5C100000, // 0041 MOVE R4 R0 + 0x7C080400, // 0042 CALL R2 2 + 0x90024402, // 0043 SETMBR R0 K34 R2 + 0xB80A0200, // 0044 GETNGBL R2 K1 + 0x8C080523, // 0045 GETMET R2 R2 K35 + 0x7C080200, // 0046 CALL R2 1 + 0x94080524, // 0047 GETIDX R2 R2 K36 + 0x740A0004, // 0048 JMPT R2 #004E + 0xB80A0200, // 0049 GETNGBL R2 K1 + 0x8C080525, // 004A GETMET R2 R2 K37 + 0x7C080200, // 004B CALL R2 1 + 0x94080524, // 004C GETIDX R2 R2 K36 + 0x780A0001, // 004D JMPF R2 #0050 + 0x8C080126, // 004E GETMET R2 R0 K38 + 0x7C080200, // 004F CALL R2 1 + 0xB80A0200, // 0050 GETNGBL R2 K1 + 0x8C080523, // 0051 GETMET R2 R2 K35 + 0x7C080200, // 0052 CALL R2 1 + 0x94080524, // 0053 GETIDX R2 R2 K36 + 0x740A0005, // 0054 JMPT R2 #005B + 0xB80A0200, // 0055 GETNGBL R2 K1 + 0x8C080527, // 0056 GETMET R2 R2 K39 + 0x58100028, // 0057 LDCONST R4 K40 + 0x84140000, // 0058 CLOSURE R5 P0 + 0x58180029, // 0059 LDCONST R6 K41 + 0x7C080800, // 005A CALL R2 4 + 0xB80A0200, // 005B GETNGBL R2 K1 + 0x8C080525, // 005C GETMET R2 R2 K37 + 0x7C080200, // 005D CALL R2 1 + 0x94080524, // 005E GETIDX R2 R2 K36 + 0x740A0005, // 005F JMPT R2 #0066 + 0xB80A0200, // 0060 GETNGBL R2 K1 + 0x8C080527, // 0061 GETMET R2 R2 K39 + 0x5810002A, // 0062 LDCONST R4 K42 + 0x84140001, // 0063 CLOSURE R5 P1 + 0x58180029, // 0064 LDCONST R6 K41 + 0x7C080800, // 0065 CALL R2 4 + 0x8C08012B, // 0066 GETMET R2 R0 K43 + 0x7C080200, // 0067 CALL R2 1 + 0xB80A0200, // 0068 GETNGBL R2 K1 + 0x8C08052C, // 0069 GETMET R2 R2 K44 + 0x5C100000, // 006A MOVE R4 R0 + 0x7C080400, // 006B CALL R2 2 + 0x8C08012D, // 006C GETMET R2 R0 K45 + 0x7C080200, // 006D CALL R2 1 + 0xA0000000, // 006E CLOSE R0 + 0x80000000, // 006F RET 0 }) ) ); @@ -623,12 +2657,103 @@ be_local_closure(Matter_Device_start_commissioning_complete, /* name */ /******************************************************************** -** Solidified function: get_plugin_remote_info +** Solidified function: adjust_next_ep ********************************************************************/ -be_local_closure(Matter_Device_get_plugin_remote_info, /* name */ +be_local_closure(Matter_Device_adjust_next_ep, /* name */ be_nested_proto( - 6, /* nstack */ - 2, /* argc */ + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(plugins_config), + /* K1 */ be_nested_str_weak(keys), + /* K2 */ be_nested_str_weak(next_ep), + /* K3 */ be_const_int(1), + /* K4 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(adjust_next_ep), + &be_const_str_solidified, + ( &(const binstruction[21]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x8C080501, // 0002 GETMET R2 R2 K1 + 0x7C080200, // 0003 CALL R2 1 + 0x7C040200, // 0004 CALL R1 1 + 0xA802000A, // 0005 EXBLK 0 #0011 + 0x5C080200, // 0006 MOVE R2 R1 + 0x7C080000, // 0007 CALL R2 0 + 0x600C0009, // 0008 GETGBL R3 G9 + 0x5C100400, // 0009 MOVE R4 R2 + 0x7C0C0200, // 000A CALL R3 1 + 0x88100102, // 000B GETMBR R4 R0 K2 + 0x28100604, // 000C GE R4 R3 R4 + 0x78120001, // 000D JMPF R4 #0010 + 0x00100703, // 000E ADD R4 R3 K3 + 0x90020404, // 000F SETMBR R0 K2 R4 + 0x7001FFF4, // 0010 JMP #0006 + 0x58040004, // 0011 LDCONST R1 K4 + 0xAC040200, // 0012 CATCH R1 1 0 + 0xB0080000, // 0013 RAISE 2 R0 R0 + 0x80000000, // 0014 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: MtrJoin +********************************************************************/ +be_local_closure(Matter_Device_MtrJoin, /* name */ + be_nested_proto( + 8, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(start_root_basic_commissioning), + /* K1 */ be_nested_str_weak(stop_basic_commissioning), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(resp_cmnd_done), + }), + be_str_weak(MtrJoin), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x60140009, // 0000 GETGBL R5 G9 + 0x5C180600, // 0001 MOVE R6 R3 + 0x7C140200, // 0002 CALL R5 1 + 0x78160002, // 0003 JMPF R5 #0007 + 0x8C180100, // 0004 GETMET R6 R0 K0 + 0x7C180200, // 0005 CALL R6 1 + 0x70020001, // 0006 JMP #0009 + 0x8C180101, // 0007 GETMET R6 R0 K1 + 0x7C180200, // 0008 CALL R6 1 + 0xB81A0400, // 0009 GETNGBL R6 K2 + 0x8C180D03, // 000A GETMET R6 R6 K3 + 0x7C180200, // 000B CALL R6 1 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_50ms +********************************************************************/ +be_local_closure(Matter_Device_every_50ms, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -636,19 +2761,16 @@ be_local_closure(Matter_Device_get_plugin_remote_info, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(plugins_config_remotes), - /* K1 */ be_nested_str_weak(find), + /* K0 */ be_nested_str_weak(tick), + /* K1 */ be_const_int(1), }), - be_str_weak(get_plugin_remote_info), + be_str_weak(every_50ms), &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 - 0x60140013, // 0003 GETGBL R5 G19 - 0x7C140000, // 0004 CALL R5 0 - 0x7C080600, // 0005 CALL R2 3 - 0x80040400, // 0006 RET 1 R2 + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x00040301, // 0001 ADD R1 R1 K1 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x80000000, // 0003 RET 0 }) ) ); @@ -656,11 +2778,254 @@ be_local_closure(Matter_Device_get_plugin_remote_info, /* name */ /******************************************************************** -** Solidified function: invoke_request +** Solidified function: k2l_num ********************************************************************/ -be_local_closure(Matter_Device_invoke_request, /* name */ +be_local_closure(Matter_Device_k2l_num, /* name */ be_nested_proto( - 12, /* nstack */ + 9, /* nstack */ + 1, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Device), + /* K1 */ be_nested_str_weak(keys), + /* K2 */ be_nested_str_weak(push), + /* K3 */ be_nested_str_weak(stop_iteration), + /* K4 */ be_const_int(1), + /* K5 */ be_const_int(0), + }), + be_str_weak(k2l_num), + &be_const_str_solidified, + ( &(const binstruction[52]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x60080012, // 0001 GETGBL R2 G18 + 0x7C080000, // 0002 CALL R2 0 + 0x4C0C0000, // 0003 LDNIL R3 + 0x1C0C0003, // 0004 EQ R3 R0 R3 + 0x780E0000, // 0005 JMPF R3 #0007 + 0x80040400, // 0006 RET 1 R2 + 0x600C0010, // 0007 GETGBL R3 G16 + 0x8C100101, // 0008 GETMET R4 R0 K1 + 0x7C100200, // 0009 CALL R4 1 + 0x7C0C0200, // 000A CALL R3 1 + 0xA8020007, // 000B EXBLK 0 #0014 + 0x5C100600, // 000C MOVE R4 R3 + 0x7C100000, // 000D CALL R4 0 + 0x8C140502, // 000E GETMET R5 R2 K2 + 0x601C0009, // 000F GETGBL R7 G9 + 0x5C200800, // 0010 MOVE R8 R4 + 0x7C1C0200, // 0011 CALL R7 1 + 0x7C140400, // 0012 CALL R5 2 + 0x7001FFF7, // 0013 JMP #000C + 0x580C0003, // 0014 LDCONST R3 K3 + 0xAC0C0200, // 0015 CATCH R3 1 0 + 0xB0080000, // 0016 RAISE 2 R0 R0 + 0x600C0010, // 0017 GETGBL R3 G16 + 0x6010000C, // 0018 GETGBL R4 G12 + 0x5C140400, // 0019 MOVE R5 R2 + 0x7C100200, // 001A CALL R4 1 + 0x04100904, // 001B SUB R4 R4 K4 + 0x40120804, // 001C CONNECT R4 K4 R4 + 0x7C0C0200, // 001D CALL R3 1 + 0xA8020010, // 001E EXBLK 0 #0030 + 0x5C100600, // 001F MOVE R4 R3 + 0x7C100000, // 0020 CALL R4 0 + 0x94140404, // 0021 GETIDX R5 R2 R4 + 0x5C180800, // 0022 MOVE R6 R4 + 0x241C0D05, // 0023 GT R7 R6 K5 + 0x781E0008, // 0024 JMPF R7 #002E + 0x041C0D04, // 0025 SUB R7 R6 K4 + 0x941C0407, // 0026 GETIDX R7 R2 R7 + 0x241C0E05, // 0027 GT R7 R7 R5 + 0x781E0004, // 0028 JMPF R7 #002E + 0x041C0D04, // 0029 SUB R7 R6 K4 + 0x941C0407, // 002A GETIDX R7 R2 R7 + 0x98080C07, // 002B SETIDX R2 R6 R7 + 0x04180D04, // 002C SUB R6 R6 K4 + 0x7001FFF4, // 002D JMP #0023 + 0x98080C05, // 002E SETIDX R2 R6 R5 + 0x7001FFEE, // 002F JMP #001F + 0x580C0003, // 0030 LDCONST R3 K3 + 0xAC0C0200, // 0031 CATCH R3 1 0 + 0xB0080000, // 0032 RAISE 2 R0 R0 + 0x80040400, // 0033 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: autoconf_sensors_list +********************************************************************/ +be_local_closure(Matter_Device_autoconf_sensors_list, /* name */ + be_nested_proto( + 10, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_nested_str_weak(k2l), + /* K1 */ be_nested_str_weak(contains), + /* K2 */ be_nested_str_weak(Temperature), + /* K3 */ be_nested_str_weak(_X23Temperature), + /* K4 */ be_nested_str_weak(push), + /* K5 */ be_nested_str_weak(type), + /* K6 */ be_nested_str_weak(temperature), + /* K7 */ be_nested_str_weak(filter), + /* K8 */ be_nested_str_weak(stop_iteration), + /* K9 */ be_nested_str_weak(Pressure), + /* K10 */ be_nested_str_weak(_X23Pressure), + /* K11 */ be_nested_str_weak(pressure), + /* K12 */ be_nested_str_weak(Illuminance), + /* K13 */ be_nested_str_weak(_X23Illuminance), + /* K14 */ be_nested_str_weak(illuminance), + /* K15 */ be_nested_str_weak(Humidity), + /* K16 */ be_nested_str_weak(_X23Humidity), + /* K17 */ be_nested_str_weak(humidity), + }), + be_str_weak(autoconf_sensors_list), + &be_const_str_solidified, + ( &(const binstruction[119]) { /* code */ + 0x60080012, // 0000 GETGBL R2 G18 + 0x7C080000, // 0001 CALL R2 0 + 0x600C0010, // 0002 GETGBL R3 G16 + 0x8C100100, // 0003 GETMET R4 R0 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x7C100400, // 0005 CALL R4 2 + 0x7C0C0200, // 0006 CALL R3 1 + 0xA8020013, // 0007 EXBLK 0 #001C + 0x5C100600, // 0008 MOVE R4 R3 + 0x7C100000, // 0009 CALL R4 0 + 0x94140204, // 000A GETIDX R5 R1 R4 + 0x6018000F, // 000B GETGBL R6 G15 + 0x5C1C0A00, // 000C MOVE R7 R5 + 0x60200013, // 000D GETGBL R8 G19 + 0x7C180400, // 000E CALL R6 2 + 0x781A000A, // 000F JMPF R6 #001B + 0x8C180B01, // 0010 GETMET R6 R5 K1 + 0x58200002, // 0011 LDCONST R8 K2 + 0x7C180400, // 0012 CALL R6 2 + 0x781A0006, // 0013 JMPF R6 #001B + 0x00180903, // 0014 ADD R6 R4 K3 + 0x8C1C0504, // 0015 GETMET R7 R2 K4 + 0x60240013, // 0016 GETGBL R9 G19 + 0x7C240000, // 0017 CALL R9 0 + 0x98260B06, // 0018 SETIDX R9 K5 K6 + 0x98260E06, // 0019 SETIDX R9 K7 R6 + 0x7C1C0400, // 001A CALL R7 2 + 0x7001FFEB, // 001B JMP #0008 + 0x580C0008, // 001C LDCONST R3 K8 + 0xAC0C0200, // 001D CATCH R3 1 0 + 0xB0080000, // 001E RAISE 2 R0 R0 + 0x600C0010, // 001F GETGBL R3 G16 + 0x8C100100, // 0020 GETMET R4 R0 K0 + 0x5C180200, // 0021 MOVE R6 R1 + 0x7C100400, // 0022 CALL R4 2 + 0x7C0C0200, // 0023 CALL R3 1 + 0xA8020013, // 0024 EXBLK 0 #0039 + 0x5C100600, // 0025 MOVE R4 R3 + 0x7C100000, // 0026 CALL R4 0 + 0x94140204, // 0027 GETIDX R5 R1 R4 + 0x6018000F, // 0028 GETGBL R6 G15 + 0x5C1C0A00, // 0029 MOVE R7 R5 + 0x60200013, // 002A GETGBL R8 G19 + 0x7C180400, // 002B CALL R6 2 + 0x781A000A, // 002C JMPF R6 #0038 + 0x8C180B01, // 002D GETMET R6 R5 K1 + 0x58200009, // 002E LDCONST R8 K9 + 0x7C180400, // 002F CALL R6 2 + 0x781A0006, // 0030 JMPF R6 #0038 + 0x0018090A, // 0031 ADD R6 R4 K10 + 0x8C1C0504, // 0032 GETMET R7 R2 K4 + 0x60240013, // 0033 GETGBL R9 G19 + 0x7C240000, // 0034 CALL R9 0 + 0x98260B0B, // 0035 SETIDX R9 K5 K11 + 0x98260E06, // 0036 SETIDX R9 K7 R6 + 0x7C1C0400, // 0037 CALL R7 2 + 0x7001FFEB, // 0038 JMP #0025 + 0x580C0008, // 0039 LDCONST R3 K8 + 0xAC0C0200, // 003A CATCH R3 1 0 + 0xB0080000, // 003B RAISE 2 R0 R0 + 0x600C0010, // 003C GETGBL R3 G16 + 0x8C100100, // 003D GETMET R4 R0 K0 + 0x5C180200, // 003E MOVE R6 R1 + 0x7C100400, // 003F CALL R4 2 + 0x7C0C0200, // 0040 CALL R3 1 + 0xA8020013, // 0041 EXBLK 0 #0056 + 0x5C100600, // 0042 MOVE R4 R3 + 0x7C100000, // 0043 CALL R4 0 + 0x94140204, // 0044 GETIDX R5 R1 R4 + 0x6018000F, // 0045 GETGBL R6 G15 + 0x5C1C0A00, // 0046 MOVE R7 R5 + 0x60200013, // 0047 GETGBL R8 G19 + 0x7C180400, // 0048 CALL R6 2 + 0x781A000A, // 0049 JMPF R6 #0055 + 0x8C180B01, // 004A GETMET R6 R5 K1 + 0x5820000C, // 004B LDCONST R8 K12 + 0x7C180400, // 004C CALL R6 2 + 0x781A0006, // 004D JMPF R6 #0055 + 0x0018090D, // 004E ADD R6 R4 K13 + 0x8C1C0504, // 004F GETMET R7 R2 K4 + 0x60240013, // 0050 GETGBL R9 G19 + 0x7C240000, // 0051 CALL R9 0 + 0x98260B0E, // 0052 SETIDX R9 K5 K14 + 0x98260E06, // 0053 SETIDX R9 K7 R6 + 0x7C1C0400, // 0054 CALL R7 2 + 0x7001FFEB, // 0055 JMP #0042 + 0x580C0008, // 0056 LDCONST R3 K8 + 0xAC0C0200, // 0057 CATCH R3 1 0 + 0xB0080000, // 0058 RAISE 2 R0 R0 + 0x600C0010, // 0059 GETGBL R3 G16 + 0x8C100100, // 005A GETMET R4 R0 K0 + 0x5C180200, // 005B MOVE R6 R1 + 0x7C100400, // 005C CALL R4 2 + 0x7C0C0200, // 005D CALL R3 1 + 0xA8020013, // 005E EXBLK 0 #0073 + 0x5C100600, // 005F MOVE R4 R3 + 0x7C100000, // 0060 CALL R4 0 + 0x94140204, // 0061 GETIDX R5 R1 R4 + 0x6018000F, // 0062 GETGBL R6 G15 + 0x5C1C0A00, // 0063 MOVE R7 R5 + 0x60200013, // 0064 GETGBL R8 G19 + 0x7C180400, // 0065 CALL R6 2 + 0x781A000A, // 0066 JMPF R6 #0072 + 0x8C180B01, // 0067 GETMET R6 R5 K1 + 0x5820000F, // 0068 LDCONST R8 K15 + 0x7C180400, // 0069 CALL R6 2 + 0x781A0006, // 006A JMPF R6 #0072 + 0x00180910, // 006B ADD R6 R4 K16 + 0x8C1C0504, // 006C GETMET R7 R2 K4 + 0x60240013, // 006D GETGBL R9 G19 + 0x7C240000, // 006E CALL R9 0 + 0x98260B11, // 006F SETIDX R9 K5 K17 + 0x98260E06, // 0070 SETIDX R9 K7 R6 + 0x7C1C0400, // 0071 CALL R7 2 + 0x7001FFEB, // 0072 JMP #005F + 0x580C0008, // 0073 LDCONST R3 K8 + 0xAC0C0200, // 0074 CATCH R3 1 0 + 0xB0080000, // 0075 RAISE 2 R0 R0 + 0x80040400, // 0076 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: msg_received +********************************************************************/ +be_local_closure(Matter_Device_msg_received, /* name */ + be_nested_proto( + 9, /* nstack */ 4, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -668,43 +3033,900 @@ be_local_closure(Matter_Device_invoke_request, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(endpoint), - /* K2 */ be_nested_str_weak(plugins), - /* K3 */ be_nested_str_weak(invoke_request), - /* K4 */ be_const_int(1), - /* K5 */ be_nested_str_weak(status), - /* K6 */ be_nested_str_weak(matter), - /* K7 */ be_nested_str_weak(UNSUPPORTED_ENDPOINT), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(message_handler), + /* K1 */ be_nested_str_weak(msg_received), }), - be_str_weak(invoke_request), + be_str_weak(msg_received), &be_const_str_solidified, - ( &(const binstruction[24]) { /* code */ - 0x58100000, // 0000 LDCONST R4 K0 - 0x88140701, // 0001 GETMBR R5 R3 K1 - 0x6018000C, // 0002 GETGBL R6 G12 - 0x881C0102, // 0003 GETMBR R7 R0 K2 - 0x7C180200, // 0004 CALL R6 1 - 0x14180806, // 0005 LT R6 R4 R6 - 0x781A000C, // 0006 JMPF R6 #0014 - 0x88180102, // 0007 GETMBR R6 R0 K2 - 0x94180C04, // 0008 GETIDX R6 R6 R4 - 0x881C0D01, // 0009 GETMBR R7 R6 K1 - 0x1C1C0E05, // 000A EQ R7 R7 R5 - 0x781E0005, // 000B JMPF R7 #0012 - 0x8C1C0D03, // 000C GETMET R7 R6 K3 - 0x5C240200, // 000D MOVE R9 R1 - 0x5C280400, // 000E MOVE R10 R2 - 0x5C2C0600, // 000F MOVE R11 R3 - 0x7C1C0800, // 0010 CALL R7 4 - 0x80040E00, // 0011 RET 1 R7 - 0x00100904, // 0012 ADD R4 R4 K4 - 0x7001FFED, // 0013 JMP #0002 - 0xB81A0C00, // 0014 GETNGBL R6 K6 - 0x88180D07, // 0015 GETMBR R6 R6 K7 - 0x900E0A06, // 0016 SETMBR R3 K5 R6 - 0x80000000, // 0017 RET 0 + ( &(const binstruction[ 7]) { /* code */ + 0x88100100, // 0000 GETMBR R4 R0 K0 + 0x8C100901, // 0001 GETMET R4 R4 K1 + 0x5C180200, // 0002 MOVE R6 R1 + 0x5C1C0400, // 0003 MOVE R7 R2 + 0x5C200600, // 0004 MOVE R8 R3 + 0x7C100800, // 0005 CALL R4 4 + 0x80040800, // 0006 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_remotes_info +********************************************************************/ +be_local_closure(Matter_Device_update_remotes_info, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(http_remotes), + /* K1 */ be_nested_str_weak(keys), + /* K2 */ be_nested_str_weak(get_info), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(stop_iteration), + /* K5 */ be_nested_str_weak(plugins_config_remotes), + }), + be_str_weak(update_remotes_info), + &be_const_str_solidified, + ( &(const binstruction[33]) { /* code */ + 0x60040013, // 0000 GETGBL R1 G19 + 0x7C040000, // 0001 CALL R1 0 + 0x88080100, // 0002 GETMBR R2 R0 K0 + 0x4C0C0000, // 0003 LDNIL R3 + 0x20080403, // 0004 NE R2 R2 R3 + 0x780A0018, // 0005 JMPF R2 #001F + 0x60080010, // 0006 GETGBL R2 G16 + 0x880C0100, // 0007 GETMBR R3 R0 K0 + 0x8C0C0701, // 0008 GETMET R3 R3 K1 + 0x7C0C0200, // 0009 CALL R3 1 + 0x7C080200, // 000A CALL R2 1 + 0xA802000F, // 000B EXBLK 0 #001C + 0x5C0C0400, // 000C MOVE R3 R2 + 0x7C0C0000, // 000D CALL R3 0 + 0x88100100, // 000E GETMBR R4 R0 K0 + 0x94100803, // 000F GETIDX R4 R4 R3 + 0x8C100902, // 0010 GETMET R4 R4 K2 + 0x7C100200, // 0011 CALL R4 1 + 0x4C140000, // 0012 LDNIL R5 + 0x20140805, // 0013 NE R5 R4 R5 + 0x78160005, // 0014 JMPF R5 #001B + 0x6014000C, // 0015 GETGBL R5 G12 + 0x5C180800, // 0016 MOVE R6 R4 + 0x7C140200, // 0017 CALL R5 1 + 0x24140B03, // 0018 GT R5 R5 K3 + 0x78160000, // 0019 JMPF R5 #001B + 0x98040604, // 001A SETIDX R1 R3 R4 + 0x7001FFEF, // 001B JMP #000C + 0x58080004, // 001C LDCONST R2 K4 + 0xAC080200, // 001D CATCH R2 1 0 + 0xB0080000, // 001E RAISE 2 R0 R0 + 0x90020A01, // 001F SETMBR R0 K5 R1 + 0x80040200, // 0020 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: _trigger_read_sensors +********************************************************************/ +be_local_closure(Matter_Device__trigger_read_sensors, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(read_sensors), + /* K3 */ be_nested_str_weak(load), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(plugins), + /* K6 */ be_nested_str_weak(parse_sensors), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(log), + /* K9 */ be_nested_str_weak(MTR_X3A_X20unable_X20to_X20parse_X20read_sensors_X3A_X20), + /* K10 */ be_const_int(3), + }), + be_str_weak(_trigger_read_sensors), + &be_const_str_solidified, + ( &(const binstruction[37]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xB80A0200, // 0001 GETNGBL R2 K1 + 0x8C080502, // 0002 GETMET R2 R2 K2 + 0x7C080200, // 0003 CALL R2 1 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C0C0403, // 0005 EQ R3 R2 R3 + 0x780E0000, // 0006 JMPF R3 #0008 + 0x80000600, // 0007 RET 0 + 0x8C0C0303, // 0008 GETMET R3 R1 K3 + 0x5C140400, // 0009 MOVE R5 R2 + 0x7C0C0400, // 000A CALL R3 2 + 0x4C100000, // 000B LDNIL R4 + 0x20100604, // 000C NE R4 R3 R4 + 0x7812000D, // 000D JMPF R4 #001C + 0x58100004, // 000E LDCONST R4 K4 + 0x6014000C, // 000F GETGBL R5 G12 + 0x88180105, // 0010 GETMBR R6 R0 K5 + 0x7C140200, // 0011 CALL R5 1 + 0x14140805, // 0012 LT R5 R4 R5 + 0x78160006, // 0013 JMPF R5 #001B + 0x88140105, // 0014 GETMBR R5 R0 K5 + 0x94140A04, // 0015 GETIDX R5 R5 R4 + 0x8C140B06, // 0016 GETMET R5 R5 K6 + 0x5C1C0600, // 0017 MOVE R7 R3 + 0x7C140400, // 0018 CALL R5 2 + 0x00100907, // 0019 ADD R4 R4 K7 + 0x7001FFF3, // 001A JMP #000F + 0x70020007, // 001B JMP #0024 + 0xB8120200, // 001C GETNGBL R4 K1 + 0x8C100908, // 001D GETMET R4 R4 K8 + 0x60180008, // 001E GETGBL R6 G8 + 0x5C1C0400, // 001F MOVE R7 R2 + 0x7C180200, // 0020 CALL R6 1 + 0x001A1206, // 0021 ADD R6 K9 R6 + 0x581C000A, // 0022 LDCONST R7 K10 + 0x7C100600, // 0023 CALL R4 3 + 0x80000000, // 0024 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: k2l +********************************************************************/ +be_local_closure(Matter_Device_k2l, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Device), + /* K1 */ be_nested_str_weak(keys), + /* K2 */ be_nested_str_weak(push), + /* K3 */ be_nested_str_weak(stop_iteration), + /* K4 */ be_const_int(1), + /* K5 */ be_const_int(0), + }), + be_str_weak(k2l), + &be_const_str_solidified, + ( &(const binstruction[50]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x60080012, // 0001 GETGBL R2 G18 + 0x7C080000, // 0002 CALL R2 0 + 0x4C0C0000, // 0003 LDNIL R3 + 0x1C0C0003, // 0004 EQ R3 R0 R3 + 0x780E0000, // 0005 JMPF R3 #0007 + 0x80040400, // 0006 RET 1 R2 + 0x600C0010, // 0007 GETGBL R3 G16 + 0x8C100101, // 0008 GETMET R4 R0 K1 + 0x7C100200, // 0009 CALL R4 1 + 0x7C0C0200, // 000A CALL R3 1 + 0xA8020005, // 000B EXBLK 0 #0012 + 0x5C100600, // 000C MOVE R4 R3 + 0x7C100000, // 000D CALL R4 0 + 0x8C140502, // 000E GETMET R5 R2 K2 + 0x5C1C0800, // 000F MOVE R7 R4 + 0x7C140400, // 0010 CALL R5 2 + 0x7001FFF9, // 0011 JMP #000C + 0x580C0003, // 0012 LDCONST R3 K3 + 0xAC0C0200, // 0013 CATCH R3 1 0 + 0xB0080000, // 0014 RAISE 2 R0 R0 + 0x600C0010, // 0015 GETGBL R3 G16 + 0x6010000C, // 0016 GETGBL R4 G12 + 0x5C140400, // 0017 MOVE R5 R2 + 0x7C100200, // 0018 CALL R4 1 + 0x04100904, // 0019 SUB R4 R4 K4 + 0x40120804, // 001A CONNECT R4 K4 R4 + 0x7C0C0200, // 001B CALL R3 1 + 0xA8020010, // 001C EXBLK 0 #002E + 0x5C100600, // 001D MOVE R4 R3 + 0x7C100000, // 001E CALL R4 0 + 0x94140404, // 001F GETIDX R5 R2 R4 + 0x5C180800, // 0020 MOVE R6 R4 + 0x241C0D05, // 0021 GT R7 R6 K5 + 0x781E0008, // 0022 JMPF R7 #002C + 0x041C0D04, // 0023 SUB R7 R6 K4 + 0x941C0407, // 0024 GETIDX R7 R2 R7 + 0x241C0E05, // 0025 GT R7 R7 R5 + 0x781E0004, // 0026 JMPF R7 #002C + 0x041C0D04, // 0027 SUB R7 R6 K4 + 0x941C0407, // 0028 GETIDX R7 R2 R7 + 0x98080C07, // 0029 SETIDX R2 R6 R7 + 0x04180D04, // 002A SUB R6 R6 K4 + 0x7001FFF4, // 002B JMP #0021 + 0x98080C05, // 002C SETIDX R2 R6 R5 + 0x7001FFEE, // 002D JMP #001D + 0x580C0003, // 002E LDCONST R3 K3 + 0xAC0C0200, // 002F CATCH R3 1 0 + 0xB0080000, // 0030 RAISE 2 R0 R0 + 0x80040400, // 0031 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: signal_endpoints_changed +********************************************************************/ +be_local_closure(Matter_Device_signal_endpoints_changed, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(3), + }), + be_str_weak(signal_endpoints_changed), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x580C0001, // 0001 LDCONST R3 K1 + 0x5412001C, // 0002 LDINT R4 29 + 0x58140002, // 0003 LDCONST R5 K2 + 0x50180000, // 0004 LDBOOL R6 0 0 + 0x7C040A00, // 0005 CALL R1 5 + 0x8C040100, // 0006 GETMET R1 R0 K0 + 0x540EFEFF, // 0007 LDINT R3 65280 + 0x5412001C, // 0008 LDINT R4 29 + 0x58140002, // 0009 LDCONST R5 K2 + 0x50180000, // 000A LDBOOL R6 0 0 + 0x7C040A00, // 000B CALL R1 5 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_root_basic_commissioning +********************************************************************/ +be_local_closure(Matter_Device_start_root_basic_commissioning, /* name */ + be_nested_proto( + 13, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[18]) { /* constants */ + /* K0 */ be_nested_str_weak(PASE_TIMEOUT), + /* K1 */ be_nested_str_weak(compute_manual_pairing_code), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(log), + /* K4 */ be_nested_str_weak(MTR_X3A_X20Manual_X20pairing_X20code_X3A_X20_X25s), + /* K5 */ be_const_int(2), + /* K6 */ be_nested_str_weak(compute_qrcode_content), + /* K7 */ be_nested_str_weak(publish_result), + /* K8 */ be_nested_str_weak(_X7B_X22Matter_X22_X3A_X7B_X22Commissioning_X22_X3A1_X2C_X22PairingCode_X22_X3A_X22_X25s_X22_X2C_X22QRCode_X22_X3A_X22_X25s_X22_X7D_X7D), + /* K9 */ be_nested_str_weak(Matter), + /* K10 */ be_nested_str_weak(_compute_pbkdf), + /* K11 */ be_nested_str_weak(root_passcode), + /* K12 */ be_nested_str_weak(root_iterations), + /* K13 */ be_nested_str_weak(root_salt), + /* K14 */ be_nested_str_weak(start_basic_commissioning), + /* K15 */ be_nested_str_weak(root_discriminator), + /* K16 */ be_nested_str_weak(root_w0), + /* K17 */ be_nested_str_weak(root_L), + }), + be_str_weak(start_root_basic_commissioning), + &be_const_str_solidified, + ( &(const binstruction[40]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x780A0000, // 0002 JMPF R2 #0004 + 0x88040100, // 0003 GETMBR R1 R0 K0 + 0x8C080101, // 0004 GETMET R2 R0 K1 + 0x7C080200, // 0005 CALL R2 1 + 0xB80E0400, // 0006 GETNGBL R3 K2 + 0x8C0C0703, // 0007 GETMET R3 R3 K3 + 0x60140018, // 0008 GETGBL R5 G24 + 0x58180004, // 0009 LDCONST R6 K4 + 0x5C1C0400, // 000A MOVE R7 R2 + 0x7C140400, // 000B CALL R5 2 + 0x58180005, // 000C LDCONST R6 K5 + 0x7C0C0600, // 000D CALL R3 3 + 0x8C0C0106, // 000E GETMET R3 R0 K6 + 0x7C0C0200, // 000F CALL R3 1 + 0xB8120400, // 0010 GETNGBL R4 K2 + 0x8C100907, // 0011 GETMET R4 R4 K7 + 0x60180018, // 0012 GETGBL R6 G24 + 0x581C0008, // 0013 LDCONST R7 K8 + 0x5C200400, // 0014 MOVE R8 R2 + 0x5C240600, // 0015 MOVE R9 R3 + 0x7C180600, // 0016 CALL R6 3 + 0x581C0009, // 0017 LDCONST R7 K9 + 0x7C100600, // 0018 CALL R4 3 + 0x8C10010A, // 0019 GETMET R4 R0 K10 + 0x8818010B, // 001A GETMBR R6 R0 K11 + 0x881C010C, // 001B GETMBR R7 R0 K12 + 0x8820010D, // 001C GETMBR R8 R0 K13 + 0x7C100800, // 001D CALL R4 4 + 0x8C10010E, // 001E GETMET R4 R0 K14 + 0x5C180200, // 001F MOVE R6 R1 + 0x881C010C, // 0020 GETMBR R7 R0 K12 + 0x8820010F, // 0021 GETMBR R8 R0 K15 + 0x8824010D, // 0022 GETMBR R9 R0 K13 + 0x88280110, // 0023 GETMBR R10 R0 K16 + 0x882C0111, // 0024 GETMBR R11 R0 K17 + 0x4C300000, // 0025 LDNIL R12 + 0x7C101000, // 0026 CALL R4 8 + 0x80000000, // 0027 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save_before_restart +********************************************************************/ +be_local_closure(Matter_Device_save_before_restart, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(stop_basic_commissioning), + /* K1 */ be_nested_str_weak(mdns_remove_op_discovery_all_fabrics), + }), + be_str_weak(save_before_restart), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x8C040101, // 0002 GETMET R1 R0 K1 + 0x7C040200, // 0003 CALL R1 1 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: register_commands +********************************************************************/ +be_local_closure(Matter_Device_register_commands, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 3]) { + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(MtrJoin), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x68100000, // 0000 GETUPV R4 U0 + 0x8C100900, // 0001 GETMET R4 R4 K0 + 0x5C180000, // 0002 MOVE R6 R0 + 0x5C1C0200, // 0003 MOVE R7 R1 + 0x5C200400, // 0004 MOVE R8 R2 + 0x5C240600, // 0005 MOVE R9 R3 + 0x7C100A00, // 0006 CALL R4 5 + 0x80040800, // 0007 RET 1 R4 + }) + ), + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(MtrUpdate), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x68100000, // 0000 GETUPV R4 U0 + 0x8C100900, // 0001 GETMET R4 R4 K0 + 0x5C180000, // 0002 MOVE R6 R0 + 0x5C1C0200, // 0003 MOVE R7 R1 + 0x5C200400, // 0004 MOVE R8 R2 + 0x5C240600, // 0005 MOVE R9 R3 + 0x7C100A00, // 0006 CALL R4 5 + 0x80040800, // 0007 RET 1 R4 + }) + ), + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(MtrInfo), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x68100000, // 0000 GETUPV R4 U0 + 0x8C100900, // 0001 GETMET R4 R4 K0 + 0x5C180000, // 0002 MOVE R6 R0 + 0x5C1C0200, // 0003 MOVE R7 R1 + 0x5C200400, // 0004 MOVE R8 R2 + 0x5C240600, // 0005 MOVE R9 R3 + 0x7C100A00, // 0006 CALL R4 5 + 0x80040800, // 0007 RET 1 R4 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(add_cmd), + /* K2 */ be_nested_str_weak(MtrJoin), + /* K3 */ be_nested_str_weak(MtrUpdate), + /* K4 */ be_nested_str_weak(MtrInfo), + }), + be_str_weak(register_commands), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x580C0002, // 0002 LDCONST R3 K2 + 0x84100000, // 0003 CLOSURE R4 P0 + 0x7C040600, // 0004 CALL R1 3 + 0xB8060000, // 0005 GETNGBL R1 K0 + 0x8C040301, // 0006 GETMET R1 R1 K1 + 0x580C0003, // 0007 LDCONST R3 K3 + 0x84100001, // 0008 CLOSURE R4 P1 + 0x7C040600, // 0009 CALL R1 3 + 0xB8060000, // 000A GETNGBL R1 K0 + 0x8C040301, // 000B GETMET R1 R1 K1 + 0x580C0004, // 000C LDCONST R3 K4 + 0x84100002, // 000D CLOSURE R4 P2 + 0x7C040600, // 000E CALL R1 3 + 0xA0000000, // 000F CLOSE R0 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: MtrInfo_one +********************************************************************/ +be_local_closure(Matter_Device_MtrInfo_one, /* name */ + be_nested_proto( + 9, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(find_plugin_by_endpoint), + /* K1 */ be_nested_str_weak(state_json), + /* K2 */ be_nested_str_weak(_X7B_X22MtrInfo_X22_X3A_X25s_X7D), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(publish_result), + /* K5 */ be_nested_str_weak(), + }), + be_str_weak(MtrInfo_one), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x1C0C0403, // 0004 EQ R3 R2 R3 + 0x780E0000, // 0005 JMPF R3 #0007 + 0x80000600, // 0006 RET 0 + 0x8C0C0501, // 0007 GETMET R3 R2 K1 + 0x7C0C0200, // 0008 CALL R3 1 + 0x780E0008, // 0009 JMPF R3 #0013 + 0x60100018, // 000A GETGBL R4 G24 + 0x58140002, // 000B LDCONST R5 K2 + 0x5C180600, // 000C MOVE R6 R3 + 0x7C100400, // 000D CALL R4 2 + 0xB8160600, // 000E GETNGBL R5 K3 + 0x8C140B04, // 000F GETMET R5 R5 K4 + 0x5C1C0800, // 0010 MOVE R7 R4 + 0x58200005, // 0011 LDCONST R8 K5 + 0x7C140600, // 0012 CALL R5 3 + 0x80000000, // 0013 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_plugin_by_friendly_name +********************************************************************/ +be_local_closure(Matter_Device_find_plugin_by_friendly_name, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(plugins), + /* K2 */ be_nested_str_weak(get_name), + /* K3 */ be_const_int(1), + }), + be_str_weak(find_plugin_by_friendly_name), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x1C080202, // 0001 EQ R2 R1 R2 + 0x740A0004, // 0002 JMPT R2 #0008 + 0x6008000C, // 0003 GETGBL R2 G12 + 0x5C0C0200, // 0004 MOVE R3 R1 + 0x7C080200, // 0005 CALL R2 1 + 0x1C080500, // 0006 EQ R2 R2 K0 + 0x780A0001, // 0007 JMPF R2 #000A + 0x4C080000, // 0008 LDNIL R2 + 0x80040400, // 0009 RET 1 R2 + 0x58080000, // 000A LDCONST R2 K0 + 0x600C000C, // 000B GETGBL R3 G12 + 0x88100101, // 000C GETMBR R4 R0 K1 + 0x7C0C0200, // 000D CALL R3 1 + 0x140C0403, // 000E LT R3 R2 R3 + 0x780E0010, // 000F JMPF R3 #0021 + 0x880C0101, // 0010 GETMBR R3 R0 K1 + 0x940C0602, // 0011 GETIDX R3 R3 R2 + 0x8C100702, // 0012 GETMET R4 R3 K2 + 0x7C100200, // 0013 CALL R4 1 + 0x4C140000, // 0014 LDNIL R5 + 0x20140805, // 0015 NE R5 R4 R5 + 0x78160007, // 0016 JMPF R5 #001F + 0x6014000C, // 0017 GETGBL R5 G12 + 0x5C180800, // 0018 MOVE R6 R4 + 0x7C140200, // 0019 CALL R5 1 + 0x24140B00, // 001A GT R5 R5 K0 + 0x78160002, // 001B JMPF R5 #001F + 0x1C140801, // 001C EQ R5 R4 R1 + 0x78160000, // 001D JMPF R5 #001F + 0x80040600, // 001E RET 1 R3 + 0x00080503, // 001F ADD R2 R2 K3 + 0x7001FFE9, // 0020 JMP #000B + 0x4C0C0000, // 0021 LDNIL R3 + 0x80040600, // 0022 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_second +********************************************************************/ +be_local_closure(Matter_Device_every_second, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(every_second), + /* K2 */ be_nested_str_weak(message_handler), + /* K3 */ be_nested_str_weak(commissioning_open), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(time_reached), + }), + be_str_weak(every_second), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x88040102, // 0003 GETMBR R1 R0 K2 + 0x8C040301, // 0004 GETMET R1 R1 K1 + 0x7C040200, // 0005 CALL R1 1 + 0x88040103, // 0006 GETMBR R1 R0 K3 + 0x4C080000, // 0007 LDNIL R2 + 0x20040202, // 0008 NE R1 R1 R2 + 0x78060006, // 0009 JMPF R1 #0011 + 0xB8060800, // 000A GETNGBL R1 K4 + 0x8C040305, // 000B GETMET R1 R1 K5 + 0x880C0103, // 000C GETMBR R3 R0 K3 + 0x7C040400, // 000D CALL R1 2 + 0x78060001, // 000E JMPF R1 #0011 + 0x4C040000, // 000F LDNIL R1 + 0x90020601, // 0010 SETMBR R0 K3 R1 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: load_param +********************************************************************/ +be_local_closure(Matter_Device_load_param, /* name */ + be_nested_proto( + 11, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[35]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(FILENAME), + /* K2 */ be_nested_str_weak(read), + /* K3 */ be_nested_str_weak(close), + /* K4 */ be_nested_str_weak(json), + /* K5 */ be_nested_str_weak(load), + /* K6 */ be_nested_str_weak(root_discriminator), + /* K7 */ be_nested_str_weak(find), + /* K8 */ be_nested_str_weak(distinguish), + /* K9 */ be_nested_str_weak(root_passcode), + /* K10 */ be_nested_str_weak(passcode), + /* K11 */ be_nested_str_weak(ipv4only), + /* K12 */ be_nested_str_weak(disable_bridge_mode), + /* K13 */ be_nested_str_weak(next_ep), + /* K14 */ be_nested_str_weak(nextep), + /* K15 */ be_nested_str_weak(plugins_config), + /* K16 */ be_nested_str_weak(config), + /* K17 */ be_nested_str_weak(tasmota), + /* K18 */ be_nested_str_weak(log), + /* K19 */ be_nested_str_weak(MTR_X3A_X20load_config_X20_X3D_X20), + /* K20 */ be_const_int(3), + /* K21 */ be_nested_str_weak(adjust_next_ep), + /* K22 */ be_nested_str_weak(plugins_persist), + /* K23 */ be_nested_str_weak(plugins_config_remotes), + /* K24 */ be_nested_str_weak(remotes), + /* K25 */ be_nested_str_weak(MTR_X3A_X20load_remotes_X20_X3D_X20), + /* K26 */ be_nested_str_weak(io_error), + /* K27 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Aload_X20Exception_X3A), + /* K28 */ be_nested_str_weak(_X7C), + /* K29 */ be_const_int(2), + /* K30 */ be_nested_str_weak(random), + /* K31 */ be_nested_str_weak(get), + /* K32 */ be_const_int(0), + /* K33 */ be_nested_str_weak(generate_random_passcode), + /* K34 */ be_nested_str_weak(save_param), + }), + be_str_weak(load_param), + &be_const_str_solidified, + ( &(const binstruction[127]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0xA802004D, // 0001 EXBLK 0 #0050 + 0x60080011, // 0002 GETGBL R2 G17 + 0x880C0101, // 0003 GETMBR R3 R0 K1 + 0x7C080200, // 0004 CALL R2 1 + 0x8C0C0502, // 0005 GETMET R3 R2 K2 + 0x7C0C0200, // 0006 CALL R3 1 + 0x8C100503, // 0007 GETMET R4 R2 K3 + 0x7C100200, // 0008 CALL R4 1 + 0xA4120800, // 0009 IMPORT R4 K4 + 0x8C140905, // 000A GETMET R5 R4 K5 + 0x5C1C0600, // 000B MOVE R7 R3 + 0x7C140400, // 000C CALL R5 2 + 0x8C180B07, // 000D GETMET R6 R5 K7 + 0x58200008, // 000E LDCONST R8 K8 + 0x88240106, // 000F GETMBR R9 R0 K6 + 0x7C180600, // 0010 CALL R6 3 + 0x90020C06, // 0011 SETMBR R0 K6 R6 + 0x8C180B07, // 0012 GETMET R6 R5 K7 + 0x5820000A, // 0013 LDCONST R8 K10 + 0x88240109, // 0014 GETMBR R9 R0 K9 + 0x7C180600, // 0015 CALL R6 3 + 0x90021206, // 0016 SETMBR R0 K9 R6 + 0x60180017, // 0017 GETGBL R6 G23 + 0x8C1C0B07, // 0018 GETMET R7 R5 K7 + 0x5824000B, // 0019 LDCONST R9 K11 + 0x50280000, // 001A LDBOOL R10 0 0 + 0x7C1C0600, // 001B CALL R7 3 + 0x7C180200, // 001C CALL R6 1 + 0x90021606, // 001D SETMBR R0 K11 R6 + 0x60180017, // 001E GETGBL R6 G23 + 0x8C1C0B07, // 001F GETMET R7 R5 K7 + 0x5824000C, // 0020 LDCONST R9 K12 + 0x50280000, // 0021 LDBOOL R10 0 0 + 0x7C1C0600, // 0022 CALL R7 3 + 0x7C180200, // 0023 CALL R6 1 + 0x90021806, // 0024 SETMBR R0 K12 R6 + 0x8C180B07, // 0025 GETMET R6 R5 K7 + 0x5820000E, // 0026 LDCONST R8 K14 + 0x8824010D, // 0027 GETMBR R9 R0 K13 + 0x7C180600, // 0028 CALL R6 3 + 0x90021A06, // 0029 SETMBR R0 K13 R6 + 0x8C180B07, // 002A GETMET R6 R5 K7 + 0x58200010, // 002B LDCONST R8 K16 + 0x7C180400, // 002C CALL R6 2 + 0x90021E06, // 002D SETMBR R0 K15 R6 + 0x8818010F, // 002E GETMBR R6 R0 K15 + 0x4C1C0000, // 002F LDNIL R7 + 0x20180C07, // 0030 NE R6 R6 R7 + 0x781A000B, // 0031 JMPF R6 #003E + 0xB81A2200, // 0032 GETNGBL R6 K17 + 0x8C180D12, // 0033 GETMET R6 R6 K18 + 0x60200008, // 0034 GETGBL R8 G8 + 0x8824010F, // 0035 GETMBR R9 R0 K15 + 0x7C200200, // 0036 CALL R8 1 + 0x00222608, // 0037 ADD R8 K19 R8 + 0x58240014, // 0038 LDCONST R9 K20 + 0x7C180600, // 0039 CALL R6 3 + 0x8C180115, // 003A GETMET R6 R0 K21 + 0x7C180200, // 003B CALL R6 1 + 0x50180200, // 003C LDBOOL R6 1 0 + 0x90022C06, // 003D SETMBR R0 K22 R6 + 0x8C180B07, // 003E GETMET R6 R5 K7 + 0x58200018, // 003F LDCONST R8 K24 + 0x60240013, // 0040 GETGBL R9 G19 + 0x7C240000, // 0041 CALL R9 0 + 0x7C180600, // 0042 CALL R6 3 + 0x90022E06, // 0043 SETMBR R0 K23 R6 + 0x88180117, // 0044 GETMBR R6 R0 K23 + 0x781A0007, // 0045 JMPF R6 #004E + 0xB81A2200, // 0046 GETNGBL R6 K17 + 0x8C180D12, // 0047 GETMET R6 R6 K18 + 0x60200008, // 0048 GETGBL R8 G8 + 0x88240117, // 0049 GETMBR R9 R0 K23 + 0x7C200200, // 004A CALL R8 1 + 0x00223208, // 004B ADD R8 K25 R8 + 0x58240014, // 004C LDCONST R9 K20 + 0x7C180600, // 004D CALL R6 3 + 0xA8040001, // 004E EXBLK 1 1 + 0x70020012, // 004F JMP #0063 + 0xAC080002, // 0050 CATCH R2 0 2 + 0x7002000F, // 0051 JMP #0062 + 0x2010051A, // 0052 NE R4 R2 K26 + 0x7812000C, // 0053 JMPF R4 #0061 + 0xB8122200, // 0054 GETNGBL R4 K17 + 0x8C100912, // 0055 GETMET R4 R4 K18 + 0x60180008, // 0056 GETGBL R6 G8 + 0x5C1C0400, // 0057 MOVE R7 R2 + 0x7C180200, // 0058 CALL R6 1 + 0x001A3606, // 0059 ADD R6 K27 R6 + 0x00180D1C, // 005A ADD R6 R6 K28 + 0x601C0008, // 005B GETGBL R7 G8 + 0x5C200600, // 005C MOVE R8 R3 + 0x7C1C0200, // 005D CALL R7 1 + 0x00180C07, // 005E ADD R6 R6 R7 + 0x581C001D, // 005F LDCONST R7 K29 + 0x7C100600, // 0060 CALL R4 3 + 0x70020000, // 0061 JMP #0063 + 0xB0080000, // 0062 RAISE 2 R0 R0 + 0x50080000, // 0063 LDBOOL R2 0 0 + 0x880C0106, // 0064 GETMBR R3 R0 K6 + 0x4C100000, // 0065 LDNIL R4 + 0x1C0C0604, // 0066 EQ R3 R3 R4 + 0x780E000A, // 0067 JMPF R3 #0073 + 0x8C0C031E, // 0068 GETMET R3 R1 K30 + 0x5814001D, // 0069 LDCONST R5 K29 + 0x7C0C0400, // 006A CALL R3 2 + 0x8C0C071F, // 006B GETMET R3 R3 K31 + 0x58140020, // 006C LDCONST R5 K32 + 0x5818001D, // 006D LDCONST R6 K29 + 0x7C0C0600, // 006E CALL R3 3 + 0x54120FFE, // 006F LDINT R4 4095 + 0x2C0C0604, // 0070 AND R3 R3 R4 + 0x90020C03, // 0071 SETMBR R0 K6 R3 + 0x50080200, // 0072 LDBOOL R2 1 0 + 0x880C0109, // 0073 GETMBR R3 R0 K9 + 0x4C100000, // 0074 LDNIL R4 + 0x1C0C0604, // 0075 EQ R3 R3 R4 + 0x780E0003, // 0076 JMPF R3 #007B + 0x8C0C0121, // 0077 GETMET R3 R0 K33 + 0x7C0C0200, // 0078 CALL R3 1 + 0x90021203, // 0079 SETMBR R0 K9 R3 + 0x50080200, // 007A LDBOOL R2 1 0 + 0x780A0001, // 007B JMPF R2 #007E + 0x8C0C0122, // 007C GETMET R3 R0 K34 + 0x7C0C0200, // 007D CALL R3 1 + 0x80000000, // 007E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: register_plugin_class +********************************************************************/ +be_local_closure(Matter_Device_register_plugin_class, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(introspect), + /* K1 */ be_nested_str_weak(get), + /* K2 */ be_nested_str_weak(TYPE), + /* K3 */ be_nested_str_weak(plugins_classes), + }), + be_str_weak(register_plugin_class), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x58180002, // 0003 LDCONST R6 K2 + 0x7C0C0600, // 0004 CALL R3 3 + 0x780E0001, // 0005 JMPF R3 #0008 + 0x88100103, // 0006 GETMBR R4 R0 K3 + 0x98100601, // 0007 SETIDX R4 R3 R1 + 0x80000000, // 0008 RET 0 }) ) ); @@ -1021,6 +4243,955 @@ be_local_closure(Matter_Device_process_attribute_expansion, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: is_commissioning_open +********************************************************************/ +be_local_closure(Matter_Device_is_commissioning_open, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(commissioning_open), + }), + be_str_weak(is_commissioning_open), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x20040202, // 0002 NE R1 R1 R2 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_commissioning_complete_deferred +********************************************************************/ +be_local_closure(Matter_Device_start_commissioning_complete_deferred, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 3, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 1), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(start_commissioning_complete), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080001, // 0002 GETUPV R2 U1 + 0x7C000400, // 0003 CALL R0 2 + 0x80040000, // 0004 RET 1 R0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(set_timer), + /* K2 */ be_const_int(0), + }), + be_str_weak(start_commissioning_complete_deferred), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x84140000, // 0003 CLOSURE R5 P0 + 0x7C080600, // 0004 CALL R2 3 + 0xA0000000, // 0005 CLOSE R0 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_operational_discovery +********************************************************************/ +be_local_closure(Matter_Device_start_operational_discovery, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(mdns), + /* K2 */ be_nested_str_weak(stop_basic_commissioning), + /* K3 */ be_nested_str_weak(root_w0), + /* K4 */ be_nested_str_weak(root_L), + /* K5 */ be_nested_str_weak(mdns_announce_op_discovery), + }), + be_str_weak(start_operational_discovery), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x8C100102, // 0002 GETMET R4 R0 K2 + 0x7C100200, // 0003 CALL R4 1 + 0x4C100000, // 0004 LDNIL R4 + 0x90020604, // 0005 SETMBR R0 K3 R4 + 0x4C100000, // 0006 LDNIL R4 + 0x90020804, // 0007 SETMBR R0 K4 R4 + 0x8C100105, // 0008 GETMET R4 R0 K5 + 0x5C180200, // 0009 MOVE R6 R1 + 0x7C100400, // 000A CALL R4 2 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: MtrInfo +********************************************************************/ +be_local_closure(Matter_Device_MtrInfo, /* name */ + be_nested_proto( + 10, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(), + /* K1 */ be_nested_str_weak(plugins), + /* K2 */ be_nested_str_weak(MtrInfo_one), + /* K3 */ be_nested_str_weak(endpoint), + /* K4 */ be_nested_str_weak(stop_iteration), + /* K5 */ be_nested_str_weak(int), + /* K6 */ be_nested_str_weak(find_plugin_by_friendly_name), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(resp_cmnd_done), + }), + be_str_weak(MtrInfo), + &be_const_str_solidified, + ( &(const binstruction[40]) { /* code */ + 0x1C140700, // 0000 EQ R5 R3 K0 + 0x7815FFFF, // 0001 JMPF R5 #0002 + 0x1C140700, // 0002 EQ R5 R3 K0 + 0x7816000D, // 0003 JMPF R5 #0012 + 0x60140010, // 0004 GETGBL R5 G16 + 0x88180101, // 0005 GETMBR R6 R0 K1 + 0x7C140200, // 0006 CALL R5 1 + 0xA8020005, // 0007 EXBLK 0 #000E + 0x5C180A00, // 0008 MOVE R6 R5 + 0x7C180000, // 0009 CALL R6 0 + 0x8C1C0102, // 000A GETMET R7 R0 K2 + 0x88240D03, // 000B GETMBR R9 R6 K3 + 0x7C1C0400, // 000C CALL R7 2 + 0x7001FFF9, // 000D JMP #0008 + 0x58140004, // 000E LDCONST R5 K4 + 0xAC140200, // 000F CATCH R5 1 0 + 0xB0080000, // 0010 RAISE 2 R0 R0 + 0x70020011, // 0011 JMP #0024 + 0x60140004, // 0012 GETGBL R5 G4 + 0x5C180800, // 0013 MOVE R6 R4 + 0x7C140200, // 0014 CALL R5 1 + 0x1C140B05, // 0015 EQ R5 R5 K5 + 0x78160003, // 0016 JMPF R5 #001B + 0x8C140102, // 0017 GETMET R5 R0 K2 + 0x5C1C0800, // 0018 MOVE R7 R4 + 0x7C140400, // 0019 CALL R5 2 + 0x70020008, // 001A JMP #0024 + 0x8C140106, // 001B GETMET R5 R0 K6 + 0x5C1C0600, // 001C MOVE R7 R3 + 0x7C140400, // 001D CALL R5 2 + 0x4C180000, // 001E LDNIL R6 + 0x20180A06, // 001F NE R6 R5 R6 + 0x781A0002, // 0020 JMPF R6 #0024 + 0x8C180102, // 0021 GETMET R6 R0 K2 + 0x88200B03, // 0022 GETMBR R8 R5 K3 + 0x7C180400, // 0023 CALL R6 2 + 0xB8160E00, // 0024 GETNGBL R5 K7 + 0x8C140B08, // 0025 GETMET R5 R5 K8 + 0x7C140200, // 0026 CALL R5 1 + 0x80000000, // 0027 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: mdns_announce_op_discovery +********************************************************************/ +be_local_closure(Matter_Device_mdns_announce_op_discovery, /* name */ + be_nested_proto( + 14, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[27]) { /* constants */ + /* K0 */ be_nested_str_weak(mdns), + /* K1 */ be_nested_str_weak(get_device_id), + /* K2 */ be_nested_str_weak(copy), + /* K3 */ be_nested_str_weak(reverse), + /* K4 */ be_nested_str_weak(get_fabric_compressed), + /* K5 */ be_nested_str_weak(tohex), + /* K6 */ be_nested_str_weak(_X2D), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(log), + /* K9 */ be_nested_str_weak(MTR_X3A_X20Operational_X20Discovery_X20node_X20_X3D_X20), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(eth), + /* K12 */ be_nested_str_weak(find), + /* K13 */ be_nested_str_weak(up), + /* K14 */ be_nested_str_weak(MTR_X3A_X20adding_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27_X20ptr_X20to_X20_X60_X25s_X2Elocal_X60), + /* K15 */ be_nested_str_weak(hostname_eth), + /* K16 */ be_nested_str_weak(add_service), + /* K17 */ be_nested_str_weak(_matter), + /* K18 */ be_nested_str_weak(_tcp), + /* K19 */ be_nested_str_weak(_I), + /* K20 */ be_nested_str_weak(MTR_X3A_X20adding_X20subtype_X3A_X20), + /* K21 */ be_nested_str_weak(add_subtype), + /* K22 */ be_nested_str_weak(wifi), + /* K23 */ be_nested_str_weak(hostname_wifi), + /* K24 */ be_nested_str_weak(MTR_X3A_X20Exception), + /* K25 */ be_nested_str_weak(_X7C), + /* K26 */ be_const_int(2), + }), + be_str_weak(mdns_announce_op_discovery), + &be_const_str_solidified, + ( &(const binstruction[121]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA8020064, // 0001 EXBLK 0 #0067 + 0x8C0C0301, // 0002 GETMET R3 R1 K1 + 0x7C0C0200, // 0003 CALL R3 1 + 0x8C0C0702, // 0004 GETMET R3 R3 K2 + 0x7C0C0200, // 0005 CALL R3 1 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x7C0C0200, // 0007 CALL R3 1 + 0x8C100304, // 0008 GETMET R4 R1 K4 + 0x7C100200, // 0009 CALL R4 1 + 0x8C140905, // 000A GETMET R5 R4 K5 + 0x7C140200, // 000B CALL R5 1 + 0x00140B06, // 000C ADD R5 R5 K6 + 0x8C180705, // 000D GETMET R6 R3 K5 + 0x7C180200, // 000E CALL R6 1 + 0x00140A06, // 000F ADD R5 R5 R6 + 0xB81A0E00, // 0010 GETNGBL R6 K7 + 0x8C180D08, // 0011 GETMET R6 R6 K8 + 0x00221205, // 0012 ADD R8 K9 R5 + 0x5824000A, // 0013 LDCONST R9 K10 + 0x7C180600, // 0014 CALL R6 3 + 0xB81A0E00, // 0015 GETNGBL R6 K7 + 0x8C180D0B, // 0016 GETMET R6 R6 K11 + 0x7C180200, // 0017 CALL R6 1 + 0x8C180D0C, // 0018 GETMET R6 R6 K12 + 0x5820000D, // 0019 LDCONST R8 K13 + 0x7C180400, // 001A CALL R6 2 + 0x781A0020, // 001B JMPF R6 #003D + 0xB81A0E00, // 001C GETNGBL R6 K7 + 0x8C180D08, // 001D GETMET R6 R6 K8 + 0x60200018, // 001E GETGBL R8 G24 + 0x5824000E, // 001F LDCONST R9 K14 + 0x5828000B, // 0020 LDCONST R10 K11 + 0x5C2C0A00, // 0021 MOVE R11 R5 + 0x8830010F, // 0022 GETMBR R12 R0 K15 + 0x7C200800, // 0023 CALL R8 4 + 0x5824000A, // 0024 LDCONST R9 K10 + 0x7C180600, // 0025 CALL R6 3 + 0x8C180510, // 0026 GETMET R6 R2 K16 + 0x58200011, // 0027 LDCONST R8 K17 + 0x58240012, // 0028 LDCONST R9 K18 + 0x542A15A3, // 0029 LDINT R10 5540 + 0x4C2C0000, // 002A LDNIL R11 + 0x5C300A00, // 002B MOVE R12 R5 + 0x8834010F, // 002C GETMBR R13 R0 K15 + 0x7C180E00, // 002D CALL R6 7 + 0x8C180905, // 002E GETMET R6 R4 K5 + 0x7C180200, // 002F CALL R6 1 + 0x001A2606, // 0030 ADD R6 K19 R6 + 0xB81E0E00, // 0031 GETNGBL R7 K7 + 0x8C1C0F08, // 0032 GETMET R7 R7 K8 + 0x00262806, // 0033 ADD R9 K20 R6 + 0x5828000A, // 0034 LDCONST R10 K10 + 0x7C1C0600, // 0035 CALL R7 3 + 0x8C1C0515, // 0036 GETMET R7 R2 K21 + 0x58240011, // 0037 LDCONST R9 K17 + 0x58280012, // 0038 LDCONST R10 K18 + 0x5C2C0A00, // 0039 MOVE R11 R5 + 0x8830010F, // 003A GETMBR R12 R0 K15 + 0x5C340C00, // 003B MOVE R13 R6 + 0x7C1C0C00, // 003C CALL R7 6 + 0xB81A0E00, // 003D GETNGBL R6 K7 + 0x8C180D16, // 003E GETMET R6 R6 K22 + 0x7C180200, // 003F CALL R6 1 + 0x8C180D0C, // 0040 GETMET R6 R6 K12 + 0x5820000D, // 0041 LDCONST R8 K13 + 0x7C180400, // 0042 CALL R6 2 + 0x781A0020, // 0043 JMPF R6 #0065 + 0xB81A0E00, // 0044 GETNGBL R6 K7 + 0x8C180D08, // 0045 GETMET R6 R6 K8 + 0x60200018, // 0046 GETGBL R8 G24 + 0x5824000E, // 0047 LDCONST R9 K14 + 0x58280016, // 0048 LDCONST R10 K22 + 0x5C2C0A00, // 0049 MOVE R11 R5 + 0x88300117, // 004A GETMBR R12 R0 K23 + 0x7C200800, // 004B CALL R8 4 + 0x5824000A, // 004C LDCONST R9 K10 + 0x7C180600, // 004D CALL R6 3 + 0x8C180510, // 004E GETMET R6 R2 K16 + 0x58200011, // 004F LDCONST R8 K17 + 0x58240012, // 0050 LDCONST R9 K18 + 0x542A15A3, // 0051 LDINT R10 5540 + 0x4C2C0000, // 0052 LDNIL R11 + 0x5C300A00, // 0053 MOVE R12 R5 + 0x88340117, // 0054 GETMBR R13 R0 K23 + 0x7C180E00, // 0055 CALL R6 7 + 0x8C180905, // 0056 GETMET R6 R4 K5 + 0x7C180200, // 0057 CALL R6 1 + 0x001A2606, // 0058 ADD R6 K19 R6 + 0xB81E0E00, // 0059 GETNGBL R7 K7 + 0x8C1C0F08, // 005A GETMET R7 R7 K8 + 0x00262806, // 005B ADD R9 K20 R6 + 0x5828000A, // 005C LDCONST R10 K10 + 0x7C1C0600, // 005D CALL R7 3 + 0x8C1C0515, // 005E GETMET R7 R2 K21 + 0x58240011, // 005F LDCONST R9 K17 + 0x58280012, // 0060 LDCONST R10 K18 + 0x5C2C0A00, // 0061 MOVE R11 R5 + 0x88300117, // 0062 GETMBR R12 R0 K23 + 0x5C340C00, // 0063 MOVE R13 R6 + 0x7C1C0C00, // 0064 CALL R7 6 + 0xA8040001, // 0065 EXBLK 1 1 + 0x70020010, // 0066 JMP #0078 + 0xAC0C0002, // 0067 CATCH R3 0 2 + 0x7002000D, // 0068 JMP #0077 + 0xB8160E00, // 0069 GETNGBL R5 K7 + 0x8C140B08, // 006A GETMET R5 R5 K8 + 0x601C0008, // 006B GETGBL R7 G8 + 0x5C200600, // 006C MOVE R8 R3 + 0x7C1C0200, // 006D CALL R7 1 + 0x001E3007, // 006E ADD R7 K24 R7 + 0x001C0F19, // 006F ADD R7 R7 K25 + 0x60200008, // 0070 GETGBL R8 G8 + 0x5C240800, // 0071 MOVE R9 R4 + 0x7C200200, // 0072 CALL R8 1 + 0x001C0E08, // 0073 ADD R7 R7 R8 + 0x5820001A, // 0074 LDCONST R8 K26 + 0x7C140600, // 0075 CALL R5 3 + 0x70020000, // 0076 JMP #0078 + 0xB0080000, // 0077 RAISE 2 R0 R0 + 0x80000000, // 0078 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_operational_discovery_deferred +********************************************************************/ +be_local_closure(Matter_Device_start_operational_discovery_deferred, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 3, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 1), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(start_operational_discovery), + }), + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x68080001, // 0002 GETUPV R2 U1 + 0x7C000400, // 0003 CALL R0 2 + 0x80040000, // 0004 RET 1 R0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(set_timer), + /* K2 */ be_const_int(0), + }), + be_str_weak(start_operational_discovery_deferred), + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0xB80A0000, // 0000 GETNGBL R2 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x58100002, // 0002 LDCONST R4 K2 + 0x84140000, // 0003 CLOSURE R5 P0 + 0x7C080600, // 0004 CALL R2 3 + 0xA0000000, // 0005 CLOSE R0 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_commissioning_complete +********************************************************************/ +be_local_closure(Matter_Device_start_commissioning_complete, /* name */ + be_nested_proto( + 11, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(get_fabric), + /* K1 */ be_nested_str_weak(get_fabric_id), + /* K2 */ be_nested_str_weak(copy), + /* K3 */ be_nested_str_weak(reverse), + /* K4 */ be_nested_str_weak(tohex), + /* K5 */ be_nested_str_weak(get_admin_vendor_name), + /* K6 */ be_nested_str_weak(tasmota), + /* K7 */ be_nested_str_weak(log), + /* K8 */ be_nested_str_weak(MTR_X3A_X20_X2D_X2D_X2D_X20Commissioning_X20complete_X20for_X20Fabric_X20_X27_X25s_X27_X20_X28Vendor_X20_X25s_X29_X20_X2D_X2D_X2D), + /* K9 */ be_const_int(2), + /* K10 */ be_nested_str_weak(stop_basic_commissioning), + }), + be_str_weak(start_commissioning_complete), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x8C080300, // 0000 GETMET R2 R1 K0 + 0x7C080200, // 0001 CALL R2 1 + 0x8C0C0501, // 0002 GETMET R3 R2 K1 + 0x7C0C0200, // 0003 CALL R3 1 + 0x8C0C0702, // 0004 GETMET R3 R3 K2 + 0x7C0C0200, // 0005 CALL R3 1 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x7C0C0200, // 0007 CALL R3 1 + 0x8C0C0704, // 0008 GETMET R3 R3 K4 + 0x7C0C0200, // 0009 CALL R3 1 + 0x8C100505, // 000A GETMET R4 R2 K5 + 0x7C100200, // 000B CALL R4 1 + 0xB8160C00, // 000C GETNGBL R5 K6 + 0x8C140B07, // 000D GETMET R5 R5 K7 + 0x601C0018, // 000E GETGBL R7 G24 + 0x58200008, // 000F LDCONST R8 K8 + 0x5C240600, // 0010 MOVE R9 R3 + 0x5C280800, // 0011 MOVE R10 R4 + 0x7C1C0600, // 0012 CALL R7 3 + 0x58200009, // 0013 LDCONST R8 K9 + 0x7C140600, // 0014 CALL R5 3 + 0x8C14010A, // 0015 GETMET R5 R0 K10 + 0x7C140200, // 0016 CALL R5 1 + 0x80000000, // 0017 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: MtrUpdate +********************************************************************/ +be_local_closure(Matter_Device_MtrUpdate, /* name */ + be_nested_proto( + 18, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[25]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(resp_cmnd_str), + /* K2 */ be_nested_str_weak(Invalid_X20JSON), + /* K3 */ be_nested_str_weak(find_key_i), + /* K4 */ be_nested_str_weak(Ep), + /* K5 */ be_nested_str_weak(Name), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(Invalid_X20_X27Ep_X27_X20attribute), + /* K8 */ be_nested_str_weak(find_plugin_by_endpoint), + /* K9 */ be_nested_str_weak(remove), + /* K10 */ be_nested_str_weak(find_plugin_by_friendly_name), + /* K11 */ be_nested_str_weak(Invalid_X20Device), + /* K12 */ be_nested_str_weak(VIRTUAL), + /* K13 */ be_nested_str_weak(Device_X20is_X20not_X20virtual), + /* K14 */ be_nested_str_weak(consolidate_update_commands), + /* K15 */ be_nested_str_weak(keys), + /* K16 */ be_nested_str_weak(find_list_i), + /* K17 */ be_nested_str_weak(Invalid_X20attribute_X20_X27_X25s_X27), + /* K18 */ be_nested_str_weak(stop_iteration), + /* K19 */ be_nested_str_weak(update_virtual), + /* K20 */ be_nested_str_weak(state_json), + /* K21 */ be_nested_str_weak(_X7B_X22_X25s_X22_X3A_X25s_X7D), + /* K22 */ be_nested_str_weak(resp_cmnd), + /* K23 */ be_nested_str_weak(resp_cmnd_done), + /* K24 */ be_nested_str_weak(Missing_X20_X27Device_X27_X20attribute), + }), + be_str_weak(MtrUpdate), + &be_const_str_solidified, + ( &(const binstruction[126]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x1C140805, // 0001 EQ R5 R4 R5 + 0x78160004, // 0002 JMPF R5 #0008 + 0xB8160000, // 0003 GETNGBL R5 K0 + 0x8C140B01, // 0004 GETMET R5 R5 K1 + 0x581C0002, // 0005 LDCONST R7 K2 + 0x7C140400, // 0006 CALL R5 2 + 0x80040A00, // 0007 RET 1 R5 + 0xB8160000, // 0008 GETNGBL R5 K0 + 0x8C140B03, // 0009 GETMET R5 R5 K3 + 0x5C1C0800, // 000A MOVE R7 R4 + 0x58200004, // 000B LDCONST R8 K4 + 0x7C140600, // 000C CALL R5 3 + 0xB81A0000, // 000D GETNGBL R6 K0 + 0x8C180D03, // 000E GETMET R6 R6 K3 + 0x5C200800, // 000F MOVE R8 R4 + 0x58240005, // 0010 LDCONST R9 K5 + 0x7C180600, // 0011 CALL R6 3 + 0x74160000, // 0012 JMPT R5 #0014 + 0x781A0064, // 0013 JMPF R6 #0079 + 0x4C1C0000, // 0014 LDNIL R7 + 0x78160010, // 0015 JMPF R5 #0027 + 0x60200009, // 0016 GETGBL R8 G9 + 0x94240805, // 0017 GETIDX R9 R4 R5 + 0x7C200200, // 0018 CALL R8 1 + 0x18241106, // 0019 LE R9 R8 K6 + 0x78260004, // 001A JMPF R9 #0020 + 0xB8260000, // 001B GETNGBL R9 K0 + 0x8C241301, // 001C GETMET R9 R9 K1 + 0x582C0007, // 001D LDCONST R11 K7 + 0x7C240400, // 001E CALL R9 2 + 0x80041200, // 001F RET 1 R9 + 0x8C240108, // 0020 GETMET R9 R0 K8 + 0x5C2C1000, // 0021 MOVE R11 R8 + 0x7C240400, // 0022 CALL R9 2 + 0x5C1C1200, // 0023 MOVE R7 R9 + 0x8C240909, // 0024 GETMET R9 R4 K9 + 0x5C2C0A00, // 0025 MOVE R11 R5 + 0x7C240400, // 0026 CALL R9 2 + 0x781A0009, // 0027 JMPF R6 #0032 + 0x4C200000, // 0028 LDNIL R8 + 0x1C200E08, // 0029 EQ R8 R7 R8 + 0x78220003, // 002A JMPF R8 #002F + 0x8C20010A, // 002B GETMET R8 R0 K10 + 0x94280806, // 002C GETIDX R10 R4 R6 + 0x7C200400, // 002D CALL R8 2 + 0x5C1C1000, // 002E MOVE R7 R8 + 0x8C200909, // 002F GETMET R8 R4 K9 + 0x5C280C00, // 0030 MOVE R10 R6 + 0x7C200400, // 0031 CALL R8 2 + 0x4C200000, // 0032 LDNIL R8 + 0x1C200E08, // 0033 EQ R8 R7 R8 + 0x78220004, // 0034 JMPF R8 #003A + 0xB8220000, // 0035 GETNGBL R8 K0 + 0x8C201101, // 0036 GETMET R8 R8 K1 + 0x5828000B, // 0037 LDCONST R10 K11 + 0x7C200400, // 0038 CALL R8 2 + 0x80041000, // 0039 RET 1 R8 + 0x88200F0C, // 003A GETMBR R8 R7 K12 + 0x74220004, // 003B JMPT R8 #0041 + 0xB8220000, // 003C GETNGBL R8 K0 + 0x8C201101, // 003D GETMET R8 R8 K1 + 0x5828000D, // 003E LDCONST R10 K13 + 0x7C200400, // 003F CALL R8 2 + 0x80041000, // 0040 RET 1 R8 + 0x8C200F0E, // 0041 GETMET R8 R7 K14 + 0x7C200200, // 0042 CALL R8 1 + 0x60240013, // 0043 GETGBL R9 G19 + 0x7C240000, // 0044 CALL R9 0 + 0x60280010, // 0045 GETGBL R10 G16 + 0x8C2C090F, // 0046 GETMET R11 R4 K15 + 0x7C2C0200, // 0047 CALL R11 1 + 0x7C280200, // 0048 CALL R10 1 + 0xA8020016, // 0049 EXBLK 0 #0061 + 0x5C2C1400, // 004A MOVE R11 R10 + 0x7C2C0000, // 004B CALL R11 0 + 0xB8320000, // 004C GETNGBL R12 K0 + 0x8C301910, // 004D GETMET R12 R12 K16 + 0x5C381000, // 004E MOVE R14 R8 + 0x5C3C1600, // 004F MOVE R15 R11 + 0x7C300600, // 0050 CALL R12 3 + 0x4C340000, // 0051 LDNIL R13 + 0x1C34180D, // 0052 EQ R13 R12 R13 + 0x78360008, // 0053 JMPF R13 #005D + 0xB8360000, // 0054 GETNGBL R13 K0 + 0x8C341B01, // 0055 GETMET R13 R13 K1 + 0x603C0018, // 0056 GETGBL R15 G24 + 0x58400011, // 0057 LDCONST R16 K17 + 0x5C441600, // 0058 MOVE R17 R11 + 0x7C3C0400, // 0059 CALL R15 2 + 0x7C340400, // 005A CALL R13 2 + 0xA8040001, // 005B EXBLK 1 1 + 0x80001A00, // 005C RET 0 + 0x9434100C, // 005D GETIDX R13 R8 R12 + 0x9438080B, // 005E GETIDX R14 R4 R11 + 0x98241A0E, // 005F SETIDX R9 R13 R14 + 0x7001FFE8, // 0060 JMP #004A + 0x58280012, // 0061 LDCONST R10 K18 + 0xAC280200, // 0062 CATCH R10 1 0 + 0xB0080000, // 0063 RAISE 2 R0 R0 + 0x8C280F13, // 0064 GETMET R10 R7 K19 + 0x5C301200, // 0065 MOVE R12 R9 + 0x7C280400, // 0066 CALL R10 2 + 0x8C280F14, // 0067 GETMET R10 R7 K20 + 0x7C280200, // 0068 CALL R10 1 + 0x782A000A, // 0069 JMPF R10 #0075 + 0x602C0018, // 006A GETGBL R11 G24 + 0x58300015, // 006B LDCONST R12 K21 + 0x5C340200, // 006C MOVE R13 R1 + 0x5C381400, // 006D MOVE R14 R10 + 0x7C2C0600, // 006E CALL R11 3 + 0xB8320000, // 006F GETNGBL R12 K0 + 0x8C301916, // 0070 GETMET R12 R12 K22 + 0x5C381600, // 0071 MOVE R14 R11 + 0x7C300400, // 0072 CALL R12 2 + 0x80041800, // 0073 RET 1 R12 + 0x70020003, // 0074 JMP #0079 + 0xB82E0000, // 0075 GETNGBL R11 K0 + 0x8C2C1717, // 0076 GETMET R11 R11 K23 + 0x7C2C0200, // 0077 CALL R11 1 + 0x80041600, // 0078 RET 1 R11 + 0xB81E0000, // 0079 GETNGBL R7 K0 + 0x8C1C0F01, // 007A GETMET R7 R7 K1 + 0x58240018, // 007B LDCONST R9 K24 + 0x7C1C0400, // 007C CALL R7 2 + 0x80000000, // 007D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: sort_distinct +********************************************************************/ +be_local_closure(Matter_Device_sort_distinct, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Device), + /* K1 */ be_const_int(1), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(stop_iteration), + /* K4 */ be_nested_str_weak(remove), + }), + be_str_weak(sort_distinct), + &be_const_str_solidified, + ( &(const binstruction[53]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x60080010, // 0001 GETGBL R2 G16 + 0x600C000C, // 0002 GETGBL R3 G12 + 0x5C100000, // 0003 MOVE R4 R0 + 0x7C0C0200, // 0004 CALL R3 1 + 0x040C0701, // 0005 SUB R3 R3 K1 + 0x400E0203, // 0006 CONNECT R3 K1 R3 + 0x7C080200, // 0007 CALL R2 1 + 0xA8020010, // 0008 EXBLK 0 #001A + 0x5C0C0400, // 0009 MOVE R3 R2 + 0x7C0C0000, // 000A CALL R3 0 + 0x94100003, // 000B GETIDX R4 R0 R3 + 0x5C140600, // 000C MOVE R5 R3 + 0x24180B02, // 000D GT R6 R5 K2 + 0x781A0008, // 000E JMPF R6 #0018 + 0x04180B01, // 000F SUB R6 R5 K1 + 0x94180006, // 0010 GETIDX R6 R0 R6 + 0x24180C04, // 0011 GT R6 R6 R4 + 0x781A0004, // 0012 JMPF R6 #0018 + 0x04180B01, // 0013 SUB R6 R5 K1 + 0x94180006, // 0014 GETIDX R6 R0 R6 + 0x98000A06, // 0015 SETIDX R0 R5 R6 + 0x04140B01, // 0016 SUB R5 R5 K1 + 0x7001FFF4, // 0017 JMP #000D + 0x98000A04, // 0018 SETIDX R0 R5 R4 + 0x7001FFEE, // 0019 JMP #0009 + 0x58080003, // 001A LDCONST R2 K3 + 0xAC080200, // 001B CATCH R2 1 0 + 0xB0080000, // 001C RAISE 2 R0 R0 + 0x58080001, // 001D LDCONST R2 K1 + 0x600C000C, // 001E GETGBL R3 G12 + 0x5C100000, // 001F MOVE R4 R0 + 0x7C0C0200, // 0020 CALL R3 1 + 0x180C0701, // 0021 LE R3 R3 K1 + 0x780E0000, // 0022 JMPF R3 #0024 + 0x80040000, // 0023 RET 1 R0 + 0x940C0102, // 0024 GETIDX R3 R0 K2 + 0x6010000C, // 0025 GETGBL R4 G12 + 0x5C140000, // 0026 MOVE R5 R0 + 0x7C100200, // 0027 CALL R4 1 + 0x14100404, // 0028 LT R4 R2 R4 + 0x78120009, // 0029 JMPF R4 #0034 + 0x94100002, // 002A GETIDX R4 R0 R2 + 0x1C100803, // 002B EQ R4 R4 R3 + 0x78120003, // 002C JMPF R4 #0031 + 0x8C100104, // 002D GETMET R4 R0 K4 + 0x5C180400, // 002E MOVE R6 R2 + 0x7C100400, // 002F CALL R4 2 + 0x70020001, // 0030 JMP #0033 + 0x940C0002, // 0031 GETIDX R3 R0 R2 + 0x00080501, // 0032 ADD R2 R2 K1 + 0x7001FFF0, // 0033 JMP #0025 + 0x80040000, // 0034 RET 1 R0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: conf_to_log +********************************************************************/ +be_local_closure(Matter_Device_conf_to_log, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Device), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(k2l), + /* K3 */ be_nested_str_weak(type), + /* K4 */ be_nested_str_weak(_X20_X25s_X3A_X25s), + /* K5 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(conf_to_log), + &be_const_str_solidified, + ( &(const binstruction[24]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x58080001, // 0001 LDCONST R2 K1 + 0x600C0010, // 0002 GETGBL R3 G16 + 0x8C100302, // 0003 GETMET R4 R1 K2 + 0x5C180000, // 0004 MOVE R6 R0 + 0x7C100400, // 0005 CALL R4 2 + 0x7C0C0200, // 0006 CALL R3 1 + 0xA802000B, // 0007 EXBLK 0 #0014 + 0x5C100600, // 0008 MOVE R4 R3 + 0x7C100000, // 0009 CALL R4 0 + 0x1C140903, // 000A EQ R5 R4 K3 + 0x78160000, // 000B JMPF R5 #000D + 0x7001FFFA, // 000C JMP #0008 + 0x60140018, // 000D GETGBL R5 G24 + 0x58180004, // 000E LDCONST R6 K4 + 0x5C1C0800, // 000F MOVE R7 R4 + 0x94200004, // 0010 GETIDX R8 R0 R4 + 0x7C140600, // 0011 CALL R5 3 + 0x00080405, // 0012 ADD R2 R2 R5 + 0x7001FFF3, // 0013 JMP #0008 + 0x580C0005, // 0014 LDCONST R3 K5 + 0xAC0C0200, // 0015 CATCH R3 1 0 + 0xB0080000, // 0016 RAISE 2 R0 R0 + 0x80040400, // 0017 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_plugin_by_endpoint +********************************************************************/ +be_local_closure(Matter_Device_find_plugin_by_endpoint, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(plugins), + /* K2 */ be_nested_str_weak(get_endpoint), + /* K3 */ be_const_int(1), + }), + be_str_weak(find_plugin_by_endpoint), + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x600C000C, // 0001 GETGBL R3 G12 + 0x88100101, // 0002 GETMBR R4 R0 K1 + 0x7C0C0200, // 0003 CALL R3 1 + 0x140C0403, // 0004 LT R3 R2 R3 + 0x780E0008, // 0005 JMPF R3 #000F + 0x880C0101, // 0006 GETMBR R3 R0 K1 + 0x940C0602, // 0007 GETIDX R3 R3 R2 + 0x8C100702, // 0008 GETMET R4 R3 K2 + 0x7C100200, // 0009 CALL R4 1 + 0x1C100801, // 000A EQ R4 R4 R1 + 0x78120000, // 000B JMPF R4 #000D + 0x80040600, // 000C RET 1 R3 + 0x00080503, // 000D ADD R2 R2 K3 + 0x7001FFF1, // 000E JMP #0001 + 0x4C0C0000, // 000F LDNIL R3 + 0x80040600, // 0010 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: received_ack +********************************************************************/ +be_local_closure(Matter_Device_received_ack, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(udp_server), + /* K1 */ be_nested_str_weak(received_ack), + }), + be_str_weak(received_ack), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: generate_random_passcode +********************************************************************/ +be_local_closure(Matter_Device_generate_random_passcode, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(random), + /* K2 */ be_nested_str_weak(get), + /* K3 */ be_const_int(0), + /* K4 */ be_const_int(134217727), + /* K5 */ be_const_int(99999998), + /* K6 */ be_nested_str_weak(PASSCODE_INVALID), + /* K7 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(generate_random_passcode), + &be_const_str_solidified, + ( &(const binstruction[35]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x500C0200, // 0002 LDBOOL R3 1 0 + 0x780E001D, // 0003 JMPF R3 #0022 + 0x8C0C0301, // 0004 GETMET R3 R1 K1 + 0x54160003, // 0005 LDINT R5 4 + 0x7C0C0400, // 0006 CALL R3 2 + 0x8C0C0702, // 0007 GETMET R3 R3 K2 + 0x58140003, // 0008 LDCONST R5 K3 + 0x541A0003, // 0009 LDINT R6 4 + 0x7C0C0600, // 000A CALL R3 3 + 0x2C0C0704, // 000B AND R3 R3 K4 + 0x5C080600, // 000C MOVE R2 R3 + 0x240C0505, // 000D GT R3 R2 K5 + 0x780E0000, // 000E JMPF R3 #0010 + 0x7001FFF1, // 000F JMP #0002 + 0x600C0010, // 0010 GETGBL R3 G16 + 0x88100106, // 0011 GETMBR R4 R0 K6 + 0x7C0C0200, // 0012 CALL R3 1 + 0xA8020005, // 0013 EXBLK 0 #001A + 0x5C100600, // 0014 MOVE R4 R3 + 0x7C100000, // 0015 CALL R4 0 + 0x1C140404, // 0016 EQ R5 R2 R4 + 0x78160000, // 0017 JMPF R5 #0019 + 0x4C080000, // 0018 LDNIL R2 + 0x7001FFF9, // 0019 JMP #0014 + 0x580C0007, // 001A LDCONST R3 K7 + 0xAC0C0200, // 001B CATCH R3 1 0 + 0xB0080000, // 001C RAISE 2 R0 R0 + 0x4C0C0000, // 001D LDNIL R3 + 0x200C0403, // 001E NE R3 R2 R3 + 0x780E0000, // 001F JMPF R3 #0021 + 0x80040400, // 0020 RET 1 R2 + 0x7001FFDF, // 0021 JMP #0002 + 0x80000000, // 0022 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: _instantiate_plugins_from_config ********************************************************************/ @@ -1227,3475 +5398,6 @@ be_local_closure(Matter_Device__instantiate_plugins_from_config, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: start_operational_discovery -********************************************************************/ -be_local_closure(Matter_Device_start_operational_discovery, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(mdns), - /* K2 */ be_nested_str_weak(stop_basic_commissioning), - /* K3 */ be_nested_str_weak(root_w0), - /* K4 */ be_nested_str_weak(root_L), - /* K5 */ be_nested_str_weak(mdns_announce_op_discovery), - }), - be_str_weak(start_operational_discovery), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0x8C100102, // 0002 GETMET R4 R0 K2 - 0x7C100200, // 0003 CALL R4 1 - 0x4C100000, // 0004 LDNIL R4 - 0x90020604, // 0005 SETMBR R0 K3 R4 - 0x4C100000, // 0006 LDNIL R4 - 0x90020804, // 0007 SETMBR R0 K4 R4 - 0x8C100105, // 0008 GETMET R4 R0 K5 - 0x5C180200, // 0009 MOVE R6 R1 - 0x7C100400, // 000A CALL R4 2 - 0x80000000, // 000B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: msg_received -********************************************************************/ -be_local_closure(Matter_Device_msg_received, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(message_handler), - /* K1 */ be_nested_str_weak(msg_received), - }), - be_str_weak(msg_received), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x88100100, // 0000 GETMBR R4 R0 K0 - 0x8C100901, // 0001 GETMET R4 R4 K1 - 0x5C180200, // 0002 MOVE R6 R1 - 0x5C1C0400, // 0003 MOVE R7 R2 - 0x5C200600, // 0004 MOVE R8 R3 - 0x7C100800, // 0005 CALL R4 4 - 0x80040800, // 0006 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: register_http_remote -********************************************************************/ -be_local_closure(Matter_Device_register_http_remote, /* name */ - be_nested_proto( - 9, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(http_remotes), - /* K1 */ be_nested_str_weak(contains), - /* K2 */ be_nested_str_weak(get_timeout), - /* K3 */ be_nested_str_weak(set_timeout), - /* K4 */ be_nested_str_weak(matter), - /* K5 */ be_nested_str_weak(HTTP_remote), - /* K6 */ be_nested_str_weak(plugins_config_remotes), - /* K7 */ be_nested_str_weak(set_info), - }), - be_str_weak(register_http_remote), - &be_const_str_solidified, - ( &(const binstruction[42]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x4C100000, // 0001 LDNIL R4 - 0x1C0C0604, // 0002 EQ R3 R3 R4 - 0x780E0002, // 0003 JMPF R3 #0007 - 0x600C0013, // 0004 GETGBL R3 G19 - 0x7C0C0000, // 0005 CALL R3 0 - 0x90020003, // 0006 SETMBR R0 K0 R3 - 0x4C0C0000, // 0007 LDNIL R3 - 0x88100100, // 0008 GETMBR R4 R0 K0 - 0x8C100901, // 0009 GETMET R4 R4 K1 - 0x5C180200, // 000A MOVE R6 R1 - 0x7C100400, // 000B CALL R4 2 - 0x78120009, // 000C JMPF R4 #0017 - 0x88100100, // 000D GETMBR R4 R0 K0 - 0x940C0801, // 000E GETIDX R3 R4 R1 - 0x8C140702, // 000F GETMET R5 R3 K2 - 0x7C140200, // 0010 CALL R5 1 - 0x14140405, // 0011 LT R5 R2 R5 - 0x78160002, // 0012 JMPF R5 #0016 - 0x8C140703, // 0013 GETMET R5 R3 K3 - 0x5C1C0400, // 0014 MOVE R7 R2 - 0x7C140400, // 0015 CALL R5 2 - 0x70020011, // 0016 JMP #0029 - 0xB8120800, // 0017 GETNGBL R4 K4 - 0x8C100905, // 0018 GETMET R4 R4 K5 - 0x5C180000, // 0019 MOVE R6 R0 - 0x5C1C0200, // 001A MOVE R7 R1 - 0x5C200400, // 001B MOVE R8 R2 - 0x7C100800, // 001C CALL R4 4 - 0x5C0C0800, // 001D MOVE R3 R4 - 0x88100106, // 001E GETMBR R4 R0 K6 - 0x8C100901, // 001F GETMET R4 R4 K1 - 0x5C180200, // 0020 MOVE R6 R1 - 0x7C100400, // 0021 CALL R4 2 - 0x78120003, // 0022 JMPF R4 #0027 - 0x8C100707, // 0023 GETMET R4 R3 K7 - 0x88180106, // 0024 GETMBR R6 R0 K6 - 0x94180C01, // 0025 GETIDX R6 R6 R1 - 0x7C100400, // 0026 CALL R4 2 - 0x88100100, // 0027 GETMBR R4 R0 K0 - 0x98100203, // 0028 SETIDX R4 R1 R3 - 0x80040600, // 0029 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: bridge_add_endpoint -********************************************************************/ -be_local_closure(Matter_Device_bridge_add_endpoint, /* name */ - be_nested_proto( - 17, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[21]) { /* constants */ - /* K0 */ be_nested_str_weak(plugins_classes), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(log), - /* K4 */ be_nested_str_weak(MTR_X3A_X20unknown_X20class_X20name_X20_X27), - /* K5 */ be_nested_str_weak(_X27_X20skipping), - /* K6 */ be_const_int(3), - /* K7 */ be_nested_str_weak(next_ep), - /* K8 */ be_nested_str_weak(plugins), - /* K9 */ be_nested_str_weak(push), - /* K10 */ be_nested_str_weak(type), - /* K11 */ be_nested_str_weak(keys), - /* K12 */ be_nested_str_weak(stop_iteration), - /* K13 */ be_nested_str_weak(MTR_X3A_X20adding_X20endpoint_X20_X3D_X20_X25i_X20type_X3A_X25s_X25s), - /* K14 */ be_nested_str_weak(conf_to_log), - /* K15 */ be_const_int(2), - /* K16 */ be_nested_str_weak(plugins_config), - /* K17 */ be_nested_str_weak(plugins_persist), - /* K18 */ be_const_int(1), - /* K19 */ be_nested_str_weak(save_param), - /* K20 */ be_nested_str_weak(signal_endpoints_changed), - }), - be_str_weak(bridge_add_endpoint), - &be_const_str_solidified, - ( &(const binstruction[70]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x8C0C0701, // 0001 GETMET R3 R3 K1 - 0x5C140200, // 0002 MOVE R5 R1 - 0x7C0C0400, // 0003 CALL R3 2 - 0x4C100000, // 0004 LDNIL R4 - 0x1C100604, // 0005 EQ R4 R3 R4 - 0x78120009, // 0006 JMPF R4 #0011 - 0xB8120400, // 0007 GETNGBL R4 K2 - 0x8C100903, // 0008 GETMET R4 R4 K3 - 0x60180008, // 0009 GETGBL R6 G8 - 0x5C1C0200, // 000A MOVE R7 R1 - 0x7C180200, // 000B CALL R6 1 - 0x001A0806, // 000C ADD R6 K4 R6 - 0x00180D05, // 000D ADD R6 R6 K5 - 0x581C0006, // 000E LDCONST R7 K6 - 0x7C100600, // 000F CALL R4 3 - 0x80000800, // 0010 RET 0 - 0x88100107, // 0011 GETMBR R4 R0 K7 - 0x60140008, // 0012 GETGBL R5 G8 - 0x5C180800, // 0013 MOVE R6 R4 - 0x7C140200, // 0014 CALL R5 1 - 0x5C180600, // 0015 MOVE R6 R3 - 0x5C1C0000, // 0016 MOVE R7 R0 - 0x5C200800, // 0017 MOVE R8 R4 - 0x5C240400, // 0018 MOVE R9 R2 - 0x7C180600, // 0019 CALL R6 3 - 0x881C0108, // 001A GETMBR R7 R0 K8 - 0x8C1C0F09, // 001B GETMET R7 R7 K9 - 0x5C240C00, // 001C MOVE R9 R6 - 0x7C1C0400, // 001D CALL R7 2 - 0x601C0013, // 001E GETGBL R7 G19 - 0x7C1C0000, // 001F CALL R7 0 - 0x981E1401, // 0020 SETIDX R7 K10 R1 - 0x60200010, // 0021 GETGBL R8 G16 - 0x8C24050B, // 0022 GETMET R9 R2 K11 - 0x7C240200, // 0023 CALL R9 1 - 0x7C200200, // 0024 CALL R8 1 - 0xA8020004, // 0025 EXBLK 0 #002B - 0x5C241000, // 0026 MOVE R9 R8 - 0x7C240000, // 0027 CALL R9 0 - 0x94280409, // 0028 GETIDX R10 R2 R9 - 0x981C120A, // 0029 SETIDX R7 R9 R10 - 0x7001FFFA, // 002A JMP #0026 - 0x5820000C, // 002B LDCONST R8 K12 - 0xAC200200, // 002C CATCH R8 1 0 - 0xB0080000, // 002D RAISE 2 R0 R0 - 0xB8220400, // 002E GETNGBL R8 K2 - 0x8C201103, // 002F GETMET R8 R8 K3 - 0x60280018, // 0030 GETGBL R10 G24 - 0x582C000D, // 0031 LDCONST R11 K13 - 0x5C300800, // 0032 MOVE R12 R4 - 0x5C340200, // 0033 MOVE R13 R1 - 0x8C38010E, // 0034 GETMET R14 R0 K14 - 0x5C400400, // 0035 MOVE R16 R2 - 0x7C380400, // 0036 CALL R14 2 - 0x7C280800, // 0037 CALL R10 4 - 0x582C000F, // 0038 LDCONST R11 K15 - 0x7C200600, // 0039 CALL R8 3 - 0x88200110, // 003A GETMBR R8 R0 K16 - 0x98200A07, // 003B SETIDX R8 R5 R7 - 0x50200200, // 003C LDBOOL R8 1 0 - 0x90022208, // 003D SETMBR R0 K17 R8 - 0x88200107, // 003E GETMBR R8 R0 K7 - 0x00201112, // 003F ADD R8 R8 K18 - 0x90020E08, // 0040 SETMBR R0 K7 R8 - 0x8C200113, // 0041 GETMET R8 R0 K19 - 0x7C200200, // 0042 CALL R8 1 - 0x8C200114, // 0043 GETMET R8 R0 K20 - 0x7C200200, // 0044 CALL R8 1 - 0x80040800, // 0045 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_plugin_class_arg -********************************************************************/ -be_local_closure(Matter_Device_get_plugin_class_arg, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(plugins_classes), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(ARG), - /* K3 */ be_nested_str_weak(), - }), - be_str_weak(get_plugin_class_arg), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C080400, // 0003 CALL R2 2 - 0x780A0001, // 0004 JMPF R2 #0007 - 0x880C0502, // 0005 GETMBR R3 R2 K2 - 0x70020000, // 0006 JMP #0008 - 0x580C0003, // 0007 LDCONST R3 K3 - 0x80040600, // 0008 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: compute_qrcode_content -********************************************************************/ -be_local_closure(Matter_Device_compute_qrcode_content, /* name */ - be_nested_proto( - 8, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ - /* K0 */ be_nested_str_weak(resize), - /* K1 */ be_nested_str_weak(setbits), - /* K2 */ be_const_int(3), - /* K3 */ be_nested_str_weak(vendorid), - /* K4 */ be_nested_str_weak(productid), - /* K5 */ be_nested_str_weak(root_discriminator), - /* K6 */ be_nested_str_weak(root_passcode), - /* K7 */ be_const_int(134217727), - /* K8 */ be_nested_str_weak(MT_X3A), - /* K9 */ be_nested_str_weak(matter), - /* K10 */ be_nested_str_weak(Base38), - /* K11 */ be_nested_str_weak(encode), - }), - be_str_weak(compute_qrcode_content), - &be_const_str_solidified, - ( &(const binstruction[40]) { /* code */ - 0x60040015, // 0000 GETGBL R1 G21 - 0x7C040000, // 0001 CALL R1 0 - 0x8C040300, // 0002 GETMET R1 R1 K0 - 0x540E000A, // 0003 LDINT R3 11 - 0x7C040400, // 0004 CALL R1 2 - 0x8C080301, // 0005 GETMET R2 R1 K1 - 0x58100002, // 0006 LDCONST R4 K2 - 0x5416000F, // 0007 LDINT R5 16 - 0x88180103, // 0008 GETMBR R6 R0 K3 - 0x7C080800, // 0009 CALL R2 4 - 0x8C080301, // 000A GETMET R2 R1 K1 - 0x54120012, // 000B LDINT R4 19 - 0x5416000F, // 000C LDINT R5 16 - 0x88180104, // 000D GETMBR R6 R0 K4 - 0x7C080800, // 000E CALL R2 4 - 0x8C080301, // 000F GETMET R2 R1 K1 - 0x54120024, // 0010 LDINT R4 37 - 0x54160007, // 0011 LDINT R5 8 - 0x541A0003, // 0012 LDINT R6 4 - 0x7C080800, // 0013 CALL R2 4 - 0x8C080301, // 0014 GETMET R2 R1 K1 - 0x5412002C, // 0015 LDINT R4 45 - 0x5416000B, // 0016 LDINT R5 12 - 0x88180105, // 0017 GETMBR R6 R0 K5 - 0x541E0FFE, // 0018 LDINT R7 4095 - 0x2C180C07, // 0019 AND R6 R6 R7 - 0x7C080800, // 001A CALL R2 4 - 0x8C080301, // 001B GETMET R2 R1 K1 - 0x54120038, // 001C LDINT R4 57 - 0x5416001A, // 001D LDINT R5 27 - 0x88180106, // 001E GETMBR R6 R0 K6 - 0x2C180D07, // 001F AND R6 R6 K7 - 0x7C080800, // 0020 CALL R2 4 - 0xB80A1200, // 0021 GETNGBL R2 K9 - 0x8808050A, // 0022 GETMBR R2 R2 K10 - 0x8C08050B, // 0023 GETMET R2 R2 K11 - 0x5C100200, // 0024 MOVE R4 R1 - 0x7C080400, // 0025 CALL R2 2 - 0x000A1002, // 0026 ADD R2 K8 R2 - 0x80040400, // 0027 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: is_commissioning_open -********************************************************************/ -be_local_closure(Matter_Device_is_commissioning_open, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(commissioning_open), - }), - be_str_weak(is_commissioning_open), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x20040202, // 0002 NE R1 R1 R2 - 0x80040200, // 0003 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: sort_distinct -********************************************************************/ -be_local_closure(Matter_Device_sort_distinct, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Device), - /* K1 */ be_const_int(1), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(stop_iteration), - /* K4 */ be_nested_str_weak(remove), - }), - be_str_weak(sort_distinct), - &be_const_str_solidified, - ( &(const binstruction[53]) { /* code */ - 0x58040000, // 0000 LDCONST R1 K0 - 0x60080010, // 0001 GETGBL R2 G16 - 0x600C000C, // 0002 GETGBL R3 G12 - 0x5C100000, // 0003 MOVE R4 R0 - 0x7C0C0200, // 0004 CALL R3 1 - 0x040C0701, // 0005 SUB R3 R3 K1 - 0x400E0203, // 0006 CONNECT R3 K1 R3 - 0x7C080200, // 0007 CALL R2 1 - 0xA8020010, // 0008 EXBLK 0 #001A - 0x5C0C0400, // 0009 MOVE R3 R2 - 0x7C0C0000, // 000A CALL R3 0 - 0x94100003, // 000B GETIDX R4 R0 R3 - 0x5C140600, // 000C MOVE R5 R3 - 0x24180B02, // 000D GT R6 R5 K2 - 0x781A0008, // 000E JMPF R6 #0018 - 0x04180B01, // 000F SUB R6 R5 K1 - 0x94180006, // 0010 GETIDX R6 R0 R6 - 0x24180C04, // 0011 GT R6 R6 R4 - 0x781A0004, // 0012 JMPF R6 #0018 - 0x04180B01, // 0013 SUB R6 R5 K1 - 0x94180006, // 0014 GETIDX R6 R0 R6 - 0x98000A06, // 0015 SETIDX R0 R5 R6 - 0x04140B01, // 0016 SUB R5 R5 K1 - 0x7001FFF4, // 0017 JMP #000D - 0x98000A04, // 0018 SETIDX R0 R5 R4 - 0x7001FFEE, // 0019 JMP #0009 - 0x58080003, // 001A LDCONST R2 K3 - 0xAC080200, // 001B CATCH R2 1 0 - 0xB0080000, // 001C RAISE 2 R0 R0 - 0x58080001, // 001D LDCONST R2 K1 - 0x600C000C, // 001E GETGBL R3 G12 - 0x5C100000, // 001F MOVE R4 R0 - 0x7C0C0200, // 0020 CALL R3 1 - 0x180C0701, // 0021 LE R3 R3 K1 - 0x780E0000, // 0022 JMPF R3 #0024 - 0x80040000, // 0023 RET 1 R0 - 0x940C0102, // 0024 GETIDX R3 R0 K2 - 0x6010000C, // 0025 GETGBL R4 G12 - 0x5C140000, // 0026 MOVE R5 R0 - 0x7C100200, // 0027 CALL R4 1 - 0x14100404, // 0028 LT R4 R2 R4 - 0x78120009, // 0029 JMPF R4 #0034 - 0x94100002, // 002A GETIDX R4 R0 R2 - 0x1C100803, // 002B EQ R4 R4 R3 - 0x78120003, // 002C JMPF R4 #0031 - 0x8C100104, // 002D GETMET R4 R0 K4 - 0x5C180400, // 002E MOVE R6 R2 - 0x7C100400, // 002F CALL R4 2 - 0x70020001, // 0030 JMP #0033 - 0x940C0002, // 0031 GETIDX R3 R0 R2 - 0x00080501, // 0032 ADD R2 R2 K1 - 0x7001FFF0, // 0033 JMP #0025 - 0x80040000, // 0034 RET 1 R0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: is_root_commissioning_open -********************************************************************/ -be_local_closure(Matter_Device_is_root_commissioning_open, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(commissioning_open), - /* K1 */ be_nested_str_weak(commissioning_admin_fabric), - }), - be_str_weak(is_root_commissioning_open), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x20040202, // 0002 NE R1 R1 R2 - 0x78060003, // 0003 JMPF R1 #0008 - 0x88040101, // 0004 GETMBR R1 R0 K1 - 0x4C080000, // 0005 LDNIL R2 - 0x1C040202, // 0006 EQ R1 R1 R2 - 0x74060000, // 0007 JMPT R1 #0009 - 0x50040001, // 0008 LDBOOL R1 0 1 - 0x50040200, // 0009 LDBOOL R1 1 0 - 0x80040200, // 000A RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_operational_discovery_deferred -********************************************************************/ -be_local_closure(Matter_Device_start_operational_discovery_deferred, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 3, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 2]) { /* upvals */ - be_local_const_upval(1, 0), - be_local_const_upval(1, 1), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(start_operational_discovery), - }), - be_str_weak(_X3Clambda_X3E), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x68080001, // 0002 GETUPV R2 U1 - 0x7C000400, // 0003 CALL R0 2 - 0x80040000, // 0004 RET 1 R0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(set_timer), - /* K2 */ be_const_int(0), - }), - be_str_weak(start_operational_discovery_deferred), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x58100002, // 0002 LDCONST R4 K2 - 0x84140000, // 0003 CLOSURE R5 P0 - 0x7C080600, // 0004 CALL R2 3 - 0xA0000000, // 0005 CLOSE R0 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: k2l -********************************************************************/ -be_local_closure(Matter_Device_k2l, /* name */ - be_nested_proto( - 8, /* nstack */ - 1, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Device), - /* K1 */ be_nested_str_weak(keys), - /* K2 */ be_nested_str_weak(push), - /* K3 */ be_nested_str_weak(stop_iteration), - /* K4 */ be_const_int(1), - /* K5 */ be_const_int(0), - }), - be_str_weak(k2l), - &be_const_str_solidified, - ( &(const binstruction[50]) { /* code */ - 0x58040000, // 0000 LDCONST R1 K0 - 0x60080012, // 0001 GETGBL R2 G18 - 0x7C080000, // 0002 CALL R2 0 - 0x4C0C0000, // 0003 LDNIL R3 - 0x1C0C0003, // 0004 EQ R3 R0 R3 - 0x780E0000, // 0005 JMPF R3 #0007 - 0x80040400, // 0006 RET 1 R2 - 0x600C0010, // 0007 GETGBL R3 G16 - 0x8C100101, // 0008 GETMET R4 R0 K1 - 0x7C100200, // 0009 CALL R4 1 - 0x7C0C0200, // 000A CALL R3 1 - 0xA8020005, // 000B EXBLK 0 #0012 - 0x5C100600, // 000C MOVE R4 R3 - 0x7C100000, // 000D CALL R4 0 - 0x8C140502, // 000E GETMET R5 R2 K2 - 0x5C1C0800, // 000F MOVE R7 R4 - 0x7C140400, // 0010 CALL R5 2 - 0x7001FFF9, // 0011 JMP #000C - 0x580C0003, // 0012 LDCONST R3 K3 - 0xAC0C0200, // 0013 CATCH R3 1 0 - 0xB0080000, // 0014 RAISE 2 R0 R0 - 0x600C0010, // 0015 GETGBL R3 G16 - 0x6010000C, // 0016 GETGBL R4 G12 - 0x5C140400, // 0017 MOVE R5 R2 - 0x7C100200, // 0018 CALL R4 1 - 0x04100904, // 0019 SUB R4 R4 K4 - 0x40120804, // 001A CONNECT R4 K4 R4 - 0x7C0C0200, // 001B CALL R3 1 - 0xA8020010, // 001C EXBLK 0 #002E - 0x5C100600, // 001D MOVE R4 R3 - 0x7C100000, // 001E CALL R4 0 - 0x94140404, // 001F GETIDX R5 R2 R4 - 0x5C180800, // 0020 MOVE R6 R4 - 0x241C0D05, // 0021 GT R7 R6 K5 - 0x781E0008, // 0022 JMPF R7 #002C - 0x041C0D04, // 0023 SUB R7 R6 K4 - 0x941C0407, // 0024 GETIDX R7 R2 R7 - 0x241C0E05, // 0025 GT R7 R7 R5 - 0x781E0004, // 0026 JMPF R7 #002C - 0x041C0D04, // 0027 SUB R7 R6 K4 - 0x941C0407, // 0028 GETIDX R7 R2 R7 - 0x98080C07, // 0029 SETIDX R2 R6 R7 - 0x04180D04, // 002A SUB R6 R6 K4 - 0x7001FFF4, // 002B JMP #0021 - 0x98080C05, // 002C SETIDX R2 R6 R5 - 0x7001FFEE, // 002D JMP #001D - 0x580C0003, // 002E LDCONST R3 K3 - 0xAC0C0200, // 002F CATCH R3 1 0 - 0xB0080000, // 0030 RAISE 2 R0 R0 - 0x80040400, // 0031 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: compute_manual_pairing_code -********************************************************************/ -be_local_closure(Matter_Device_compute_manual_pairing_code, /* name */ - be_nested_proto( - 9, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(root_discriminator), - /* K1 */ be_nested_str_weak(root_passcode), - /* K2 */ be_nested_str_weak(_X251i_X2505i_X2504i), - /* K3 */ be_nested_str_weak(matter), - /* K4 */ be_nested_str_weak(Verhoeff), - /* K5 */ be_nested_str_weak(checksum), - }), - be_str_weak(compute_manual_pairing_code), - &be_const_str_solidified, - ( &(const binstruction[30]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x540A0FFE, // 0001 LDINT R2 4095 - 0x2C040202, // 0002 AND R1 R1 R2 - 0x540A0009, // 0003 LDINT R2 10 - 0x3C040202, // 0004 SHR R1 R1 R2 - 0x88080100, // 0005 GETMBR R2 R0 K0 - 0x540E02FF, // 0006 LDINT R3 768 - 0x2C080403, // 0007 AND R2 R2 R3 - 0x540E0005, // 0008 LDINT R3 6 - 0x38080403, // 0009 SHL R2 R2 R3 - 0x880C0101, // 000A GETMBR R3 R0 K1 - 0x54123FFE, // 000B LDINT R4 16383 - 0x2C0C0604, // 000C AND R3 R3 R4 - 0x30080403, // 000D OR R2 R2 R3 - 0x880C0101, // 000E GETMBR R3 R0 K1 - 0x5412000D, // 000F LDINT R4 14 - 0x3C0C0604, // 0010 SHR R3 R3 R4 - 0x60100018, // 0011 GETGBL R4 G24 - 0x58140002, // 0012 LDCONST R5 K2 - 0x5C180200, // 0013 MOVE R6 R1 - 0x5C1C0400, // 0014 MOVE R7 R2 - 0x5C200600, // 0015 MOVE R8 R3 - 0x7C100800, // 0016 CALL R4 4 - 0xB8160600, // 0017 GETNGBL R5 K3 - 0x88140B04, // 0018 GETMBR R5 R5 K4 - 0x8C140B05, // 0019 GETMET R5 R5 K5 - 0x5C1C0800, // 001A MOVE R7 R4 - 0x7C140400, // 001B CALL R5 2 - 0x00100805, // 001C ADD R4 R4 R5 - 0x80040800, // 001D RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: event_fabrics_saved -********************************************************************/ -be_local_closure(Matter_Device_event_fabrics_saved, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(count_active_fabrics), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(plugins_persist), - /* K4 */ be_nested_str_weak(save_param), - }), - be_str_weak(event_fabrics_saved), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x24040302, // 0003 GT R1 R1 K2 - 0x78060005, // 0004 JMPF R1 #000B - 0x88040103, // 0005 GETMBR R1 R0 K3 - 0x74060003, // 0006 JMPT R1 #000B - 0x50040200, // 0007 LDBOOL R1 1 0 - 0x90020601, // 0008 SETMBR R0 K3 R1 - 0x8C040104, // 0009 GETMET R1 R0 K4 - 0x7C040200, // 000A CALL R1 1 - 0x80000000, // 000B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_commissioning_complete_deferred -********************************************************************/ -be_local_closure(Matter_Device_start_commissioning_complete_deferred, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 3, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 2]) { /* upvals */ - be_local_const_upval(1, 0), - be_local_const_upval(1, 1), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(start_commissioning_complete), - }), - be_str_weak(_X3Clambda_X3E), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x68080001, // 0002 GETUPV R2 U1 - 0x7C000400, // 0003 CALL R0 2 - 0x80040000, // 0004 RET 1 R0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(set_timer), - /* K2 */ be_const_int(0), - }), - be_str_weak(start_commissioning_complete_deferred), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x58100002, // 0002 LDCONST R4 K2 - 0x84140000, // 0003 CLOSURE R5 P0 - 0x7C080600, // 0004 CALL R2 3 - 0xA0000000, // 0005 CLOSE R0 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: mdns_announce_op_discovery -********************************************************************/ -be_local_closure(Matter_Device_mdns_announce_op_discovery, /* name */ - be_nested_proto( - 14, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[27]) { /* constants */ - /* K0 */ be_nested_str_weak(mdns), - /* K1 */ be_nested_str_weak(get_device_id), - /* K2 */ be_nested_str_weak(copy), - /* K3 */ be_nested_str_weak(reverse), - /* K4 */ be_nested_str_weak(get_fabric_compressed), - /* K5 */ be_nested_str_weak(tohex), - /* K6 */ be_nested_str_weak(_X2D), - /* K7 */ be_nested_str_weak(tasmota), - /* K8 */ be_nested_str_weak(log), - /* K9 */ be_nested_str_weak(MTR_X3A_X20Operational_X20Discovery_X20node_X20_X3D_X20), - /* K10 */ be_const_int(3), - /* K11 */ be_nested_str_weak(eth), - /* K12 */ be_nested_str_weak(find), - /* K13 */ be_nested_str_weak(up), - /* K14 */ be_nested_str_weak(MTR_X3A_X20adding_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27_X20ptr_X20to_X20_X60_X25s_X2Elocal_X60), - /* K15 */ be_nested_str_weak(hostname_eth), - /* K16 */ be_nested_str_weak(add_service), - /* K17 */ be_nested_str_weak(_matter), - /* K18 */ be_nested_str_weak(_tcp), - /* K19 */ be_nested_str_weak(_I), - /* K20 */ be_nested_str_weak(MTR_X3A_X20adding_X20subtype_X3A_X20), - /* K21 */ be_nested_str_weak(add_subtype), - /* K22 */ be_nested_str_weak(wifi), - /* K23 */ be_nested_str_weak(hostname_wifi), - /* K24 */ be_nested_str_weak(MTR_X3A_X20Exception), - /* K25 */ be_nested_str_weak(_X7C), - /* K26 */ be_const_int(2), - }), - be_str_weak(mdns_announce_op_discovery), - &be_const_str_solidified, - ( &(const binstruction[121]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0xA8020064, // 0001 EXBLK 0 #0067 - 0x8C0C0301, // 0002 GETMET R3 R1 K1 - 0x7C0C0200, // 0003 CALL R3 1 - 0x8C0C0702, // 0004 GETMET R3 R3 K2 - 0x7C0C0200, // 0005 CALL R3 1 - 0x8C0C0703, // 0006 GETMET R3 R3 K3 - 0x7C0C0200, // 0007 CALL R3 1 - 0x8C100304, // 0008 GETMET R4 R1 K4 - 0x7C100200, // 0009 CALL R4 1 - 0x8C140905, // 000A GETMET R5 R4 K5 - 0x7C140200, // 000B CALL R5 1 - 0x00140B06, // 000C ADD R5 R5 K6 - 0x8C180705, // 000D GETMET R6 R3 K5 - 0x7C180200, // 000E CALL R6 1 - 0x00140A06, // 000F ADD R5 R5 R6 - 0xB81A0E00, // 0010 GETNGBL R6 K7 - 0x8C180D08, // 0011 GETMET R6 R6 K8 - 0x00221205, // 0012 ADD R8 K9 R5 - 0x5824000A, // 0013 LDCONST R9 K10 - 0x7C180600, // 0014 CALL R6 3 - 0xB81A0E00, // 0015 GETNGBL R6 K7 - 0x8C180D0B, // 0016 GETMET R6 R6 K11 - 0x7C180200, // 0017 CALL R6 1 - 0x8C180D0C, // 0018 GETMET R6 R6 K12 - 0x5820000D, // 0019 LDCONST R8 K13 - 0x7C180400, // 001A CALL R6 2 - 0x781A0020, // 001B JMPF R6 #003D - 0xB81A0E00, // 001C GETNGBL R6 K7 - 0x8C180D08, // 001D GETMET R6 R6 K8 - 0x60200018, // 001E GETGBL R8 G24 - 0x5824000E, // 001F LDCONST R9 K14 - 0x5828000B, // 0020 LDCONST R10 K11 - 0x5C2C0A00, // 0021 MOVE R11 R5 - 0x8830010F, // 0022 GETMBR R12 R0 K15 - 0x7C200800, // 0023 CALL R8 4 - 0x5824000A, // 0024 LDCONST R9 K10 - 0x7C180600, // 0025 CALL R6 3 - 0x8C180510, // 0026 GETMET R6 R2 K16 - 0x58200011, // 0027 LDCONST R8 K17 - 0x58240012, // 0028 LDCONST R9 K18 - 0x542A15A3, // 0029 LDINT R10 5540 - 0x4C2C0000, // 002A LDNIL R11 - 0x5C300A00, // 002B MOVE R12 R5 - 0x8834010F, // 002C GETMBR R13 R0 K15 - 0x7C180E00, // 002D CALL R6 7 - 0x8C180905, // 002E GETMET R6 R4 K5 - 0x7C180200, // 002F CALL R6 1 - 0x001A2606, // 0030 ADD R6 K19 R6 - 0xB81E0E00, // 0031 GETNGBL R7 K7 - 0x8C1C0F08, // 0032 GETMET R7 R7 K8 - 0x00262806, // 0033 ADD R9 K20 R6 - 0x5828000A, // 0034 LDCONST R10 K10 - 0x7C1C0600, // 0035 CALL R7 3 - 0x8C1C0515, // 0036 GETMET R7 R2 K21 - 0x58240011, // 0037 LDCONST R9 K17 - 0x58280012, // 0038 LDCONST R10 K18 - 0x5C2C0A00, // 0039 MOVE R11 R5 - 0x8830010F, // 003A GETMBR R12 R0 K15 - 0x5C340C00, // 003B MOVE R13 R6 - 0x7C1C0C00, // 003C CALL R7 6 - 0xB81A0E00, // 003D GETNGBL R6 K7 - 0x8C180D16, // 003E GETMET R6 R6 K22 - 0x7C180200, // 003F CALL R6 1 - 0x8C180D0C, // 0040 GETMET R6 R6 K12 - 0x5820000D, // 0041 LDCONST R8 K13 - 0x7C180400, // 0042 CALL R6 2 - 0x781A0020, // 0043 JMPF R6 #0065 - 0xB81A0E00, // 0044 GETNGBL R6 K7 - 0x8C180D08, // 0045 GETMET R6 R6 K8 - 0x60200018, // 0046 GETGBL R8 G24 - 0x5824000E, // 0047 LDCONST R9 K14 - 0x58280016, // 0048 LDCONST R10 K22 - 0x5C2C0A00, // 0049 MOVE R11 R5 - 0x88300117, // 004A GETMBR R12 R0 K23 - 0x7C200800, // 004B CALL R8 4 - 0x5824000A, // 004C LDCONST R9 K10 - 0x7C180600, // 004D CALL R6 3 - 0x8C180510, // 004E GETMET R6 R2 K16 - 0x58200011, // 004F LDCONST R8 K17 - 0x58240012, // 0050 LDCONST R9 K18 - 0x542A15A3, // 0051 LDINT R10 5540 - 0x4C2C0000, // 0052 LDNIL R11 - 0x5C300A00, // 0053 MOVE R12 R5 - 0x88340117, // 0054 GETMBR R13 R0 K23 - 0x7C180E00, // 0055 CALL R6 7 - 0x8C180905, // 0056 GETMET R6 R4 K5 - 0x7C180200, // 0057 CALL R6 1 - 0x001A2606, // 0058 ADD R6 K19 R6 - 0xB81E0E00, // 0059 GETNGBL R7 K7 - 0x8C1C0F08, // 005A GETMET R7 R7 K8 - 0x00262806, // 005B ADD R9 K20 R6 - 0x5828000A, // 005C LDCONST R10 K10 - 0x7C1C0600, // 005D CALL R7 3 - 0x8C1C0515, // 005E GETMET R7 R2 K21 - 0x58240011, // 005F LDCONST R9 K17 - 0x58280012, // 0060 LDCONST R10 K18 - 0x5C2C0A00, // 0061 MOVE R11 R5 - 0x88300117, // 0062 GETMBR R12 R0 K23 - 0x5C340C00, // 0063 MOVE R13 R6 - 0x7C1C0C00, // 0064 CALL R7 6 - 0xA8040001, // 0065 EXBLK 1 1 - 0x70020010, // 0066 JMP #0078 - 0xAC0C0002, // 0067 CATCH R3 0 2 - 0x7002000D, // 0068 JMP #0077 - 0xB8160E00, // 0069 GETNGBL R5 K7 - 0x8C140B08, // 006A GETMET R5 R5 K8 - 0x601C0008, // 006B GETGBL R7 G8 - 0x5C200600, // 006C MOVE R8 R3 - 0x7C1C0200, // 006D CALL R7 1 - 0x001E3007, // 006E ADD R7 K24 R7 - 0x001C0F19, // 006F ADD R7 R7 K25 - 0x60200008, // 0070 GETGBL R8 G8 - 0x5C240800, // 0071 MOVE R9 R4 - 0x7C200200, // 0072 CALL R8 1 - 0x001C0E08, // 0073 ADD R7 R7 R8 - 0x5820001A, // 0074 LDCONST R8 K26 - 0x7C140600, // 0075 CALL R5 3 - 0x70020000, // 0076 JMP #0078 - 0xB0080000, // 0077 RAISE 2 R0 R0 - 0x80000000, // 0078 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: msg_send -********************************************************************/ -be_local_closure(Matter_Device_msg_send, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(udp_server), - /* K1 */ be_nested_str_weak(send_UDP), - }), - be_str_weak(msg_send), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C080400, // 0003 CALL R2 2 - 0x80040400, // 0004 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_plugin_by_endpoint -********************************************************************/ -be_local_closure(Matter_Device_find_plugin_by_endpoint, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(plugins), - /* K2 */ be_nested_str_weak(get_endpoint), - /* K3 */ be_const_int(1), - }), - be_str_weak(find_plugin_by_endpoint), - &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x600C000C, // 0001 GETGBL R3 G12 - 0x88100101, // 0002 GETMBR R4 R0 K1 - 0x7C0C0200, // 0003 CALL R3 1 - 0x140C0403, // 0004 LT R3 R2 R3 - 0x780E0008, // 0005 JMPF R3 #000F - 0x880C0101, // 0006 GETMBR R3 R0 K1 - 0x940C0602, // 0007 GETIDX R3 R3 R2 - 0x8C100702, // 0008 GETMET R4 R3 K2 - 0x7C100200, // 0009 CALL R4 1 - 0x1C100801, // 000A EQ R4 R4 R1 - 0x78120000, // 000B JMPF R4 #000D - 0x80040600, // 000C RET 1 R3 - 0x00080503, // 000D ADD R2 R2 K3 - 0x7001FFF1, // 000E JMP #0001 - 0x4C0C0000, // 000F LDNIL R3 - 0x80040600, // 0010 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: mdns_remove_op_discovery -********************************************************************/ -be_local_closure(Matter_Device_mdns_remove_op_discovery, /* name */ - be_nested_proto( - 12, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[23]) { /* constants */ - /* K0 */ be_nested_str_weak(mdns), - /* K1 */ be_nested_str_weak(get_device_id), - /* K2 */ be_nested_str_weak(copy), - /* K3 */ be_nested_str_weak(reverse), - /* K4 */ be_nested_str_weak(get_fabric_compressed), - /* K5 */ be_nested_str_weak(tohex), - /* K6 */ be_nested_str_weak(_X2D), - /* K7 */ be_nested_str_weak(tasmota), - /* K8 */ be_nested_str_weak(eth), - /* K9 */ be_nested_str_weak(find), - /* K10 */ be_nested_str_weak(up), - /* K11 */ be_nested_str_weak(log), - /* K12 */ be_nested_str_weak(MTR_X3A_X20remove_X20mDNS_X20on_X20_X25s_X20_X27_X25s_X27), - /* K13 */ be_const_int(3), - /* K14 */ be_nested_str_weak(remove_service), - /* K15 */ be_nested_str_weak(_matter), - /* K16 */ be_nested_str_weak(_tcp), - /* K17 */ be_nested_str_weak(hostname_eth), - /* K18 */ be_nested_str_weak(wifi), - /* K19 */ be_nested_str_weak(hostname_wifi), - /* K20 */ be_nested_str_weak(MTR_X3A_X20Exception), - /* K21 */ be_nested_str_weak(_X7C), - /* K22 */ be_const_int(2), - }), - be_str_weak(mdns_remove_op_discovery), - &be_const_str_solidified, - ( &(const binstruction[80]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0xA802003B, // 0001 EXBLK 0 #003E - 0x8C0C0301, // 0002 GETMET R3 R1 K1 - 0x7C0C0200, // 0003 CALL R3 1 - 0x8C0C0702, // 0004 GETMET R3 R3 K2 - 0x7C0C0200, // 0005 CALL R3 1 - 0x8C0C0703, // 0006 GETMET R3 R3 K3 - 0x7C0C0200, // 0007 CALL R3 1 - 0x8C100304, // 0008 GETMET R4 R1 K4 - 0x7C100200, // 0009 CALL R4 1 - 0x8C140905, // 000A GETMET R5 R4 K5 - 0x7C140200, // 000B CALL R5 1 - 0x00140B06, // 000C ADD R5 R5 K6 - 0x8C180705, // 000D GETMET R6 R3 K5 - 0x7C180200, // 000E CALL R6 1 - 0x00140A06, // 000F ADD R5 R5 R6 - 0xB81A0E00, // 0010 GETNGBL R6 K7 - 0x8C180D08, // 0011 GETMET R6 R6 K8 - 0x7C180200, // 0012 CALL R6 1 - 0x8C180D09, // 0013 GETMET R6 R6 K9 - 0x5820000A, // 0014 LDCONST R8 K10 - 0x7C180400, // 0015 CALL R6 2 - 0x781A000E, // 0016 JMPF R6 #0026 - 0xB81A0E00, // 0017 GETNGBL R6 K7 - 0x8C180D0B, // 0018 GETMET R6 R6 K11 - 0x60200018, // 0019 GETGBL R8 G24 - 0x5824000C, // 001A LDCONST R9 K12 - 0x58280008, // 001B LDCONST R10 K8 - 0x5C2C0A00, // 001C MOVE R11 R5 - 0x7C200600, // 001D CALL R8 3 - 0x5824000D, // 001E LDCONST R9 K13 - 0x7C180600, // 001F CALL R6 3 - 0x8C18050E, // 0020 GETMET R6 R2 K14 - 0x5820000F, // 0021 LDCONST R8 K15 - 0x58240010, // 0022 LDCONST R9 K16 - 0x5C280A00, // 0023 MOVE R10 R5 - 0x882C0111, // 0024 GETMBR R11 R0 K17 - 0x7C180A00, // 0025 CALL R6 5 - 0xB81A0E00, // 0026 GETNGBL R6 K7 - 0x8C180D12, // 0027 GETMET R6 R6 K18 - 0x7C180200, // 0028 CALL R6 1 - 0x8C180D09, // 0029 GETMET R6 R6 K9 - 0x5820000A, // 002A LDCONST R8 K10 - 0x7C180400, // 002B CALL R6 2 - 0x781A000E, // 002C JMPF R6 #003C - 0xB81A0E00, // 002D GETNGBL R6 K7 - 0x8C180D0B, // 002E GETMET R6 R6 K11 - 0x60200018, // 002F GETGBL R8 G24 - 0x5824000C, // 0030 LDCONST R9 K12 - 0x58280012, // 0031 LDCONST R10 K18 - 0x5C2C0A00, // 0032 MOVE R11 R5 - 0x7C200600, // 0033 CALL R8 3 - 0x5824000D, // 0034 LDCONST R9 K13 - 0x7C180600, // 0035 CALL R6 3 - 0x8C18050E, // 0036 GETMET R6 R2 K14 - 0x5820000F, // 0037 LDCONST R8 K15 - 0x58240010, // 0038 LDCONST R9 K16 - 0x5C280A00, // 0039 MOVE R10 R5 - 0x882C0113, // 003A GETMBR R11 R0 K19 - 0x7C180A00, // 003B CALL R6 5 - 0xA8040001, // 003C EXBLK 1 1 - 0x70020010, // 003D JMP #004F - 0xAC0C0002, // 003E CATCH R3 0 2 - 0x7002000D, // 003F JMP #004E - 0xB8160E00, // 0040 GETNGBL R5 K7 - 0x8C140B0B, // 0041 GETMET R5 R5 K11 - 0x601C0008, // 0042 GETGBL R7 G8 - 0x5C200600, // 0043 MOVE R8 R3 - 0x7C1C0200, // 0044 CALL R7 1 - 0x001E2807, // 0045 ADD R7 K20 R7 - 0x001C0F15, // 0046 ADD R7 R7 K21 - 0x60200008, // 0047 GETGBL R8 G8 - 0x5C240800, // 0048 MOVE R9 R4 - 0x7C200200, // 0049 CALL R8 1 - 0x001C0E08, // 004A ADD R7 R7 R8 - 0x58200016, // 004B LDCONST R8 K22 - 0x7C140600, // 004C CALL R5 3 - 0x70020000, // 004D JMP #004F - 0xB0080000, // 004E RAISE 2 R0 R0 - 0x80000000, // 004F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Device_init, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 2]) { - be_nested_proto( - 4, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(start), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(remove_rule), - /* K3 */ be_nested_str_weak(Wifi_X23Connected), - /* K4 */ be_nested_str_weak(matter_start), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x7C000200, // 0002 CALL R0 1 - 0xB8020200, // 0003 GETNGBL R0 K1 - 0x8C000102, // 0004 GETMET R0 R0 K2 - 0x58080003, // 0005 LDCONST R2 K3 - 0x580C0004, // 0006 LDCONST R3 K4 - 0x7C000600, // 0007 CALL R0 3 - 0x80000000, // 0008 RET 0 - }) - ), - be_nested_proto( - 4, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(start), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(remove_rule), - /* K3 */ be_nested_str_weak(Eth_X23Connected), - /* K4 */ be_nested_str_weak(matter_start), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x7C000200, // 0002 CALL R0 1 - 0xB8020200, // 0003 GETNGBL R0 K1 - 0x8C000102, // 0004 GETMET R0 R0 K2 - 0x58080003, // 0005 LDCONST R2 K3 - 0x580C0004, // 0006 LDCONST R3 K4 - 0x7C000600, // 0007 CALL R0 3 - 0x80000000, // 0008 RET 0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[46]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(get_option), - /* K3 */ be_nested_str_weak(matter), - /* K4 */ be_nested_str_weak(MATTER_OPTION), - /* K5 */ be_nested_str_weak(UI), - /* K6 */ be_nested_str_weak(profiler), - /* K7 */ be_nested_str_weak(Profiler), - /* K8 */ be_nested_str_weak(started), - /* K9 */ be_nested_str_weak(tick), - /* K10 */ be_const_int(0), - /* K11 */ be_nested_str_weak(plugins), - /* K12 */ be_nested_str_weak(plugins_persist), - /* K13 */ be_nested_str_weak(plugins_classes), - /* K14 */ be_nested_str_weak(plugins_config_remotes), - /* K15 */ be_nested_str_weak(register_native_classes), - /* K16 */ be_nested_str_weak(vendorid), - /* K17 */ be_nested_str_weak(VENDOR_ID), - /* K18 */ be_nested_str_weak(productid), - /* K19 */ be_nested_str_weak(PRODUCT_ID), - /* K20 */ be_nested_str_weak(root_iterations), - /* K21 */ be_nested_str_weak(PBKDF_ITERATIONS), - /* K22 */ be_nested_str_weak(next_ep), - /* K23 */ be_const_int(1), - /* K24 */ be_nested_str_weak(root_salt), - /* K25 */ be_nested_str_weak(random), - /* K26 */ be_nested_str_weak(ipv4only), - /* K27 */ be_nested_str_weak(disable_bridge_mode), - /* K28 */ be_nested_str_weak(load_param), - /* K29 */ be_nested_str_weak(sessions), - /* K30 */ be_nested_str_weak(Session_Store), - /* K31 */ be_nested_str_weak(load_fabrics), - /* K32 */ be_nested_str_weak(message_handler), - /* K33 */ be_nested_str_weak(MessageHandler), - /* K34 */ be_nested_str_weak(ui), - /* K35 */ be_nested_str_weak(wifi), - /* K36 */ be_nested_str_weak(up), - /* K37 */ be_nested_str_weak(eth), - /* K38 */ be_nested_str_weak(start), - /* K39 */ be_nested_str_weak(add_rule), - /* K40 */ be_nested_str_weak(Wifi_X23Connected), - /* K41 */ be_nested_str_weak(matter_start), - /* K42 */ be_nested_str_weak(Eth_X23Connected), - /* K43 */ be_nested_str_weak(_init_basic_commissioning), - /* K44 */ be_nested_str_weak(add_driver), - /* K45 */ be_nested_str_weak(register_commands), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[112]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xB80A0200, // 0001 GETNGBL R2 K1 - 0x8C080502, // 0002 GETMET R2 R2 K2 - 0xB8120600, // 0003 GETNGBL R4 K3 - 0x88100904, // 0004 GETMBR R4 R4 K4 - 0x7C080400, // 0005 CALL R2 2 - 0x740A0004, // 0006 JMPT R2 #000C - 0xB80A0600, // 0007 GETNGBL R2 K3 - 0x8C080505, // 0008 GETMET R2 R2 K5 - 0x5C100000, // 0009 MOVE R4 R0 - 0x7C080400, // 000A CALL R2 2 - 0x80000400, // 000B RET 0 - 0xB80A0600, // 000C GETNGBL R2 K3 - 0xB80E0600, // 000D GETNGBL R3 K3 - 0x8C0C0707, // 000E GETMET R3 R3 K7 - 0x7C0C0200, // 000F CALL R3 1 - 0x900A0C03, // 0010 SETMBR R2 K6 R3 - 0x50080000, // 0011 LDBOOL R2 0 0 - 0x90021002, // 0012 SETMBR R0 K8 R2 - 0x9002130A, // 0013 SETMBR R0 K9 K10 - 0x60080012, // 0014 GETGBL R2 G18 - 0x7C080000, // 0015 CALL R2 0 - 0x90021602, // 0016 SETMBR R0 K11 R2 - 0x50080000, // 0017 LDBOOL R2 0 0 - 0x90021802, // 0018 SETMBR R0 K12 R2 - 0x60080013, // 0019 GETGBL R2 G19 - 0x7C080000, // 001A CALL R2 0 - 0x90021A02, // 001B SETMBR R0 K13 R2 - 0x60080013, // 001C GETGBL R2 G19 - 0x7C080000, // 001D CALL R2 0 - 0x90021C02, // 001E SETMBR R0 K14 R2 - 0x8C08010F, // 001F GETMET R2 R0 K15 - 0x7C080200, // 0020 CALL R2 1 - 0x88080111, // 0021 GETMBR R2 R0 K17 - 0x90022002, // 0022 SETMBR R0 K16 R2 - 0x88080113, // 0023 GETMBR R2 R0 K19 - 0x90022402, // 0024 SETMBR R0 K18 R2 - 0x88080115, // 0025 GETMBR R2 R0 K21 - 0x90022802, // 0026 SETMBR R0 K20 R2 - 0x90022D17, // 0027 SETMBR R0 K22 K23 - 0x8C080319, // 0028 GETMET R2 R1 K25 - 0x5412000F, // 0029 LDINT R4 16 - 0x7C080400, // 002A CALL R2 2 - 0x90023002, // 002B SETMBR R0 K24 R2 - 0x50080000, // 002C LDBOOL R2 0 0 - 0x90023402, // 002D SETMBR R0 K26 R2 - 0x50080000, // 002E LDBOOL R2 0 0 - 0x90023602, // 002F SETMBR R0 K27 R2 - 0x8C08011C, // 0030 GETMET R2 R0 K28 - 0x7C080200, // 0031 CALL R2 1 - 0xB80A0600, // 0032 GETNGBL R2 K3 - 0x8C08051E, // 0033 GETMET R2 R2 K30 - 0x5C100000, // 0034 MOVE R4 R0 - 0x7C080400, // 0035 CALL R2 2 - 0x90023A02, // 0036 SETMBR R0 K29 R2 - 0x8808011D, // 0037 GETMBR R2 R0 K29 - 0x8C08051F, // 0038 GETMET R2 R2 K31 - 0x7C080200, // 0039 CALL R2 1 - 0xB80A0600, // 003A GETNGBL R2 K3 - 0x8C080521, // 003B GETMET R2 R2 K33 - 0x5C100000, // 003C MOVE R4 R0 - 0x7C080400, // 003D CALL R2 2 - 0x90024002, // 003E SETMBR R0 K32 R2 - 0xB80A0600, // 003F GETNGBL R2 K3 - 0x8C080505, // 0040 GETMET R2 R2 K5 - 0x5C100000, // 0041 MOVE R4 R0 - 0x7C080400, // 0042 CALL R2 2 - 0x90024402, // 0043 SETMBR R0 K34 R2 - 0xB80A0200, // 0044 GETNGBL R2 K1 - 0x8C080523, // 0045 GETMET R2 R2 K35 - 0x7C080200, // 0046 CALL R2 1 - 0x94080524, // 0047 GETIDX R2 R2 K36 - 0x740A0004, // 0048 JMPT R2 #004E - 0xB80A0200, // 0049 GETNGBL R2 K1 - 0x8C080525, // 004A GETMET R2 R2 K37 - 0x7C080200, // 004B CALL R2 1 - 0x94080524, // 004C GETIDX R2 R2 K36 - 0x780A0001, // 004D JMPF R2 #0050 - 0x8C080126, // 004E GETMET R2 R0 K38 - 0x7C080200, // 004F CALL R2 1 - 0xB80A0200, // 0050 GETNGBL R2 K1 - 0x8C080523, // 0051 GETMET R2 R2 K35 - 0x7C080200, // 0052 CALL R2 1 - 0x94080524, // 0053 GETIDX R2 R2 K36 - 0x740A0005, // 0054 JMPT R2 #005B - 0xB80A0200, // 0055 GETNGBL R2 K1 - 0x8C080527, // 0056 GETMET R2 R2 K39 - 0x58100028, // 0057 LDCONST R4 K40 - 0x84140000, // 0058 CLOSURE R5 P0 - 0x58180029, // 0059 LDCONST R6 K41 - 0x7C080800, // 005A CALL R2 4 - 0xB80A0200, // 005B GETNGBL R2 K1 - 0x8C080525, // 005C GETMET R2 R2 K37 - 0x7C080200, // 005D CALL R2 1 - 0x94080524, // 005E GETIDX R2 R2 K36 - 0x740A0005, // 005F JMPT R2 #0066 - 0xB80A0200, // 0060 GETNGBL R2 K1 - 0x8C080527, // 0061 GETMET R2 R2 K39 - 0x5810002A, // 0062 LDCONST R4 K42 - 0x84140001, // 0063 CLOSURE R5 P1 - 0x58180029, // 0064 LDCONST R6 K41 - 0x7C080800, // 0065 CALL R2 4 - 0x8C08012B, // 0066 GETMET R2 R0 K43 - 0x7C080200, // 0067 CALL R2 1 - 0xB80A0200, // 0068 GETNGBL R2 K1 - 0x8C08052C, // 0069 GETMET R2 R2 K44 - 0x5C100000, // 006A MOVE R4 R0 - 0x7C080400, // 006B CALL R2 2 - 0x8C08012D, // 006C GETMET R2 R0 K45 - 0x7C080200, // 006D CALL R2 1 - 0xA0000000, // 006E CLOSE R0 - 0x80000000, // 006F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: _start_udp -********************************************************************/ -be_local_closure(Matter_Device__start_udp, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 8, /* nstack */ - 3, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(msg_received), - }), - be_str_weak(_X3Clambda_X3E), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x680C0000, // 0000 GETUPV R3 U0 - 0x8C0C0700, // 0001 GETMET R3 R3 K0 - 0x5C140000, // 0002 MOVE R5 R0 - 0x5C180200, // 0003 MOVE R6 R1 - 0x5C1C0400, // 0004 MOVE R7 R2 - 0x7C0C0800, // 0005 CALL R3 4 - 0x80040600, // 0006 RET 1 R3 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(udp_server), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(log), - /* K3 */ be_nested_str_weak(MTR_X3A_X20Starting_X20UDP_X20server_X20on_X20port_X3A_X20), - /* K4 */ be_const_int(2), - /* K5 */ be_nested_str_weak(matter), - /* K6 */ be_nested_str_weak(UDPServer), - /* K7 */ be_nested_str_weak(), - /* K8 */ be_nested_str_weak(start), - }), - be_str_weak(_start_udp), - &be_const_str_solidified, - ( &(const binstruction[28]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A0000, // 0001 JMPF R2 #0003 - 0x80000400, // 0002 RET 0 - 0x4C080000, // 0003 LDNIL R2 - 0x1C080202, // 0004 EQ R2 R1 R2 - 0x780A0000, // 0005 JMPF R2 #0007 - 0x540615A3, // 0006 LDINT R1 5540 - 0xB80A0200, // 0007 GETNGBL R2 K1 - 0x8C080502, // 0008 GETMET R2 R2 K2 - 0x60100008, // 0009 GETGBL R4 G8 - 0x5C140200, // 000A MOVE R5 R1 - 0x7C100200, // 000B CALL R4 1 - 0x00120604, // 000C ADD R4 K3 R4 - 0x58140004, // 000D LDCONST R5 K4 - 0x7C080600, // 000E CALL R2 3 - 0xB80A0A00, // 000F GETNGBL R2 K5 - 0x8C080506, // 0010 GETMET R2 R2 K6 - 0x5C100000, // 0011 MOVE R4 R0 - 0x58140007, // 0012 LDCONST R5 K7 - 0x5C180200, // 0013 MOVE R6 R1 - 0x7C080800, // 0014 CALL R2 4 - 0x90020002, // 0015 SETMBR R0 K0 R2 - 0x88080100, // 0016 GETMBR R2 R0 K0 - 0x8C080508, // 0017 GETMET R2 R2 K8 - 0x84100000, // 0018 CLOSURE R4 P0 - 0x7C080400, // 0019 CALL R2 2 - 0xA0000000, // 001A CLOSE R0 - 0x80000000, // 001B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: load_param -********************************************************************/ -be_local_closure(Matter_Device_load_param, /* name */ - be_nested_proto( - 11, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[35]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(FILENAME), - /* K2 */ be_nested_str_weak(read), - /* K3 */ be_nested_str_weak(close), - /* K4 */ be_nested_str_weak(json), - /* K5 */ be_nested_str_weak(load), - /* K6 */ be_nested_str_weak(root_discriminator), - /* K7 */ be_nested_str_weak(find), - /* K8 */ be_nested_str_weak(distinguish), - /* K9 */ be_nested_str_weak(root_passcode), - /* K10 */ be_nested_str_weak(passcode), - /* K11 */ be_nested_str_weak(ipv4only), - /* K12 */ be_nested_str_weak(disable_bridge_mode), - /* K13 */ be_nested_str_weak(next_ep), - /* K14 */ be_nested_str_weak(nextep), - /* K15 */ be_nested_str_weak(plugins_config), - /* K16 */ be_nested_str_weak(config), - /* K17 */ be_nested_str_weak(tasmota), - /* K18 */ be_nested_str_weak(log), - /* K19 */ be_nested_str_weak(MTR_X3A_X20load_config_X20_X3D_X20), - /* K20 */ be_const_int(3), - /* K21 */ be_nested_str_weak(adjust_next_ep), - /* K22 */ be_nested_str_weak(plugins_persist), - /* K23 */ be_nested_str_weak(plugins_config_remotes), - /* K24 */ be_nested_str_weak(remotes), - /* K25 */ be_nested_str_weak(MTR_X3A_X20load_remotes_X20_X3D_X20), - /* K26 */ be_nested_str_weak(io_error), - /* K27 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Aload_X20Exception_X3A), - /* K28 */ be_nested_str_weak(_X7C), - /* K29 */ be_const_int(2), - /* K30 */ be_nested_str_weak(random), - /* K31 */ be_nested_str_weak(get), - /* K32 */ be_const_int(0), - /* K33 */ be_nested_str_weak(generate_random_passcode), - /* K34 */ be_nested_str_weak(save_param), - }), - be_str_weak(load_param), - &be_const_str_solidified, - ( &(const binstruction[127]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xA802004D, // 0001 EXBLK 0 #0050 - 0x60080011, // 0002 GETGBL R2 G17 - 0x880C0101, // 0003 GETMBR R3 R0 K1 - 0x7C080200, // 0004 CALL R2 1 - 0x8C0C0502, // 0005 GETMET R3 R2 K2 - 0x7C0C0200, // 0006 CALL R3 1 - 0x8C100503, // 0007 GETMET R4 R2 K3 - 0x7C100200, // 0008 CALL R4 1 - 0xA4120800, // 0009 IMPORT R4 K4 - 0x8C140905, // 000A GETMET R5 R4 K5 - 0x5C1C0600, // 000B MOVE R7 R3 - 0x7C140400, // 000C CALL R5 2 - 0x8C180B07, // 000D GETMET R6 R5 K7 - 0x58200008, // 000E LDCONST R8 K8 - 0x88240106, // 000F GETMBR R9 R0 K6 - 0x7C180600, // 0010 CALL R6 3 - 0x90020C06, // 0011 SETMBR R0 K6 R6 - 0x8C180B07, // 0012 GETMET R6 R5 K7 - 0x5820000A, // 0013 LDCONST R8 K10 - 0x88240109, // 0014 GETMBR R9 R0 K9 - 0x7C180600, // 0015 CALL R6 3 - 0x90021206, // 0016 SETMBR R0 K9 R6 - 0x60180017, // 0017 GETGBL R6 G23 - 0x8C1C0B07, // 0018 GETMET R7 R5 K7 - 0x5824000B, // 0019 LDCONST R9 K11 - 0x50280000, // 001A LDBOOL R10 0 0 - 0x7C1C0600, // 001B CALL R7 3 - 0x7C180200, // 001C CALL R6 1 - 0x90021606, // 001D SETMBR R0 K11 R6 - 0x60180017, // 001E GETGBL R6 G23 - 0x8C1C0B07, // 001F GETMET R7 R5 K7 - 0x5824000C, // 0020 LDCONST R9 K12 - 0x50280000, // 0021 LDBOOL R10 0 0 - 0x7C1C0600, // 0022 CALL R7 3 - 0x7C180200, // 0023 CALL R6 1 - 0x90021806, // 0024 SETMBR R0 K12 R6 - 0x8C180B07, // 0025 GETMET R6 R5 K7 - 0x5820000E, // 0026 LDCONST R8 K14 - 0x8824010D, // 0027 GETMBR R9 R0 K13 - 0x7C180600, // 0028 CALL R6 3 - 0x90021A06, // 0029 SETMBR R0 K13 R6 - 0x8C180B07, // 002A GETMET R6 R5 K7 - 0x58200010, // 002B LDCONST R8 K16 - 0x7C180400, // 002C CALL R6 2 - 0x90021E06, // 002D SETMBR R0 K15 R6 - 0x8818010F, // 002E GETMBR R6 R0 K15 - 0x4C1C0000, // 002F LDNIL R7 - 0x20180C07, // 0030 NE R6 R6 R7 - 0x781A000B, // 0031 JMPF R6 #003E - 0xB81A2200, // 0032 GETNGBL R6 K17 - 0x8C180D12, // 0033 GETMET R6 R6 K18 - 0x60200008, // 0034 GETGBL R8 G8 - 0x8824010F, // 0035 GETMBR R9 R0 K15 - 0x7C200200, // 0036 CALL R8 1 - 0x00222608, // 0037 ADD R8 K19 R8 - 0x58240014, // 0038 LDCONST R9 K20 - 0x7C180600, // 0039 CALL R6 3 - 0x8C180115, // 003A GETMET R6 R0 K21 - 0x7C180200, // 003B CALL R6 1 - 0x50180200, // 003C LDBOOL R6 1 0 - 0x90022C06, // 003D SETMBR R0 K22 R6 - 0x8C180B07, // 003E GETMET R6 R5 K7 - 0x58200018, // 003F LDCONST R8 K24 - 0x60240013, // 0040 GETGBL R9 G19 - 0x7C240000, // 0041 CALL R9 0 - 0x7C180600, // 0042 CALL R6 3 - 0x90022E06, // 0043 SETMBR R0 K23 R6 - 0x88180117, // 0044 GETMBR R6 R0 K23 - 0x781A0007, // 0045 JMPF R6 #004E - 0xB81A2200, // 0046 GETNGBL R6 K17 - 0x8C180D12, // 0047 GETMET R6 R6 K18 - 0x60200008, // 0048 GETGBL R8 G8 - 0x88240117, // 0049 GETMBR R9 R0 K23 - 0x7C200200, // 004A CALL R8 1 - 0x00223208, // 004B ADD R8 K25 R8 - 0x58240014, // 004C LDCONST R9 K20 - 0x7C180600, // 004D CALL R6 3 - 0xA8040001, // 004E EXBLK 1 1 - 0x70020012, // 004F JMP #0063 - 0xAC080002, // 0050 CATCH R2 0 2 - 0x7002000F, // 0051 JMP #0062 - 0x2010051A, // 0052 NE R4 R2 K26 - 0x7812000C, // 0053 JMPF R4 #0061 - 0xB8122200, // 0054 GETNGBL R4 K17 - 0x8C100912, // 0055 GETMET R4 R4 K18 - 0x60180008, // 0056 GETGBL R6 G8 - 0x5C1C0400, // 0057 MOVE R7 R2 - 0x7C180200, // 0058 CALL R6 1 - 0x001A3606, // 0059 ADD R6 K27 R6 - 0x00180D1C, // 005A ADD R6 R6 K28 - 0x601C0008, // 005B GETGBL R7 G8 - 0x5C200600, // 005C MOVE R8 R3 - 0x7C1C0200, // 005D CALL R7 1 - 0x00180C07, // 005E ADD R6 R6 R7 - 0x581C001D, // 005F LDCONST R7 K29 - 0x7C100600, // 0060 CALL R4 3 - 0x70020000, // 0061 JMP #0063 - 0xB0080000, // 0062 RAISE 2 R0 R0 - 0x50080000, // 0063 LDBOOL R2 0 0 - 0x880C0106, // 0064 GETMBR R3 R0 K6 - 0x4C100000, // 0065 LDNIL R4 - 0x1C0C0604, // 0066 EQ R3 R3 R4 - 0x780E000A, // 0067 JMPF R3 #0073 - 0x8C0C031E, // 0068 GETMET R3 R1 K30 - 0x5814001D, // 0069 LDCONST R5 K29 - 0x7C0C0400, // 006A CALL R3 2 - 0x8C0C071F, // 006B GETMET R3 R3 K31 - 0x58140020, // 006C LDCONST R5 K32 - 0x5818001D, // 006D LDCONST R6 K29 - 0x7C0C0600, // 006E CALL R3 3 - 0x54120FFE, // 006F LDINT R4 4095 - 0x2C0C0604, // 0070 AND R3 R3 R4 - 0x90020C03, // 0071 SETMBR R0 K6 R3 - 0x50080200, // 0072 LDBOOL R2 1 0 - 0x880C0109, // 0073 GETMBR R3 R0 K9 - 0x4C100000, // 0074 LDNIL R4 - 0x1C0C0604, // 0075 EQ R3 R3 R4 - 0x780E0003, // 0076 JMPF R3 #007B - 0x8C0C0121, // 0077 GETMET R3 R0 K33 - 0x7C0C0200, // 0078 CALL R3 1 - 0x90021203, // 0079 SETMBR R0 K9 R3 - 0x50080200, // 007A LDBOOL R2 1 0 - 0x780A0001, // 007B JMPF R2 #007E - 0x8C0C0122, // 007C GETMET R3 R0 K34 - 0x7C0C0200, // 007D CALL R3 1 - 0x80000000, // 007E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: adjust_next_ep -********************************************************************/ -be_local_closure(Matter_Device_adjust_next_ep, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(plugins_config), - /* K1 */ be_nested_str_weak(keys), - /* K2 */ be_nested_str_weak(next_ep), - /* K3 */ be_const_int(1), - /* K4 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(adjust_next_ep), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x8C080501, // 0002 GETMET R2 R2 K1 - 0x7C080200, // 0003 CALL R2 1 - 0x7C040200, // 0004 CALL R1 1 - 0xA802000A, // 0005 EXBLK 0 #0011 - 0x5C080200, // 0006 MOVE R2 R1 - 0x7C080000, // 0007 CALL R2 0 - 0x600C0009, // 0008 GETGBL R3 G9 - 0x5C100400, // 0009 MOVE R4 R2 - 0x7C0C0200, // 000A CALL R3 1 - 0x88100102, // 000B GETMBR R4 R0 K2 - 0x28100604, // 000C GE R4 R3 R4 - 0x78120001, // 000D JMPF R4 #0010 - 0x00100703, // 000E ADD R4 R3 K3 - 0x90020404, // 000F SETMBR R0 K2 R4 - 0x7001FFF4, // 0010 JMP #0006 - 0x58040004, // 0011 LDCONST R1 K4 - 0xAC040200, // 0012 CATCH R1 1 0 - 0xB0080000, // 0013 RAISE 2 R0 R0 - 0x80000000, // 0014 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: register_commands -********************************************************************/ -be_local_closure(Matter_Device_register_commands, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 10, /* nstack */ - 4, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(MtrJoin), - }), - be_str_weak(_X3Clambda_X3E), - &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x68100000, // 0000 GETUPV R4 U0 - 0x8C100900, // 0001 GETMET R4 R4 K0 - 0x5C180000, // 0002 MOVE R6 R0 - 0x5C1C0200, // 0003 MOVE R7 R1 - 0x5C200400, // 0004 MOVE R8 R2 - 0x5C240600, // 0005 MOVE R9 R3 - 0x7C100A00, // 0006 CALL R4 5 - 0x80040800, // 0007 RET 1 R4 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(add_cmd), - /* K2 */ be_nested_str_weak(MtrJoin), - }), - be_str_weak(register_commands), - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x580C0002, // 0002 LDCONST R3 K2 - 0x84100000, // 0003 CLOSURE R4 P0 - 0x7C040600, // 0004 CALL R1 3 - 0xA0000000, // 0005 CLOSE R0 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: autoconf_device_map -********************************************************************/ -be_local_closure(Matter_Device_autoconf_device_map, /* name */ - be_nested_proto( - 20, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[36]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_const_int(1), - /* K2 */ be_nested_str_weak(light), - /* K3 */ be_nested_str_weak(get), - /* K4 */ be_nested_str_weak(find), - /* K5 */ be_nested_str_weak(channels), - /* K6 */ be_nested_str_weak(), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str_weak(type), - /* K9 */ be_nested_str_weak(light1), - /* K10 */ be_const_int(2), - /* K11 */ be_nested_str_weak(light2), - /* K12 */ be_nested_str_weak(light3), - /* K13 */ be_nested_str_weak(tasmota), - /* K14 */ be_nested_str_weak(cmd), - /* K15 */ be_nested_str_weak(Status_X2013), - /* K16 */ be_nested_str_weak(log), - /* K17 */ be_nested_str_weak(MTR_X3A_X20Status_X2013_X20_X3D_X20), - /* K18 */ be_const_int(3), - /* K19 */ be_nested_str_weak(contains), - /* K20 */ be_nested_str_weak(StatusSHT), - /* K21 */ be_nested_str_weak(SHT), - /* K22 */ be_nested_str_weak(MTR_X3A_X20_X27_X25s_X27_X20_X3D_X20_X25s), - /* K23 */ be_nested_str_weak(Relay1), - /* K24 */ be_nested_str_weak(Relay2), - /* K25 */ be_nested_str_weak(push), - /* K26 */ be_nested_str_weak(MTR_X3A_X20relay1_X3D_X25s_X20relay2_X3D_X25s), - /* K27 */ be_nested_str_weak(TiltConfig), - /* K28 */ be_nested_str_weak(shutter_X2Btilt), - /* K29 */ be_nested_str_weak(shutter), - /* K30 */ be_nested_str_weak(get_power), - /* K31 */ be_nested_str_weak(relay), - /* K32 */ be_nested_str_weak(load), - /* K33 */ be_nested_str_weak(read_sensors), - /* K34 */ be_nested_str_weak(autoconf_sensors_list), - /* K35 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(autoconf_device_map), - &be_const_str_solidified, - ( &(const binstruction[198]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x60080013, // 0001 GETGBL R2 G19 - 0x7C080000, // 0002 CALL R2 0 - 0x580C0001, // 0003 LDCONST R3 K1 - 0x50100000, // 0004 LDBOOL R4 0 0 - 0xA4160400, // 0005 IMPORT R5 K2 - 0x8C180B03, // 0006 GETMET R6 R5 K3 - 0x7C180200, // 0007 CALL R6 1 - 0x4C1C0000, // 0008 LDNIL R7 - 0x201C0C07, // 0009 NE R7 R6 R7 - 0x781E0024, // 000A JMPF R7 #0030 - 0x601C000C, // 000B GETGBL R7 G12 - 0x8C200D04, // 000C GETMET R8 R6 K4 - 0x58280005, // 000D LDCONST R10 K5 - 0x582C0006, // 000E LDCONST R11 K6 - 0x7C200600, // 000F CALL R8 3 - 0x7C1C0200, // 0010 CALL R7 1 - 0x24200F07, // 0011 GT R8 R7 K7 - 0x7822001C, // 0012 JMPF R8 #0030 - 0x1C200F01, // 0013 EQ R8 R7 K1 - 0x78220007, // 0014 JMPF R8 #001D - 0x60200008, // 0015 GETGBL R8 G8 - 0x5C240600, // 0016 MOVE R9 R3 - 0x7C200200, // 0017 CALL R8 1 - 0x60240013, // 0018 GETGBL R9 G19 - 0x7C240000, // 0019 CALL R9 0 - 0x98261109, // 001A SETIDX R9 K8 K9 - 0x98081009, // 001B SETIDX R2 R8 R9 - 0x70020010, // 001C JMP #002E - 0x1C200F0A, // 001D EQ R8 R7 K10 - 0x78220007, // 001E JMPF R8 #0027 - 0x60200008, // 001F GETGBL R8 G8 - 0x5C240600, // 0020 MOVE R9 R3 - 0x7C200200, // 0021 CALL R8 1 - 0x60240013, // 0022 GETGBL R9 G19 - 0x7C240000, // 0023 CALL R9 0 - 0x9826110B, // 0024 SETIDX R9 K8 K11 - 0x98081009, // 0025 SETIDX R2 R8 R9 - 0x70020006, // 0026 JMP #002E - 0x60200008, // 0027 GETGBL R8 G8 - 0x5C240600, // 0028 MOVE R9 R3 - 0x7C200200, // 0029 CALL R8 1 - 0x60240013, // 002A GETGBL R9 G19 - 0x7C240000, // 002B CALL R9 0 - 0x9826110C, // 002C SETIDX R9 K8 K12 - 0x98081009, // 002D SETIDX R2 R8 R9 - 0x50100200, // 002E LDBOOL R4 1 0 - 0x000C0701, // 002F ADD R3 R3 K1 - 0xB81E1A00, // 0030 GETNGBL R7 K13 - 0x8C1C0F0E, // 0031 GETMET R7 R7 K14 - 0x5824000F, // 0032 LDCONST R9 K15 - 0x50280200, // 0033 LDBOOL R10 1 0 - 0x7C1C0600, // 0034 CALL R7 3 - 0x60200012, // 0035 GETGBL R8 G18 - 0x7C200000, // 0036 CALL R8 0 - 0xB8261A00, // 0037 GETNGBL R9 K13 - 0x8C241310, // 0038 GETMET R9 R9 K16 - 0x602C0008, // 0039 GETGBL R11 G8 - 0x5C300E00, // 003A MOVE R12 R7 - 0x7C2C0200, // 003B CALL R11 1 - 0x002E220B, // 003C ADD R11 K17 R11 - 0x58300012, // 003D LDCONST R12 K18 - 0x7C240600, // 003E CALL R9 3 - 0x4C240000, // 003F LDNIL R9 - 0x20240E09, // 0040 NE R9 R7 R9 - 0x7826004F, // 0041 JMPF R9 #0092 - 0x8C240F13, // 0042 GETMET R9 R7 K19 - 0x582C0014, // 0043 LDCONST R11 K20 - 0x7C240400, // 0044 CALL R9 2 - 0x7826004B, // 0045 JMPF R9 #0092 - 0x941C0F14, // 0046 GETIDX R7 R7 K20 - 0x58240007, // 0047 LDCONST R9 K7 - 0x50280200, // 0048 LDBOOL R10 1 0 - 0x782A0047, // 0049 JMPF R10 #0092 - 0x60280008, // 004A GETGBL R10 G8 - 0x5C2C1200, // 004B MOVE R11 R9 - 0x7C280200, // 004C CALL R10 1 - 0x002A2A0A, // 004D ADD R10 K21 R10 - 0x8C2C0F13, // 004E GETMET R11 R7 K19 - 0x5C341400, // 004F MOVE R13 R10 - 0x7C2C0400, // 0050 CALL R11 2 - 0x742E0000, // 0051 JMPT R11 #0053 - 0x7002003E, // 0052 JMP #0092 - 0x942C0E0A, // 0053 GETIDX R11 R7 R10 - 0xB8321A00, // 0054 GETNGBL R12 K13 - 0x8C301910, // 0055 GETMET R12 R12 K16 - 0x60380018, // 0056 GETGBL R14 G24 - 0x583C0016, // 0057 LDCONST R15 K22 - 0x5C401400, // 0058 MOVE R16 R10 - 0x60440008, // 0059 GETGBL R17 G8 - 0x5C481600, // 005A MOVE R18 R11 - 0x7C440200, // 005B CALL R17 1 - 0x7C380600, // 005C CALL R14 3 - 0x583C0012, // 005D LDCONST R15 K18 - 0x7C300600, // 005E CALL R12 3 - 0x8C301704, // 005F GETMET R12 R11 K4 - 0x58380017, // 0060 LDCONST R14 K23 - 0x543DFFFE, // 0061 LDINT R15 -1 - 0x7C300600, // 0062 CALL R12 3 - 0x8C341704, // 0063 GETMET R13 R11 K4 - 0x583C0018, // 0064 LDCONST R15 K24 - 0x5441FFFE, // 0065 LDINT R16 -1 - 0x7C340600, // 0066 CALL R13 3 - 0x24381907, // 0067 GT R14 R12 K7 - 0x783A0002, // 0068 JMPF R14 #006C - 0x8C381119, // 0069 GETMET R14 R8 K25 - 0x04401901, // 006A SUB R16 R12 K1 - 0x7C380400, // 006B CALL R14 2 - 0x24381B07, // 006C GT R14 R13 K7 - 0x783A0002, // 006D JMPF R14 #0071 - 0x8C381119, // 006E GETMET R14 R8 K25 - 0x04401B01, // 006F SUB R16 R13 K1 - 0x7C380400, // 0070 CALL R14 2 - 0xB83A1A00, // 0071 GETNGBL R14 K13 - 0x8C381D10, // 0072 GETMET R14 R14 K16 - 0x60400018, // 0073 GETGBL R16 G24 - 0x5844001A, // 0074 LDCONST R17 K26 - 0x5C481800, // 0075 MOVE R18 R12 - 0x5C4C1A00, // 0076 MOVE R19 R13 - 0x7C400600, // 0077 CALL R16 3 - 0x58440012, // 0078 LDCONST R17 K18 - 0x7C380600, // 0079 CALL R14 3 - 0x8C381704, // 007A GETMET R14 R11 K4 - 0x5840001B, // 007B LDCONST R16 K27 - 0x7C380400, // 007C CALL R14 2 - 0x783A0002, // 007D JMPF R14 #0081 - 0x943C1D0A, // 007E GETIDX R15 R14 K10 - 0x243C1F07, // 007F GT R15 R15 K7 - 0x743E0000, // 0080 JMPT R15 #0082 - 0x503C0001, // 0081 LDBOOL R15 0 1 - 0x503C0200, // 0082 LDBOOL R15 1 0 - 0x60400008, // 0083 GETGBL R16 G8 - 0x5C440600, // 0084 MOVE R17 R3 - 0x7C400200, // 0085 CALL R16 1 - 0x60440013, // 0086 GETGBL R17 G19 - 0x7C440000, // 0087 CALL R17 0 - 0x783E0001, // 0088 JMPF R15 #008B - 0x5848001C, // 0089 LDCONST R18 K28 - 0x70020000, // 008A JMP #008C - 0x5848001D, // 008B LDCONST R18 K29 - 0x98461012, // 008C SETIDX R17 K8 R18 - 0x98463A09, // 008D SETIDX R17 K29 R9 - 0x98082011, // 008E SETIDX R2 R16 R17 - 0x000C0701, // 008F ADD R3 R3 K1 - 0x00241301, // 0090 ADD R9 R9 K1 - 0x7001FFB5, // 0091 JMP #0048 - 0x6024000C, // 0092 GETGBL R9 G12 - 0xB82A1A00, // 0093 GETNGBL R10 K13 - 0x8C28151E, // 0094 GETMET R10 R10 K30 - 0x7C280200, // 0095 CALL R10 1 - 0x7C240200, // 0096 CALL R9 1 - 0x58280007, // 0097 LDCONST R10 K7 - 0x78120000, // 0098 JMPF R4 #009A - 0x04241301, // 0099 SUB R9 R9 K1 - 0x142C1409, // 009A LT R11 R10 R9 - 0x782E0011, // 009B JMPF R11 #00AE - 0x8C2C1104, // 009C GETMET R11 R8 K4 - 0x5C341400, // 009D MOVE R13 R10 - 0x7C2C0400, // 009E CALL R11 2 - 0x4C300000, // 009F LDNIL R12 - 0x1C2C160C, // 00A0 EQ R11 R11 R12 - 0x782E0009, // 00A1 JMPF R11 #00AC - 0x602C0008, // 00A2 GETGBL R11 G8 - 0x5C300600, // 00A3 MOVE R12 R3 - 0x7C2C0200, // 00A4 CALL R11 1 - 0x60300013, // 00A5 GETGBL R12 G19 - 0x7C300000, // 00A6 CALL R12 0 - 0x9832111F, // 00A7 SETIDX R12 K8 K31 - 0x00341501, // 00A8 ADD R13 R10 K1 - 0x98323E0D, // 00A9 SETIDX R12 K31 R13 - 0x9808160C, // 00AA SETIDX R2 R11 R12 - 0x000C0701, // 00AB ADD R3 R3 K1 - 0x00281501, // 00AC ADD R10 R10 K1 - 0x7001FFEB, // 00AD JMP #009A - 0x8C2C0320, // 00AE GETMET R11 R1 K32 - 0xB8361A00, // 00AF GETNGBL R13 K13 - 0x8C341B21, // 00B0 GETMET R13 R13 K33 - 0x7C340200, // 00B1 CALL R13 1 - 0x7C2C0400, // 00B2 CALL R11 2 - 0x8C300122, // 00B3 GETMET R12 R0 K34 - 0x5C381600, // 00B4 MOVE R14 R11 - 0x7C300400, // 00B5 CALL R12 2 - 0x60340010, // 00B6 GETGBL R13 G16 - 0x5C381800, // 00B7 MOVE R14 R12 - 0x7C340200, // 00B8 CALL R13 1 - 0xA8020007, // 00B9 EXBLK 0 #00C2 - 0x5C381A00, // 00BA MOVE R14 R13 - 0x7C380000, // 00BB CALL R14 0 - 0x603C0008, // 00BC GETGBL R15 G8 - 0x5C400600, // 00BD MOVE R16 R3 - 0x7C3C0200, // 00BE CALL R15 1 - 0x98081E0E, // 00BF SETIDX R2 R15 R14 - 0x000C0701, // 00C0 ADD R3 R3 K1 - 0x7001FFF7, // 00C1 JMP #00BA - 0x58340023, // 00C2 LDCONST R13 K35 - 0xAC340200, // 00C3 CATCH R13 1 0 - 0xB0080000, // 00C4 RAISE 2 R0 R0 - 0x80040400, // 00C5 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: _trigger_read_sensors -********************************************************************/ -be_local_closure(Matter_Device__trigger_read_sensors, /* name */ - be_nested_proto( - 8, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(read_sensors), - /* K3 */ be_nested_str_weak(load), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_str_weak(plugins), - /* K6 */ be_nested_str_weak(parse_sensors), - /* K7 */ be_const_int(1), - /* K8 */ be_nested_str_weak(log), - /* K9 */ be_nested_str_weak(MTR_X3A_X20unable_X20to_X20parse_X20read_sensors_X3A_X20), - /* K10 */ be_const_int(3), - }), - be_str_weak(_trigger_read_sensors), - &be_const_str_solidified, - ( &(const binstruction[37]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0xB80A0200, // 0001 GETNGBL R2 K1 - 0x8C080502, // 0002 GETMET R2 R2 K2 - 0x7C080200, // 0003 CALL R2 1 - 0x4C0C0000, // 0004 LDNIL R3 - 0x1C0C0403, // 0005 EQ R3 R2 R3 - 0x780E0000, // 0006 JMPF R3 #0008 - 0x80000600, // 0007 RET 0 - 0x8C0C0303, // 0008 GETMET R3 R1 K3 - 0x5C140400, // 0009 MOVE R5 R2 - 0x7C0C0400, // 000A CALL R3 2 - 0x4C100000, // 000B LDNIL R4 - 0x20100604, // 000C NE R4 R3 R4 - 0x7812000D, // 000D JMPF R4 #001C - 0x58100004, // 000E LDCONST R4 K4 - 0x6014000C, // 000F GETGBL R5 G12 - 0x88180105, // 0010 GETMBR R6 R0 K5 - 0x7C140200, // 0011 CALL R5 1 - 0x14140805, // 0012 LT R5 R4 R5 - 0x78160006, // 0013 JMPF R5 #001B - 0x88140105, // 0014 GETMBR R5 R0 K5 - 0x94140A04, // 0015 GETIDX R5 R5 R4 - 0x8C140B06, // 0016 GETMET R5 R5 K6 - 0x5C1C0600, // 0017 MOVE R7 R3 - 0x7C140400, // 0018 CALL R5 2 - 0x00100907, // 0019 ADD R4 R4 K7 - 0x7001FFF3, // 001A JMP #000F - 0x70020007, // 001B JMP #0024 - 0xB8120200, // 001C GETNGBL R4 K1 - 0x8C100908, // 001D GETMET R4 R4 K8 - 0x60180008, // 001E GETGBL R6 G8 - 0x5C1C0400, // 001F MOVE R7 R2 - 0x7C180200, // 0020 CALL R6 1 - 0x001A1206, // 0021 ADD R6 K9 R6 - 0x581C000A, // 0022 LDCONST R7 K10 - 0x7C100600, // 0023 CALL R4 3 - 0x80000000, // 0024 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: every_50ms -********************************************************************/ -be_local_closure(Matter_Device_every_50ms, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(tick), - /* K1 */ be_const_int(1), - }), - be_str_weak(every_50ms), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x00040301, // 0001 ADD R1 R1 K1 - 0x90020001, // 0002 SETMBR R0 K0 R1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: every_second -********************************************************************/ -be_local_closure(Matter_Device_every_second, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(every_second), - /* K2 */ be_nested_str_weak(message_handler), - /* K3 */ be_nested_str_weak(commissioning_open), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(time_reached), - }), - be_str_weak(every_second), - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x88040102, // 0003 GETMBR R1 R0 K2 - 0x8C040301, // 0004 GETMET R1 R1 K1 - 0x7C040200, // 0005 CALL R1 1 - 0x88040103, // 0006 GETMBR R1 R0 K3 - 0x4C080000, // 0007 LDNIL R2 - 0x20040202, // 0008 NE R1 R1 R2 - 0x78060006, // 0009 JMPF R1 #0011 - 0xB8060800, // 000A GETNGBL R1 K4 - 0x8C040305, // 000B GETMET R1 R1 K5 - 0x880C0103, // 000C GETMBR R3 R0 K3 - 0x7C040400, // 000D CALL R1 2 - 0x78060001, // 000E JMPF R1 #0011 - 0x4C040000, // 000F LDNIL R1 - 0x90020601, // 0010 SETMBR R0 K3 R1 - 0x80000000, // 0011 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_active_endpoints -********************************************************************/ -be_local_closure(Matter_Device_get_active_endpoints, /* name */ - be_nested_proto( - 9, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(plugins), - /* K1 */ be_nested_str_weak(get_endpoint), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(find), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(get_active_endpoints), - &be_const_str_solidified, - ( &(const binstruction[28]) { /* code */ - 0x60080012, // 0000 GETGBL R2 G18 - 0x7C080000, // 0001 CALL R2 0 - 0x600C0010, // 0002 GETGBL R3 G16 - 0x88100100, // 0003 GETMBR R4 R0 K0 - 0x7C0C0200, // 0004 CALL R3 1 - 0xA8020011, // 0005 EXBLK 0 #0018 - 0x5C100600, // 0006 MOVE R4 R3 - 0x7C100000, // 0007 CALL R4 0 - 0x8C140901, // 0008 GETMET R5 R4 K1 - 0x7C140200, // 0009 CALL R5 1 - 0x78060002, // 000A JMPF R1 #000E - 0x1C180B02, // 000B EQ R6 R5 K2 - 0x781A0000, // 000C JMPF R6 #000E - 0x7001FFF7, // 000D JMP #0006 - 0x8C180503, // 000E GETMET R6 R2 K3 - 0x5C200A00, // 000F MOVE R8 R5 - 0x7C180400, // 0010 CALL R6 2 - 0x4C1C0000, // 0011 LDNIL R7 - 0x1C180C07, // 0012 EQ R6 R6 R7 - 0x781A0002, // 0013 JMPF R6 #0017 - 0x8C180504, // 0014 GETMET R6 R2 K4 - 0x5C200A00, // 0015 MOVE R8 R5 - 0x7C180400, // 0016 CALL R6 2 - 0x7001FFED, // 0017 JMP #0006 - 0x580C0005, // 0018 LDCONST R3 K5 - 0xAC0C0200, // 0019 CATCH R3 1 0 - 0xB0080000, // 001A RAISE 2 R0 R0 - 0x80040400, // 001B RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: _mdns_announce_hostname -********************************************************************/ -be_local_closure(Matter_Device__mdns_announce_hostname, /* name */ - be_nested_proto( - 14, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[26]) { /* constants */ - /* K0 */ be_nested_str_weak(mdns), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(start), - /* K3 */ be_nested_str_weak(tasmota), - /* K4 */ be_nested_str_weak(eth), - /* K5 */ be_nested_str_weak(hostname_eth), - /* K6 */ be_nested_str_weak(replace), - /* K7 */ be_nested_str_weak(find), - /* K8 */ be_nested_str_weak(mac), - /* K9 */ be_nested_str_weak(_X3A), - /* K10 */ be_nested_str_weak(), - /* K11 */ be_nested_str_weak(ipv4only), - /* K12 */ be_nested_str_weak(add_hostname), - /* K13 */ be_nested_str_weak(ip6local), - /* K14 */ be_nested_str_weak(ip), - /* K15 */ be_nested_str_weak(ip6), - /* K16 */ be_nested_str_weak(log), - /* K17 */ be_nested_str_weak(MTR_X3A_X20calling_X20mdns_X2Eadd_hostname_X28_X25s_X2C_X20_X25s_X29), - /* K18 */ be_const_int(3), - /* K19 */ be_nested_str_weak(wifi), - /* K20 */ be_nested_str_weak(hostname_wifi), - /* K21 */ be_nested_str_weak(MTR_X3A_X20start_X20mDNS_X20on_X20_X25s_X20host_X20_X27_X25s_X2Elocal_X27), - /* K22 */ be_nested_str_weak(MTR_X3A_X20Exception), - /* K23 */ be_nested_str_weak(_X7C), - /* K24 */ be_const_int(2), - /* K25 */ be_nested_str_weak(mdns_announce_op_discovery_all_fabrics), - }), - be_str_weak(_mdns_announce_hostname), - &be_const_str_solidified, - ( &(const binstruction[140]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0xA40E0200, // 0001 IMPORT R3 K1 - 0x8C100502, // 0002 GETMET R4 R2 K2 - 0x7C100200, // 0003 CALL R4 1 - 0xA8020072, // 0004 EXBLK 0 #0078 - 0x78060030, // 0005 JMPF R1 #0037 - 0xB8120600, // 0006 GETNGBL R4 K3 - 0x8C100904, // 0007 GETMET R4 R4 K4 - 0x7C100200, // 0008 CALL R4 1 - 0x8C140706, // 0009 GETMET R5 R3 K6 - 0x8C1C0907, // 000A GETMET R7 R4 K7 - 0x58240008, // 000B LDCONST R9 K8 - 0x7C1C0400, // 000C CALL R7 2 - 0x58200009, // 000D LDCONST R8 K9 - 0x5824000A, // 000E LDCONST R9 K10 - 0x7C140800, // 000F CALL R5 4 - 0x90020A05, // 0010 SETMBR R0 K5 R5 - 0x8814010B, // 0011 GETMBR R5 R0 K11 - 0x7416000F, // 0012 JMPT R5 #0023 - 0x8C14050C, // 0013 GETMET R5 R2 K12 - 0x881C0105, // 0014 GETMBR R7 R0 K5 - 0x8C200907, // 0015 GETMET R8 R4 K7 - 0x5828000D, // 0016 LDCONST R10 K13 - 0x582C000A, // 0017 LDCONST R11 K10 - 0x7C200600, // 0018 CALL R8 3 - 0x8C240907, // 0019 GETMET R9 R4 K7 - 0x582C000E, // 001A LDCONST R11 K14 - 0x5830000A, // 001B LDCONST R12 K10 - 0x7C240600, // 001C CALL R9 3 - 0x8C280907, // 001D GETMET R10 R4 K7 - 0x5830000F, // 001E LDCONST R12 K15 - 0x5834000A, // 001F LDCONST R13 K10 - 0x7C280600, // 0020 CALL R10 3 - 0x7C140A00, // 0021 CALL R5 5 - 0x70020012, // 0022 JMP #0036 - 0xB8160600, // 0023 GETNGBL R5 K3 - 0x8C140B10, // 0024 GETMET R5 R5 K16 - 0x601C0018, // 0025 GETGBL R7 G24 - 0x58200011, // 0026 LDCONST R8 K17 - 0x88240105, // 0027 GETMBR R9 R0 K5 - 0x8C280907, // 0028 GETMET R10 R4 K7 - 0x5830000E, // 0029 LDCONST R12 K14 - 0x5834000A, // 002A LDCONST R13 K10 - 0x7C280600, // 002B CALL R10 3 - 0x7C1C0600, // 002C CALL R7 3 - 0x58200012, // 002D LDCONST R8 K18 - 0x7C140600, // 002E CALL R5 3 - 0x8C14050C, // 002F GETMET R5 R2 K12 - 0x881C0105, // 0030 GETMBR R7 R0 K5 - 0x8C200907, // 0031 GETMET R8 R4 K7 - 0x5828000E, // 0032 LDCONST R10 K14 - 0x582C000A, // 0033 LDCONST R11 K10 - 0x7C200600, // 0034 CALL R8 3 - 0x7C140600, // 0035 CALL R5 3 - 0x7002002F, // 0036 JMP #0067 - 0xB8120600, // 0037 GETNGBL R4 K3 - 0x8C100913, // 0038 GETMET R4 R4 K19 - 0x7C100200, // 0039 CALL R4 1 - 0x8C140706, // 003A GETMET R5 R3 K6 - 0x8C1C0907, // 003B GETMET R7 R4 K7 - 0x58240008, // 003C LDCONST R9 K8 - 0x7C1C0400, // 003D CALL R7 2 - 0x58200009, // 003E LDCONST R8 K9 - 0x5824000A, // 003F LDCONST R9 K10 - 0x7C140800, // 0040 CALL R5 4 - 0x90022805, // 0041 SETMBR R0 K20 R5 - 0x8814010B, // 0042 GETMBR R5 R0 K11 - 0x7416000F, // 0043 JMPT R5 #0054 - 0x8C14050C, // 0044 GETMET R5 R2 K12 - 0x881C0114, // 0045 GETMBR R7 R0 K20 - 0x8C200907, // 0046 GETMET R8 R4 K7 - 0x5828000D, // 0047 LDCONST R10 K13 - 0x582C000A, // 0048 LDCONST R11 K10 - 0x7C200600, // 0049 CALL R8 3 - 0x8C240907, // 004A GETMET R9 R4 K7 - 0x582C000E, // 004B LDCONST R11 K14 - 0x5830000A, // 004C LDCONST R12 K10 - 0x7C240600, // 004D CALL R9 3 - 0x8C280907, // 004E GETMET R10 R4 K7 - 0x5830000F, // 004F LDCONST R12 K15 - 0x5834000A, // 0050 LDCONST R13 K10 - 0x7C280600, // 0051 CALL R10 3 - 0x7C140A00, // 0052 CALL R5 5 - 0x70020012, // 0053 JMP #0067 - 0xB8160600, // 0054 GETNGBL R5 K3 - 0x8C140B10, // 0055 GETMET R5 R5 K16 - 0x601C0018, // 0056 GETGBL R7 G24 - 0x58200011, // 0057 LDCONST R8 K17 - 0x88240105, // 0058 GETMBR R9 R0 K5 - 0x8C280907, // 0059 GETMET R10 R4 K7 - 0x5830000E, // 005A LDCONST R12 K14 - 0x5834000A, // 005B LDCONST R13 K10 - 0x7C280600, // 005C CALL R10 3 - 0x7C1C0600, // 005D CALL R7 3 - 0x58200012, // 005E LDCONST R8 K18 - 0x7C140600, // 005F CALL R5 3 - 0x8C14050C, // 0060 GETMET R5 R2 K12 - 0x881C0114, // 0061 GETMBR R7 R0 K20 - 0x8C200907, // 0062 GETMET R8 R4 K7 - 0x5828000E, // 0063 LDCONST R10 K14 - 0x582C000A, // 0064 LDCONST R11 K10 - 0x7C200600, // 0065 CALL R8 3 - 0x7C140600, // 0066 CALL R5 3 - 0xB8120600, // 0067 GETNGBL R4 K3 - 0x8C100910, // 0068 GETMET R4 R4 K16 - 0x60180018, // 0069 GETGBL R6 G24 - 0x581C0015, // 006A LDCONST R7 K21 - 0x78060001, // 006B JMPF R1 #006E - 0x58200004, // 006C LDCONST R8 K4 - 0x70020000, // 006D JMP #006F - 0x58200013, // 006E LDCONST R8 K19 - 0x78060001, // 006F JMPF R1 #0072 - 0x88240105, // 0070 GETMBR R9 R0 K5 - 0x70020000, // 0071 JMP #0073 - 0x88240114, // 0072 GETMBR R9 R0 K20 - 0x7C180600, // 0073 CALL R6 3 - 0x581C0012, // 0074 LDCONST R7 K18 - 0x7C100600, // 0075 CALL R4 3 - 0xA8040001, // 0076 EXBLK 1 1 - 0x70020010, // 0077 JMP #0089 - 0xAC100002, // 0078 CATCH R4 0 2 - 0x7002000D, // 0079 JMP #0088 - 0xB81A0600, // 007A GETNGBL R6 K3 - 0x8C180D10, // 007B GETMET R6 R6 K16 - 0x60200008, // 007C GETGBL R8 G8 - 0x5C240800, // 007D MOVE R9 R4 - 0x7C200200, // 007E CALL R8 1 - 0x00222C08, // 007F ADD R8 K22 R8 - 0x00201117, // 0080 ADD R8 R8 K23 - 0x60240008, // 0081 GETGBL R9 G8 - 0x5C280A00, // 0082 MOVE R10 R5 - 0x7C240200, // 0083 CALL R9 1 - 0x00201009, // 0084 ADD R8 R8 R9 - 0x58240018, // 0085 LDCONST R9 K24 - 0x7C180600, // 0086 CALL R6 3 - 0x70020000, // 0087 JMP #0089 - 0xB0080000, // 0088 RAISE 2 R0 R0 - 0x8C100119, // 0089 GETMET R4 R0 K25 - 0x7C100200, // 008A CALL R4 1 - 0x80000000, // 008B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_plugin_class_displayname -********************************************************************/ -be_local_closure(Matter_Device_get_plugin_class_displayname, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(plugins_classes), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(NAME), - /* K3 */ be_nested_str_weak(), - }), - be_str_weak(get_plugin_class_displayname), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C080400, // 0003 CALL R2 2 - 0x780A0001, // 0004 JMPF R2 #0007 - 0x880C0502, // 0005 GETMBR R3 R2 K2 - 0x70020000, // 0006 JMP #0008 - 0x580C0003, // 0007 LDCONST R3 K3 - 0x80040600, // 0008 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: generate_random_passcode -********************************************************************/ -be_local_closure(Matter_Device_generate_random_passcode, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(random), - /* K2 */ be_nested_str_weak(get), - /* K3 */ be_const_int(0), - /* K4 */ be_const_int(134217727), - /* K5 */ be_const_int(99999998), - /* K6 */ be_nested_str_weak(PASSCODE_INVALID), - /* K7 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(generate_random_passcode), - &be_const_str_solidified, - ( &(const binstruction[35]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x500C0200, // 0002 LDBOOL R3 1 0 - 0x780E001D, // 0003 JMPF R3 #0022 - 0x8C0C0301, // 0004 GETMET R3 R1 K1 - 0x54160003, // 0005 LDINT R5 4 - 0x7C0C0400, // 0006 CALL R3 2 - 0x8C0C0702, // 0007 GETMET R3 R3 K2 - 0x58140003, // 0008 LDCONST R5 K3 - 0x541A0003, // 0009 LDINT R6 4 - 0x7C0C0600, // 000A CALL R3 3 - 0x2C0C0704, // 000B AND R3 R3 K4 - 0x5C080600, // 000C MOVE R2 R3 - 0x240C0505, // 000D GT R3 R2 K5 - 0x780E0000, // 000E JMPF R3 #0010 - 0x7001FFF1, // 000F JMP #0002 - 0x600C0010, // 0010 GETGBL R3 G16 - 0x88100106, // 0011 GETMBR R4 R0 K6 - 0x7C0C0200, // 0012 CALL R3 1 - 0xA8020005, // 0013 EXBLK 0 #001A - 0x5C100600, // 0014 MOVE R4 R3 - 0x7C100000, // 0015 CALL R4 0 - 0x1C140404, // 0016 EQ R5 R2 R4 - 0x78160000, // 0017 JMPF R5 #0019 - 0x4C080000, // 0018 LDNIL R2 - 0x7001FFF9, // 0019 JMP #0014 - 0x580C0007, // 001A LDCONST R3 K7 - 0xAC0C0200, // 001B CATCH R3 1 0 - 0xB0080000, // 001C RAISE 2 R0 R0 - 0x4C0C0000, // 001D LDNIL R3 - 0x200C0403, // 001E NE R3 R2 R3 - 0x780E0000, // 001F JMPF R3 #0021 - 0x80040400, // 0020 RET 1 R2 - 0x7001FFDF, // 0021 JMP #0002 - 0x80000000, // 0022 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: update_remotes_info -********************************************************************/ -be_local_closure(Matter_Device_update_remotes_info, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(http_remotes), - /* K1 */ be_nested_str_weak(keys), - /* K2 */ be_nested_str_weak(get_info), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(stop_iteration), - /* K5 */ be_nested_str_weak(plugins_config_remotes), - }), - be_str_weak(update_remotes_info), - &be_const_str_solidified, - ( &(const binstruction[33]) { /* code */ - 0x60040013, // 0000 GETGBL R1 G19 - 0x7C040000, // 0001 CALL R1 0 - 0x88080100, // 0002 GETMBR R2 R0 K0 - 0x4C0C0000, // 0003 LDNIL R3 - 0x20080403, // 0004 NE R2 R2 R3 - 0x780A0018, // 0005 JMPF R2 #001F - 0x60080010, // 0006 GETGBL R2 G16 - 0x880C0100, // 0007 GETMBR R3 R0 K0 - 0x8C0C0701, // 0008 GETMET R3 R3 K1 - 0x7C0C0200, // 0009 CALL R3 1 - 0x7C080200, // 000A CALL R2 1 - 0xA802000F, // 000B EXBLK 0 #001C - 0x5C0C0400, // 000C MOVE R3 R2 - 0x7C0C0000, // 000D CALL R3 0 - 0x88100100, // 000E GETMBR R4 R0 K0 - 0x94100803, // 000F GETIDX R4 R4 R3 - 0x8C100902, // 0010 GETMET R4 R4 K2 - 0x7C100200, // 0011 CALL R4 1 - 0x4C140000, // 0012 LDNIL R5 - 0x20140805, // 0013 NE R5 R4 R5 - 0x78160005, // 0014 JMPF R5 #001B - 0x6014000C, // 0015 GETGBL R5 G12 - 0x5C180800, // 0016 MOVE R6 R4 - 0x7C140200, // 0017 CALL R5 1 - 0x24140B03, // 0018 GT R5 R5 K3 - 0x78160000, // 0019 JMPF R5 #001B - 0x98040604, // 001A SETIDX R1 R3 R4 - 0x7001FFEF, // 001B JMP #000C - 0x58080004, // 001C LDCONST R2 K4 - 0xAC080200, // 001D CATCH R2 1 0 - 0xB0080000, // 001E RAISE 2 R0 R0 - 0x90020A01, // 001F SETMBR R0 K5 R1 - 0x80040200, // 0020 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: MtrJoin -********************************************************************/ -be_local_closure(Matter_Device_MtrJoin, /* name */ - be_nested_proto( - 8, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(start_root_basic_commissioning), - /* K1 */ be_nested_str_weak(stop_basic_commissioning), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(resp_cmnd_done), - }), - be_str_weak(MtrJoin), - &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x60140009, // 0000 GETGBL R5 G9 - 0x5C180600, // 0001 MOVE R6 R3 - 0x7C140200, // 0002 CALL R5 1 - 0x78160002, // 0003 JMPF R5 #0007 - 0x8C180100, // 0004 GETMET R6 R0 K0 - 0x7C180200, // 0005 CALL R6 1 - 0x70020001, // 0006 JMP #0009 - 0x8C180101, // 0007 GETMET R6 R0 K1 - 0x7C180200, // 0008 CALL R6 1 - 0xB81A0400, // 0009 GETNGBL R6 K2 - 0x8C180D03, // 000A GETMET R6 R6 K3 - 0x7C180200, // 000B CALL R6 1 - 0x80000000, // 000C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_root_basic_commissioning -********************************************************************/ -be_local_closure(Matter_Device_start_root_basic_commissioning, /* name */ - be_nested_proto( - 13, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[18]) { /* constants */ - /* K0 */ be_nested_str_weak(PASE_TIMEOUT), - /* K1 */ be_nested_str_weak(compute_manual_pairing_code), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(log), - /* K4 */ be_nested_str_weak(MTR_X3A_X20Manual_X20pairing_X20code_X3A_X20_X25s), - /* K5 */ be_const_int(2), - /* K6 */ be_nested_str_weak(compute_qrcode_content), - /* K7 */ be_nested_str_weak(publish_result), - /* K8 */ be_nested_str_weak(_X7B_X22Matter_X22_X3A_X7B_X22Commissioning_X22_X3A1_X2C_X22PairingCode_X22_X3A_X22_X25s_X22_X2C_X22QRCode_X22_X3A_X22_X25s_X22_X7D_X7D), - /* K9 */ be_nested_str_weak(Matter), - /* K10 */ be_nested_str_weak(_compute_pbkdf), - /* K11 */ be_nested_str_weak(root_passcode), - /* K12 */ be_nested_str_weak(root_iterations), - /* K13 */ be_nested_str_weak(root_salt), - /* K14 */ be_nested_str_weak(start_basic_commissioning), - /* K15 */ be_nested_str_weak(root_discriminator), - /* K16 */ be_nested_str_weak(root_w0), - /* K17 */ be_nested_str_weak(root_L), - }), - be_str_weak(start_root_basic_commissioning), - &be_const_str_solidified, - ( &(const binstruction[40]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x1C080202, // 0001 EQ R2 R1 R2 - 0x780A0000, // 0002 JMPF R2 #0004 - 0x88040100, // 0003 GETMBR R1 R0 K0 - 0x8C080101, // 0004 GETMET R2 R0 K1 - 0x7C080200, // 0005 CALL R2 1 - 0xB80E0400, // 0006 GETNGBL R3 K2 - 0x8C0C0703, // 0007 GETMET R3 R3 K3 - 0x60140018, // 0008 GETGBL R5 G24 - 0x58180004, // 0009 LDCONST R6 K4 - 0x5C1C0400, // 000A MOVE R7 R2 - 0x7C140400, // 000B CALL R5 2 - 0x58180005, // 000C LDCONST R6 K5 - 0x7C0C0600, // 000D CALL R3 3 - 0x8C0C0106, // 000E GETMET R3 R0 K6 - 0x7C0C0200, // 000F CALL R3 1 - 0xB8120400, // 0010 GETNGBL R4 K2 - 0x8C100907, // 0011 GETMET R4 R4 K7 - 0x60180018, // 0012 GETGBL R6 G24 - 0x581C0008, // 0013 LDCONST R7 K8 - 0x5C200400, // 0014 MOVE R8 R2 - 0x5C240600, // 0015 MOVE R9 R3 - 0x7C180600, // 0016 CALL R6 3 - 0x581C0009, // 0017 LDCONST R7 K9 - 0x7C100600, // 0018 CALL R4 3 - 0x8C10010A, // 0019 GETMET R4 R0 K10 - 0x8818010B, // 001A GETMBR R6 R0 K11 - 0x881C010C, // 001B GETMBR R7 R0 K12 - 0x8820010D, // 001C GETMBR R8 R0 K13 - 0x7C100800, // 001D CALL R4 4 - 0x8C10010E, // 001E GETMET R4 R0 K14 - 0x5C180200, // 001F MOVE R6 R1 - 0x881C010C, // 0020 GETMBR R7 R0 K12 - 0x8820010F, // 0021 GETMBR R8 R0 K15 - 0x8824010D, // 0022 GETMBR R9 R0 K13 - 0x88280110, // 0023 GETMBR R10 R0 K16 - 0x882C0111, // 0024 GETMBR R11 R0 K17 - 0x4C300000, // 0025 LDNIL R12 - 0x7C101000, // 0026 CALL R4 8 - 0x80000000, // 0027 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: bridge_remove_endpoint -********************************************************************/ -be_local_closure(Matter_Device_bridge_remove_endpoint, /* name */ - be_nested_proto( - 11, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[18]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(plugins_config), - /* K2 */ be_nested_str_weak(contains), - /* K3 */ be_nested_str_weak(tasmota), - /* K4 */ be_nested_str_weak(log), - /* K5 */ be_nested_str_weak(MTR_X3A_X20Cannot_X20remove_X20an_X20enpoint_X20not_X20configured_X3A_X20), - /* K6 */ be_const_int(3), - /* K7 */ be_nested_str_weak(MTR_X3A_X20deleting_X20endpoint_X20_X3D_X20_X25i), - /* K8 */ be_const_int(2), - /* K9 */ be_nested_str_weak(remove), - /* K10 */ be_nested_str_weak(plugins_persist), - /* K11 */ be_const_int(0), - /* K12 */ be_nested_str_weak(plugins), - /* K13 */ be_nested_str_weak(get_endpoint), - /* K14 */ be_const_int(1), - /* K15 */ be_nested_str_weak(clean_remotes), - /* K16 */ be_nested_str_weak(save_param), - /* K17 */ be_nested_str_weak(signal_endpoints_changed), - }), - be_str_weak(bridge_remove_endpoint), - &be_const_str_solidified, - ( &(const binstruction[58]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x600C0008, // 0001 GETGBL R3 G8 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C0C0200, // 0003 CALL R3 1 - 0x4C100000, // 0004 LDNIL R4 - 0x4C140000, // 0005 LDNIL R5 - 0x88180101, // 0006 GETMBR R6 R0 K1 - 0x8C180D02, // 0007 GETMET R6 R6 K2 - 0x5C200600, // 0008 MOVE R8 R3 - 0x7C180400, // 0009 CALL R6 2 - 0x741A0005, // 000A JMPT R6 #0011 - 0xB81A0600, // 000B GETNGBL R6 K3 - 0x8C180D04, // 000C GETMET R6 R6 K4 - 0x00220A03, // 000D ADD R8 K5 R3 - 0x58240006, // 000E LDCONST R9 K6 - 0x7C180600, // 000F CALL R6 3 - 0x80000C00, // 0010 RET 0 - 0xB81A0600, // 0011 GETNGBL R6 K3 - 0x8C180D04, // 0012 GETMET R6 R6 K4 - 0x60200018, // 0013 GETGBL R8 G24 - 0x58240007, // 0014 LDCONST R9 K7 - 0x5C280200, // 0015 MOVE R10 R1 - 0x7C200400, // 0016 CALL R8 2 - 0x58240008, // 0017 LDCONST R9 K8 - 0x7C180600, // 0018 CALL R6 3 - 0x88180101, // 0019 GETMBR R6 R0 K1 - 0x8C180D09, // 001A GETMET R6 R6 K9 - 0x5C200600, // 001B MOVE R8 R3 - 0x7C180400, // 001C CALL R6 2 - 0x50180200, // 001D LDBOOL R6 1 0 - 0x90021406, // 001E SETMBR R0 K10 R6 - 0x5818000B, // 001F LDCONST R6 K11 - 0x601C000C, // 0020 GETGBL R7 G12 - 0x8820010C, // 0021 GETMBR R8 R0 K12 - 0x7C1C0200, // 0022 CALL R7 1 - 0x141C0C07, // 0023 LT R7 R6 R7 - 0x781E000D, // 0024 JMPF R7 #0033 - 0x881C010C, // 0025 GETMBR R7 R0 K12 - 0x941C0E06, // 0026 GETIDX R7 R7 R6 - 0x8C1C0F0D, // 0027 GETMET R7 R7 K13 - 0x7C1C0200, // 0028 CALL R7 1 - 0x1C1C0207, // 0029 EQ R7 R1 R7 - 0x781E0005, // 002A JMPF R7 #0031 - 0x881C010C, // 002B GETMBR R7 R0 K12 - 0x8C1C0F09, // 002C GETMET R7 R7 K9 - 0x5C240C00, // 002D MOVE R9 R6 - 0x7C1C0400, // 002E CALL R7 2 - 0x70020002, // 002F JMP #0033 - 0x70020000, // 0030 JMP #0032 - 0x00180D0E, // 0031 ADD R6 R6 K14 - 0x7001FFEC, // 0032 JMP #0020 - 0x8C1C010F, // 0033 GETMET R7 R0 K15 - 0x7C1C0200, // 0034 CALL R7 1 - 0x8C1C0110, // 0035 GETMET R7 R0 K16 - 0x7C1C0200, // 0036 CALL R7 1 - 0x8C1C0111, // 0037 GETMET R7 R0 K17 - 0x7C1C0200, // 0038 CALL R7 1 - 0x80000000, // 0039 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: conf_to_log -********************************************************************/ -be_local_closure(Matter_Device_conf_to_log, /* name */ - be_nested_proto( - 9, /* nstack */ - 1, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Device), - /* K1 */ be_nested_str_weak(), - /* K2 */ be_nested_str_weak(k2l), - /* K3 */ be_nested_str_weak(type), - /* K4 */ be_nested_str_weak(_X20_X25s_X3A_X25s), - /* K5 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(conf_to_log), - &be_const_str_solidified, - ( &(const binstruction[24]) { /* code */ - 0x58040000, // 0000 LDCONST R1 K0 - 0x58080001, // 0001 LDCONST R2 K1 - 0x600C0010, // 0002 GETGBL R3 G16 - 0x8C100302, // 0003 GETMET R4 R1 K2 - 0x5C180000, // 0004 MOVE R6 R0 - 0x7C100400, // 0005 CALL R4 2 - 0x7C0C0200, // 0006 CALL R3 1 - 0xA802000B, // 0007 EXBLK 0 #0014 - 0x5C100600, // 0008 MOVE R4 R3 - 0x7C100000, // 0009 CALL R4 0 - 0x1C140903, // 000A EQ R5 R4 K3 - 0x78160000, // 000B JMPF R5 #000D - 0x7001FFFA, // 000C JMP #0008 - 0x60140018, // 000D GETGBL R5 G24 - 0x58180004, // 000E LDCONST R6 K4 - 0x5C1C0800, // 000F MOVE R7 R4 - 0x94200004, // 0010 GETIDX R8 R0 R4 - 0x7C140600, // 0011 CALL R5 3 - 0x00080405, // 0012 ADD R2 R2 R5 - 0x7001FFF3, // 0013 JMP #0008 - 0x580C0005, // 0014 LDCONST R3 K5 - 0xAC0C0200, // 0015 CATCH R3 1 0 - 0xB0080000, // 0016 RAISE 2 R0 R0 - 0x80040400, // 0017 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: mdns_remove_op_discovery_all_fabrics -********************************************************************/ -be_local_closure(Matter_Device_mdns_remove_op_discovery_all_fabrics, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(active_fabrics), - /* K2 */ be_nested_str_weak(get_device_id), - /* K3 */ be_nested_str_weak(get_fabric_id), - /* K4 */ be_nested_str_weak(mdns_remove_op_discovery), - /* K5 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(mdns_remove_op_discovery_all_fabrics), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x8C080501, // 0002 GETMET R2 R2 K1 - 0x7C080200, // 0003 CALL R2 1 - 0x7C040200, // 0004 CALL R1 1 - 0xA802000B, // 0005 EXBLK 0 #0012 - 0x5C080200, // 0006 MOVE R2 R1 - 0x7C080000, // 0007 CALL R2 0 - 0x8C0C0502, // 0008 GETMET R3 R2 K2 - 0x7C0C0200, // 0009 CALL R3 1 - 0x780E0005, // 000A JMPF R3 #0011 - 0x8C0C0503, // 000B GETMET R3 R2 K3 - 0x7C0C0200, // 000C CALL R3 1 - 0x780E0002, // 000D JMPF R3 #0011 - 0x8C0C0104, // 000E GETMET R3 R0 K4 - 0x5C140400, // 000F MOVE R5 R2 - 0x7C0C0400, // 0010 CALL R3 2 - 0x7001FFF3, // 0011 JMP #0006 - 0x58040005, // 0012 LDCONST R1 K5 - 0xAC040200, // 0013 CATCH R1 1 0 - 0xB0080000, // 0014 RAISE 2 R0 R0 - 0x80000000, // 0015 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: _init_basic_commissioning -********************************************************************/ -be_local_closure(Matter_Device__init_basic_commissioning, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(sessions), - /* K1 */ be_nested_str_weak(count_active_fabrics), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(start_root_basic_commissioning), - }), - be_str_weak(_init_basic_commissioning), - &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x1C040302, // 0003 EQ R1 R1 K2 - 0x78060001, // 0004 JMPF R1 #0007 - 0x8C040103, // 0005 GETMET R1 R0 K3 - 0x7C040200, // 0006 CALL R1 1 - 0x80000000, // 0007 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: attribute_updated -********************************************************************/ -be_local_closure(Matter_Device_attribute_updated, /* name */ - be_nested_proto( - 10, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(Path), - /* K2 */ be_nested_str_weak(endpoint), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(attribute), - /* K5 */ be_nested_str_weak(message_handler), - /* K6 */ be_nested_str_weak(im), - /* K7 */ be_nested_str_weak(subs_shop), - /* K8 */ be_nested_str_weak(attribute_updated_ctx), - }), - be_str_weak(attribute_updated), - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x4C140000, // 0000 LDNIL R5 - 0x1C140805, // 0001 EQ R5 R4 R5 - 0x78160000, // 0002 JMPF R5 #0004 - 0x50100000, // 0003 LDBOOL R4 0 0 - 0xB8160000, // 0004 GETNGBL R5 K0 - 0x8C140B01, // 0005 GETMET R5 R5 K1 - 0x7C140200, // 0006 CALL R5 1 - 0x90160401, // 0007 SETMBR R5 K2 R1 - 0x90160602, // 0008 SETMBR R5 K3 R2 - 0x90160803, // 0009 SETMBR R5 K4 R3 - 0x88180105, // 000A GETMBR R6 R0 K5 - 0x88180D06, // 000B GETMBR R6 R6 K6 - 0x88180D07, // 000C GETMBR R6 R6 K7 - 0x8C180D08, // 000D GETMET R6 R6 K8 - 0x5C200A00, // 000E MOVE R8 R5 - 0x5C240800, // 000F MOVE R9 R4 - 0x7C180600, // 0010 CALL R6 3 - 0x80000000, // 0011 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: register_plugin_class -********************************************************************/ -be_local_closure(Matter_Device_register_plugin_class, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(introspect), - /* K1 */ be_nested_str_weak(get), - /* K2 */ be_nested_str_weak(TYPE), - /* K3 */ be_nested_str_weak(plugins_classes), - }), - be_str_weak(register_plugin_class), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x8C0C0501, // 0001 GETMET R3 R2 K1 - 0x5C140200, // 0002 MOVE R5 R1 - 0x58180002, // 0003 LDCONST R6 K2 - 0x7C0C0600, // 0004 CALL R3 3 - 0x780E0001, // 0005 JMPF R3 #0008 - 0x88100103, // 0006 GETMBR R4 R0 K3 - 0x98100601, // 0007 SETIDX R4 R3 R1 - 0x80000000, // 0008 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: received_ack -********************************************************************/ -be_local_closure(Matter_Device_received_ack, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(udp_server), - /* K1 */ be_nested_str_weak(received_ack), - }), - be_str_weak(received_ack), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C080400, // 0003 CALL R2 2 - 0x80040400, // 0004 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: register_native_classes -********************************************************************/ -be_local_closure(Matter_Device_register_native_classes, /* name */ - be_nested_proto( - 12, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_nested_str_weak(introspect), - /* K1 */ be_nested_str_weak(string), - /* K2 */ be_nested_str_weak(members), - /* K3 */ be_nested_str_weak(matter), - /* K4 */ be_nested_str_weak(get), - /* K5 */ be_nested_str_weak(class), - /* K6 */ be_nested_str_weak(find), - /* K7 */ be_nested_str_weak(Plugin_), - /* K8 */ be_const_int(0), - /* K9 */ be_nested_str_weak(register_plugin_class), - /* K10 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(register_native_classes), - &be_const_str_solidified, - ( &(const binstruction[33]) { /* code */ - 0xA40E0000, // 0000 IMPORT R3 K0 - 0xA4120200, // 0001 IMPORT R4 K1 - 0x60140010, // 0002 GETGBL R5 G16 - 0x8C180702, // 0003 GETMET R6 R3 K2 - 0xB8220600, // 0004 GETNGBL R8 K3 - 0x7C180400, // 0005 CALL R6 2 - 0x7C140200, // 0006 CALL R5 1 - 0xA8020014, // 0007 EXBLK 0 #001D - 0x5C180A00, // 0008 MOVE R6 R5 - 0x7C180000, // 0009 CALL R6 0 - 0x8C1C0704, // 000A GETMET R7 R3 K4 - 0xB8260600, // 000B GETNGBL R9 K3 - 0x5C280C00, // 000C MOVE R10 R6 - 0x7C1C0600, // 000D CALL R7 3 - 0x60200004, // 000E GETGBL R8 G4 - 0x5C240E00, // 000F MOVE R9 R7 - 0x7C200200, // 0010 CALL R8 1 - 0x1C201105, // 0011 EQ R8 R8 K5 - 0x78220008, // 0012 JMPF R8 #001C - 0x8C200906, // 0013 GETMET R8 R4 K6 - 0x5C280C00, // 0014 MOVE R10 R6 - 0x582C0007, // 0015 LDCONST R11 K7 - 0x7C200600, // 0016 CALL R8 3 - 0x1C201108, // 0017 EQ R8 R8 K8 - 0x78220002, // 0018 JMPF R8 #001C - 0x8C200109, // 0019 GETMET R8 R0 K9 - 0x5C280E00, // 001A MOVE R10 R7 - 0x7C200400, // 001B CALL R8 2 - 0x7001FFEA, // 001C JMP #0008 - 0x5814000A, // 001D LDCONST R5 K10 - 0xAC140200, // 001E CATCH R5 1 0 - 0xB0080000, // 001F RAISE 2 R0 R0 - 0x80000000, // 0020 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start -********************************************************************/ -be_local_closure(Matter_Device_start, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 2, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(_trigger_read_sensors), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x7C000200, // 0002 CALL R0 1 - 0x80000000, // 0003 RET 0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(started), - /* K1 */ be_nested_str_weak(autoconf_device), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(add_cron), - /* K4 */ be_nested_str_weak(_X2A_X2F30_X20_X2A_X20_X2A_X20_X2A_X20_X2A_X20_X2A), - /* K5 */ be_nested_str_weak(matter_sensors_30s), - /* K6 */ be_nested_str_weak(_start_udp), - /* K7 */ be_nested_str_weak(UDP_PORT), - /* K8 */ be_nested_str_weak(start_mdns_announce_hostnames), - }), - be_str_weak(start), - &be_const_str_solidified, - ( &(const binstruction[20]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060000, // 0001 JMPF R1 #0003 - 0x80000200, // 0002 RET 0 - 0x8C040101, // 0003 GETMET R1 R0 K1 - 0x7C040200, // 0004 CALL R1 1 - 0xB8060400, // 0005 GETNGBL R1 K2 - 0x8C040303, // 0006 GETMET R1 R1 K3 - 0x580C0004, // 0007 LDCONST R3 K4 - 0x84100000, // 0008 CLOSURE R4 P0 - 0x58140005, // 0009 LDCONST R5 K5 - 0x7C040800, // 000A CALL R1 4 - 0x8C040106, // 000B GETMET R1 R0 K6 - 0x880C0107, // 000C GETMBR R3 R0 K7 - 0x7C040400, // 000D CALL R1 2 - 0x8C040108, // 000E GETMET R1 R0 K8 - 0x7C040200, // 000F CALL R1 1 - 0x50040200, // 0010 LDBOOL R1 1 0 - 0x90020001, // 0011 SETMBR R0 K0 R1 - 0xA0000000, // 0012 CLOSE R0 - 0x80000000, // 0013 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_basic_commissioning -********************************************************************/ -be_local_closure(Matter_Device_start_basic_commissioning, /* name */ - be_nested_proto( - 13, /* nstack */ - 8, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 2]) { - be_nested_proto( - 4, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(mdns_announce_PASE), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(remove_rule), - /* K3 */ be_nested_str_weak(Wifi_X23Connected), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x7C000200, // 0002 CALL R0 1 - 0xB8020200, // 0003 GETNGBL R0 K1 - 0x8C000102, // 0004 GETMET R0 R0 K2 - 0x58080003, // 0005 LDCONST R2 K3 - 0x580C0000, // 0006 LDCONST R3 K0 - 0x7C000600, // 0007 CALL R0 3 - 0x80000000, // 0008 RET 0 - }) - ), - be_nested_proto( - 4, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(mdns_announce_PASE), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(remove_rule), - /* K3 */ be_nested_str_weak(Eth_X23Connected), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x7C000200, // 0002 CALL R0 1 - 0xB8020200, // 0003 GETNGBL R0 K1 - 0x8C000102, // 0004 GETMET R0 R0 K2 - 0x58080003, // 0005 LDCONST R2 K3 - 0x580C0000, // 0006 LDCONST R3 K0 - 0x7C000600, // 0007 CALL R0 3 - 0x80000000, // 0008 RET 0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ - /* K0 */ be_nested_str_weak(commissioning_open), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(millis), - /* K3 */ be_nested_str_weak(commissioning_iterations), - /* K4 */ be_nested_str_weak(commissioning_discriminator), - /* K5 */ be_nested_str_weak(commissioning_salt), - /* K6 */ be_nested_str_weak(commissioning_w0), - /* K7 */ be_nested_str_weak(commissioning_L), - /* K8 */ be_nested_str_weak(commissioning_admin_fabric), - /* K9 */ be_nested_str_weak(wifi), - /* K10 */ be_nested_str_weak(up), - /* K11 */ be_nested_str_weak(eth), - /* K12 */ be_nested_str_weak(mdns_announce_PASE), - /* K13 */ be_nested_str_weak(add_rule), - /* K14 */ be_nested_str_weak(Wifi_X23Connected), - /* K15 */ be_nested_str_weak(Eth_X23Connected), - }), - be_str_weak(start_basic_commissioning), - &be_const_str_solidified, - ( &(const binstruction[40]) { /* code */ - 0xB8220200, // 0000 GETNGBL R8 K1 - 0x8C201102, // 0001 GETMET R8 R8 K2 - 0x7C200200, // 0002 CALL R8 1 - 0x542603E7, // 0003 LDINT R9 1000 - 0x08240209, // 0004 MUL R9 R1 R9 - 0x00201009, // 0005 ADD R8 R8 R9 - 0x90020008, // 0006 SETMBR R0 K0 R8 - 0x90020602, // 0007 SETMBR R0 K3 R2 - 0x90020803, // 0008 SETMBR R0 K4 R3 - 0x90020A04, // 0009 SETMBR R0 K5 R4 - 0x90020C05, // 000A SETMBR R0 K6 R5 - 0x90020E06, // 000B SETMBR R0 K7 R6 - 0x90021007, // 000C SETMBR R0 K8 R7 - 0xB8220200, // 000D GETNGBL R8 K1 - 0x8C201109, // 000E GETMET R8 R8 K9 - 0x7C200200, // 000F CALL R8 1 - 0x9420110A, // 0010 GETIDX R8 R8 K10 - 0x74220004, // 0011 JMPT R8 #0017 - 0xB8220200, // 0012 GETNGBL R8 K1 - 0x8C20110B, // 0013 GETMET R8 R8 K11 - 0x7C200200, // 0014 CALL R8 1 - 0x9420110A, // 0015 GETIDX R8 R8 K10 - 0x78220002, // 0016 JMPF R8 #001A - 0x8C20010C, // 0017 GETMET R8 R0 K12 - 0x7C200200, // 0018 CALL R8 1 - 0x7002000B, // 0019 JMP #0026 - 0xB8220200, // 001A GETNGBL R8 K1 - 0x8C20110D, // 001B GETMET R8 R8 K13 - 0x5828000E, // 001C LDCONST R10 K14 - 0x842C0000, // 001D CLOSURE R11 P0 - 0x5830000C, // 001E LDCONST R12 K12 - 0x7C200800, // 001F CALL R8 4 - 0xB8220200, // 0020 GETNGBL R8 K1 - 0x8C20110D, // 0021 GETMET R8 R8 K13 - 0x5828000F, // 0022 LDCONST R10 K15 - 0x842C0001, // 0023 CLOSURE R11 P1 - 0x5830000C, // 0024 LDCONST R12 K12 - 0x7C200800, // 0025 CALL R8 4 - 0xA0000000, // 0026 CLOSE R0 - 0x80000000, // 0027 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: signal_endpoints_changed -********************************************************************/ -be_local_closure(Matter_Device_signal_endpoints_changed, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - /* K2 */ be_const_int(3), - }), - be_str_weak(signal_endpoints_changed), - &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x580C0001, // 0001 LDCONST R3 K1 - 0x5412001C, // 0002 LDINT R4 29 - 0x58140002, // 0003 LDCONST R5 K2 - 0x50180000, // 0004 LDBOOL R6 0 0 - 0x7C040A00, // 0005 CALL R1 5 - 0x8C040100, // 0006 GETMET R1 R0 K0 - 0x540EFEFF, // 0007 LDINT R3 65280 - 0x5412001C, // 0008 LDINT R4 29 - 0x58140002, // 0009 LDCONST R5 K2 - 0x50180000, // 000A LDBOOL R6 0 0 - 0x7C040A00, // 000B CALL R1 5 - 0x80000000, // 000C RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: _compute_pbkdf ********************************************************************/ @@ -4770,6 +5472,404 @@ be_local_closure(Matter_Device__compute_pbkdf, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: get_plugin_class_arg +********************************************************************/ +be_local_closure(Matter_Device_get_plugin_class_arg, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(plugins_classes), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(ARG), + /* K3 */ be_nested_str_weak(), + }), + be_str_weak(get_plugin_class_arg), + &be_const_str_solidified, + ( &(const binstruction[ 9]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x780A0001, // 0004 JMPF R2 #0007 + 0x880C0502, // 0005 GETMBR R3 R2 K2 + 0x70020000, // 0006 JMP #0008 + 0x580C0003, // 0007 LDCONST R3 K3 + 0x80040600, // 0008 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: mdns_announce_op_discovery_all_fabrics +********************************************************************/ +be_local_closure(Matter_Device_mdns_announce_op_discovery_all_fabrics, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(active_fabrics), + /* K2 */ be_nested_str_weak(get_device_id), + /* K3 */ be_nested_str_weak(get_fabric_id), + /* K4 */ be_nested_str_weak(mdns_announce_op_discovery), + /* K5 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(mdns_announce_op_discovery_all_fabrics), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x8C080501, // 0002 GETMET R2 R2 K1 + 0x7C080200, // 0003 CALL R2 1 + 0x7C040200, // 0004 CALL R1 1 + 0xA802000B, // 0005 EXBLK 0 #0012 + 0x5C080200, // 0006 MOVE R2 R1 + 0x7C080000, // 0007 CALL R2 0 + 0x8C0C0502, // 0008 GETMET R3 R2 K2 + 0x7C0C0200, // 0009 CALL R3 1 + 0x780E0005, // 000A JMPF R3 #0011 + 0x8C0C0503, // 000B GETMET R3 R2 K3 + 0x7C0C0200, // 000C CALL R3 1 + 0x780E0002, // 000D JMPF R3 #0011 + 0x8C0C0104, // 000E GETMET R3 R0 K4 + 0x5C140400, // 000F MOVE R5 R2 + 0x7C0C0400, // 0010 CALL R3 2 + 0x7001FFF3, // 0011 JMP #0006 + 0x58040005, // 0012 LDCONST R1 K5 + 0xAC040200, // 0013 CATCH R1 1 0 + 0xB0080000, // 0014 RAISE 2 R0 R0 + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: event_fabrics_saved +********************************************************************/ +be_local_closure(Matter_Device_event_fabrics_saved, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(sessions), + /* K1 */ be_nested_str_weak(count_active_fabrics), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(plugins_persist), + /* K4 */ be_nested_str_weak(save_param), + }), + be_str_weak(event_fabrics_saved), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x24040302, // 0003 GT R1 R1 K2 + 0x78060005, // 0004 JMPF R1 #000B + 0x88040103, // 0005 GETMBR R1 R0 K3 + 0x74060003, // 0006 JMPT R1 #000B + 0x50040200, // 0007 LDBOOL R1 1 0 + 0x90020601, // 0008 SETMBR R0 K3 R1 + 0x8C040104, // 0009 GETMET R1 R0 K4 + 0x7C040200, // 000A CALL R1 1 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: start_mdns_announce_hostnames +********************************************************************/ +be_local_closure(Matter_Device_start_mdns_announce_hostnames, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 2]) { + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(_mdns_announce_hostname), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(remove_rule), + /* K3 */ be_nested_str_weak(Wifi_X23Connected), + /* K4 */ be_nested_str_weak(matter_mdns_host), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x50080000, // 0002 LDBOOL R2 0 0 + 0x7C000400, // 0003 CALL R0 2 + 0xB8020200, // 0004 GETNGBL R0 K1 + 0x8C000102, // 0005 GETMET R0 R0 K2 + 0x58080003, // 0006 LDCONST R2 K3 + 0x580C0004, // 0007 LDCONST R3 K4 + 0x7C000600, // 0008 CALL R0 3 + 0x80000000, // 0009 RET 0 + }) + ), + be_nested_proto( + 4, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 1]) { /* upvals */ + be_local_const_upval(1, 0), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(_mdns_announce_hostname), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(remove_rule), + /* K3 */ be_nested_str_weak(Eth_X23Connected), + /* K4 */ be_nested_str_weak(matter_mdns_host), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x8C000100, // 0001 GETMET R0 R0 K0 + 0x50080200, // 0002 LDBOOL R2 1 0 + 0x7C000400, // 0003 CALL R0 2 + 0xB8020200, // 0004 GETNGBL R0 K1 + 0x8C000102, // 0005 GETMET R0 R0 K2 + 0x58080003, // 0006 LDCONST R2 K3 + 0x580C0004, // 0007 LDCONST R3 K4 + 0x7C000600, // 0008 CALL R0 3 + 0x80000000, // 0009 RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(wifi), + /* K2 */ be_nested_str_weak(up), + /* K3 */ be_nested_str_weak(_mdns_announce_hostname), + /* K4 */ be_nested_str_weak(add_rule), + /* K5 */ be_nested_str_weak(Wifi_X23Connected), + /* K6 */ be_nested_str_weak(matter_mdns_host), + /* K7 */ be_nested_str_weak(eth), + /* K8 */ be_nested_str_weak(Eth_X23Connected), + }), + be_str_weak(start_mdns_announce_hostnames), + &be_const_str_solidified, + ( &(const binstruction[32]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x94040302, // 0003 GETIDX R1 R1 K2 + 0x78060003, // 0004 JMPF R1 #0009 + 0x8C040103, // 0005 GETMET R1 R0 K3 + 0x500C0000, // 0006 LDBOOL R3 0 0 + 0x7C040400, // 0007 CALL R1 2 + 0x70020005, // 0008 JMP #000F + 0xB8060000, // 0009 GETNGBL R1 K0 + 0x8C040304, // 000A GETMET R1 R1 K4 + 0x580C0005, // 000B LDCONST R3 K5 + 0x84100000, // 000C CLOSURE R4 P0 + 0x58140006, // 000D LDCONST R5 K6 + 0x7C040800, // 000E CALL R1 4 + 0xB8060000, // 000F GETNGBL R1 K0 + 0x8C040307, // 0010 GETMET R1 R1 K7 + 0x7C040200, // 0011 CALL R1 1 + 0x94040302, // 0012 GETIDX R1 R1 K2 + 0x78060003, // 0013 JMPF R1 #0018 + 0x8C040103, // 0014 GETMET R1 R0 K3 + 0x500C0200, // 0015 LDBOOL R3 1 0 + 0x7C040400, // 0016 CALL R1 2 + 0x70020005, // 0017 JMP #001E + 0xB8060000, // 0018 GETNGBL R1 K0 + 0x8C040304, // 0019 GETMET R1 R1 K4 + 0x580C0008, // 001A LDCONST R3 K8 + 0x84100001, // 001B CLOSURE R4 P1 + 0x58140006, // 001C LDCONST R5 K6 + 0x7C040800, // 001D CALL R1 4 + 0xA0000000, // 001E CLOSE R0 + 0x80000000, // 001F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: save_param +********************************************************************/ +be_local_closure(Matter_Device_save_param, /* name */ + be_nested_proto( + 10, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[30]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(update_remotes_info), + /* K2 */ be_nested_str_weak(_X7B_X22distinguish_X22_X3A_X25i_X2C_X22passcode_X22_X3A_X25i_X2C_X22ipv4only_X22_X3A_X25s_X2C_X22disable_bridge_mode_X22_X3A_X25s_X2C_X22nextep_X22_X3A_X25i), + /* K3 */ be_nested_str_weak(root_discriminator), + /* K4 */ be_nested_str_weak(root_passcode), + /* K5 */ be_nested_str_weak(ipv4only), + /* K6 */ be_nested_str_weak(true), + /* K7 */ be_nested_str_weak(false), + /* K8 */ be_nested_str_weak(disable_bridge_mode), + /* K9 */ be_nested_str_weak(next_ep), + /* K10 */ be_nested_str_weak(plugins_persist), + /* K11 */ be_nested_str_weak(_X2C_X22config_X22_X3A), + /* K12 */ be_nested_str_weak(dump), + /* K13 */ be_nested_str_weak(plugins_config), + /* K14 */ be_nested_str_weak(plugins_config_remotes), + /* K15 */ be_const_int(0), + /* K16 */ be_nested_str_weak(_X2C_X22remotes_X22_X3A), + /* K17 */ be_nested_str_weak(_X7D), + /* K18 */ be_nested_str_weak(FILENAME), + /* K19 */ be_nested_str_weak(w), + /* K20 */ be_nested_str_weak(write), + /* K21 */ be_nested_str_weak(close), + /* K22 */ be_nested_str_weak(tasmota), + /* K23 */ be_nested_str_weak(log), + /* K24 */ be_nested_str_weak(MTR_X3A_X20_X3DSaved_X20_X20_X20_X20_X20parameters_X25s), + /* K25 */ be_nested_str_weak(_X20and_X20configuration), + /* K26 */ be_nested_str_weak(), + /* K27 */ be_const_int(2), + /* K28 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), + /* K29 */ be_nested_str_weak(_X7C), + }), + be_str_weak(save_param), + &be_const_str_solidified, + ( &(const binstruction[82]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080101, // 0001 GETMET R2 R0 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x60080018, // 0003 GETGBL R2 G24 + 0x580C0002, // 0004 LDCONST R3 K2 + 0x88100103, // 0005 GETMBR R4 R0 K3 + 0x88140104, // 0006 GETMBR R5 R0 K4 + 0x88180105, // 0007 GETMBR R6 R0 K5 + 0x781A0001, // 0008 JMPF R6 #000B + 0x58180006, // 0009 LDCONST R6 K6 + 0x70020000, // 000A JMP #000C + 0x58180007, // 000B LDCONST R6 K7 + 0x881C0108, // 000C GETMBR R7 R0 K8 + 0x781E0001, // 000D JMPF R7 #0010 + 0x581C0006, // 000E LDCONST R7 K6 + 0x70020000, // 000F JMP #0011 + 0x581C0007, // 0010 LDCONST R7 K7 + 0x88200109, // 0011 GETMBR R8 R0 K9 + 0x7C080C00, // 0012 CALL R2 6 + 0x880C010A, // 0013 GETMBR R3 R0 K10 + 0x780E000E, // 0014 JMPF R3 #0024 + 0x0008050B, // 0015 ADD R2 R2 K11 + 0x8C0C030C, // 0016 GETMET R3 R1 K12 + 0x8814010D, // 0017 GETMBR R5 R0 K13 + 0x7C0C0400, // 0018 CALL R3 2 + 0x00080403, // 0019 ADD R2 R2 R3 + 0x600C000C, // 001A GETGBL R3 G12 + 0x8810010E, // 001B GETMBR R4 R0 K14 + 0x7C0C0200, // 001C CALL R3 1 + 0x240C070F, // 001D GT R3 R3 K15 + 0x780E0004, // 001E JMPF R3 #0024 + 0x00080510, // 001F ADD R2 R2 K16 + 0x8C0C030C, // 0020 GETMET R3 R1 K12 + 0x8814010E, // 0021 GETMBR R5 R0 K14 + 0x7C0C0400, // 0022 CALL R3 2 + 0x00080403, // 0023 ADD R2 R2 R3 + 0x00080511, // 0024 ADD R2 R2 K17 + 0xA8020018, // 0025 EXBLK 0 #003F + 0x600C0011, // 0026 GETGBL R3 G17 + 0x88100112, // 0027 GETMBR R4 R0 K18 + 0x58140013, // 0028 LDCONST R5 K19 + 0x7C0C0400, // 0029 CALL R3 2 + 0x8C100714, // 002A GETMET R4 R3 K20 + 0x5C180400, // 002B MOVE R6 R2 + 0x7C100400, // 002C CALL R4 2 + 0x8C100715, // 002D GETMET R4 R3 K21 + 0x7C100200, // 002E CALL R4 1 + 0xB8122C00, // 002F GETNGBL R4 K22 + 0x8C100917, // 0030 GETMET R4 R4 K23 + 0x60180018, // 0031 GETGBL R6 G24 + 0x581C0018, // 0032 LDCONST R7 K24 + 0x8820010A, // 0033 GETMBR R8 R0 K10 + 0x78220001, // 0034 JMPF R8 #0037 + 0x58200019, // 0035 LDCONST R8 K25 + 0x70020000, // 0036 JMP #0038 + 0x5820001A, // 0037 LDCONST R8 K26 + 0x7C180400, // 0038 CALL R6 2 + 0x581C001B, // 0039 LDCONST R7 K27 + 0x7C100600, // 003A CALL R4 3 + 0xA8040001, // 003B EXBLK 1 1 + 0x80040400, // 003C RET 1 R2 + 0xA8040001, // 003D EXBLK 1 1 + 0x70020011, // 003E JMP #0051 + 0xAC0C0002, // 003F CATCH R3 0 2 + 0x7002000E, // 0040 JMP #0050 + 0xB8162C00, // 0041 GETNGBL R5 K22 + 0x8C140B17, // 0042 GETMET R5 R5 K23 + 0x601C0008, // 0043 GETGBL R7 G8 + 0x5C200600, // 0044 MOVE R8 R3 + 0x7C1C0200, // 0045 CALL R7 1 + 0x001E3807, // 0046 ADD R7 K28 R7 + 0x001C0F1D, // 0047 ADD R7 R7 K29 + 0x60200008, // 0048 GETGBL R8 G8 + 0x5C240800, // 0049 MOVE R9 R4 + 0x7C200200, // 004A CALL R8 1 + 0x001C0E08, // 004B ADD R7 R7 R8 + 0x5820001B, // 004C LDCONST R8 K27 + 0x7C140600, // 004D CALL R5 3 + 0x80040400, // 004E RET 1 R2 + 0x70020000, // 004F JMP #0051 + 0xB0080000, // 0050 RAISE 2 R0 R0 + 0x80000000, // 0051 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: mdns_announce_PASE ********************************************************************/ @@ -5071,692 +6171,17 @@ be_local_closure(Matter_Device_mdns_announce_PASE, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: save_param -********************************************************************/ -be_local_closure(Matter_Device_save_param, /* name */ - be_nested_proto( - 10, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[30]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(update_remotes_info), - /* K2 */ be_nested_str_weak(_X7B_X22distinguish_X22_X3A_X25i_X2C_X22passcode_X22_X3A_X25i_X2C_X22ipv4only_X22_X3A_X25s_X2C_X22disable_bridge_mode_X22_X3A_X25s_X2C_X22nextep_X22_X3A_X25i), - /* K3 */ be_nested_str_weak(root_discriminator), - /* K4 */ be_nested_str_weak(root_passcode), - /* K5 */ be_nested_str_weak(ipv4only), - /* K6 */ be_nested_str_weak(true), - /* K7 */ be_nested_str_weak(false), - /* K8 */ be_nested_str_weak(disable_bridge_mode), - /* K9 */ be_nested_str_weak(next_ep), - /* K10 */ be_nested_str_weak(plugins_persist), - /* K11 */ be_nested_str_weak(_X2C_X22config_X22_X3A), - /* K12 */ be_nested_str_weak(dump), - /* K13 */ be_nested_str_weak(plugins_config), - /* K14 */ be_nested_str_weak(plugins_config_remotes), - /* K15 */ be_const_int(0), - /* K16 */ be_nested_str_weak(_X2C_X22remotes_X22_X3A), - /* K17 */ be_nested_str_weak(_X7D), - /* K18 */ be_nested_str_weak(FILENAME), - /* K19 */ be_nested_str_weak(w), - /* K20 */ be_nested_str_weak(write), - /* K21 */ be_nested_str_weak(close), - /* K22 */ be_nested_str_weak(tasmota), - /* K23 */ be_nested_str_weak(log), - /* K24 */ be_nested_str_weak(MTR_X3A_X20_X3DSaved_X20_X20_X20_X20_X20parameters_X25s), - /* K25 */ be_nested_str_weak(_X20and_X20configuration), - /* K26 */ be_nested_str_weak(), - /* K27 */ be_const_int(2), - /* K28 */ be_nested_str_weak(MTR_X3A_X20Session_Store_X3A_X3Asave_X20Exception_X3A), - /* K29 */ be_nested_str_weak(_X7C), - }), - be_str_weak(save_param), - &be_const_str_solidified, - ( &(const binstruction[82]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080101, // 0001 GETMET R2 R0 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x60080018, // 0003 GETGBL R2 G24 - 0x580C0002, // 0004 LDCONST R3 K2 - 0x88100103, // 0005 GETMBR R4 R0 K3 - 0x88140104, // 0006 GETMBR R5 R0 K4 - 0x88180105, // 0007 GETMBR R6 R0 K5 - 0x781A0001, // 0008 JMPF R6 #000B - 0x58180006, // 0009 LDCONST R6 K6 - 0x70020000, // 000A JMP #000C - 0x58180007, // 000B LDCONST R6 K7 - 0x881C0108, // 000C GETMBR R7 R0 K8 - 0x781E0001, // 000D JMPF R7 #0010 - 0x581C0006, // 000E LDCONST R7 K6 - 0x70020000, // 000F JMP #0011 - 0x581C0007, // 0010 LDCONST R7 K7 - 0x88200109, // 0011 GETMBR R8 R0 K9 - 0x7C080C00, // 0012 CALL R2 6 - 0x880C010A, // 0013 GETMBR R3 R0 K10 - 0x780E000E, // 0014 JMPF R3 #0024 - 0x0008050B, // 0015 ADD R2 R2 K11 - 0x8C0C030C, // 0016 GETMET R3 R1 K12 - 0x8814010D, // 0017 GETMBR R5 R0 K13 - 0x7C0C0400, // 0018 CALL R3 2 - 0x00080403, // 0019 ADD R2 R2 R3 - 0x600C000C, // 001A GETGBL R3 G12 - 0x8810010E, // 001B GETMBR R4 R0 K14 - 0x7C0C0200, // 001C CALL R3 1 - 0x240C070F, // 001D GT R3 R3 K15 - 0x780E0004, // 001E JMPF R3 #0024 - 0x00080510, // 001F ADD R2 R2 K16 - 0x8C0C030C, // 0020 GETMET R3 R1 K12 - 0x8814010E, // 0021 GETMBR R5 R0 K14 - 0x7C0C0400, // 0022 CALL R3 2 - 0x00080403, // 0023 ADD R2 R2 R3 - 0x00080511, // 0024 ADD R2 R2 K17 - 0xA8020018, // 0025 EXBLK 0 #003F - 0x600C0011, // 0026 GETGBL R3 G17 - 0x88100112, // 0027 GETMBR R4 R0 K18 - 0x58140013, // 0028 LDCONST R5 K19 - 0x7C0C0400, // 0029 CALL R3 2 - 0x8C100714, // 002A GETMET R4 R3 K20 - 0x5C180400, // 002B MOVE R6 R2 - 0x7C100400, // 002C CALL R4 2 - 0x8C100715, // 002D GETMET R4 R3 K21 - 0x7C100200, // 002E CALL R4 1 - 0xB8122C00, // 002F GETNGBL R4 K22 - 0x8C100917, // 0030 GETMET R4 R4 K23 - 0x60180018, // 0031 GETGBL R6 G24 - 0x581C0018, // 0032 LDCONST R7 K24 - 0x8820010A, // 0033 GETMBR R8 R0 K10 - 0x78220001, // 0034 JMPF R8 #0037 - 0x58200019, // 0035 LDCONST R8 K25 - 0x70020000, // 0036 JMP #0038 - 0x5820001A, // 0037 LDCONST R8 K26 - 0x7C180400, // 0038 CALL R6 2 - 0x581C001B, // 0039 LDCONST R7 K27 - 0x7C100600, // 003A CALL R4 3 - 0xA8040001, // 003B EXBLK 1 1 - 0x80040400, // 003C RET 1 R2 - 0xA8040001, // 003D EXBLK 1 1 - 0x70020011, // 003E JMP #0051 - 0xAC0C0002, // 003F CATCH R3 0 2 - 0x7002000E, // 0040 JMP #0050 - 0xB8162C00, // 0041 GETNGBL R5 K22 - 0x8C140B17, // 0042 GETMET R5 R5 K23 - 0x601C0008, // 0043 GETGBL R7 G8 - 0x5C200600, // 0044 MOVE R8 R3 - 0x7C1C0200, // 0045 CALL R7 1 - 0x001E3807, // 0046 ADD R7 K28 R7 - 0x001C0F1D, // 0047 ADD R7 R7 K29 - 0x60200008, // 0048 GETGBL R8 G8 - 0x5C240800, // 0049 MOVE R9 R4 - 0x7C200200, // 004A CALL R8 1 - 0x001C0E08, // 004B ADD R7 R7 R8 - 0x5820001B, // 004C LDCONST R8 K27 - 0x7C140600, // 004D CALL R5 3 - 0x80040400, // 004E RET 1 R2 - 0x70020000, // 004F JMP #0051 - 0xB0080000, // 0050 RAISE 2 R0 R0 - 0x80000000, // 0051 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: start_mdns_announce_hostnames -********************************************************************/ -be_local_closure(Matter_Device_start_mdns_announce_hostnames, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 2]) { - be_nested_proto( - 4, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(_mdns_announce_hostname), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(remove_rule), - /* K3 */ be_nested_str_weak(Wifi_X23Connected), - /* K4 */ be_nested_str_weak(matter_mdns_host), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x50080000, // 0002 LDBOOL R2 0 0 - 0x7C000400, // 0003 CALL R0 2 - 0xB8020200, // 0004 GETNGBL R0 K1 - 0x8C000102, // 0005 GETMET R0 R0 K2 - 0x58080003, // 0006 LDCONST R2 K3 - 0x580C0004, // 0007 LDCONST R3 K4 - 0x7C000600, // 0008 CALL R0 3 - 0x80000000, // 0009 RET 0 - }) - ), - be_nested_proto( - 4, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 1]) { /* upvals */ - be_local_const_upval(1, 0), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(_mdns_announce_hostname), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(remove_rule), - /* K3 */ be_nested_str_weak(Eth_X23Connected), - /* K4 */ be_nested_str_weak(matter_mdns_host), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x8C000100, // 0001 GETMET R0 R0 K0 - 0x50080200, // 0002 LDBOOL R2 1 0 - 0x7C000400, // 0003 CALL R0 2 - 0xB8020200, // 0004 GETNGBL R0 K1 - 0x8C000102, // 0005 GETMET R0 R0 K2 - 0x58080003, // 0006 LDCONST R2 K3 - 0x580C0004, // 0007 LDCONST R3 K4 - 0x7C000600, // 0008 CALL R0 3 - 0x80000000, // 0009 RET 0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(wifi), - /* K2 */ be_nested_str_weak(up), - /* K3 */ be_nested_str_weak(_mdns_announce_hostname), - /* K4 */ be_nested_str_weak(add_rule), - /* K5 */ be_nested_str_weak(Wifi_X23Connected), - /* K6 */ be_nested_str_weak(matter_mdns_host), - /* K7 */ be_nested_str_weak(eth), - /* K8 */ be_nested_str_weak(Eth_X23Connected), - }), - be_str_weak(start_mdns_announce_hostnames), - &be_const_str_solidified, - ( &(const binstruction[32]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x94040302, // 0003 GETIDX R1 R1 K2 - 0x78060003, // 0004 JMPF R1 #0009 - 0x8C040103, // 0005 GETMET R1 R0 K3 - 0x500C0000, // 0006 LDBOOL R3 0 0 - 0x7C040400, // 0007 CALL R1 2 - 0x70020005, // 0008 JMP #000F - 0xB8060000, // 0009 GETNGBL R1 K0 - 0x8C040304, // 000A GETMET R1 R1 K4 - 0x580C0005, // 000B LDCONST R3 K5 - 0x84100000, // 000C CLOSURE R4 P0 - 0x58140006, // 000D LDCONST R5 K6 - 0x7C040800, // 000E CALL R1 4 - 0xB8060000, // 000F GETNGBL R1 K0 - 0x8C040307, // 0010 GETMET R1 R1 K7 - 0x7C040200, // 0011 CALL R1 1 - 0x94040302, // 0012 GETIDX R1 R1 K2 - 0x78060003, // 0013 JMPF R1 #0018 - 0x8C040103, // 0014 GETMET R1 R0 K3 - 0x500C0200, // 0015 LDBOOL R3 1 0 - 0x7C040400, // 0016 CALL R1 2 - 0x70020005, // 0017 JMP #001E - 0xB8060000, // 0018 GETNGBL R1 K0 - 0x8C040304, // 0019 GETMET R1 R1 K4 - 0x580C0008, // 001A LDCONST R3 K8 - 0x84100001, // 001B CLOSURE R4 P1 - 0x58140006, // 001C LDCONST R5 K6 - 0x7C040800, // 001D CALL R1 4 - 0xA0000000, // 001E CLOSE R0 - 0x80000000, // 001F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: k2l_num -********************************************************************/ -be_local_closure(Matter_Device_k2l_num, /* name */ - be_nested_proto( - 9, /* nstack */ - 1, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Device), - /* K1 */ be_nested_str_weak(keys), - /* K2 */ be_nested_str_weak(push), - /* K3 */ be_nested_str_weak(stop_iteration), - /* K4 */ be_const_int(1), - /* K5 */ be_const_int(0), - }), - be_str_weak(k2l_num), - &be_const_str_solidified, - ( &(const binstruction[52]) { /* code */ - 0x58040000, // 0000 LDCONST R1 K0 - 0x60080012, // 0001 GETGBL R2 G18 - 0x7C080000, // 0002 CALL R2 0 - 0x4C0C0000, // 0003 LDNIL R3 - 0x1C0C0003, // 0004 EQ R3 R0 R3 - 0x780E0000, // 0005 JMPF R3 #0007 - 0x80040400, // 0006 RET 1 R2 - 0x600C0010, // 0007 GETGBL R3 G16 - 0x8C100101, // 0008 GETMET R4 R0 K1 - 0x7C100200, // 0009 CALL R4 1 - 0x7C0C0200, // 000A CALL R3 1 - 0xA8020007, // 000B EXBLK 0 #0014 - 0x5C100600, // 000C MOVE R4 R3 - 0x7C100000, // 000D CALL R4 0 - 0x8C140502, // 000E GETMET R5 R2 K2 - 0x601C0009, // 000F GETGBL R7 G9 - 0x5C200800, // 0010 MOVE R8 R4 - 0x7C1C0200, // 0011 CALL R7 1 - 0x7C140400, // 0012 CALL R5 2 - 0x7001FFF7, // 0013 JMP #000C - 0x580C0003, // 0014 LDCONST R3 K3 - 0xAC0C0200, // 0015 CATCH R3 1 0 - 0xB0080000, // 0016 RAISE 2 R0 R0 - 0x600C0010, // 0017 GETGBL R3 G16 - 0x6010000C, // 0018 GETGBL R4 G12 - 0x5C140400, // 0019 MOVE R5 R2 - 0x7C100200, // 001A CALL R4 1 - 0x04100904, // 001B SUB R4 R4 K4 - 0x40120804, // 001C CONNECT R4 K4 R4 - 0x7C0C0200, // 001D CALL R3 1 - 0xA8020010, // 001E EXBLK 0 #0030 - 0x5C100600, // 001F MOVE R4 R3 - 0x7C100000, // 0020 CALL R4 0 - 0x94140404, // 0021 GETIDX R5 R2 R4 - 0x5C180800, // 0022 MOVE R6 R4 - 0x241C0D05, // 0023 GT R7 R6 K5 - 0x781E0008, // 0024 JMPF R7 #002E - 0x041C0D04, // 0025 SUB R7 R6 K4 - 0x941C0407, // 0026 GETIDX R7 R2 R7 - 0x241C0E05, // 0027 GT R7 R7 R5 - 0x781E0004, // 0028 JMPF R7 #002E - 0x041C0D04, // 0029 SUB R7 R6 K4 - 0x941C0407, // 002A GETIDX R7 R2 R7 - 0x98080C07, // 002B SETIDX R2 R6 R7 - 0x04180D04, // 002C SUB R6 R6 K4 - 0x7001FFF4, // 002D JMP #0023 - 0x98080C05, // 002E SETIDX R2 R6 R5 - 0x7001FFEE, // 002F JMP #001F - 0x580C0003, // 0030 LDCONST R3 K3 - 0xAC0C0200, // 0031 CATCH R3 1 0 - 0xB0080000, // 0032 RAISE 2 R0 R0 - 0x80040400, // 0033 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: autoconf_device -********************************************************************/ -be_local_closure(Matter_Device_autoconf_device, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ - /* K0 */ be_nested_str_weak(json), - /* K1 */ be_nested_str_weak(plugins), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(plugins_persist), - /* K4 */ be_nested_str_weak(plugins_config), - /* K5 */ be_nested_str_weak(autoconf_device_map), - /* K6 */ be_nested_str_weak(plugins_config_remotes), - /* K7 */ be_nested_str_weak(adjust_next_ep), - /* K8 */ be_nested_str_weak(tasmota), - /* K9 */ be_nested_str_weak(log), - /* K10 */ be_nested_str_weak(MTR_X3A_X20autoconfig_X20_X3D_X20), - /* K11 */ be_const_int(3), - /* K12 */ be_nested_str_weak(_instantiate_plugins_from_config), - /* K13 */ be_nested_str_weak(sessions), - /* K14 */ be_nested_str_weak(count_active_fabrics), - /* K15 */ be_nested_str_weak(save_param), - }), - be_str_weak(autoconf_device), - &be_const_str_solidified, - ( &(const binstruction[40]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x6008000C, // 0001 GETGBL R2 G12 - 0x880C0101, // 0002 GETMBR R3 R0 K1 - 0x7C080200, // 0003 CALL R2 1 - 0x24080502, // 0004 GT R2 R2 K2 - 0x780A0000, // 0005 JMPF R2 #0007 - 0x80000400, // 0006 RET 0 - 0x88080103, // 0007 GETMBR R2 R0 K3 - 0x740A000F, // 0008 JMPT R2 #0019 - 0x8C080105, // 0009 GETMET R2 R0 K5 - 0x7C080200, // 000A CALL R2 1 - 0x90020802, // 000B SETMBR R0 K4 R2 - 0x60080013, // 000C GETGBL R2 G19 - 0x7C080000, // 000D CALL R2 0 - 0x90020C02, // 000E SETMBR R0 K6 R2 - 0x8C080107, // 000F GETMET R2 R0 K7 - 0x7C080200, // 0010 CALL R2 1 - 0xB80A1000, // 0011 GETNGBL R2 K8 - 0x8C080509, // 0012 GETMET R2 R2 K9 - 0x60100008, // 0013 GETGBL R4 G8 - 0x88140104, // 0014 GETMBR R5 R0 K4 - 0x7C100200, // 0015 CALL R4 1 - 0x00121404, // 0016 ADD R4 K10 R4 - 0x5814000B, // 0017 LDCONST R5 K11 - 0x7C080600, // 0018 CALL R2 3 - 0x8C08010C, // 0019 GETMET R2 R0 K12 - 0x88100104, // 001A GETMBR R4 R0 K4 - 0x7C080400, // 001B CALL R2 2 - 0x88080103, // 001C GETMBR R2 R0 K3 - 0x740A0008, // 001D JMPT R2 #0027 - 0x8808010D, // 001E GETMBR R2 R0 K13 - 0x8C08050E, // 001F GETMET R2 R2 K14 - 0x7C080200, // 0020 CALL R2 1 - 0x24080502, // 0021 GT R2 R2 K2 - 0x780A0003, // 0022 JMPF R2 #0027 - 0x50080200, // 0023 LDBOOL R2 1 0 - 0x90020602, // 0024 SETMBR R0 K3 R2 - 0x8C08010F, // 0025 GETMET R2 R0 K15 - 0x7C080200, // 0026 CALL R2 1 - 0x80000000, // 0027 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_fabric -********************************************************************/ -be_local_closure(Matter_Device_remove_fabric, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(log), - /* K2 */ be_nested_str_weak(MTR_X3A_X20removing_X20fabric_X20), - /* K3 */ be_nested_str_weak(get_fabric_id), - /* K4 */ be_nested_str_weak(copy), - /* K5 */ be_nested_str_weak(reverse), - /* K6 */ be_nested_str_weak(tohex), - /* K7 */ be_const_int(2), - /* K8 */ be_nested_str_weak(message_handler), - /* K9 */ be_nested_str_weak(im), - /* K10 */ be_nested_str_weak(subs_shop), - /* K11 */ be_nested_str_weak(remove_by_fabric), - /* K12 */ be_nested_str_weak(mdns_remove_op_discovery), - /* K13 */ be_nested_str_weak(sessions), - /* K14 */ be_nested_str_weak(remove_fabric), - /* K15 */ be_nested_str_weak(save_fabrics), - }), - be_str_weak(remove_fabric), - &be_const_str_solidified, - ( &(const binstruction[33]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x20080202, // 0001 NE R2 R1 R2 - 0x780A0019, // 0002 JMPF R2 #001D - 0xB80A0000, // 0003 GETNGBL R2 K0 - 0x8C080501, // 0004 GETMET R2 R2 K1 - 0x8C100303, // 0005 GETMET R4 R1 K3 - 0x7C100200, // 0006 CALL R4 1 - 0x8C100904, // 0007 GETMET R4 R4 K4 - 0x7C100200, // 0008 CALL R4 1 - 0x8C100905, // 0009 GETMET R4 R4 K5 - 0x7C100200, // 000A CALL R4 1 - 0x8C100906, // 000B GETMET R4 R4 K6 - 0x7C100200, // 000C CALL R4 1 - 0x00120404, // 000D ADD R4 K2 R4 - 0x58140007, // 000E LDCONST R5 K7 - 0x7C080600, // 000F CALL R2 3 - 0x88080108, // 0010 GETMBR R2 R0 K8 - 0x88080509, // 0011 GETMBR R2 R2 K9 - 0x8808050A, // 0012 GETMBR R2 R2 K10 - 0x8C08050B, // 0013 GETMET R2 R2 K11 - 0x5C100200, // 0014 MOVE R4 R1 - 0x7C080400, // 0015 CALL R2 2 - 0x8C08010C, // 0016 GETMET R2 R0 K12 - 0x5C100200, // 0017 MOVE R4 R1 - 0x7C080400, // 0018 CALL R2 2 - 0x8808010D, // 0019 GETMBR R2 R0 K13 - 0x8C08050E, // 001A GETMET R2 R2 K14 - 0x5C100200, // 001B MOVE R4 R1 - 0x7C080400, // 001C CALL R2 2 - 0x8808010D, // 001D GETMBR R2 R0 K13 - 0x8C08050F, // 001E GETMET R2 R2 K15 - 0x7C080200, // 001F CALL R2 1 - 0x80000000, // 0020 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: autoconf_sensors_list -********************************************************************/ -be_local_closure(Matter_Device_autoconf_sensors_list, /* name */ - be_nested_proto( - 10, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[18]) { /* constants */ - /* K0 */ be_nested_str_weak(k2l), - /* K1 */ be_nested_str_weak(contains), - /* K2 */ be_nested_str_weak(Temperature), - /* K3 */ be_nested_str_weak(_X23Temperature), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_nested_str_weak(type), - /* K6 */ be_nested_str_weak(temperature), - /* K7 */ be_nested_str_weak(filter), - /* K8 */ be_nested_str_weak(stop_iteration), - /* K9 */ be_nested_str_weak(Pressure), - /* K10 */ be_nested_str_weak(_X23Pressure), - /* K11 */ be_nested_str_weak(pressure), - /* K12 */ be_nested_str_weak(Illuminance), - /* K13 */ be_nested_str_weak(_X23Illuminance), - /* K14 */ be_nested_str_weak(illuminance), - /* K15 */ be_nested_str_weak(Humidity), - /* K16 */ be_nested_str_weak(_X23Humidity), - /* K17 */ be_nested_str_weak(humidity), - }), - be_str_weak(autoconf_sensors_list), - &be_const_str_solidified, - ( &(const binstruction[119]) { /* code */ - 0x60080012, // 0000 GETGBL R2 G18 - 0x7C080000, // 0001 CALL R2 0 - 0x600C0010, // 0002 GETGBL R3 G16 - 0x8C100100, // 0003 GETMET R4 R0 K0 - 0x5C180200, // 0004 MOVE R6 R1 - 0x7C100400, // 0005 CALL R4 2 - 0x7C0C0200, // 0006 CALL R3 1 - 0xA8020013, // 0007 EXBLK 0 #001C - 0x5C100600, // 0008 MOVE R4 R3 - 0x7C100000, // 0009 CALL R4 0 - 0x94140204, // 000A GETIDX R5 R1 R4 - 0x6018000F, // 000B GETGBL R6 G15 - 0x5C1C0A00, // 000C MOVE R7 R5 - 0x60200013, // 000D GETGBL R8 G19 - 0x7C180400, // 000E CALL R6 2 - 0x781A000A, // 000F JMPF R6 #001B - 0x8C180B01, // 0010 GETMET R6 R5 K1 - 0x58200002, // 0011 LDCONST R8 K2 - 0x7C180400, // 0012 CALL R6 2 - 0x781A0006, // 0013 JMPF R6 #001B - 0x00180903, // 0014 ADD R6 R4 K3 - 0x8C1C0504, // 0015 GETMET R7 R2 K4 - 0x60240013, // 0016 GETGBL R9 G19 - 0x7C240000, // 0017 CALL R9 0 - 0x98260B06, // 0018 SETIDX R9 K5 K6 - 0x98260E06, // 0019 SETIDX R9 K7 R6 - 0x7C1C0400, // 001A CALL R7 2 - 0x7001FFEB, // 001B JMP #0008 - 0x580C0008, // 001C LDCONST R3 K8 - 0xAC0C0200, // 001D CATCH R3 1 0 - 0xB0080000, // 001E RAISE 2 R0 R0 - 0x600C0010, // 001F GETGBL R3 G16 - 0x8C100100, // 0020 GETMET R4 R0 K0 - 0x5C180200, // 0021 MOVE R6 R1 - 0x7C100400, // 0022 CALL R4 2 - 0x7C0C0200, // 0023 CALL R3 1 - 0xA8020013, // 0024 EXBLK 0 #0039 - 0x5C100600, // 0025 MOVE R4 R3 - 0x7C100000, // 0026 CALL R4 0 - 0x94140204, // 0027 GETIDX R5 R1 R4 - 0x6018000F, // 0028 GETGBL R6 G15 - 0x5C1C0A00, // 0029 MOVE R7 R5 - 0x60200013, // 002A GETGBL R8 G19 - 0x7C180400, // 002B CALL R6 2 - 0x781A000A, // 002C JMPF R6 #0038 - 0x8C180B01, // 002D GETMET R6 R5 K1 - 0x58200009, // 002E LDCONST R8 K9 - 0x7C180400, // 002F CALL R6 2 - 0x781A0006, // 0030 JMPF R6 #0038 - 0x0018090A, // 0031 ADD R6 R4 K10 - 0x8C1C0504, // 0032 GETMET R7 R2 K4 - 0x60240013, // 0033 GETGBL R9 G19 - 0x7C240000, // 0034 CALL R9 0 - 0x98260B0B, // 0035 SETIDX R9 K5 K11 - 0x98260E06, // 0036 SETIDX R9 K7 R6 - 0x7C1C0400, // 0037 CALL R7 2 - 0x7001FFEB, // 0038 JMP #0025 - 0x580C0008, // 0039 LDCONST R3 K8 - 0xAC0C0200, // 003A CATCH R3 1 0 - 0xB0080000, // 003B RAISE 2 R0 R0 - 0x600C0010, // 003C GETGBL R3 G16 - 0x8C100100, // 003D GETMET R4 R0 K0 - 0x5C180200, // 003E MOVE R6 R1 - 0x7C100400, // 003F CALL R4 2 - 0x7C0C0200, // 0040 CALL R3 1 - 0xA8020013, // 0041 EXBLK 0 #0056 - 0x5C100600, // 0042 MOVE R4 R3 - 0x7C100000, // 0043 CALL R4 0 - 0x94140204, // 0044 GETIDX R5 R1 R4 - 0x6018000F, // 0045 GETGBL R6 G15 - 0x5C1C0A00, // 0046 MOVE R7 R5 - 0x60200013, // 0047 GETGBL R8 G19 - 0x7C180400, // 0048 CALL R6 2 - 0x781A000A, // 0049 JMPF R6 #0055 - 0x8C180B01, // 004A GETMET R6 R5 K1 - 0x5820000C, // 004B LDCONST R8 K12 - 0x7C180400, // 004C CALL R6 2 - 0x781A0006, // 004D JMPF R6 #0055 - 0x0018090D, // 004E ADD R6 R4 K13 - 0x8C1C0504, // 004F GETMET R7 R2 K4 - 0x60240013, // 0050 GETGBL R9 G19 - 0x7C240000, // 0051 CALL R9 0 - 0x98260B0E, // 0052 SETIDX R9 K5 K14 - 0x98260E06, // 0053 SETIDX R9 K7 R6 - 0x7C1C0400, // 0054 CALL R7 2 - 0x7001FFEB, // 0055 JMP #0042 - 0x580C0008, // 0056 LDCONST R3 K8 - 0xAC0C0200, // 0057 CATCH R3 1 0 - 0xB0080000, // 0058 RAISE 2 R0 R0 - 0x600C0010, // 0059 GETGBL R3 G16 - 0x8C100100, // 005A GETMET R4 R0 K0 - 0x5C180200, // 005B MOVE R6 R1 - 0x7C100400, // 005C CALL R4 2 - 0x7C0C0200, // 005D CALL R3 1 - 0xA8020013, // 005E EXBLK 0 #0073 - 0x5C100600, // 005F MOVE R4 R3 - 0x7C100000, // 0060 CALL R4 0 - 0x94140204, // 0061 GETIDX R5 R1 R4 - 0x6018000F, // 0062 GETGBL R6 G15 - 0x5C1C0A00, // 0063 MOVE R7 R5 - 0x60200013, // 0064 GETGBL R8 G19 - 0x7C180400, // 0065 CALL R6 2 - 0x781A000A, // 0066 JMPF R6 #0072 - 0x8C180B01, // 0067 GETMET R6 R5 K1 - 0x5820000F, // 0068 LDCONST R8 K15 - 0x7C180400, // 0069 CALL R6 2 - 0x781A0006, // 006A JMPF R6 #0072 - 0x00180910, // 006B ADD R6 R4 K16 - 0x8C1C0504, // 006C GETMET R7 R2 K4 - 0x60240013, // 006D GETGBL R9 G19 - 0x7C240000, // 006E CALL R9 0 - 0x98260B11, // 006F SETIDX R9 K5 K17 - 0x98260E06, // 0070 SETIDX R9 K7 R6 - 0x7C1C0400, // 0071 CALL R7 2 - 0x7001FFEB, // 0072 JMP #005F - 0x580C0008, // 0073 LDCONST R3 K8 - 0xAC0C0200, // 0074 CATCH R3 1 0 - 0xB0080000, // 0075 RAISE 2 R0 R0 - 0x80040400, // 0076 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Device ********************************************************************/ be_local_class(Matter_Device, 37, NULL, - be_nested_map(110, + be_nested_map(114, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(clean_remotes, -1), be_const_closure(Matter_Device_clean_remotes_closure) }, - { be_const_key_weak(plugins, 84), be_const_var(1) }, - { be_const_key_weak(autoconf_sensors_list, 41), be_const_closure(Matter_Device_autoconf_sensors_list_closure) }, - { be_const_key_weak(tick, -1), be_const_var(11) }, - { be_const_key_weak(process_attribute_read_solo, -1), be_const_closure(Matter_Device_process_attribute_read_solo_closure) }, - { be_const_key_weak(mdns_pase_wifi, -1), be_const_var(26) }, - { be_const_key_weak(PASE_TIMEOUT, -1), be_const_int(600) }, - { be_const_key_weak(commissioning_iterations, -1), be_const_var(13) }, - { be_const_key_weak(root_passcode, -1), be_const_var(29) }, - { be_const_key_weak(mdns_announce_op_discovery_all_fabrics, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_all_fabrics_closure) }, - { be_const_key_weak(mdns_remove_PASE, -1), be_const_closure(Matter_Device_mdns_remove_PASE_closure) }, - { be_const_key_weak(bridge_add_endpoint, -1), be_const_closure(Matter_Device_bridge_add_endpoint_closure) }, - { be_const_key_weak(root_discriminator, 35), be_const_var(28) }, - { be_const_key_weak(PASSCODE_INVALID, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_weak(PRODUCT_ID, -1), be_const_int(32768) }, + { be_const_key_weak(autoconf_device_map, -1), be_const_closure(Matter_Device_autoconf_device_map_closure) }, + { be_const_key_weak(PASSCODE_INVALID, 23), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(12, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), @@ -5772,102 +6197,117 @@ be_local_class(Matter_Device, be_const_int(12345678), be_const_int(87654321), })) ) } )) }, - { be_const_key_weak(stop_basic_commissioning, 90), be_const_closure(Matter_Device_stop_basic_commissioning_closure) }, - { be_const_key_weak(start_commissioning_complete, -1), be_const_closure(Matter_Device_start_commissioning_complete_closure) }, - { be_const_key_weak(root_iterations, -1), be_const_var(33) }, - { be_const_key_weak(get_plugin_remote_info, 94), be_const_closure(Matter_Device_get_plugin_remote_info_closure) }, - { be_const_key_weak(sessions, -1), be_const_var(9) }, - { be_const_key_weak(commissioning_L, -1), be_const_var(17) }, - { be_const_key_weak(commissioning_admin_fabric, 82), be_const_var(18) }, - { be_const_key_weak(commissioning_instance_eth, -1), be_const_var(20) }, - { be_const_key_weak(start_operational_discovery_deferred, -1), be_const_closure(Matter_Device_start_operational_discovery_deferred_closure) }, - { be_const_key_weak(process_attribute_expansion, -1), be_const_closure(Matter_Device_process_attribute_expansion_closure) }, - { be_const_key_weak(hostname_eth, 63), be_const_var(22) }, - { be_const_key_weak(autoconf_device, 78), be_const_closure(Matter_Device_autoconf_device_closure) }, - { be_const_key_weak(next_ep, -1), be_const_var(32) }, - { be_const_key_weak(stop, 92), be_const_closure(Matter_Device_stop_closure) }, - { be_const_key_weak(msg_received, 36), be_const_closure(Matter_Device_msg_received_closure) }, - { be_const_key_weak(k2l, -1), be_const_static_closure(Matter_Device_k2l_closure) }, - { be_const_key_weak(register_http_remote, 11), be_const_closure(Matter_Device_register_http_remote_closure) }, - { be_const_key_weak(get_plugin_class_arg, 106), be_const_closure(Matter_Device_get_plugin_class_arg_closure) }, - { be_const_key_weak(FILENAME, 91), be_nested_str_weak(_matter_device_X2Ejson) }, - { be_const_key_weak(compute_manual_pairing_code, 104), be_const_closure(Matter_Device_compute_manual_pairing_code_closure) }, - { be_const_key_weak(is_commissioning_open, -1), be_const_closure(Matter_Device_is_commissioning_open_closure) }, - { be_const_key_weak(event_fabrics_saved, -1), be_const_closure(Matter_Device_event_fabrics_saved_closure) }, - { be_const_key_weak(root_L, 48), be_const_var(36) }, - { be_const_key_weak(compute_qrcode_content, 22), be_const_closure(Matter_Device_compute_qrcode_content_closure) }, - { be_const_key_weak(plugins_config_remotes, -1), be_const_var(5) }, - { be_const_key_weak(commissioning_open, 25), be_const_var(12) }, - { be_const_key_weak(every_250ms, 83), be_const_closure(Matter_Device_every_250ms_closure) }, - { be_const_key_weak(start_mdns_announce_hostnames, -1), be_const_closure(Matter_Device_start_mdns_announce_hostnames_closure) }, - { be_const_key_weak(sort_distinct, 29), be_const_static_closure(Matter_Device_sort_distinct_closure) }, - { be_const_key_weak(save_param, -1), be_const_closure(Matter_Device_save_param_closure) }, - { be_const_key_weak(find_plugin_by_endpoint, -1), be_const_closure(Matter_Device_find_plugin_by_endpoint_closure) }, - { be_const_key_weak(_compute_pbkdf, 64), be_const_closure(Matter_Device__compute_pbkdf_closure) }, - { be_const_key_weak(started, -1), be_const_var(0) }, - { be_const_key_weak(signal_endpoints_changed, -1), be_const_closure(Matter_Device_signal_endpoints_changed_closure) }, - { be_const_key_weak(start_basic_commissioning, -1), be_const_closure(Matter_Device_start_basic_commissioning_closure) }, - { be_const_key_weak(start, -1), be_const_closure(Matter_Device_start_closure) }, - { be_const_key_weak(udp_server, -1), be_const_var(6) }, - { be_const_key_weak(VENDOR_ID, -1), be_const_int(65521) }, - { be_const_key_weak(commissioning_w0, 100), be_const_var(16) }, - { be_const_key_weak(commissioning_salt, 99), be_const_var(15) }, - { be_const_key_weak(PRODUCT_ID, 44), be_const_int(32768) }, - { be_const_key_weak(mdns_pase_eth, 96), be_const_var(25) }, - { be_const_key_weak(commissioning_instance_wifi, -1), be_const_var(19) }, - { be_const_key_weak(UDP_PORT, -1), be_const_int(5540) }, - { be_const_key_weak(_start_udp, 57), be_const_closure(Matter_Device__start_udp_closure) }, - { be_const_key_weak(load_param, -1), be_const_closure(Matter_Device_load_param_closure) }, - { be_const_key_weak(register_native_classes, -1), be_const_closure(Matter_Device_register_native_classes_closure) }, - { be_const_key_weak(register_commands, -1), be_const_closure(Matter_Device_register_commands_closure) }, - { be_const_key_weak(autoconf_device_map, -1), be_const_closure(Matter_Device_autoconf_device_map_closure) }, - { be_const_key_weak(received_ack, -1), be_const_closure(Matter_Device_received_ack_closure) }, - { be_const_key_weak(disable_bridge_mode, -1), be_const_var(31) }, - { be_const_key_weak(start_commissioning_complete_deferred, 93), be_const_closure(Matter_Device_start_commissioning_complete_deferred_closure) }, - { be_const_key_weak(plugins_config, -1), be_const_var(4) }, - { be_const_key_weak(get_active_endpoints, -1), be_const_closure(Matter_Device_get_active_endpoints_closure) }, - { be_const_key_weak(_mdns_announce_hostname, -1), be_const_closure(Matter_Device__mdns_announce_hostname_closure) }, - { be_const_key_weak(register_plugin_class, -1), be_const_closure(Matter_Device_register_plugin_class_closure) }, - { be_const_key_weak(plugins_persist, -1), be_const_var(2) }, - { be_const_key_weak(generate_random_passcode, 49), be_const_closure(Matter_Device_generate_random_passcode_closure) }, - { be_const_key_weak(profiler, 21), be_const_var(7) }, - { be_const_key_weak(attribute_updated, -1), be_const_closure(Matter_Device_attribute_updated_closure) }, - { be_const_key_weak(MtrJoin, 3), be_const_closure(Matter_Device_MtrJoin_closure) }, - { be_const_key_weak(init, 79), be_const_closure(Matter_Device_init_closure) }, - { be_const_key_weak(get_plugin_class_displayname, 70), be_const_closure(Matter_Device_get_plugin_class_displayname_closure) }, - { be_const_key_weak(bridge_remove_endpoint, 60), be_const_closure(Matter_Device_bridge_remove_endpoint_closure) }, - { be_const_key_weak(message_handler, -1), be_const_var(8) }, - { be_const_key_weak(start_root_basic_commissioning, -1), be_const_closure(Matter_Device_start_root_basic_commissioning_closure) }, - { be_const_key_weak(ipv4only, -1), be_const_var(30) }, - { be_const_key_weak(productid, -1), be_const_var(24) }, - { be_const_key_weak(mdns_remove_op_discovery_all_fabrics, -1), be_const_closure(Matter_Device_mdns_remove_op_discovery_all_fabrics_closure) }, - { be_const_key_weak(conf_to_log, 33), be_const_static_closure(Matter_Device_conf_to_log_closure) }, - { be_const_key_weak(_instantiate_plugins_from_config, -1), be_const_closure(Matter_Device__instantiate_plugins_from_config_closure) }, - { be_const_key_weak(root_w0, 73), be_const_var(35) }, - { be_const_key_weak(hostname_wifi, -1), be_const_var(21) }, - { be_const_key_weak(invoke_request, 69), be_const_closure(Matter_Device_invoke_request_closure) }, - { be_const_key_weak(every_50ms, 66), be_const_closure(Matter_Device_every_50ms_closure) }, - { be_const_key_weak(_init_basic_commissioning, 45), be_const_closure(Matter_Device__init_basic_commissioning_closure) }, - { be_const_key_weak(adjust_next_ep, -1), be_const_closure(Matter_Device_adjust_next_ep_closure) }, - { be_const_key_weak(root_salt, -1), be_const_var(34) }, - { be_const_key_weak(ui, 108), be_const_var(10) }, - { be_const_key_weak(every_second, -1), be_const_closure(Matter_Device_every_second_closure) }, - { be_const_key_weak(_trigger_read_sensors, -1), be_const_closure(Matter_Device__trigger_read_sensors_closure) }, - { be_const_key_weak(update_remotes_info, 47), be_const_closure(Matter_Device_update_remotes_info_closure) }, - { be_const_key_weak(mdns_remove_op_discovery, -1), be_const_closure(Matter_Device_mdns_remove_op_discovery_closure) }, - { be_const_key_weak(mdns_announce_PASE, -1), be_const_closure(Matter_Device_mdns_announce_PASE_closure) }, - { be_const_key_weak(save_before_restart, 43), be_const_closure(Matter_Device_save_before_restart_closure) }, - { be_const_key_weak(msg_send, -1), be_const_closure(Matter_Device_msg_send_closure) }, - { be_const_key_weak(mdns_announce_op_discovery, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_closure) }, - { be_const_key_weak(k2l_num, -1), be_const_static_closure(Matter_Device_k2l_num_closure) }, - { be_const_key_weak(vendorid, -1), be_const_var(23) }, - { be_const_key_weak(http_remotes, -1), be_const_var(27) }, - { be_const_key_weak(plugins_classes, -1), be_const_var(3) }, - { be_const_key_weak(commissioning_discriminator, -1), be_const_var(14) }, - { be_const_key_weak(is_root_commissioning_open, -1), be_const_closure(Matter_Device_is_root_commissioning_open_closure) }, { be_const_key_weak(remove_fabric, -1), be_const_closure(Matter_Device_remove_fabric_closure) }, - { be_const_key_weak(start_operational_discovery, -1), be_const_closure(Matter_Device_start_operational_discovery_closure) }, - { be_const_key_weak(PBKDF_ITERATIONS, 2), be_const_int(1000) }, + { be_const_key_weak(is_root_commissioning_open, -1), be_const_closure(Matter_Device_is_root_commissioning_open_closure) }, + { be_const_key_weak(_init_basic_commissioning, 4), be_const_closure(Matter_Device__init_basic_commissioning_closure) }, + { be_const_key_weak(compute_manual_pairing_code, -1), be_const_closure(Matter_Device_compute_manual_pairing_code_closure) }, + { be_const_key_weak(ui, -1), be_const_var(10) }, + { be_const_key_weak(vendorid, 50), be_const_var(23) }, + { be_const_key_weak(root_L, 87), be_const_var(36) }, + { be_const_key_weak(sessions, -1), be_const_var(9) }, + { be_const_key_weak(stop, -1), be_const_closure(Matter_Device_stop_closure) }, + { be_const_key_weak(bridge_add_endpoint, -1), be_const_closure(Matter_Device_bridge_add_endpoint_closure) }, + { be_const_key_weak(mdns_remove_op_discovery, -1), be_const_closure(Matter_Device_mdns_remove_op_discovery_closure) }, + { be_const_key_weak(start_mdns_announce_hostnames, 36), be_const_closure(Matter_Device_start_mdns_announce_hostnames_closure) }, + { be_const_key_weak(disable_bridge_mode, 17), be_const_var(31) }, + { be_const_key_weak(get_plugin_class_displayname, 1), be_const_closure(Matter_Device_get_plugin_class_displayname_closure) }, + { be_const_key_weak(http_remotes, -1), be_const_var(27) }, + { be_const_key_weak(clean_remotes, -1), be_const_closure(Matter_Device_clean_remotes_closure) }, + { be_const_key_weak(get_plugin_remote_info, 49), be_const_closure(Matter_Device_get_plugin_remote_info_closure) }, + { be_const_key_weak(_mdns_announce_hostname, -1), be_const_closure(Matter_Device__mdns_announce_hostname_closure) }, + { be_const_key_weak(register_native_classes, 55), be_const_closure(Matter_Device_register_native_classes_closure) }, + { be_const_key_weak(_start_udp, 109), be_const_closure(Matter_Device__start_udp_closure) }, + { be_const_key_weak(get_plugin_class_arg, 33), be_const_closure(Matter_Device_get_plugin_class_arg_closure) }, + { be_const_key_weak(commissioning_admin_fabric, -1), be_const_var(18) }, + { be_const_key_weak(msg_send, -1), be_const_closure(Matter_Device_msg_send_closure) }, + { be_const_key_weak(commissioning_w0, 102), be_const_var(16) }, + { be_const_key_weak(mdns_pase_eth, -1), be_const_var(25) }, + { be_const_key_weak(process_attribute_read_solo, -1), be_const_closure(Matter_Device_process_attribute_read_solo_closure) }, + { be_const_key_weak(invoke_request, 108), be_const_closure(Matter_Device_invoke_request_closure) }, + { be_const_key_weak(adjust_next_ep, 104), be_const_closure(Matter_Device_adjust_next_ep_closure) }, + { be_const_key_weak(attribute_updated, -1), be_const_closure(Matter_Device_attribute_updated_closure) }, + { be_const_key_weak(mdns_remove_PASE, 107), be_const_closure(Matter_Device_mdns_remove_PASE_closure) }, + { be_const_key_weak(_compute_pbkdf, 90), be_const_closure(Matter_Device__compute_pbkdf_closure) }, + { be_const_key_weak(ipv4only, 71), be_const_var(30) }, + { be_const_key_weak(get_active_endpoints, -1), be_const_closure(Matter_Device_get_active_endpoints_closure) }, + { be_const_key_weak(k2l_num, -1), be_const_static_closure(Matter_Device_k2l_num_closure) }, + { be_const_key_weak(autoconf_sensors_list, -1), be_const_closure(Matter_Device_autoconf_sensors_list_closure) }, + { be_const_key_weak(start_basic_commissioning, -1), be_const_closure(Matter_Device_start_basic_commissioning_closure) }, + { be_const_key_weak(bridge_remove_endpoint, 14), be_const_closure(Matter_Device_bridge_remove_endpoint_closure) }, + { be_const_key_weak(msg_received, -1), be_const_closure(Matter_Device_msg_received_closure) }, + { be_const_key_weak(start, -1), be_const_closure(Matter_Device_start_closure) }, + { be_const_key_weak(stop_basic_commissioning, -1), be_const_closure(Matter_Device_stop_basic_commissioning_closure) }, + { be_const_key_weak(generate_random_passcode, -1), be_const_closure(Matter_Device_generate_random_passcode_closure) }, + { be_const_key_weak(started, 65), be_const_var(0) }, + { be_const_key_weak(signal_endpoints_changed, -1), be_const_closure(Matter_Device_signal_endpoints_changed_closure) }, + { be_const_key_weak(MtrJoin, 48), be_const_closure(Matter_Device_MtrJoin_closure) }, + { be_const_key_weak(productid, -1), be_const_var(24) }, + { be_const_key_weak(find_plugin_by_endpoint, -1), be_const_closure(Matter_Device_find_plugin_by_endpoint_closure) }, + { be_const_key_weak(PBKDF_ITERATIONS, 3), be_const_int(1000) }, + { be_const_key_weak(hostname_eth, 97), be_const_var(22) }, + { be_const_key_weak(init, 37), be_const_closure(Matter_Device_init_closure) }, + { be_const_key_weak(register_http_remote, 40), be_const_closure(Matter_Device_register_http_remote_closure) }, + { be_const_key_weak(commissioning_salt, 98), be_const_var(15) }, + { be_const_key_weak(mdns_pase_wifi, -1), be_const_var(26) }, + { be_const_key_weak(load_param, -1), be_const_closure(Matter_Device_load_param_closure) }, + { be_const_key_weak(hostname_wifi, 93), be_const_var(21) }, + { be_const_key_weak(compute_qrcode_content, 45), be_const_closure(Matter_Device_compute_qrcode_content_closure) }, + { be_const_key_weak(plugins_config, -1), be_const_var(4) }, + { be_const_key_weak(start_root_basic_commissioning, -1), be_const_closure(Matter_Device_start_root_basic_commissioning_closure) }, + { be_const_key_weak(save_before_restart, -1), be_const_closure(Matter_Device_save_before_restart_closure) }, + { be_const_key_weak(register_commands, 54), be_const_closure(Matter_Device_register_commands_closure) }, + { be_const_key_weak(root_salt, -1), be_const_var(34) }, + { be_const_key_weak(commissioning_iterations, 2), be_const_var(13) }, + { be_const_key_weak(find_plugin_by_friendly_name, -1), be_const_closure(Matter_Device_find_plugin_by_friendly_name_closure) }, + { be_const_key_weak(plugins_persist, -1), be_const_var(2) }, + { be_const_key_weak(udp_server, -1), be_const_var(6) }, + { be_const_key_weak(next_ep, -1), be_const_var(32) }, + { be_const_key_weak(start_operational_discovery_deferred, 72), be_const_closure(Matter_Device_start_operational_discovery_deferred_closure) }, + { be_const_key_weak(every_second, -1), be_const_closure(Matter_Device_every_second_closure) }, + { be_const_key_weak(UDP_PORT, -1), be_const_int(5540) }, + { be_const_key_weak(mdns_announce_op_discovery, 30), be_const_closure(Matter_Device_mdns_announce_op_discovery_closure) }, + { be_const_key_weak(message_handler, -1), be_const_var(8) }, + { be_const_key_weak(process_attribute_expansion, 43), be_const_closure(Matter_Device_process_attribute_expansion_closure) }, + { be_const_key_weak(is_commissioning_open, 62), be_const_closure(Matter_Device_is_commissioning_open_closure) }, + { be_const_key_weak(start_commissioning_complete_deferred, -1), be_const_closure(Matter_Device_start_commissioning_complete_deferred_closure) }, + { be_const_key_weak(plugins_classes, 44), be_const_var(3) }, + { be_const_key_weak(start_operational_discovery, 68), be_const_closure(Matter_Device_start_operational_discovery_closure) }, + { be_const_key_weak(mdns_remove_op_discovery_all_fabrics, 9), be_const_closure(Matter_Device_mdns_remove_op_discovery_all_fabrics_closure) }, + { be_const_key_weak(commissioning_discriminator, -1), be_const_var(14) }, + { be_const_key_weak(FILENAME, -1), be_nested_str_weak(_matter_device_X2Ejson) }, + { be_const_key_weak(root_iterations, 112), be_const_var(33) }, + { be_const_key_weak(commissioning_open, -1), be_const_var(12) }, + { be_const_key_weak(_trigger_read_sensors, 82), be_const_closure(Matter_Device__trigger_read_sensors_closure) }, + { be_const_key_weak(commissioning_instance_wifi, 81), be_const_var(19) }, + { be_const_key_weak(VENDOR_ID, -1), be_const_int(65521) }, + { be_const_key_weak(tick, -1), be_const_var(11) }, + { be_const_key_weak(MtrInfo, -1), be_const_closure(Matter_Device_MtrInfo_closure) }, + { be_const_key_weak(root_discriminator, 67), be_const_var(28) }, + { be_const_key_weak(start_commissioning_complete, 7), be_const_closure(Matter_Device_start_commissioning_complete_closure) }, + { be_const_key_weak(register_plugin_class, 95), be_const_closure(Matter_Device_register_plugin_class_closure) }, + { be_const_key_weak(MtrUpdate, -1), be_const_closure(Matter_Device_MtrUpdate_closure) }, + { be_const_key_weak(sort_distinct, -1), be_const_static_closure(Matter_Device_sort_distinct_closure) }, + { be_const_key_weak(commissioning_instance_eth, -1), be_const_var(20) }, + { be_const_key_weak(conf_to_log, -1), be_const_static_closure(Matter_Device_conf_to_log_closure) }, + { be_const_key_weak(MtrInfo_one, -1), be_const_closure(Matter_Device_MtrInfo_one_closure) }, + { be_const_key_weak(received_ack, -1), be_const_closure(Matter_Device_received_ack_closure) }, + { be_const_key_weak(k2l, -1), be_const_static_closure(Matter_Device_k2l_closure) }, + { be_const_key_weak(update_remotes_info, -1), be_const_closure(Matter_Device_update_remotes_info_closure) }, + { be_const_key_weak(plugins, -1), be_const_var(1) }, + { be_const_key_weak(profiler, -1), be_const_var(7) }, + { be_const_key_weak(_instantiate_plugins_from_config, -1), be_const_closure(Matter_Device__instantiate_plugins_from_config_closure) }, + { be_const_key_weak(every_50ms, 22), be_const_closure(Matter_Device_every_50ms_closure) }, + { be_const_key_weak(commissioning_L, -1), be_const_var(17) }, + { be_const_key_weak(PASE_TIMEOUT, -1), be_const_int(600) }, + { be_const_key_weak(mdns_announce_op_discovery_all_fabrics, -1), be_const_closure(Matter_Device_mdns_announce_op_discovery_all_fabrics_closure) }, + { be_const_key_weak(event_fabrics_saved, -1), be_const_closure(Matter_Device_event_fabrics_saved_closure) }, + { be_const_key_weak(every_250ms, -1), be_const_closure(Matter_Device_every_250ms_closure) }, + { be_const_key_weak(autoconf_device, -1), be_const_closure(Matter_Device_autoconf_device_closure) }, + { be_const_key_weak(root_passcode, -1), be_const_var(29) }, + { be_const_key_weak(save_param, -1), be_const_closure(Matter_Device_save_param_closure) }, + { be_const_key_weak(mdns_announce_PASE, -1), be_const_closure(Matter_Device_mdns_announce_PASE_closure) }, + { be_const_key_weak(plugins_config_remotes, -1), be_const_var(5) }, + { be_const_key_weak(root_w0, -1), be_const_var(35) }, })), be_str_weak(Matter_Device) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h index e9a29ad82..94c9b58fd 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_IM.h @@ -346,7 +346,7 @@ be_local_closure(Matter_IM_attributedata2raw, /* name */ ********************************************************************/ be_local_closure(Matter_IM_process_invoke_request_solo, /* name */ be_nested_proto( - 16, /* nstack */ + 15, /* nstack */ 3, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -354,7 +354,7 @@ be_local_closure(Matter_IM_process_invoke_request_solo, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[45]) { /* constants */ + ( &(const bvalue[42]) { /* constants */ /* K0 */ be_nested_str_weak(matter), /* K1 */ be_nested_str_weak(profiler), /* K2 */ be_nested_str_weak(log), @@ -373,37 +373,34 @@ be_local_closure(Matter_IM_process_invoke_request_solo, /* name */ /* K15 */ be_nested_str_weak(_X28), /* K16 */ be_nested_str_weak(_X29_X20), /* K17 */ be_nested_str_weak(), - /* K18 */ be_nested_str_weak(endpoint), - /* K19 */ be_const_int(0), - /* K20 */ be_const_int(2), - /* K21 */ be_const_int(3), - /* K22 */ be_nested_str_weak(tasmota), - /* K23 */ be_nested_str_weak(loglevel), - /* K24 */ be_nested_str_weak(MTR_X3A_X20_X3ECommand1_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s_X20_X25s), - /* K25 */ be_nested_str_weak(local_session_id), - /* K26 */ be_nested_str_weak(add), - /* K27 */ be_const_int(354943030), - /* K28 */ be_const_int(1), - /* K29 */ be_nested_str_weak(SUCCESS), - /* K30 */ be_nested_str_weak(invokeresponse2raw), - /* K31 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20OK_X20exch_X3D_X25i), - /* K32 */ be_nested_str_weak(exchange_id), - /* K33 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s), - /* K34 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20Status_X3D0x_X2502X_X20exch_X3D_X25i), - /* K35 */ be_nested_str_weak(MTR_X3A_X20_Ignore_X20_X20_X20_X20_X28_X256i_X29_X20exch_X3D_X25i), - /* K36 */ be_const_int(405077761), - /* K37 */ be_nested_str_weak(build_response), - /* K38 */ be_nested_str_weak(message_handler), - /* K39 */ be_nested_str_weak(raw), - /* K40 */ be_nested_str_weak(clear), - /* K41 */ be_nested_str_weak(encode_frame), - /* K42 */ be_nested_str_weak(encrypt), - /* K43 */ be_nested_str_weak(send_response_frame), - /* K44 */ be_nested_str_weak(RESPONSE_X20SENT), + /* K18 */ be_nested_str_weak(tasmota), + /* K19 */ be_nested_str_weak(loglevel), + /* K20 */ be_const_int(3), + /* K21 */ be_nested_str_weak(MTR_X3A_X20_X3ECommand1_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s_X20_X25s), + /* K22 */ be_nested_str_weak(local_session_id), + /* K23 */ be_nested_str_weak(add), + /* K24 */ be_const_int(354943030), + /* K25 */ be_const_int(1), + /* K26 */ be_nested_str_weak(SUCCESS), + /* K27 */ be_nested_str_weak(invokeresponse2raw), + /* K28 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20OK_X20exch_X3D_X25i), + /* K29 */ be_nested_str_weak(exchange_id), + /* K30 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s), + /* K31 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20Status_X3D0x_X2502X_X20exch_X3D_X25i), + /* K32 */ be_nested_str_weak(MTR_X3A_X20_Ignore_X20_X20_X20_X20_X28_X256i_X29_X20exch_X3D_X25i), + /* K33 */ be_const_int(405077761), + /* K34 */ be_nested_str_weak(build_response), + /* K35 */ be_nested_str_weak(message_handler), + /* K36 */ be_nested_str_weak(raw), + /* K37 */ be_nested_str_weak(clear), + /* K38 */ be_nested_str_weak(encode_frame), + /* K39 */ be_nested_str_weak(encrypt), + /* K40 */ be_nested_str_weak(send_response_frame), + /* K41 */ be_nested_str_weak(RESPONSE_X20SENT), }), be_str_weak(process_invoke_request_solo), &be_const_str_solidified, - ( &(const binstruction[214]) { /* code */ + ( &(const binstruction[208]) { /* code */ 0xB80E0000, // 0000 GETNGBL R3 K0 0x880C0701, // 0001 GETMBR R3 R3 K1 0x8C0C0702, // 0002 GETMET R3 R3 K2 @@ -443,181 +440,175 @@ be_local_closure(Matter_IM_process_invoke_request_solo, /* name */ 0x00180D10, // 0024 ADD R6 R6 K16 0x70020000, // 0025 JMP #0027 0x58180011, // 0026 LDCONST R6 K17 - 0x881C0512, // 0027 GETMBR R7 R2 K18 - 0x201C0F13, // 0028 NE R7 R7 K19 - 0x781E0001, // 0029 JMPF R7 #002C - 0x581C0014, // 002A LDCONST R7 K20 - 0x70020000, // 002B JMP #002D - 0x581C0015, // 002C LDCONST R7 K21 - 0xB8222C00, // 002D GETNGBL R8 K22 - 0x8C201117, // 002E GETMET R8 R8 K23 - 0x5C280E00, // 002F MOVE R10 R7 - 0x7C200400, // 0030 CALL R8 2 - 0x7822000E, // 0031 JMPF R8 #0041 - 0xB8222C00, // 0032 GETNGBL R8 K22 - 0x8C201102, // 0033 GETMET R8 R8 K2 - 0x60280018, // 0034 GETGBL R10 G24 - 0x582C0018, // 0035 LDCONST R11 K24 - 0x8830030C, // 0036 GETMBR R12 R1 K12 - 0x88301919, // 0037 GETMBR R12 R12 K25 - 0x5C340800, // 0038 MOVE R13 R4 - 0x780E0001, // 0039 JMPF R3 #003C - 0x5C380600, // 003A MOVE R14 R3 - 0x70020000, // 003B JMP #003D - 0x58380011, // 003C LDCONST R14 K17 - 0x5C3C0C00, // 003D MOVE R15 R6 - 0x7C280A00, // 003E CALL R10 5 - 0x5C2C0E00, // 003F MOVE R11 R7 - 0x7C200600, // 0040 CALL R8 3 - 0x4C200000, // 0041 LDNIL R8 - 0x900A0408, // 0042 SETMBR R2 K2 R8 - 0x60200015, // 0043 GETGBL R8 G21 - 0x5426002F, // 0044 LDINT R9 48 - 0x7C200200, // 0045 CALL R8 1 - 0x8C24111A, // 0046 GETMET R9 R8 K26 - 0x582C001B, // 0047 LDCONST R11 K27 - 0x5431FFFB, // 0048 LDINT R12 -4 - 0x7C240600, // 0049 CALL R9 3 - 0x8C24111A, // 004A GETMET R9 R8 K26 - 0x582C001C, // 004B LDCONST R11 K28 - 0x5830001C, // 004C LDCONST R12 K28 - 0x7C240600, // 004D CALL R9 3 - 0x50240200, // 004E LDBOOL R9 1 0 - 0x1C240A09, // 004F EQ R9 R5 R9 - 0x74260004, // 0050 JMPT R9 #0056 - 0x88240505, // 0051 GETMBR R9 R2 K5 - 0xB82A0000, // 0052 GETNGBL R10 K0 - 0x8828151D, // 0053 GETMBR R10 R10 K29 - 0x1C24120A, // 0054 EQ R9 R9 R10 - 0x78260017, // 0055 JMPF R9 #006E - 0xB8260000, // 0056 GETNGBL R9 K0 - 0x8824131D, // 0057 GETMBR R9 R9 K29 - 0x900A0A09, // 0058 SETMBR R2 K5 R9 - 0x8C24011E, // 0059 GETMET R9 R0 K30 - 0x5C2C1000, // 005A MOVE R11 R8 - 0x5C300400, // 005B MOVE R12 R2 - 0x4C340000, // 005C LDNIL R13 - 0x7C240800, // 005D CALL R9 4 - 0xB8262C00, // 005E GETNGBL R9 K22 - 0x8C241317, // 005F GETMET R9 R9 K23 - 0x582C0015, // 0060 LDCONST R11 K21 - 0x7C240400, // 0061 CALL R9 2 - 0x78260009, // 0062 JMPF R9 #006D - 0xB8262C00, // 0063 GETNGBL R9 K22 - 0x8C241302, // 0064 GETMET R9 R9 K2 - 0x602C0018, // 0065 GETGBL R11 G24 - 0x5830001F, // 0066 LDCONST R12 K31 - 0x8834030C, // 0067 GETMBR R13 R1 K12 - 0x88341B19, // 0068 GETMBR R13 R13 K25 - 0x88380320, // 0069 GETMBR R14 R1 K32 - 0x7C2C0600, // 006A CALL R11 3 - 0x58300015, // 006B LDCONST R12 K21 - 0x7C240600, // 006C CALL R9 3 - 0x70020046, // 006D JMP #00B5 - 0x4C240000, // 006E LDNIL R9 - 0x20240A09, // 006F NE R9 R5 R9 - 0x78260018, // 0070 JMPF R9 #008A - 0x8C24011E, // 0071 GETMET R9 R0 K30 - 0x5C2C1000, // 0072 MOVE R11 R8 - 0x5C300400, // 0073 MOVE R12 R2 - 0x5C340A00, // 0074 MOVE R13 R5 - 0x7C240800, // 0075 CALL R9 4 - 0x5C240600, // 0076 MOVE R9 R3 - 0x74260000, // 0077 JMPT R9 #0079 - 0x580C0011, // 0078 LDCONST R3 K17 - 0xB8262C00, // 0079 GETNGBL R9 K22 - 0x8C241317, // 007A GETMET R9 R9 K23 - 0x582C0015, // 007B LDCONST R11 K21 - 0x7C240400, // 007C CALL R9 2 - 0x7826000A, // 007D JMPF R9 #0089 - 0xB8262C00, // 007E GETNGBL R9 K22 - 0x8C241302, // 007F GETMET R9 R9 K2 - 0x602C0018, // 0080 GETGBL R11 G24 - 0x58300021, // 0081 LDCONST R12 K33 - 0x8834030C, // 0082 GETMBR R13 R1 K12 - 0x88341B19, // 0083 GETMBR R13 R13 K25 - 0x5C380400, // 0084 MOVE R14 R2 - 0x5C3C0600, // 0085 MOVE R15 R3 - 0x7C2C0800, // 0086 CALL R11 4 - 0x58300015, // 0087 LDCONST R12 K21 - 0x7C240600, // 0088 CALL R9 3 - 0x7002002A, // 0089 JMP #00B5 - 0x88240505, // 008A GETMBR R9 R2 K5 - 0x4C280000, // 008B LDNIL R10 - 0x2024120A, // 008C NE R9 R9 R10 - 0x78260015, // 008D JMPF R9 #00A4 - 0x8C24011E, // 008E GETMET R9 R0 K30 - 0x5C2C1000, // 008F MOVE R11 R8 - 0x5C300400, // 0090 MOVE R12 R2 - 0x4C340000, // 0091 LDNIL R13 - 0x7C240800, // 0092 CALL R9 4 - 0xB8262C00, // 0093 GETNGBL R9 K22 - 0x8C241317, // 0094 GETMET R9 R9 K23 - 0x582C0015, // 0095 LDCONST R11 K21 - 0x7C240400, // 0096 CALL R9 2 - 0x7826000A, // 0097 JMPF R9 #00A3 - 0xB8262C00, // 0098 GETNGBL R9 K22 - 0x8C241302, // 0099 GETMET R9 R9 K2 - 0x602C0018, // 009A GETGBL R11 G24 - 0x58300022, // 009B LDCONST R12 K34 - 0x8834030C, // 009C GETMBR R13 R1 K12 - 0x88341B19, // 009D GETMBR R13 R13 K25 - 0x88380505, // 009E GETMBR R14 R2 K5 - 0x883C0320, // 009F GETMBR R15 R1 K32 - 0x7C2C0800, // 00A0 CALL R11 4 - 0x58300015, // 00A1 LDCONST R12 K21 - 0x7C240600, // 00A2 CALL R9 3 - 0x70020010, // 00A3 JMP #00B5 - 0xB8262C00, // 00A4 GETNGBL R9 K22 - 0x8C241317, // 00A5 GETMET R9 R9 K23 - 0x582C0015, // 00A6 LDCONST R11 K21 - 0x7C240400, // 00A7 CALL R9 2 - 0x78260009, // 00A8 JMPF R9 #00B3 - 0xB8262C00, // 00A9 GETNGBL R9 K22 - 0x8C241302, // 00AA GETMET R9 R9 K2 - 0x602C0018, // 00AB GETGBL R11 G24 - 0x58300023, // 00AC LDCONST R12 K35 - 0x8834030C, // 00AD GETMBR R13 R1 K12 - 0x88341B19, // 00AE GETMBR R13 R13 K25 - 0x88380320, // 00AF GETMBR R14 R1 K32 - 0x7C2C0600, // 00B0 CALL R11 3 - 0x58300015, // 00B1 LDCONST R12 K21 - 0x7C240600, // 00B2 CALL R9 3 - 0x50240000, // 00B3 LDBOOL R9 0 0 - 0x80041200, // 00B4 RET 1 R9 - 0x8C24111A, // 00B5 GETMET R9 R8 K26 - 0x582C0024, // 00B6 LDCONST R11 K36 - 0x5431FFFB, // 00B7 LDINT R12 -4 - 0x7C240600, // 00B8 CALL R9 3 - 0x8C24111A, // 00B9 GETMET R9 R8 K26 - 0x542E0017, // 00BA LDINT R11 24 - 0x5830001C, // 00BB LDCONST R12 K28 - 0x7C240600, // 00BC CALL R9 3 - 0x8C240325, // 00BD GETMET R9 R1 K37 - 0x542E0008, // 00BE LDINT R11 9 - 0x50300200, // 00BF LDBOOL R12 1 0 - 0x7C240600, // 00C0 CALL R9 3 - 0x8828010A, // 00C1 GETMBR R10 R0 K10 - 0x88281526, // 00C2 GETMBR R10 R10 K38 - 0x882C0327, // 00C3 GETMBR R11 R1 K39 - 0x8C301728, // 00C4 GETMET R12 R11 K40 - 0x7C300200, // 00C5 CALL R12 1 - 0x8C301329, // 00C6 GETMET R12 R9 K41 - 0x5C381000, // 00C7 MOVE R14 R8 - 0x5C3C1600, // 00C8 MOVE R15 R11 - 0x7C300600, // 00C9 CALL R12 3 - 0x8C30132A, // 00CA GETMET R12 R9 K42 - 0x7C300200, // 00CB CALL R12 1 - 0x8C30152B, // 00CC GETMET R12 R10 K43 - 0x5C381200, // 00CD MOVE R14 R9 - 0x7C300400, // 00CE CALL R12 2 - 0xB8320000, // 00CF GETNGBL R12 K0 - 0x88301901, // 00D0 GETMBR R12 R12 K1 - 0x8C301902, // 00D1 GETMET R12 R12 K2 - 0x5838002C, // 00D2 LDCONST R14 K44 - 0x7C300400, // 00D3 CALL R12 2 - 0x50300200, // 00D4 LDBOOL R12 1 0 - 0x80041800, // 00D5 RET 1 R12 + 0xB81E2400, // 0027 GETNGBL R7 K18 + 0x8C1C0F13, // 0028 GETMET R7 R7 K19 + 0x58240014, // 0029 LDCONST R9 K20 + 0x7C1C0400, // 002A CALL R7 2 + 0x781E000E, // 002B JMPF R7 #003B + 0xB81E2400, // 002C GETNGBL R7 K18 + 0x8C1C0F02, // 002D GETMET R7 R7 K2 + 0x60240018, // 002E GETGBL R9 G24 + 0x58280015, // 002F LDCONST R10 K21 + 0x882C030C, // 0030 GETMBR R11 R1 K12 + 0x882C1716, // 0031 GETMBR R11 R11 K22 + 0x5C300800, // 0032 MOVE R12 R4 + 0x780E0001, // 0033 JMPF R3 #0036 + 0x5C340600, // 0034 MOVE R13 R3 + 0x70020000, // 0035 JMP #0037 + 0x58340011, // 0036 LDCONST R13 K17 + 0x5C380C00, // 0037 MOVE R14 R6 + 0x7C240A00, // 0038 CALL R9 5 + 0x58280014, // 0039 LDCONST R10 K20 + 0x7C1C0600, // 003A CALL R7 3 + 0x4C1C0000, // 003B LDNIL R7 + 0x900A0407, // 003C SETMBR R2 K2 R7 + 0x601C0015, // 003D GETGBL R7 G21 + 0x5422002F, // 003E LDINT R8 48 + 0x7C1C0200, // 003F CALL R7 1 + 0x8C200F17, // 0040 GETMET R8 R7 K23 + 0x58280018, // 0041 LDCONST R10 K24 + 0x542DFFFB, // 0042 LDINT R11 -4 + 0x7C200600, // 0043 CALL R8 3 + 0x8C200F17, // 0044 GETMET R8 R7 K23 + 0x58280019, // 0045 LDCONST R10 K25 + 0x582C0019, // 0046 LDCONST R11 K25 + 0x7C200600, // 0047 CALL R8 3 + 0x50200200, // 0048 LDBOOL R8 1 0 + 0x1C200A08, // 0049 EQ R8 R5 R8 + 0x74220004, // 004A JMPT R8 #0050 + 0x88200505, // 004B GETMBR R8 R2 K5 + 0xB8260000, // 004C GETNGBL R9 K0 + 0x8824131A, // 004D GETMBR R9 R9 K26 + 0x1C201009, // 004E EQ R8 R8 R9 + 0x78220017, // 004F JMPF R8 #0068 + 0xB8220000, // 0050 GETNGBL R8 K0 + 0x8820111A, // 0051 GETMBR R8 R8 K26 + 0x900A0A08, // 0052 SETMBR R2 K5 R8 + 0x8C20011B, // 0053 GETMET R8 R0 K27 + 0x5C280E00, // 0054 MOVE R10 R7 + 0x5C2C0400, // 0055 MOVE R11 R2 + 0x4C300000, // 0056 LDNIL R12 + 0x7C200800, // 0057 CALL R8 4 + 0xB8222400, // 0058 GETNGBL R8 K18 + 0x8C201113, // 0059 GETMET R8 R8 K19 + 0x58280014, // 005A LDCONST R10 K20 + 0x7C200400, // 005B CALL R8 2 + 0x78220009, // 005C JMPF R8 #0067 + 0xB8222400, // 005D GETNGBL R8 K18 + 0x8C201102, // 005E GETMET R8 R8 K2 + 0x60280018, // 005F GETGBL R10 G24 + 0x582C001C, // 0060 LDCONST R11 K28 + 0x8830030C, // 0061 GETMBR R12 R1 K12 + 0x88301916, // 0062 GETMBR R12 R12 K22 + 0x8834031D, // 0063 GETMBR R13 R1 K29 + 0x7C280600, // 0064 CALL R10 3 + 0x582C0014, // 0065 LDCONST R11 K20 + 0x7C200600, // 0066 CALL R8 3 + 0x70020046, // 0067 JMP #00AF + 0x4C200000, // 0068 LDNIL R8 + 0x20200A08, // 0069 NE R8 R5 R8 + 0x78220018, // 006A JMPF R8 #0084 + 0x8C20011B, // 006B GETMET R8 R0 K27 + 0x5C280E00, // 006C MOVE R10 R7 + 0x5C2C0400, // 006D MOVE R11 R2 + 0x5C300A00, // 006E MOVE R12 R5 + 0x7C200800, // 006F CALL R8 4 + 0x5C200600, // 0070 MOVE R8 R3 + 0x74220000, // 0071 JMPT R8 #0073 + 0x580C0011, // 0072 LDCONST R3 K17 + 0xB8222400, // 0073 GETNGBL R8 K18 + 0x8C201113, // 0074 GETMET R8 R8 K19 + 0x58280014, // 0075 LDCONST R10 K20 + 0x7C200400, // 0076 CALL R8 2 + 0x7822000A, // 0077 JMPF R8 #0083 + 0xB8222400, // 0078 GETNGBL R8 K18 + 0x8C201102, // 0079 GETMET R8 R8 K2 + 0x60280018, // 007A GETGBL R10 G24 + 0x582C001E, // 007B LDCONST R11 K30 + 0x8830030C, // 007C GETMBR R12 R1 K12 + 0x88301916, // 007D GETMBR R12 R12 K22 + 0x5C340400, // 007E MOVE R13 R2 + 0x5C380600, // 007F MOVE R14 R3 + 0x7C280800, // 0080 CALL R10 4 + 0x582C0014, // 0081 LDCONST R11 K20 + 0x7C200600, // 0082 CALL R8 3 + 0x7002002A, // 0083 JMP #00AF + 0x88200505, // 0084 GETMBR R8 R2 K5 + 0x4C240000, // 0085 LDNIL R9 + 0x20201009, // 0086 NE R8 R8 R9 + 0x78220015, // 0087 JMPF R8 #009E + 0x8C20011B, // 0088 GETMET R8 R0 K27 + 0x5C280E00, // 0089 MOVE R10 R7 + 0x5C2C0400, // 008A MOVE R11 R2 + 0x4C300000, // 008B LDNIL R12 + 0x7C200800, // 008C CALL R8 4 + 0xB8222400, // 008D GETNGBL R8 K18 + 0x8C201113, // 008E GETMET R8 R8 K19 + 0x58280014, // 008F LDCONST R10 K20 + 0x7C200400, // 0090 CALL R8 2 + 0x7822000A, // 0091 JMPF R8 #009D + 0xB8222400, // 0092 GETNGBL R8 K18 + 0x8C201102, // 0093 GETMET R8 R8 K2 + 0x60280018, // 0094 GETGBL R10 G24 + 0x582C001F, // 0095 LDCONST R11 K31 + 0x8830030C, // 0096 GETMBR R12 R1 K12 + 0x88301916, // 0097 GETMBR R12 R12 K22 + 0x88340505, // 0098 GETMBR R13 R2 K5 + 0x8838031D, // 0099 GETMBR R14 R1 K29 + 0x7C280800, // 009A CALL R10 4 + 0x582C0014, // 009B LDCONST R11 K20 + 0x7C200600, // 009C CALL R8 3 + 0x70020010, // 009D JMP #00AF + 0xB8222400, // 009E GETNGBL R8 K18 + 0x8C201113, // 009F GETMET R8 R8 K19 + 0x58280014, // 00A0 LDCONST R10 K20 + 0x7C200400, // 00A1 CALL R8 2 + 0x78220009, // 00A2 JMPF R8 #00AD + 0xB8222400, // 00A3 GETNGBL R8 K18 + 0x8C201102, // 00A4 GETMET R8 R8 K2 + 0x60280018, // 00A5 GETGBL R10 G24 + 0x582C0020, // 00A6 LDCONST R11 K32 + 0x8830030C, // 00A7 GETMBR R12 R1 K12 + 0x88301916, // 00A8 GETMBR R12 R12 K22 + 0x8834031D, // 00A9 GETMBR R13 R1 K29 + 0x7C280600, // 00AA CALL R10 3 + 0x582C0014, // 00AB LDCONST R11 K20 + 0x7C200600, // 00AC CALL R8 3 + 0x50200000, // 00AD LDBOOL R8 0 0 + 0x80041000, // 00AE RET 1 R8 + 0x8C200F17, // 00AF GETMET R8 R7 K23 + 0x58280021, // 00B0 LDCONST R10 K33 + 0x542DFFFB, // 00B1 LDINT R11 -4 + 0x7C200600, // 00B2 CALL R8 3 + 0x8C200F17, // 00B3 GETMET R8 R7 K23 + 0x542A0017, // 00B4 LDINT R10 24 + 0x582C0019, // 00B5 LDCONST R11 K25 + 0x7C200600, // 00B6 CALL R8 3 + 0x8C200322, // 00B7 GETMET R8 R1 K34 + 0x542A0008, // 00B8 LDINT R10 9 + 0x502C0200, // 00B9 LDBOOL R11 1 0 + 0x7C200600, // 00BA CALL R8 3 + 0x8824010A, // 00BB GETMBR R9 R0 K10 + 0x88241323, // 00BC GETMBR R9 R9 K35 + 0x88280324, // 00BD GETMBR R10 R1 K36 + 0x8C2C1525, // 00BE GETMET R11 R10 K37 + 0x7C2C0200, // 00BF CALL R11 1 + 0x8C2C1126, // 00C0 GETMET R11 R8 K38 + 0x5C340E00, // 00C1 MOVE R13 R7 + 0x5C381400, // 00C2 MOVE R14 R10 + 0x7C2C0600, // 00C3 CALL R11 3 + 0x8C2C1127, // 00C4 GETMET R11 R8 K39 + 0x7C2C0200, // 00C5 CALL R11 1 + 0x8C2C1328, // 00C6 GETMET R11 R9 K40 + 0x5C341000, // 00C7 MOVE R13 R8 + 0x7C2C0400, // 00C8 CALL R11 2 + 0xB82E0000, // 00C9 GETNGBL R11 K0 + 0x882C1701, // 00CA GETMBR R11 R11 K1 + 0x8C2C1702, // 00CB GETMET R11 R11 K2 + 0x58340029, // 00CC LDCONST R13 K41 + 0x7C2C0400, // 00CD CALL R11 2 + 0x502C0200, // 00CE LDBOOL R11 1 0 + 0x80041600, // 00CF RET 1 R11 }) ) ); @@ -858,7 +849,7 @@ be_local_closure(Matter_IM_process_invoke_request, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[44]) { /* constants */ + ( &(const bvalue[43]) { /* constants */ /* K0 */ be_nested_str_weak(matter), /* K1 */ be_nested_str_weak(profiler), /* K2 */ be_nested_str_weak(log), @@ -889,24 +880,23 @@ be_local_closure(Matter_IM_process_invoke_request, /* name */ /* K27 */ be_nested_str_weak(tasmota), /* K28 */ be_nested_str_weak(MTR_X3A_X20_X3ECommand_X20_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s_X20_X25s), /* K29 */ be_nested_str_weak(local_session_id), - /* K30 */ be_const_int(0), - /* K31 */ be_const_int(2), - /* K32 */ be_const_int(3), - /* K33 */ be_nested_str_weak(SUCCESS), - /* K34 */ be_nested_str_weak(invokeresponse2raw), - /* K35 */ be_nested_str_weak(push), - /* K36 */ be_nested_str_weak(loglevel), - /* K37 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20OK_X20exch_X3D_X25i), - /* K38 */ be_nested_str_weak(exchange_id), - /* K39 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s), - /* K40 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20Status_X3D0x_X2502X_X20exch_X3D_X25i), - /* K41 */ be_nested_str_weak(MTR_X3A_X20_Ignore_X20_X20_X20_X20_X28_X256i_X29_X20exch_X3D_X25i), - /* K42 */ be_nested_str_weak(stop_iteration), - /* K43 */ be_nested_str_weak(send_invoke_response), + /* K30 */ be_const_int(3), + /* K31 */ be_nested_str_weak(SUCCESS), + /* K32 */ be_nested_str_weak(invokeresponse2raw), + /* K33 */ be_nested_str_weak(push), + /* K34 */ be_nested_str_weak(loglevel), + /* K35 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20OK_X20exch_X3D_X25i), + /* K36 */ be_nested_str_weak(exchange_id), + /* K37 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20_X25s_X20_X25s), + /* K38 */ be_nested_str_weak(MTR_X3A_X20_X3CReplied_X20_X20_X20_X28_X256i_X29_X20Status_X3D0x_X2502X_X20exch_X3D_X25i), + /* K39 */ be_nested_str_weak(MTR_X3A_X20_Ignore_X20_X20_X20_X20_X28_X256i_X29_X20exch_X3D_X25i), + /* K40 */ be_nested_str_weak(stop_iteration), + /* K41 */ be_const_int(0), + /* K42 */ be_nested_str_weak(send_invoke_response), }), be_str_weak(process_invoke_request), &be_const_str_solidified, - ( &(const binstruction[238]) { /* code */ + ( &(const binstruction[233]) { /* code */ 0xB80E0000, // 0000 GETNGBL R3 K0 0x880C0701, // 0001 GETMBR R3 R3 K1 0x8C0C0702, // 0002 GETMET R3 R3 K2 @@ -925,7 +915,7 @@ be_local_closure(Matter_IM_process_invoke_request, /* name */ 0x88140908, // 000F GETMBR R5 R4 K8 0x4C180000, // 0010 LDNIL R6 0x20140A06, // 0011 NE R5 R5 R6 - 0x781600D9, // 0012 JMPF R5 #00ED + 0x781600D4, // 0012 JMPF R5 #00E8 0xB8160000, // 0013 GETNGBL R5 K0 0x8C140B09, // 0014 GETMET R5 R5 K9 0x7C140200, // 0015 CALL R5 1 @@ -937,7 +927,7 @@ be_local_closure(Matter_IM_process_invoke_request, /* name */ 0x60180010, // 001B GETGBL R6 G16 0x881C0908, // 001C GETMBR R7 R4 K8 0x7C180200, // 001D CALL R6 1 - 0xA80200BC, // 001E EXBLK 0 #00DC + 0xA80200B7, // 001E EXBLK 0 #00D7 0x5C1C0C00, // 001F MOVE R7 R6 0x7C1C0000, // 0020 CALL R7 0 0x88200F0D, // 0021 GETMBR R8 R7 K13 @@ -995,156 +985,151 @@ be_local_closure(Matter_IM_process_invoke_request, /* name */ 0x5848001A, // 0055 LDCONST R18 K26 0x5C4C1600, // 0056 MOVE R19 R11 0x7C380A00, // 0057 CALL R14 5 - 0x883C070C, // 0058 GETMBR R15 R3 K12 - 0x203C1F1E, // 0059 NE R15 R15 K30 - 0x783E0001, // 005A JMPF R15 #005D - 0x583C001F, // 005B LDCONST R15 K31 - 0x70020000, // 005C JMP #005E - 0x583C0020, // 005D LDCONST R15 K32 - 0x7C300600, // 005E CALL R12 3 - 0x4C300000, // 005F LDNIL R12 - 0x900E040C, // 0060 SETMBR R3 K2 R12 - 0x60300015, // 0061 GETGBL R12 G21 - 0x5436001F, // 0062 LDINT R13 32 - 0x7C300200, // 0063 CALL R12 1 - 0x50340200, // 0064 LDBOOL R13 1 0 - 0x1C34140D, // 0065 EQ R13 R10 R13 - 0x74360004, // 0066 JMPT R13 #006C - 0x88340710, // 0067 GETMBR R13 R3 K16 - 0xB83A0000, // 0068 GETNGBL R14 K0 - 0x88381D21, // 0069 GETMBR R14 R14 K33 - 0x1C341A0E, // 006A EQ R13 R13 R14 - 0x7836001B, // 006B JMPF R13 #0088 - 0xB8360000, // 006C GETNGBL R13 K0 - 0x88341B21, // 006D GETMBR R13 R13 K33 - 0x900E200D, // 006E SETMBR R3 K16 R13 - 0x8C340122, // 006F GETMET R13 R0 K34 - 0x5C3C1800, // 0070 MOVE R15 R12 - 0x5C400600, // 0071 MOVE R16 R3 - 0x4C440000, // 0072 LDNIL R17 - 0x7C340800, // 0073 CALL R13 4 - 0x88340B0B, // 0074 GETMBR R13 R5 K11 - 0x8C341B23, // 0075 GETMET R13 R13 K35 - 0x5C3C1800, // 0076 MOVE R15 R12 - 0x7C340400, // 0077 CALL R13 2 + 0x583C001E, // 0058 LDCONST R15 K30 + 0x7C300600, // 0059 CALL R12 3 + 0x4C300000, // 005A LDNIL R12 + 0x900E040C, // 005B SETMBR R3 K2 R12 + 0x60300015, // 005C GETGBL R12 G21 + 0x5436001F, // 005D LDINT R13 32 + 0x7C300200, // 005E CALL R12 1 + 0x50340200, // 005F LDBOOL R13 1 0 + 0x1C34140D, // 0060 EQ R13 R10 R13 + 0x74360004, // 0061 JMPT R13 #0067 + 0x88340710, // 0062 GETMBR R13 R3 K16 + 0xB83A0000, // 0063 GETNGBL R14 K0 + 0x88381D1F, // 0064 GETMBR R14 R14 K31 + 0x1C341A0E, // 0065 EQ R13 R13 R14 + 0x7836001B, // 0066 JMPF R13 #0083 + 0xB8360000, // 0067 GETNGBL R13 K0 + 0x88341B1F, // 0068 GETMBR R13 R13 K31 + 0x900E200D, // 0069 SETMBR R3 K16 R13 + 0x8C340120, // 006A GETMET R13 R0 K32 + 0x5C3C1800, // 006B MOVE R15 R12 + 0x5C400600, // 006C MOVE R16 R3 + 0x4C440000, // 006D LDNIL R17 + 0x7C340800, // 006E CALL R13 4 + 0x88340B0B, // 006F GETMBR R13 R5 K11 + 0x8C341B21, // 0070 GETMET R13 R13 K33 + 0x5C3C1800, // 0071 MOVE R15 R12 + 0x7C340400, // 0072 CALL R13 2 + 0xB8363600, // 0073 GETNGBL R13 K27 + 0x8C341B22, // 0074 GETMET R13 R13 K34 + 0x583C001E, // 0075 LDCONST R15 K30 + 0x7C340400, // 0076 CALL R13 2 + 0x78360009, // 0077 JMPF R13 #0082 0xB8363600, // 0078 GETNGBL R13 K27 - 0x8C341B24, // 0079 GETMET R13 R13 K36 - 0x583C0020, // 007A LDCONST R15 K32 - 0x7C340400, // 007B CALL R13 2 - 0x78360009, // 007C JMPF R13 #0087 - 0xB8363600, // 007D GETNGBL R13 K27 - 0x8C341B02, // 007E GETMET R13 R13 K2 - 0x603C0018, // 007F GETGBL R15 G24 - 0x58400025, // 0080 LDCONST R16 K37 - 0x88440315, // 0081 GETMBR R17 R1 K21 - 0x8844231D, // 0082 GETMBR R17 R17 K29 - 0x88480326, // 0083 GETMBR R18 R1 K38 - 0x7C3C0600, // 0084 CALL R15 3 - 0x58400020, // 0085 LDCONST R16 K32 - 0x7C340600, // 0086 CALL R13 3 - 0x70020052, // 0087 JMP #00DB - 0x4C340000, // 0088 LDNIL R13 - 0x2034140D, // 0089 NE R13 R10 R13 - 0x78360022, // 008A JMPF R13 #00AE - 0x8C340122, // 008B GETMET R13 R0 K34 - 0x5C3C1800, // 008C MOVE R15 R12 - 0x5C400600, // 008D MOVE R16 R3 - 0x5C441400, // 008E MOVE R17 R10 - 0x7C340800, // 008F CALL R13 4 - 0x88340B0B, // 0090 GETMBR R13 R5 K11 - 0x8C341B23, // 0091 GETMET R13 R13 K35 - 0x5C3C1800, // 0092 MOVE R15 R12 - 0x7C340400, // 0093 CALL R13 2 - 0xB8360000, // 0094 GETNGBL R13 K0 - 0x8C341B12, // 0095 GETMET R13 R13 K18 - 0x883C070E, // 0096 GETMBR R15 R3 K14 - 0x8840070F, // 0097 GETMBR R16 R3 K15 - 0x7C340600, // 0098 CALL R13 3 - 0x5C201A00, // 0099 MOVE R8 R13 - 0x5C341000, // 009A MOVE R13 R8 - 0x74360000, // 009B JMPT R13 #009D - 0x5820001A, // 009C LDCONST R8 K26 + 0x8C341B02, // 0079 GETMET R13 R13 K2 + 0x603C0018, // 007A GETGBL R15 G24 + 0x58400023, // 007B LDCONST R16 K35 + 0x88440315, // 007C GETMBR R17 R1 K21 + 0x8844231D, // 007D GETMBR R17 R17 K29 + 0x88480324, // 007E GETMBR R18 R1 K36 + 0x7C3C0600, // 007F CALL R15 3 + 0x5840001E, // 0080 LDCONST R16 K30 + 0x7C340600, // 0081 CALL R13 3 + 0x70020052, // 0082 JMP #00D6 + 0x4C340000, // 0083 LDNIL R13 + 0x2034140D, // 0084 NE R13 R10 R13 + 0x78360022, // 0085 JMPF R13 #00A9 + 0x8C340120, // 0086 GETMET R13 R0 K32 + 0x5C3C1800, // 0087 MOVE R15 R12 + 0x5C400600, // 0088 MOVE R16 R3 + 0x5C441400, // 0089 MOVE R17 R10 + 0x7C340800, // 008A CALL R13 4 + 0x88340B0B, // 008B GETMBR R13 R5 K11 + 0x8C341B21, // 008C GETMET R13 R13 K33 + 0x5C3C1800, // 008D MOVE R15 R12 + 0x7C340400, // 008E CALL R13 2 + 0xB8360000, // 008F GETNGBL R13 K0 + 0x8C341B12, // 0090 GETMET R13 R13 K18 + 0x883C070E, // 0091 GETMBR R15 R3 K14 + 0x8840070F, // 0092 GETMBR R16 R3 K15 + 0x7C340600, // 0093 CALL R13 3 + 0x5C201A00, // 0094 MOVE R8 R13 + 0x5C341000, // 0095 MOVE R13 R8 + 0x74360000, // 0096 JMPT R13 #0098 + 0x5820001A, // 0097 LDCONST R8 K26 + 0xB8363600, // 0098 GETNGBL R13 K27 + 0x8C341B22, // 0099 GETMET R13 R13 K34 + 0x583C001E, // 009A LDCONST R15 K30 + 0x7C340400, // 009B CALL R13 2 + 0x7836000A, // 009C JMPF R13 #00A8 0xB8363600, // 009D GETNGBL R13 K27 - 0x8C341B24, // 009E GETMET R13 R13 K36 - 0x583C0020, // 009F LDCONST R15 K32 - 0x7C340400, // 00A0 CALL R13 2 - 0x7836000A, // 00A1 JMPF R13 #00AD - 0xB8363600, // 00A2 GETNGBL R13 K27 - 0x8C341B02, // 00A3 GETMET R13 R13 K2 - 0x603C0018, // 00A4 GETGBL R15 G24 - 0x58400027, // 00A5 LDCONST R16 K39 - 0x88440315, // 00A6 GETMBR R17 R1 K21 - 0x8844231D, // 00A7 GETMBR R17 R17 K29 - 0x5C480600, // 00A8 MOVE R18 R3 - 0x5C4C1000, // 00A9 MOVE R19 R8 - 0x7C3C0800, // 00AA CALL R15 4 - 0x58400020, // 00AB LDCONST R16 K32 - 0x7C340600, // 00AC CALL R13 3 - 0x7002002C, // 00AD JMP #00DB - 0x88340710, // 00AE GETMBR R13 R3 K16 - 0x4C380000, // 00AF LDNIL R14 - 0x20341A0E, // 00B0 NE R13 R13 R14 - 0x78360019, // 00B1 JMPF R13 #00CC - 0x8C340122, // 00B2 GETMET R13 R0 K34 - 0x5C3C1800, // 00B3 MOVE R15 R12 - 0x5C400600, // 00B4 MOVE R16 R3 - 0x4C440000, // 00B5 LDNIL R17 - 0x7C340800, // 00B6 CALL R13 4 - 0x88340B0B, // 00B7 GETMBR R13 R5 K11 - 0x8C341B23, // 00B8 GETMET R13 R13 K35 - 0x5C3C1800, // 00B9 MOVE R15 R12 - 0x7C340400, // 00BA CALL R13 2 + 0x8C341B02, // 009E GETMET R13 R13 K2 + 0x603C0018, // 009F GETGBL R15 G24 + 0x58400025, // 00A0 LDCONST R16 K37 + 0x88440315, // 00A1 GETMBR R17 R1 K21 + 0x8844231D, // 00A2 GETMBR R17 R17 K29 + 0x5C480600, // 00A3 MOVE R18 R3 + 0x5C4C1000, // 00A4 MOVE R19 R8 + 0x7C3C0800, // 00A5 CALL R15 4 + 0x5840001E, // 00A6 LDCONST R16 K30 + 0x7C340600, // 00A7 CALL R13 3 + 0x7002002C, // 00A8 JMP #00D6 + 0x88340710, // 00A9 GETMBR R13 R3 K16 + 0x4C380000, // 00AA LDNIL R14 + 0x20341A0E, // 00AB NE R13 R13 R14 + 0x78360019, // 00AC JMPF R13 #00C7 + 0x8C340120, // 00AD GETMET R13 R0 K32 + 0x5C3C1800, // 00AE MOVE R15 R12 + 0x5C400600, // 00AF MOVE R16 R3 + 0x4C440000, // 00B0 LDNIL R17 + 0x7C340800, // 00B1 CALL R13 4 + 0x88340B0B, // 00B2 GETMBR R13 R5 K11 + 0x8C341B21, // 00B3 GETMET R13 R13 K33 + 0x5C3C1800, // 00B4 MOVE R15 R12 + 0x7C340400, // 00B5 CALL R13 2 + 0xB8363600, // 00B6 GETNGBL R13 K27 + 0x8C341B22, // 00B7 GETMET R13 R13 K34 + 0x583C001E, // 00B8 LDCONST R15 K30 + 0x7C340400, // 00B9 CALL R13 2 + 0x7836000A, // 00BA JMPF R13 #00C6 0xB8363600, // 00BB GETNGBL R13 K27 - 0x8C341B24, // 00BC GETMET R13 R13 K36 - 0x583C0020, // 00BD LDCONST R15 K32 - 0x7C340400, // 00BE CALL R13 2 - 0x7836000A, // 00BF JMPF R13 #00CB - 0xB8363600, // 00C0 GETNGBL R13 K27 - 0x8C341B02, // 00C1 GETMET R13 R13 K2 - 0x603C0018, // 00C2 GETGBL R15 G24 - 0x58400028, // 00C3 LDCONST R16 K40 - 0x88440315, // 00C4 GETMBR R17 R1 K21 - 0x8844231D, // 00C5 GETMBR R17 R17 K29 - 0x88480710, // 00C6 GETMBR R18 R3 K16 - 0x884C0326, // 00C7 GETMBR R19 R1 K38 - 0x7C3C0800, // 00C8 CALL R15 4 - 0x58400020, // 00C9 LDCONST R16 K32 - 0x7C340600, // 00CA CALL R13 3 - 0x7002000E, // 00CB JMP #00DB + 0x8C341B02, // 00BC GETMET R13 R13 K2 + 0x603C0018, // 00BD GETGBL R15 G24 + 0x58400026, // 00BE LDCONST R16 K38 + 0x88440315, // 00BF GETMBR R17 R1 K21 + 0x8844231D, // 00C0 GETMBR R17 R17 K29 + 0x88480710, // 00C1 GETMBR R18 R3 K16 + 0x884C0324, // 00C2 GETMBR R19 R1 K36 + 0x7C3C0800, // 00C3 CALL R15 4 + 0x5840001E, // 00C4 LDCONST R16 K30 + 0x7C340600, // 00C5 CALL R13 3 + 0x7002000E, // 00C6 JMP #00D6 + 0xB8363600, // 00C7 GETNGBL R13 K27 + 0x8C341B22, // 00C8 GETMET R13 R13 K34 + 0x583C001E, // 00C9 LDCONST R15 K30 + 0x7C340400, // 00CA CALL R13 2 + 0x78360009, // 00CB JMPF R13 #00D6 0xB8363600, // 00CC GETNGBL R13 K27 - 0x8C341B24, // 00CD GETMET R13 R13 K36 - 0x583C0020, // 00CE LDCONST R15 K32 - 0x7C340400, // 00CF CALL R13 2 - 0x78360009, // 00D0 JMPF R13 #00DB - 0xB8363600, // 00D1 GETNGBL R13 K27 - 0x8C341B02, // 00D2 GETMET R13 R13 K2 - 0x603C0018, // 00D3 GETGBL R15 G24 - 0x58400029, // 00D4 LDCONST R16 K41 - 0x88440315, // 00D5 GETMBR R17 R1 K21 - 0x8844231D, // 00D6 GETMBR R17 R17 K29 - 0x88480326, // 00D7 GETMBR R18 R1 K38 - 0x7C3C0600, // 00D8 CALL R15 3 - 0x58400020, // 00D9 LDCONST R16 K32 - 0x7C340600, // 00DA CALL R13 3 - 0x7001FF42, // 00DB JMP #001F - 0x5818002A, // 00DC LDCONST R6 K42 - 0xAC180200, // 00DD CATCH R6 1 0 - 0xB0080000, // 00DE RAISE 2 R0 R0 - 0x6018000C, // 00DF GETGBL R6 G12 - 0x881C0B0B, // 00E0 GETMBR R7 R5 K11 - 0x7C180200, // 00E1 CALL R6 1 - 0x24180D1E, // 00E2 GT R6 R6 K30 - 0x781A0004, // 00E3 JMPF R6 #00E9 - 0x8C18012B, // 00E4 GETMET R6 R0 K43 - 0x5C200200, // 00E5 MOVE R8 R1 - 0x5C240A00, // 00E6 MOVE R9 R5 - 0x7C180600, // 00E7 CALL R6 3 - 0x70020001, // 00E8 JMP #00EB - 0x50180000, // 00E9 LDBOOL R6 0 0 - 0x80040C00, // 00EA RET 1 R6 - 0x50180200, // 00EB LDBOOL R6 1 0 - 0x80040C00, // 00EC RET 1 R6 - 0x80000000, // 00ED RET 0 + 0x8C341B02, // 00CD GETMET R13 R13 K2 + 0x603C0018, // 00CE GETGBL R15 G24 + 0x58400027, // 00CF LDCONST R16 K39 + 0x88440315, // 00D0 GETMBR R17 R1 K21 + 0x8844231D, // 00D1 GETMBR R17 R17 K29 + 0x88480324, // 00D2 GETMBR R18 R1 K36 + 0x7C3C0600, // 00D3 CALL R15 3 + 0x5840001E, // 00D4 LDCONST R16 K30 + 0x7C340600, // 00D5 CALL R13 3 + 0x7001FF47, // 00D6 JMP #001F + 0x58180028, // 00D7 LDCONST R6 K40 + 0xAC180200, // 00D8 CATCH R6 1 0 + 0xB0080000, // 00D9 RAISE 2 R0 R0 + 0x6018000C, // 00DA GETGBL R6 G12 + 0x881C0B0B, // 00DB GETMBR R7 R5 K11 + 0x7C180200, // 00DC CALL R6 1 + 0x24180D29, // 00DD GT R6 R6 K41 + 0x781A0004, // 00DE JMPF R6 #00E4 + 0x8C18012A, // 00DF GETMET R6 R0 K42 + 0x5C200200, // 00E0 MOVE R8 R1 + 0x5C240A00, // 00E1 MOVE R9 R5 + 0x7C180600, // 00E2 CALL R6 3 + 0x70020001, // 00E3 JMP #00E6 + 0x50180000, // 00E4 LDBOOL R6 0 0 + 0x80040C00, // 00E5 RET 1 R6 + 0x50180200, // 00E6 LDBOOL R6 1 0 + 0x80040C00, // 00E7 RET 1 R6 + 0x80000000, // 00E8 RET 0 }) ) ); @@ -2467,9 +2452,9 @@ be_local_closure(Matter_IM__inner_process_read_request, /* name */ 0x5C341400, // 00C3 MOVE R13 R10 0x7C2C0400, // 00C4 CALL R11 2 0x70020014, // 00C5 JMP #00DB - 0x542DFFFE, // 00C6 LDINT R11 -1 - 0x88300121, // 00C7 GETMBR R12 R0 K33 - 0x942C180B, // 00C8 GETIDX R11 R12 R11 + 0x882C0121, // 00C6 GETMBR R11 R0 K33 + 0x5431FFFE, // 00C7 LDINT R12 -1 + 0x942C160C, // 00C8 GETIDX R11 R11 R12 0x6034000C, // 00C9 GETGBL R13 G12 0x5C381600, // 00CA MOVE R14 R11 0x7C340200, // 00CB CALL R13 1 diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_0.h similarity index 74% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_0.h index 806c7361f..6e5811686 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_0.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin.h */ +/* Solidification of Matter_Plugin_0.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,424 +6,6 @@ extern const bclass be_class_Matter_Plugin; -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_init, /* name */ - be_nested_proto( - 7, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(device), - /* K1 */ be_nested_str_weak(endpoint), - /* K2 */ be_nested_str_weak(clusters), - /* K3 */ be_nested_str_weak(consolidate_clusters), - /* K4 */ be_nested_str_weak(parse_configuration), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x90020001, // 0000 SETMBR R0 K0 R1 - 0x90020202, // 0001 SETMBR R0 K1 R2 - 0x8C100103, // 0002 GETMET R4 R0 K3 - 0x7C100200, // 0003 CALL R4 1 - 0x90020404, // 0004 SETMBR R0 K2 R4 - 0x8C100104, // 0005 GETMET R4 R0 K4 - 0x5C180600, // 0006 MOVE R6 R3 - 0x7C100400, // 0007 CALL R4 2 - 0x80000000, // 0008 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: read_event -********************************************************************/ -be_local_closure(Matter_Plugin_read_event, /* name */ - be_nested_proto( - 6, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(read_event), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C140000, // 0000 LDNIL R5 - 0x80040A00, // 0001 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: is_local_device -********************************************************************/ -be_local_closure(Matter_Plugin_is_local_device, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(is_local_device), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x50040200, // 0000 LDBOOL R1 1 0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: write_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_write_attribute, /* name */ - be_nested_proto( - 5, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(write_attribute), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C100000, // 0000 LDNIL R4 - 0x80040800, // 0001 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: ui_conf_to_string -********************************************************************/ -be_local_closure(Matter_Plugin_ui_conf_to_string, /* name */ - be_nested_proto( - 9, /* nstack */ - 2, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Plugin), - /* K1 */ be_nested_str_weak(ARG), - /* K2 */ be_nested_str_weak(find), - /* K3 */ be_nested_str_weak(), - }), - be_str_weak(ui_conf_to_string), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x58080000, // 0000 LDCONST R2 K0 - 0x880C0101, // 0001 GETMBR R3 R0 K1 - 0x780E0006, // 0002 JMPF R3 #000A - 0x60100008, // 0003 GETGBL R4 G8 - 0x8C140302, // 0004 GETMET R5 R1 K2 - 0x5C1C0600, // 0005 MOVE R7 R3 - 0x58200003, // 0006 LDCONST R8 K3 - 0x7C140600, // 0007 CALL R5 3 - 0x7C100200, // 0008 CALL R4 1 - 0x70020000, // 0009 JMP #000B - 0x58100003, // 000A LDCONST R4 K3 - 0x80040800, // 000B RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: every_250ms -********************************************************************/ -be_local_closure(Matter_Plugin_every_250ms, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[10]) { /* constants */ - /* K0 */ be_nested_str_weak(update_next), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(jitter), - /* K3 */ be_nested_str_weak(UPDATE_TIME), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(time_reached), - /* K6 */ be_nested_str_weak(tick), - /* K7 */ be_nested_str_weak(device), - /* K8 */ be_nested_str_weak(update_shadow), - /* K9 */ be_nested_str_weak(millis), - }), - be_str_weak(every_250ms), - &be_const_str_solidified, - ( &(const binstruction[28]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x4C080000, // 0001 LDNIL R2 - 0x1C040202, // 0002 EQ R1 R1 R2 - 0x78060005, // 0003 JMPF R1 #000A - 0xB8060200, // 0004 GETNGBL R1 K1 - 0x8C040302, // 0005 GETMET R1 R1 K2 - 0x880C0103, // 0006 GETMBR R3 R0 K3 - 0x7C040400, // 0007 CALL R1 2 - 0x90020001, // 0008 SETMBR R0 K0 R1 - 0x70020010, // 0009 JMP #001B - 0xB8060800, // 000A GETNGBL R1 K4 - 0x8C040305, // 000B GETMET R1 R1 K5 - 0x880C0100, // 000C GETMBR R3 R0 K0 - 0x7C040400, // 000D CALL R1 2 - 0x7806000B, // 000E JMPF R1 #001B - 0x88040106, // 000F GETMBR R1 R0 K6 - 0x88080107, // 0010 GETMBR R2 R0 K7 - 0x88080506, // 0011 GETMBR R2 R2 K6 - 0x20040202, // 0012 NE R1 R1 R2 - 0x78060001, // 0013 JMPF R1 #0016 - 0x8C040108, // 0014 GETMET R1 R0 K8 - 0x7C040200, // 0015 CALL R1 1 - 0xB8060800, // 0016 GETNGBL R1 K4 - 0x8C040309, // 0017 GETMET R1 R1 K9 - 0x880C0103, // 0018 GETMBR R3 R0 K3 - 0x7C040400, // 0019 CALL R1 2 - 0x90020001, // 001A SETMBR R0 K0 R1 - 0x80000000, // 001B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: contains_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_contains_attribute, /* name */ - be_nested_proto( - 7, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(clusters), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_const_int(0), - /* K3 */ be_const_int(1), - }), - be_str_weak(contains_attribute), - &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x8C0C0701, // 0001 GETMET R3 R3 K1 - 0x5C140200, // 0002 MOVE R5 R1 - 0x7C0C0400, // 0003 CALL R3 2 - 0x4C100000, // 0004 LDNIL R4 - 0x20100604, // 0005 NE R4 R3 R4 - 0x7812000C, // 0006 JMPF R4 #0014 - 0x58100002, // 0007 LDCONST R4 K2 - 0x6014000C, // 0008 GETGBL R5 G12 - 0x5C180600, // 0009 MOVE R6 R3 - 0x7C140200, // 000A CALL R5 1 - 0x14140805, // 000B LT R5 R4 R5 - 0x78160006, // 000C JMPF R5 #0014 - 0x94140604, // 000D GETIDX R5 R3 R4 - 0x1C140A02, // 000E EQ R5 R5 R2 - 0x78160001, // 000F JMPF R5 #0012 - 0x50140200, // 0010 LDBOOL R5 1 0 - 0x80040A00, // 0011 RET 1 R5 - 0x00100903, // 0012 ADD R4 R4 K3 - 0x7001FFF3, // 0013 JMP #0008 - 0x50100000, // 0014 LDBOOL R4 0 0 - 0x80040800, // 0015 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: parse_sensors -********************************************************************/ -be_local_closure(Matter_Plugin_parse_sensors, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(parse_sensors), - &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: has -********************************************************************/ -be_local_closure(Matter_Plugin_has, /* name */ - be_nested_proto( - 6, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(clusters), - /* K1 */ be_nested_str_weak(contains), - /* K2 */ be_nested_str_weak(endpoints), - /* K3 */ be_nested_str_weak(find), - }), - be_str_weak(has), - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x8C0C0701, // 0001 GETMET R3 R3 K1 - 0x5C140200, // 0002 MOVE R5 R1 - 0x7C0C0400, // 0003 CALL R3 2 - 0x780E0006, // 0004 JMPF R3 #000C - 0x880C0102, // 0005 GETMBR R3 R0 K2 - 0x8C0C0703, // 0006 GETMET R3 R3 K3 - 0x5C140400, // 0007 MOVE R5 R2 - 0x7C0C0400, // 0008 CALL R3 2 - 0x4C100000, // 0009 LDNIL R4 - 0x200C0604, // 000A NE R3 R3 R4 - 0x740E0000, // 000B JMPT R3 #000D - 0x500C0001, // 000C LDBOOL R3 0 1 - 0x500C0200, // 000D LDBOOL R3 1 0 - 0x80040600, // 000E RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: parse_configuration -********************************************************************/ -be_local_closure(Matter_Plugin_parse_configuration, /* name */ - be_nested_proto( - 2, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(parse_configuration), - &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: ui_string_to_conf -********************************************************************/ -be_local_closure(Matter_Plugin_ui_string_to_conf, /* name */ - be_nested_proto( - 8, /* nstack */ - 3, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_const_class(be_class_Matter_Plugin), - /* K1 */ be_nested_str_weak(ARG), - /* K2 */ be_nested_str_weak(ARG_TYPE), - }), - be_str_weak(ui_string_to_conf), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x580C0000, // 0000 LDCONST R3 K0 - 0x88100101, // 0001 GETMBR R4 R0 K1 - 0x88140102, // 0002 GETMBR R5 R0 K2 - 0x780A0004, // 0003 JMPF R2 #0009 - 0x78120003, // 0004 JMPF R4 #0009 - 0x5C180A00, // 0005 MOVE R6 R5 - 0x5C1C0400, // 0006 MOVE R7 R2 - 0x7C180200, // 0007 CALL R6 1 - 0x98040806, // 0008 SETIDX R1 R4 R6 - 0x80040200, // 0009 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: subscribe_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_subscribe_attribute, /* name */ - be_nested_proto( - 6, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(subscribe_attribute), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C140000, // 0000 LDNIL R5 - 0x80040A00, // 0001 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: ack_request ********************************************************************/ @@ -467,11 +49,11 @@ be_local_closure(Matter_Plugin_ack_request, /* name */ /******************************************************************** -** Solidified function: get_cluster_list +** Solidified function: consolidate_clusters ********************************************************************/ -be_local_closure(Matter_Plugin_get_cluster_list, /* name */ +be_local_closure(Matter_Plugin_consolidate_clusters, /* name */ be_nested_proto( - 7, /* nstack */ + 2, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -479,33 +61,199 @@ be_local_closure(Matter_Plugin_get_cluster_list, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(clusters), - /* K1 */ be_nested_str_weak(keys), - /* K2 */ be_nested_str_weak(push), - /* K3 */ be_nested_str_weak(stop_iteration), + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(CLUSTERS), }), - be_str_weak(get_cluster_list), + be_str_weak(consolidate_clusters), &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x60080010, // 0002 GETGBL R2 G16 - 0x880C0100, // 0003 GETMBR R3 R0 K0 - 0x8C0C0701, // 0004 GETMET R3 R3 K1 - 0x7C0C0200, // 0005 CALL R3 1 - 0x7C080200, // 0006 CALL R2 1 - 0xA8020005, // 0007 EXBLK 0 #000E - 0x5C0C0400, // 0008 MOVE R3 R2 - 0x7C0C0000, // 0009 CALL R3 0 - 0x8C100302, // 000A GETMET R4 R1 K2 - 0x5C180600, // 000B MOVE R6 R3 - 0x7C100400, // 000C CALL R4 2 - 0x7001FFF9, // 000D JMP #0008 - 0x58080003, // 000E LDCONST R2 K3 - 0xAC080200, // 000F CATCH R2 1 0 - 0xB0080000, // 0010 RAISE 2 R0 R0 - 0x80040200, // 0011 RET 1 R1 + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_update_shadow, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(tick), + /* K1 */ be_nested_str_weak(device), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040101, // 0000 GETMBR R1 R0 K1 + 0x88040300, // 0001 GETMBR R1 R1 K0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_sensors +********************************************************************/ +be_local_closure(Matter_Plugin_parse_sensors, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(parse_sensors), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: consolidate_update_commands +********************************************************************/ +be_local_closure(Matter_Plugin_consolidate_update_commands, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(UPDATE_COMMANDS), + }), + be_str_weak(consolidate_update_commands), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: publish_command +********************************************************************/ +be_local_closure(Matter_Plugin_publish_command, /* name */ + be_nested_proto( + 16, /* nstack */ + 7, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(_X25s_X3A_X25s), + /* K2 */ be_nested_str_weak(dump), + /* K3 */ be_nested_str_weak(_X25s_X2C_X25s_X3A_X25s), + /* K4 */ be_nested_str_weak(matter), + /* K5 */ be_nested_str_weak(publish_command), + /* K6 */ be_nested_str_weak(MtrReceived), + /* K7 */ be_nested_str_weak(endpoint), + /* K8 */ be_nested_str_weak(node_label), + }), + be_str_weak(publish_command), + &be_const_str_solidified, + ( &(const binstruction[46]) { /* code */ + 0xA41E0000, // 0000 IMPORT R7 K0 + 0x60200018, // 0001 GETGBL R8 G24 + 0x58240001, // 0002 LDCONST R9 K1 + 0x8C280F02, // 0003 GETMET R10 R7 K2 + 0x5C300200, // 0004 MOVE R12 R1 + 0x7C280400, // 0005 CALL R10 2 + 0x8C2C0F02, // 0006 GETMET R11 R7 K2 + 0x5C340400, // 0007 MOVE R13 R2 + 0x7C2C0400, // 0008 CALL R11 2 + 0x7C200600, // 0009 CALL R8 3 + 0x4C240000, // 000A LDNIL R9 + 0x20240609, // 000B NE R9 R3 R9 + 0x7826000A, // 000C JMPF R9 #0018 + 0x60240018, // 000D GETGBL R9 G24 + 0x58280003, // 000E LDCONST R10 K3 + 0x5C2C1000, // 000F MOVE R11 R8 + 0x8C300F02, // 0010 GETMET R12 R7 K2 + 0x5C380600, // 0011 MOVE R14 R3 + 0x7C300400, // 0012 CALL R12 2 + 0x8C340F02, // 0013 GETMET R13 R7 K2 + 0x5C3C0800, // 0014 MOVE R15 R4 + 0x7C340400, // 0015 CALL R13 2 + 0x7C240800, // 0016 CALL R9 4 + 0x5C201200, // 0017 MOVE R8 R9 + 0x4C240000, // 0018 LDNIL R9 + 0x20240A09, // 0019 NE R9 R5 R9 + 0x7826000A, // 001A JMPF R9 #0026 + 0x60240018, // 001B GETGBL R9 G24 + 0x58280003, // 001C LDCONST R10 K3 + 0x5C2C1000, // 001D MOVE R11 R8 + 0x8C300F02, // 001E GETMET R12 R7 K2 + 0x5C380A00, // 001F MOVE R14 R5 + 0x7C300400, // 0020 CALL R12 2 + 0x8C340F02, // 0021 GETMET R13 R7 K2 + 0x5C3C0C00, // 0022 MOVE R15 R6 + 0x7C340400, // 0023 CALL R13 2 + 0x7C240800, // 0024 CALL R9 4 + 0x5C201200, // 0025 MOVE R8 R9 + 0xB8260800, // 0026 GETNGBL R9 K4 + 0x8C241305, // 0027 GETMET R9 R9 K5 + 0x582C0006, // 0028 LDCONST R11 K6 + 0x88300107, // 0029 GETMBR R12 R0 K7 + 0x88340108, // 002A GETMBR R13 R0 K8 + 0x5C381000, // 002B MOVE R14 R8 + 0x7C240A00, // 002C CALL R9 5 + 0x80000000, // 002D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_subscribe_attribute, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(subscribe_attribute), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 }) ) ); @@ -671,11 +419,36 @@ be_local_closure(Matter_Plugin_read_attribute, /* name */ /******************************************************************** -** Solidified function: contains_cluster +** Solidified function: timed_request ********************************************************************/ -be_local_closure(Matter_Plugin_contains_cluster, /* name */ +be_local_closure(Matter_Plugin_timed_request, /* name */ be_nested_proto( 5, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(timed_request), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x80040800, // 0001 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_name +********************************************************************/ +be_local_closure(Matter_Plugin_set_name, /* name */ + be_nested_proto( + 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -684,17 +457,21 @@ be_local_closure(Matter_Plugin_contains_cluster, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(clusters), - /* K1 */ be_nested_str_weak(contains), + /* K0 */ be_nested_str_weak(node_label), + /* K1 */ be_nested_str_weak(attribute_updated), }), - be_str_weak(contains_cluster), + be_str_weak(set_name), &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ + ( &(const binstruction[ 9]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C080400, // 0003 CALL R2 2 - 0x80040400, // 0004 RET 1 R2 + 0x20080202, // 0001 NE R2 R1 R2 + 0x780A0003, // 0002 JMPF R2 #0007 + 0x8C080101, // 0003 GETMET R2 R0 K1 + 0x54120038, // 0004 LDINT R4 57 + 0x54160004, // 0005 LDINT R5 5 + 0x7C080600, // 0006 CALL R2 3 + 0x90020001, // 0007 SETMBR R0 K0 R1 + 0x80000000, // 0008 RET 0 }) ) ); @@ -702,26 +479,24 @@ be_local_closure(Matter_Plugin_contains_cluster, /* name */ /******************************************************************** -** Solidified function: +** Solidified function: is_local_device ********************************************************************/ -be_local_closure(Matter_Plugin__X3Clambda_X3E, /* name */ +be_local_closure(Matter_Plugin_is_local_device, /* name */ be_nested_proto( - 3, /* nstack */ + 2, /* nstack */ 1, /* argc */ - 0, /* varg */ + 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 0, /* has constants */ NULL, /* no const */ - be_str_weak(_X3Clambda_X3E), + be_str_weak(is_local_device), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040008, // 0000 GETGBL R1 G8 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x80040200, // 0003 RET 1 R1 + ( &(const binstruction[ 2]) { /* code */ + 0x50040200, // 0000 LDBOOL R1 1 0 + 0x80040200, // 0001 RET 1 R1 }) ) ); @@ -729,11 +504,38 @@ be_local_closure(Matter_Plugin__X3Clambda_X3E, /* name */ /******************************************************************** -** Solidified function: attribute_updated +** Solidified function: get_name ********************************************************************/ -be_local_closure(Matter_Plugin_attribute_updated, /* name */ +be_local_closure(Matter_Plugin_get_name, /* name */ be_nested_proto( - 10, /* nstack */ + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(node_label), + }), + be_str_weak(get_name), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x80040200, // 0001 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_init, /* name */ + be_nested_proto( + 8, /* nstack */ 4, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -741,47 +543,34 @@ be_local_closure(Matter_Plugin_attribute_updated, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ + ( &(const bvalue[ 9]) { /* constants */ /* K0 */ be_nested_str_weak(device), - /* K1 */ be_nested_str_weak(attribute_updated), - /* K2 */ be_nested_str_weak(endpoint), + /* K1 */ be_nested_str_weak(endpoint), + /* K2 */ be_nested_str_weak(clusters), + /* K3 */ be_nested_str_weak(consolidate_clusters), + /* K4 */ be_nested_str_weak(parse_configuration), + /* K5 */ be_nested_str_weak(node_label), + /* K6 */ be_nested_str_weak(find), + /* K7 */ be_nested_str_weak(name), + /* K8 */ be_nested_str_weak(), }), - be_str_weak(attribute_updated), + be_str_weak(init), &be_const_str_solidified, - ( &(const binstruction[ 8]) { /* code */ - 0x88100100, // 0000 GETMBR R4 R0 K0 - 0x8C100901, // 0001 GETMET R4 R4 K1 - 0x88180102, // 0002 GETMBR R6 R0 K2 - 0x5C1C0200, // 0003 MOVE R7 R1 - 0x5C200400, // 0004 MOVE R8 R2 - 0x5C240600, // 0005 MOVE R9 R3 - 0x7C100A00, // 0006 CALL R4 5 - 0x80000000, // 0007 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_invoke_request, /* name */ - be_nested_proto( - 5, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C100000, // 0000 LDNIL R4 - 0x80040800, // 0001 RET 1 R4 + ( &(const binstruction[14]) { /* code */ + 0x90020001, // 0000 SETMBR R0 K0 R1 + 0x90020202, // 0001 SETMBR R0 K1 R2 + 0x8C100103, // 0002 GETMET R4 R0 K3 + 0x7C100200, // 0003 CALL R4 1 + 0x90020404, // 0004 SETMBR R0 K2 R4 + 0x8C100104, // 0005 GETMET R4 R0 K4 + 0x5C180600, // 0006 MOVE R6 R3 + 0x7C100400, // 0007 CALL R4 2 + 0x8C100706, // 0008 GETMET R4 R3 K6 + 0x58180007, // 0009 LDCONST R6 K7 + 0x581C0008, // 000A LDCONST R7 K8 + 0x7C100600, // 000B CALL R4 3 + 0x90020A04, // 000C SETMBR R0 K5 R4 + 0x80000000, // 000D RET 0 }) ) ); @@ -826,6 +615,68 @@ be_local_closure(Matter_Plugin_update_shadow_lazy, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_invoke_request, /* name */ + be_nested_proto( + 5, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x80040800, // 0001 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: ui_string_to_conf +********************************************************************/ +be_local_closure(Matter_Plugin_ui_string_to_conf, /* name */ + be_nested_proto( + 8, /* nstack */ + 3, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Plugin), + /* K1 */ be_nested_str_weak(ARG), + /* K2 */ be_nested_str_weak(ARG_TYPE), + }), + be_str_weak(ui_string_to_conf), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x580C0000, // 0000 LDCONST R3 K0 + 0x88100101, // 0001 GETMBR R4 R0 K1 + 0x88140102, // 0002 GETMBR R5 R0 K2 + 0x780A0004, // 0003 JMPF R2 #0009 + 0x78120003, // 0004 JMPF R4 #0009 + 0x5C180A00, // 0005 MOVE R6 R5 + 0x5C1C0400, // 0006 MOVE R7 R2 + 0x7C180200, // 0007 CALL R6 1 + 0x98040806, // 0008 SETIDX R1 R4 R6 + 0x80040200, // 0009 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: get_endpoint ********************************************************************/ @@ -853,189 +704,6 @@ be_local_closure(Matter_Plugin_get_endpoint, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: timed_request -********************************************************************/ -be_local_closure(Matter_Plugin_timed_request, /* name */ - be_nested_proto( - 5, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(timed_request), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C100000, // 0000 LDNIL R4 - 0x80040800, // 0001 RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: subscribe_event -********************************************************************/ -be_local_closure(Matter_Plugin_subscribe_event, /* name */ - be_nested_proto( - 6, /* nstack */ - 5, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(subscribe_event), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x4C140000, // 0000 LDNIL R5 - 0x80040A00, // 0001 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_update_shadow, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(tick), - /* K1 */ be_nested_str_weak(device), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x88040101, // 0000 GETMBR R1 R0 K1 - 0x88040300, // 0001 GETMBR R1 R1 K0 - 0x90020001, // 0002 SETMBR R0 K0 R1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: consolidate_clusters -********************************************************************/ -be_local_closure(Matter_Plugin_consolidate_clusters, /* name */ - be_nested_proto( - 12, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 0, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(real_super), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040003, // 0000 GETGBL R1 G3 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x80040200, // 0003 RET 1 R1 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(CLUSTERS), - /* K1 */ be_nested_str_weak(keys), - /* K2 */ be_nested_str_weak(contains), - /* K3 */ be_nested_str_weak(find), - /* K4 */ be_nested_str_weak(push), - /* K5 */ be_nested_str_weak(stop_iteration), - }), - be_str_weak(consolidate_clusters), - &be_const_str_solidified, - ( &(const binstruction[53]) { /* code */ - 0x84040000, // 0000 CLOSURE R1 P0 - 0x60080013, // 0001 GETGBL R2 G19 - 0x7C080000, // 0002 CALL R2 0 - 0x5C0C0000, // 0003 MOVE R3 R0 - 0x4C100000, // 0004 LDNIL R4 - 0x20100604, // 0005 NE R4 R3 R4 - 0x7812002C, // 0006 JMPF R4 #0034 - 0x88100700, // 0007 GETMBR R4 R3 K0 - 0x60140010, // 0008 GETGBL R5 G16 - 0x8C180901, // 0009 GETMET R6 R4 K1 - 0x7C180200, // 000A CALL R6 1 - 0x7C140200, // 000B CALL R5 1 - 0xA802001E, // 000C EXBLK 0 #002C - 0x5C180A00, // 000D MOVE R6 R5 - 0x7C180000, // 000E CALL R6 0 - 0x8C1C0502, // 000F GETMET R7 R2 K2 - 0x5C240C00, // 0010 MOVE R9 R6 - 0x7C1C0400, // 0011 CALL R7 2 - 0x741E0002, // 0012 JMPT R7 #0016 - 0x601C0012, // 0013 GETGBL R7 G18 - 0x7C1C0000, // 0014 CALL R7 0 - 0x98080C07, // 0015 SETIDX R2 R6 R7 - 0x601C0010, // 0016 GETGBL R7 G16 - 0x94200806, // 0017 GETIDX R8 R4 R6 - 0x7C1C0200, // 0018 CALL R7 1 - 0xA802000D, // 0019 EXBLK 0 #0028 - 0x5C200E00, // 001A MOVE R8 R7 - 0x7C200000, // 001B CALL R8 0 - 0x94240406, // 001C GETIDX R9 R2 R6 - 0x8C241303, // 001D GETMET R9 R9 K3 - 0x5C2C1000, // 001E MOVE R11 R8 - 0x7C240400, // 001F CALL R9 2 - 0x4C280000, // 0020 LDNIL R10 - 0x1C24120A, // 0021 EQ R9 R9 R10 - 0x78260003, // 0022 JMPF R9 #0027 - 0x94240406, // 0023 GETIDX R9 R2 R6 - 0x8C241304, // 0024 GETMET R9 R9 K4 - 0x5C2C1000, // 0025 MOVE R11 R8 - 0x7C240400, // 0026 CALL R9 2 - 0x7001FFF1, // 0027 JMP #001A - 0x581C0005, // 0028 LDCONST R7 K5 - 0xAC1C0200, // 0029 CATCH R7 1 0 - 0xB0080000, // 002A RAISE 2 R0 R0 - 0x7001FFE0, // 002B JMP #000D - 0x58140005, // 002C LDCONST R5 K5 - 0xAC140200, // 002D CATCH R5 1 0 - 0xB0080000, // 002E RAISE 2 R0 R0 - 0x5C140200, // 002F MOVE R5 R1 - 0x5C180600, // 0030 MOVE R6 R3 - 0x7C140200, // 0031 CALL R5 1 - 0x5C0C0A00, // 0032 MOVE R3 R5 - 0x7001FFCF, // 0033 JMP #0004 - 0x80040400, // 0034 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: get_attribute_list ********************************************************************/ @@ -1069,26 +737,572 @@ be_local_closure(Matter_Plugin_get_attribute_list, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: append_state_json +********************************************************************/ +be_local_closure(Matter_Plugin_append_state_json, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str_weak(), + }), + be_str_weak(append_state_json), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80060000, // 0000 RET 1 K0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_event +********************************************************************/ +be_local_closure(Matter_Plugin_read_event, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(read_event), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_configuration +********************************************************************/ +be_local_closure(Matter_Plugin_parse_configuration, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(parse_configuration), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: state_json +********************************************************************/ +be_local_closure(Matter_Plugin_state_json, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(json), + /* K1 */ be_nested_str_weak(node_label), + /* K2 */ be_nested_str_weak(_X2C_X22Name_X22_X3A_X25s), + /* K3 */ be_nested_str_weak(dump), + /* K4 */ be_nested_str_weak(), + /* K5 */ be_nested_str_weak(append_state_json), + /* K6 */ be_nested_str_weak(_X7B_X22Ep_X22_X3A_X25i_X25s_X25s_X7D), + /* K7 */ be_nested_str_weak(endpoint), + }), + be_str_weak(state_json), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x88080101, // 0001 GETMBR R2 R0 K1 + 0x780A0006, // 0002 JMPF R2 #000A + 0x60080018, // 0003 GETGBL R2 G24 + 0x580C0002, // 0004 LDCONST R3 K2 + 0x8C100303, // 0005 GETMET R4 R1 K3 + 0x88180101, // 0006 GETMBR R6 R0 K1 + 0x7C100400, // 0007 CALL R4 2 + 0x7C080400, // 0008 CALL R2 2 + 0x70020000, // 0009 JMP #000B + 0x58080004, // 000A LDCONST R2 K4 + 0x8C0C0105, // 000B GETMET R3 R0 K5 + 0x7C0C0200, // 000C CALL R3 1 + 0x780E0007, // 000D JMPF R3 #0016 + 0x60100018, // 000E GETGBL R4 G24 + 0x58140006, // 000F LDCONST R5 K6 + 0x88180107, // 0010 GETMBR R6 R0 K7 + 0x5C1C0400, // 0011 MOVE R7 R2 + 0x5C200600, // 0012 MOVE R8 R3 + 0x7C100800, // 0013 CALL R4 4 + 0x80040800, // 0014 RET 1 R4 + 0x70020001, // 0015 JMP #0018 + 0x4C100000, // 0016 LDNIL R4 + 0x80040800, // 0017 RET 1 R4 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: subscribe_event +********************************************************************/ +be_local_closure(Matter_Plugin_subscribe_event, /* name */ + be_nested_proto( + 6, /* nstack */ + 5, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(subscribe_event), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C140000, // 0000 LDNIL R5 + 0x80040A00, // 0001 RET 1 R5 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: has +********************************************************************/ +be_local_closure(Matter_Plugin_has, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(clusters), + /* K1 */ be_nested_str_weak(contains), + /* K2 */ be_nested_str_weak(endpoints), + /* K3 */ be_nested_str_weak(find), + }), + be_str_weak(has), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x780E0006, // 0004 JMPF R3 #000C + 0x880C0102, // 0005 GETMBR R3 R0 K2 + 0x8C0C0703, // 0006 GETMET R3 R3 K3 + 0x5C140400, // 0007 MOVE R5 R2 + 0x7C0C0400, // 0008 CALL R3 2 + 0x4C100000, // 0009 LDNIL R4 + 0x200C0604, // 000A NE R3 R3 R4 + 0x740E0000, // 000B JMPT R3 #000D + 0x500C0001, // 000C LDBOOL R3 0 1 + 0x500C0200, // 000D LDBOOL R3 1 0 + 0x80040600, // 000E RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_250ms +********************************************************************/ +be_local_closure(Matter_Plugin_every_250ms, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[10]) { /* constants */ + /* K0 */ be_nested_str_weak(update_next), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(jitter), + /* K3 */ be_nested_str_weak(UPDATE_TIME), + /* K4 */ be_nested_str_weak(tasmota), + /* K5 */ be_nested_str_weak(time_reached), + /* K6 */ be_nested_str_weak(tick), + /* K7 */ be_nested_str_weak(device), + /* K8 */ be_nested_str_weak(update_shadow), + /* K9 */ be_nested_str_weak(millis), + }), + be_str_weak(every_250ms), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x1C040202, // 0002 EQ R1 R1 R2 + 0x78060005, // 0003 JMPF R1 #000A + 0xB8060200, // 0004 GETNGBL R1 K1 + 0x8C040302, // 0005 GETMET R1 R1 K2 + 0x880C0103, // 0006 GETMBR R3 R0 K3 + 0x7C040400, // 0007 CALL R1 2 + 0x90020001, // 0008 SETMBR R0 K0 R1 + 0x70020010, // 0009 JMP #001B + 0xB8060800, // 000A GETNGBL R1 K4 + 0x8C040305, // 000B GETMET R1 R1 K5 + 0x880C0100, // 000C GETMBR R3 R0 K0 + 0x7C040400, // 000D CALL R1 2 + 0x7806000B, // 000E JMPF R1 #001B + 0x88040106, // 000F GETMBR R1 R0 K6 + 0x88080107, // 0010 GETMBR R2 R0 K7 + 0x88080506, // 0011 GETMBR R2 R2 K6 + 0x20040202, // 0012 NE R1 R1 R2 + 0x78060001, // 0013 JMPF R1 #0016 + 0x8C040108, // 0014 GETMET R1 R0 K8 + 0x7C040200, // 0015 CALL R1 1 + 0xB8060800, // 0016 GETNGBL R1 K4 + 0x8C040309, // 0017 GETMET R1 R1 K9 + 0x880C0103, // 0018 GETMBR R3 R0 K3 + 0x7C040400, // 0019 CALL R1 2 + 0x90020001, // 001A SETMBR R0 K0 R1 + 0x80000000, // 001B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: contains_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_contains_attribute, /* name */ + be_nested_proto( + 7, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(clusters), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_const_int(0), + /* K3 */ be_const_int(1), + }), + be_str_weak(contains_attribute), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x8C0C0701, // 0001 GETMET R3 R3 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x4C100000, // 0004 LDNIL R4 + 0x20100604, // 0005 NE R4 R3 R4 + 0x7812000C, // 0006 JMPF R4 #0014 + 0x58100002, // 0007 LDCONST R4 K2 + 0x6014000C, // 0008 GETGBL R5 G12 + 0x5C180600, // 0009 MOVE R6 R3 + 0x7C140200, // 000A CALL R5 1 + 0x14140805, // 000B LT R5 R4 R5 + 0x78160006, // 000C JMPF R5 #0014 + 0x94140604, // 000D GETIDX R5 R3 R4 + 0x1C140A02, // 000E EQ R5 R5 R2 + 0x78160001, // 000F JMPF R5 #0012 + 0x50140200, // 0010 LDBOOL R5 1 0 + 0x80040A00, // 0011 RET 1 R5 + 0x00100903, // 0012 ADD R4 R4 K3 + 0x7001FFF3, // 0013 JMP #0008 + 0x50100000, // 0014 LDBOOL R4 0 0 + 0x80040800, // 0015 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: write_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_write_attribute, /* name */ + be_nested_proto( + 5, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(write_attribute), + &be_const_str_solidified, + ( &(const binstruction[ 2]) { /* code */ + 0x4C100000, // 0000 LDNIL R4 + 0x80040800, // 0001 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: attribute_updated +********************************************************************/ +be_local_closure(Matter_Plugin_attribute_updated, /* name */ + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(attribute_updated), + /* K2 */ be_nested_str_weak(endpoint), + }), + be_str_weak(attribute_updated), + &be_const_str_solidified, + ( &(const binstruction[ 8]) { /* code */ + 0x88100100, // 0000 GETMBR R4 R0 K0 + 0x8C100901, // 0001 GETMET R4 R4 K1 + 0x88180102, // 0002 GETMBR R6 R0 K2 + 0x5C1C0200, // 0003 MOVE R7 R1 + 0x5C200400, // 0004 MOVE R8 R2 + 0x5C240600, // 0005 MOVE R9 R3 + 0x7C100A00, // 0006 CALL R4 5 + 0x80000000, // 0007 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: +********************************************************************/ +be_local_closure(Matter_Plugin__X3Clambda_X3E, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040008, // 0000 GETGBL R1 G8 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_virtual +********************************************************************/ +be_local_closure(Matter_Plugin_update_virtual, /* name */ + be_nested_proto( + 2, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(update_virtual), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_cluster_list +********************************************************************/ +be_local_closure(Matter_Plugin_get_cluster_list, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(clusters), + /* K1 */ be_nested_str_weak(keys), + /* K2 */ be_nested_str_weak(push), + /* K3 */ be_nested_str_weak(stop_iteration), + }), + be_str_weak(get_cluster_list), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x60080010, // 0002 GETGBL R2 G16 + 0x880C0100, // 0003 GETMBR R3 R0 K0 + 0x8C0C0701, // 0004 GETMET R3 R3 K1 + 0x7C0C0200, // 0005 CALL R3 1 + 0x7C080200, // 0006 CALL R2 1 + 0xA8020005, // 0007 EXBLK 0 #000E + 0x5C0C0400, // 0008 MOVE R3 R2 + 0x7C0C0000, // 0009 CALL R3 0 + 0x8C100302, // 000A GETMET R4 R1 K2 + 0x5C180600, // 000B MOVE R6 R3 + 0x7C100400, // 000C CALL R4 2 + 0x7001FFF9, // 000D JMP #0008 + 0x58080003, // 000E LDCONST R2 K3 + 0xAC080200, // 000F CATCH R2 1 0 + 0xB0080000, // 0010 RAISE 2 R0 R0 + 0x80040200, // 0011 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: ui_conf_to_string +********************************************************************/ +be_local_closure(Matter_Plugin_ui_conf_to_string, /* name */ + be_nested_proto( + 9, /* nstack */ + 2, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Plugin), + /* K1 */ be_nested_str_weak(ARG), + /* K2 */ be_nested_str_weak(find), + /* K3 */ be_nested_str_weak(), + }), + be_str_weak(ui_conf_to_string), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0x880C0101, // 0001 GETMBR R3 R0 K1 + 0x780E0006, // 0002 JMPF R3 #000A + 0x60100008, // 0003 GETGBL R4 G8 + 0x8C140302, // 0004 GETMET R5 R1 K2 + 0x5C1C0600, // 0005 MOVE R7 R3 + 0x58200003, // 0006 LDCONST R8 K3 + 0x7C140600, // 0007 CALL R5 3 + 0x7C100200, // 0008 CALL R4 1 + 0x70020000, // 0009 JMP #000B + 0x58100003, // 000A LDCONST R4 K3 + 0x80040800, // 000B RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: contains_cluster +********************************************************************/ +be_local_closure(Matter_Plugin_contains_cluster, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(clusters), + /* K1 */ be_nested_str_weak(contains), + }), + be_str_weak(contains_cluster), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x8C080501, // 0001 GETMET R2 R2 K1 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C080400, // 0003 CALL R2 2 + 0x80040400, // 0004 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin ********************************************************************/ be_local_class(Matter_Plugin, - 5, + 6, NULL, - be_nested_map(37, + be_nested_map(47, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_init_closure) }, - { be_const_key_weak(read_event, 11), be_const_closure(Matter_Plugin_read_event_closure) }, - { be_const_key_weak(tick, -1), be_const_var(4) }, - { be_const_key_weak(is_local_device, 18), be_const_closure(Matter_Plugin_is_local_device_closure) }, - { be_const_key_weak(UPDATE_TIME, -1), be_const_int(5000) }, - { be_const_key_weak(get_attribute_list, -1), be_const_closure(Matter_Plugin_get_attribute_list_closure) }, - { be_const_key_weak(ui_conf_to_string, 26), be_const_static_closure(Matter_Plugin_ui_conf_to_string_closure) }, - { be_const_key_weak(every_250ms, -1), be_const_closure(Matter_Plugin_every_250ms_closure) }, { be_const_key_weak(ack_request, -1), be_const_closure(Matter_Plugin_ack_request_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak() }, { be_const_key_weak(parse_sensors, -1), be_const_closure(Matter_Plugin_parse_sensors_closure) }, - { be_const_key_weak(CLUSTERS, 36), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(ui_conf_to_string, 45), be_const_static_closure(Matter_Plugin_ui_conf_to_string_closure) }, + { be_const_key_weak(clusters, 27), be_const_var(3) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(subscribe_attribute, -1), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, + { be_const_key_weak(timed_request, -1), be_const_closure(Matter_Plugin_timed_request_closure) }, + { be_const_key_weak(endpoint, -1), be_const_var(2) }, + { be_const_key_weak(DISPLAY_NAME, 1), be_nested_str_weak() }, + { be_const_key_weak(update_shadow, 2), be_const_closure(Matter_Plugin_update_shadow_closure) }, + { be_const_key_weak(ARG_TYPE, -1), be_const_static_closure(Matter_Plugin__X3Clambda_X3E_closure) }, + { be_const_key_weak(publish_command, -1), be_const_closure(Matter_Plugin_publish_command_closure) }, + { be_const_key_weak(consolidate_clusters, 5), be_const_closure(Matter_Plugin_consolidate_clusters_closure) }, + { be_const_key_weak(set_name, 42), be_const_closure(Matter_Plugin_set_name_closure) }, + { be_const_key_weak(write_attribute, 23), be_const_closure(Matter_Plugin_write_attribute_closure) }, + { be_const_key_weak(VIRTUAL, 6), be_const_bool(0) }, + { be_const_key_weak(node_label, 34), be_const_var(5) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(2, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { @@ -1107,31 +1321,38 @@ be_local_class(Matter_Plugin, be_const_int(17), })) ) } )) }, })) ) } )) }, - { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_parse_configuration_closure) }, - { be_const_key_weak(ui_string_to_conf, -1), be_const_static_closure(Matter_Plugin_ui_string_to_conf_closure) }, - { be_const_key_weak(contains_cluster, -1), be_const_closure(Matter_Plugin_contains_cluster_closure) }, - { be_const_key_weak(ARG_TYPE, -1), be_const_static_closure(Matter_Plugin__X3Clambda_X3E_closure) }, - { be_const_key_weak(has, 8), be_const_closure(Matter_Plugin_has_closure) }, - { be_const_key_weak(device, 4), be_const_var(1) }, - { be_const_key_weak(timed_request, -1), be_const_closure(Matter_Plugin_timed_request_closure) }, - { be_const_key_weak(get_cluster_list, -1), be_const_closure(Matter_Plugin_get_cluster_list_closure) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_read_attribute_closure) }, - { be_const_key_weak(ARG, 14), be_nested_str_weak() }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_invoke_request_closure) }, - { be_const_key_weak(subscribe_attribute, 24), be_const_closure(Matter_Plugin_subscribe_attribute_closure) }, - { be_const_key_weak(get_endpoint, 30), be_const_closure(Matter_Plugin_get_endpoint_closure) }, - { be_const_key_weak(write_attribute, 28), be_const_closure(Matter_Plugin_write_attribute_closure) }, - { be_const_key_weak(ARG_HINT, 22), be_nested_str_weak(_Not_X20used_) }, { be_const_key_weak(update_shadow_lazy, -1), be_const_closure(Matter_Plugin_update_shadow_lazy_closure) }, - { be_const_key_weak(clusters, -1), be_const_var(3) }, - { be_const_key_weak(endpoint, -1), be_const_var(2) }, - { be_const_key_weak(attribute_updated, 15), be_const_closure(Matter_Plugin_attribute_updated_closure) }, - { be_const_key_weak(subscribe_event, -1), be_const_closure(Matter_Plugin_subscribe_event_closure) }, - { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_update_shadow_closure) }, - { be_const_key_weak(consolidate_clusters, -1), be_const_closure(Matter_Plugin_consolidate_clusters_closure) }, + { be_const_key_weak(update_next, 40), be_const_var(0) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_invoke_request_closure) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_init_closure) }, + { be_const_key_weak(ARG, 14), be_nested_str_weak() }, + { be_const_key_weak(get_endpoint, 17), be_const_closure(Matter_Plugin_get_endpoint_closure) }, + { be_const_key_weak(get_name, 20), be_const_closure(Matter_Plugin_get_name_closure) }, + { be_const_key_weak(ui_string_to_conf, 10), be_const_static_closure(Matter_Plugin_ui_string_to_conf_closure) }, + { be_const_key_weak(tick, 18), be_const_var(4) }, { be_const_key_weak(TYPE, -1), be_nested_str_weak() }, - { be_const_key_weak(update_next, 5), be_const_var(0) }, + { be_const_key_weak(append_state_json, -1), be_const_closure(Matter_Plugin_append_state_json_closure) }, + { be_const_key_weak(read_event, -1), be_const_closure(Matter_Plugin_read_event_closure) }, + { be_const_key_weak(device, -1), be_const_var(1) }, + { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_parse_configuration_closure) }, + { be_const_key_weak(state_json, -1), be_const_closure(Matter_Plugin_state_json_closure) }, + { be_const_key_weak(subscribe_event, -1), be_const_closure(Matter_Plugin_subscribe_event_closure) }, + { be_const_key_weak(get_attribute_list, -1), be_const_closure(Matter_Plugin_get_attribute_list_closure) }, + { be_const_key_weak(read_attribute, 26), be_const_closure(Matter_Plugin_read_attribute_closure) }, + { be_const_key_weak(has, -1), be_const_closure(Matter_Plugin_has_closure) }, + { be_const_key_weak(UPDATE_TIME, -1), be_const_int(5000) }, + { be_const_key_weak(every_250ms, -1), be_const_closure(Matter_Plugin_every_250ms_closure) }, { be_const_key_weak(contains_attribute, -1), be_const_closure(Matter_Plugin_contains_attribute_closure) }, + { be_const_key_weak(is_local_device, 13), be_const_closure(Matter_Plugin_is_local_device_closure) }, + { be_const_key_weak(attribute_updated, -1), be_const_closure(Matter_Plugin_attribute_updated_closure) }, + { be_const_key_weak(UPDATE_COMMANDS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_weak(update_virtual, -1), be_const_closure(Matter_Plugin_update_virtual_closure) }, + { be_const_key_weak(get_cluster_list, -1), be_const_closure(Matter_Plugin_get_cluster_list_closure) }, + { be_const_key_weak(consolidate_update_commands, -1), be_const_closure(Matter_Plugin_consolidate_update_commands_closure) }, + { be_const_key_weak(contains_cluster, -1), be_const_closure(Matter_Plugin_contains_cluster_closure) }, })), be_str_weak(Matter_Plugin) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Device.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Device.h similarity index 75% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Device.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Device.h index af4eb7167..b43be5a83 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Device.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Device.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Device.h */ +/* Solidification of Matter_Plugin_1_Device.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,197 +6,6 @@ extern const bclass be_class_Matter_Plugin_Device; -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_Device_init, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(node_label), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(name), - /* K3 */ be_nested_str_weak(), - /* K4 */ be_nested_str_weak(init), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[14]) { /* code */ - 0x8C100701, // 0000 GETMET R4 R3 K1 - 0x58180002, // 0001 LDCONST R6 K2 - 0x581C0003, // 0002 LDCONST R7 K3 - 0x7C100600, // 0003 CALL R4 3 - 0x90020004, // 0004 SETMBR R0 K0 R4 - 0x60100003, // 0005 GETGBL R4 G3 - 0x5C140000, // 0006 MOVE R5 R0 - 0x7C100200, // 0007 CALL R4 1 - 0x8C100904, // 0008 GETMET R4 R4 K4 - 0x5C180200, // 0009 MOVE R6 R1 - 0x5C1C0400, // 000A MOVE R7 R2 - 0x5C200600, // 000B MOVE R8 R3 - 0x7C100800, // 000C CALL R4 4 - 0x80000000, // 000D RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_name -********************************************************************/ -be_local_closure(Matter_Plugin_Device_set_name, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(node_label), - /* K1 */ be_nested_str_weak(attribute_updated), - }), - be_str_weak(set_name), - &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x20080202, // 0001 NE R2 R1 R2 - 0x780A0003, // 0002 JMPF R2 #0007 - 0x8C080101, // 0003 GETMET R2 R0 K1 - 0x54120038, // 0004 LDINT R4 57 - 0x54160004, // 0005 LDINT R5 5 - 0x7C080600, // 0006 CALL R2 3 - 0x90020001, // 0007 SETMBR R0 K0 R1 - 0x80000000, // 0008 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_name -********************************************************************/ -be_local_closure(Matter_Plugin_Device_get_name, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str_weak(node_label), - }), - be_str_weak(get_name), - &be_const_str_solidified, - ( &(const binstruction[ 2]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x80040200, // 0001 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Device_invoke_request, /* name */ - be_nested_proto( - 13, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(TLV), - /* K2 */ be_nested_str_weak(cluster), - /* K3 */ be_nested_str_weak(command), - /* K4 */ be_const_int(3), - /* K5 */ be_const_int(0), - /* K6 */ be_const_int(1), - /* K7 */ be_nested_str_weak(Matter_TLV_struct), - /* K8 */ be_nested_str_weak(add_TLV), - /* K9 */ be_nested_str_weak(U2), - /* K10 */ be_nested_str_weak(invoke_request), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[51]) { /* code */ - 0xB8120000, // 0000 GETNGBL R4 K0 - 0x88100901, // 0001 GETMBR R4 R4 K1 - 0x88140702, // 0002 GETMBR R5 R3 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x1C1C0B04, // 0004 EQ R7 R5 K4 - 0x781E0016, // 0005 JMPF R7 #001D - 0x1C1C0D05, // 0006 EQ R7 R6 K5 - 0x781E0002, // 0007 JMPF R7 #000B - 0x501C0200, // 0008 LDBOOL R7 1 0 - 0x80040E00, // 0009 RET 1 R7 - 0x70020010, // 000A JMP #001C - 0x1C1C0D06, // 000B EQ R7 R6 K6 - 0x781E0009, // 000C JMPF R7 #0017 - 0x8C1C0907, // 000D GETMET R7 R4 K7 - 0x7C1C0200, // 000E CALL R7 1 - 0x8C200F08, // 000F GETMET R8 R7 K8 - 0x58280005, // 0010 LDCONST R10 K5 - 0x882C0909, // 0011 GETMBR R11 R4 K9 - 0x58300005, // 0012 LDCONST R12 K5 - 0x7C200800, // 0013 CALL R8 4 - 0x900E0705, // 0014 SETMBR R3 K3 K5 - 0x80040E00, // 0015 RET 1 R7 - 0x70020004, // 0016 JMP #001C - 0x541E003F, // 0017 LDINT R7 64 - 0x1C1C0C07, // 0018 EQ R7 R6 R7 - 0x781E0001, // 0019 JMPF R7 #001C - 0x501C0200, // 001A LDBOOL R7 1 0 - 0x80040E00, // 001B RET 1 R7 - 0x70020014, // 001C JMP #0032 - 0x541E0003, // 001D LDINT R7 4 - 0x1C1C0A07, // 001E EQ R7 R5 R7 - 0x781E0002, // 001F JMPF R7 #0023 - 0x501C0200, // 0020 LDBOOL R7 1 0 - 0x80040E00, // 0021 RET 1 R7 - 0x7002000E, // 0022 JMP #0032 - 0x541E0004, // 0023 LDINT R7 5 - 0x1C1C0A07, // 0024 EQ R7 R5 R7 - 0x781E0002, // 0025 JMPF R7 #0029 - 0x501C0200, // 0026 LDBOOL R7 1 0 - 0x80040E00, // 0027 RET 1 R7 - 0x70020008, // 0028 JMP #0032 - 0x601C0003, // 0029 GETGBL R7 G3 - 0x5C200000, // 002A MOVE R8 R0 - 0x7C1C0200, // 002B CALL R7 1 - 0x8C1C0F0A, // 002C GETMET R7 R7 K10 - 0x5C240200, // 002D MOVE R9 R1 - 0x5C280400, // 002E MOVE R10 R2 - 0x5C2C0600, // 002F MOVE R11 R3 - 0x7C1C0800, // 0030 CALL R7 4 - 0x80040E00, // 0031 RET 1 R7 - 0x80000000, // 0032 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -522,52 +331,260 @@ be_local_closure(Matter_Plugin_Device_read_attribute, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: append_state_json +********************************************************************/ +be_local_closure(Matter_Plugin_Device_append_state_json, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 12, /* nstack */ + 2, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 2), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(introspect), + /* K1 */ be_nested_str_weak(json), + /* K2 */ be_nested_str_weak(get), + /* K3 */ be_nested_str_weak(bool), + /* K4 */ be_nested_str_weak(_X2C_X22_X25s_X22_X3A_X25s), + /* K5 */ be_nested_str_weak(dump), + }), + be_str_weak(_stats_json_inner), + &be_const_str_solidified, + ( &(const binstruction[31]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0xA40E0200, // 0001 IMPORT R3 K1 + 0x4C100000, // 0002 LDNIL R4 + 0x8C140502, // 0003 GETMET R5 R2 K2 + 0x681C0000, // 0004 GETUPV R7 U0 + 0x5C200000, // 0005 MOVE R8 R0 + 0x7C140600, // 0006 CALL R5 3 + 0x5C100A00, // 0007 MOVE R4 R5 + 0x4C180000, // 0008 LDNIL R6 + 0x20140A06, // 0009 NE R5 R5 R6 + 0x78160012, // 000A JMPF R5 #001E + 0x60140004, // 000B GETGBL R5 G4 + 0x5C180800, // 000C MOVE R6 R4 + 0x7C140200, // 000D CALL R5 1 + 0x1C140B03, // 000E EQ R5 R5 K3 + 0x78160003, // 000F JMPF R5 #0014 + 0x60140009, // 0010 GETGBL R5 G9 + 0x5C180800, // 0011 MOVE R6 R4 + 0x7C140200, // 0012 CALL R5 1 + 0x5C100A00, // 0013 MOVE R4 R5 + 0x60180018, // 0014 GETGBL R6 G24 + 0x581C0004, // 0015 LDCONST R7 K4 + 0x5C200200, // 0016 MOVE R8 R1 + 0x8C240705, // 0017 GETMET R9 R3 K5 + 0x5C2C0800, // 0018 MOVE R11 R4 + 0x7C240400, // 0019 CALL R9 2 + 0x7C180600, // 001A CALL R6 3 + 0x68140001, // 001B GETUPV R5 U1 + 0x00140A06, // 001C ADD R5 R5 R6 + 0x6C140001, // 001D SETUPV R5 U1 + 0x80000000, // 001E RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[22]) { /* constants */ + /* K0 */ be_nested_str_weak(introspect), + /* K1 */ be_nested_str_weak(), + /* K2 */ be_nested_str_weak(shadow_onoff), + /* K3 */ be_nested_str_weak(Power), + /* K4 */ be_nested_str_weak(shadow_bri), + /* K5 */ be_nested_str_weak(Bri), + /* K6 */ be_nested_str_weak(shadow_ct), + /* K7 */ be_nested_str_weak(CT), + /* K8 */ be_nested_str_weak(shadow_hue), + /* K9 */ be_nested_str_weak(Hue), + /* K10 */ be_nested_str_weak(shadow_sat), + /* K11 */ be_nested_str_weak(Sat), + /* K12 */ be_nested_str_weak(shadow_shutter_pos), + /* K13 */ be_nested_str_weak(ShutterPos), + /* K14 */ be_nested_str_weak(shadow_shutter_target), + /* K15 */ be_nested_str_weak(ShutterTarget), + /* K16 */ be_nested_str_weak(shadow_shutter_tilt), + /* K17 */ be_nested_str_weak(ShutterTilt), + /* K18 */ be_nested_str_weak(shadow_contact), + /* K19 */ be_nested_str_weak(Contact), + /* K20 */ be_nested_str_weak(shadow_occupancy), + /* K21 */ be_nested_str_weak(Occupancy), + }), + be_str_weak(append_state_json), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x58080001, // 0001 LDCONST R2 K1 + 0x840C0000, // 0002 CLOSURE R3 P0 + 0x5C100600, // 0003 MOVE R4 R3 + 0x58140002, // 0004 LDCONST R5 K2 + 0x58180003, // 0005 LDCONST R6 K3 + 0x7C100400, // 0006 CALL R4 2 + 0x5C100600, // 0007 MOVE R4 R3 + 0x58140004, // 0008 LDCONST R5 K4 + 0x58180005, // 0009 LDCONST R6 K5 + 0x7C100400, // 000A CALL R4 2 + 0x5C100600, // 000B MOVE R4 R3 + 0x58140006, // 000C LDCONST R5 K6 + 0x58180007, // 000D LDCONST R6 K7 + 0x7C100400, // 000E CALL R4 2 + 0x5C100600, // 000F MOVE R4 R3 + 0x58140008, // 0010 LDCONST R5 K8 + 0x58180009, // 0011 LDCONST R6 K9 + 0x7C100400, // 0012 CALL R4 2 + 0x5C100600, // 0013 MOVE R4 R3 + 0x5814000A, // 0014 LDCONST R5 K10 + 0x5818000B, // 0015 LDCONST R6 K11 + 0x7C100400, // 0016 CALL R4 2 + 0x5C100600, // 0017 MOVE R4 R3 + 0x5814000C, // 0018 LDCONST R5 K12 + 0x5818000D, // 0019 LDCONST R6 K13 + 0x7C100400, // 001A CALL R4 2 + 0x5C100600, // 001B MOVE R4 R3 + 0x5814000E, // 001C LDCONST R5 K14 + 0x5818000F, // 001D LDCONST R6 K15 + 0x7C100400, // 001E CALL R4 2 + 0x5C100600, // 001F MOVE R4 R3 + 0x58140010, // 0020 LDCONST R5 K16 + 0x58180011, // 0021 LDCONST R6 K17 + 0x7C100400, // 0022 CALL R4 2 + 0x5C100600, // 0023 MOVE R4 R3 + 0x58140012, // 0024 LDCONST R5 K18 + 0x58180013, // 0025 LDCONST R6 K19 + 0x7C100400, // 0026 CALL R4 2 + 0x5C100600, // 0027 MOVE R4 R3 + 0x58140014, // 0028 LDCONST R5 K20 + 0x58180015, // 0029 LDCONST R6 K21 + 0x7C100400, // 002A CALL R4 2 + 0xA0000000, // 002B CLOSE R0 + 0x80040400, // 002C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Device_invoke_request, /* name */ + be_nested_proto( + 13, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(command), + /* K4 */ be_const_int(3), + /* K5 */ be_const_int(0), + /* K6 */ be_const_int(1), + /* K7 */ be_nested_str_weak(Matter_TLV_struct), + /* K8 */ be_nested_str_weak(add_TLV), + /* K9 */ be_nested_str_weak(U2), + /* K10 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[51]) { /* code */ + 0xB8120000, // 0000 GETNGBL R4 K0 + 0x88100901, // 0001 GETMBR R4 R4 K1 + 0x88140702, // 0002 GETMBR R5 R3 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x1C1C0B04, // 0004 EQ R7 R5 K4 + 0x781E0016, // 0005 JMPF R7 #001D + 0x1C1C0D05, // 0006 EQ R7 R6 K5 + 0x781E0002, // 0007 JMPF R7 #000B + 0x501C0200, // 0008 LDBOOL R7 1 0 + 0x80040E00, // 0009 RET 1 R7 + 0x70020010, // 000A JMP #001C + 0x1C1C0D06, // 000B EQ R7 R6 K6 + 0x781E0009, // 000C JMPF R7 #0017 + 0x8C1C0907, // 000D GETMET R7 R4 K7 + 0x7C1C0200, // 000E CALL R7 1 + 0x8C200F08, // 000F GETMET R8 R7 K8 + 0x58280005, // 0010 LDCONST R10 K5 + 0x882C0909, // 0011 GETMBR R11 R4 K9 + 0x58300005, // 0012 LDCONST R12 K5 + 0x7C200800, // 0013 CALL R8 4 + 0x900E0705, // 0014 SETMBR R3 K3 K5 + 0x80040E00, // 0015 RET 1 R7 + 0x70020004, // 0016 JMP #001C + 0x541E003F, // 0017 LDINT R7 64 + 0x1C1C0C07, // 0018 EQ R7 R6 R7 + 0x781E0001, // 0019 JMPF R7 #001C + 0x501C0200, // 001A LDBOOL R7 1 0 + 0x80040E00, // 001B RET 1 R7 + 0x70020014, // 001C JMP #0032 + 0x541E0003, // 001D LDINT R7 4 + 0x1C1C0A07, // 001E EQ R7 R5 R7 + 0x781E0002, // 001F JMPF R7 #0023 + 0x501C0200, // 0020 LDBOOL R7 1 0 + 0x80040E00, // 0021 RET 1 R7 + 0x7002000E, // 0022 JMP #0032 + 0x541E0004, // 0023 LDINT R7 5 + 0x1C1C0A07, // 0024 EQ R7 R5 R7 + 0x781E0002, // 0025 JMPF R7 #0029 + 0x501C0200, // 0026 LDBOOL R7 1 0 + 0x80040E00, // 0027 RET 1 R7 + 0x70020008, // 0028 JMP #0032 + 0x601C0003, // 0029 GETGBL R7 G3 + 0x5C200000, // 002A MOVE R8 R0 + 0x7C1C0200, // 002B CALL R7 1 + 0x8C1C0F0A, // 002C GETMET R7 R7 K10 + 0x5C240200, // 002D MOVE R9 R1 + 0x5C280400, // 002E MOVE R10 R2 + 0x5C2C0600, // 002F MOVE R11 R3 + 0x7C1C0800, // 0030 CALL R7 4 + 0x80040E00, // 0031 RET 1 R7 + 0x80000000, // 0032 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin_Device ********************************************************************/ extern const bclass be_class_Matter_Plugin; be_local_class(Matter_Plugin_Device, - 1, + 0, &be_class_Matter_Plugin, - be_nested_map(9, + be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(NON_BRIDGE_VENDOR, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(2, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(4631), - be_const_int(4993), - })) ) } )) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Device_read_attribute_closure) }, { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Device_invoke_request_closure) }, - { be_const_key_weak(TYPES, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(19, -1), be_const_int(1) }, })) ) } )) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Device_read_attribute_closure) }, - { be_const_key_weak(set_name, 8), be_const_closure(Matter_Plugin_Device_set_name_closure) }, - { be_const_key_weak(get_name, 1), be_const_closure(Matter_Plugin_Device_get_name_closure) }, - { be_const_key_weak(init, 3), be_const_closure(Matter_Plugin_Device_init_closure) }, - { be_const_key_weak(node_label, -1), be_const_var(0) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(4, + { be_const_key_weak(append_state_json, -1), be_const_closure(Matter_Plugin_Device_append_state_json_closure) }, + { be_const_key_weak(CLUSTERS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(5, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(3, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(65532), - be_const_int(65533), - })) ) } )) }, - { be_const_key_int(57, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(6, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(3), - be_const_int(5), - be_const_int(10), - be_const_int(15), - be_const_int(17), - be_const_int(18), - })) ) } )) }, { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(8, ( (struct bvalue*) &(const bvalue[]) { @@ -579,6 +596,24 @@ be_local_class(Matter_Plugin_Device, be_const_int(5), be_const_int(65532), be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), })) ) } )) }, { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(4, @@ -588,6 +623,22 @@ be_local_class(Matter_Plugin_Device, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(NON_BRIDGE_VENDOR, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(2, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(4631), + be_const_int(4993), })) ) } )) }, })), be_str_weak(Matter_Plugin_Device) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Root.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Root.h similarity index 98% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Root.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Root.h index 0532fdda0..b435e2ca6 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Root.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_1_Root.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Root.h */ +/* Solidification of Matter_Plugin_1_Root.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,871 +6,6 @@ extern const bclass be_class_Matter_Plugin_Root; -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Root_invoke_request, /* name */ - be_nested_proto( - 30, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 1, /* has sup protos */ - ( &(const struct bproto*[ 1]) { - be_nested_proto( - 3, /* nstack */ - 0, /* argc */ - 0, /* varg */ - 1, /* has upvals */ - ( &(const bupvaldesc[ 2]) { /* upvals */ - be_local_const_upval(1, 0), - be_local_const_upval(1, 10), - }), - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(device), - /* K1 */ be_nested_str_weak(remove_fabric), - }), - be_str_weak(_anonymous_), - &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0x68000000, // 0000 GETUPV R0 U0 - 0x88000100, // 0001 GETMBR R0 R0 K0 - 0x8C000101, // 0002 GETMET R0 R0 K1 - 0x68080001, // 0003 GETUPV R2 U1 - 0x7C000400, // 0004 CALL R0 2 - 0x80000000, // 0005 RET 0 - }) - ), - }), - 1, /* has constants */ - ( &(const bvalue[100]) { /* constants */ - /* K0 */ be_nested_str_weak(crypto), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(command), - /* K5 */ be_const_int(0), - /* K6 */ be_nested_str_weak(findsubval), - /* K7 */ be_const_int(1), - /* K8 */ be_nested_str_weak(_breadcrumb), - /* K9 */ be_nested_str_weak(Matter_TLV_struct), - /* K10 */ be_nested_str_weak(add_TLV), - /* K11 */ be_nested_str_weak(U1), - /* K12 */ be_nested_str_weak(UTF1), - /* K13 */ be_nested_str_weak(), - /* K14 */ be_const_int(2), - /* K15 */ be_nested_str_weak(XX), - /* K16 */ be_const_int(3), - /* K17 */ be_nested_str_weak(ack_request), - /* K18 */ be_nested_str_weak(_fabric), - /* K19 */ be_nested_str_weak(fabric_completed), - /* K20 */ be_nested_str_weak(set_no_expiration), - /* K21 */ be_nested_str_weak(save), - /* K22 */ be_nested_str_weak(device), - /* K23 */ be_nested_str_weak(start_commissioning_complete_deferred), - /* K24 */ be_nested_str_weak(context_error), - /* K25 */ be_nested_str_weak(CommissioningComplete_X3A_X20no_X20fabric_X20attached), - /* K26 */ be_nested_str_weak(status), - /* K27 */ be_nested_str_weak(UNSUPPORTED_COMMAND), - /* K28 */ be_nested_str_weak(B2), - /* K29 */ be_nested_str_weak(DAC_Cert_FFF1_8000), - /* K30 */ be_nested_str_weak(PAI_Cert_FFF1), - /* K31 */ be_nested_str_weak(CD_FFF1_8000), - /* K32 */ be_nested_str_weak(B1), - /* K33 */ be_nested_str_weak(U4), - /* K34 */ be_nested_str_weak(tasmota), - /* K35 */ be_nested_str_weak(rtc_utc), - /* K36 */ be_nested_str_weak(tlv2raw), - /* K37 */ be_nested_str_weak(get_ac), - /* K38 */ be_nested_str_weak(EC_P256), - /* K39 */ be_nested_str_weak(ecdsa_sign_sha256), - /* K40 */ be_nested_str_weak(DAC_Priv_FFF1_8000), - /* K41 */ be_nested_str_weak(gen_CSR), - /* K42 */ be_nested_str_weak(set_temp_ca), - /* K43 */ be_nested_str_weak(SUCCESS), - /* K44 */ be_nested_str_weak(log), - /* K45 */ be_nested_str_weak(MTR_X3A_X20AddNoc_X20Args_X3D), - /* K46 */ be_nested_str_weak(get_temp_ca), - /* K47 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20AdNOC_X20without_X20CA), - /* K48 */ be_nested_str_weak(sessions), - /* K49 */ be_nested_str_weak(create_fabric), - /* K50 */ be_nested_str_weak(set_ca), - /* K51 */ be_nested_str_weak(set_noc_icac), - /* K52 */ be_nested_str_weak(set_ipk_epoch_key), - /* K53 */ be_nested_str_weak(set_admin_subject_vendor), - /* K54 */ be_nested_str_weak(set_pk), - /* K55 */ be_nested_str_weak(get_pk), - /* K56 */ be_nested_str_weak(parse), - /* K57 */ be_nested_str_weak(findsub), - /* K58 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20no_X20fabricid_X20nor_X20deviceid_X20in_X20NOC_X20certificate), - /* K59 */ be_nested_str_weak(int), - /* K60 */ be_nested_str_weak(int64), - /* K61 */ be_nested_str_weak(fromu32), - /* K62 */ be_nested_str_weak(tobytes), - /* K63 */ be_nested_str_weak(get_temp_ca_pub), - /* K64 */ be_const_int(2147483647), - /* K65 */ be_nested_str_weak(fromstring), - /* K66 */ be_nested_str_weak(CompressedFabric), - /* K67 */ be_nested_str_weak(HKDF_SHA256), - /* K68 */ be_nested_str_weak(copy), - /* K69 */ be_nested_str_weak(reverse), - /* K70 */ be_nested_str_weak(derive), - /* K71 */ be_nested_str_weak(commissioning_admin_fabric), - /* K72 */ be_nested_str_weak(set_fabric_device), - /* K73 */ be_nested_str_weak(fabric_candidate), - /* K74 */ be_nested_str_weak(start_operational_discovery_deferred), - /* K75 */ be_nested_str_weak(is_PASE), - /* K76 */ be_nested_str_weak(set_expire_in_seconds), - /* K77 */ be_nested_str_weak(log_new_fabric), - /* K78 */ be_nested_str_weak(set_fabric_label), - /* K79 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Update_X20fabric_X20_X27_X25s_X27_X20label_X3D_X27_X25s_X27), - /* K80 */ be_nested_str_weak(get_fabric_id), - /* K81 */ be_nested_str_weak(tohex), - /* K82 */ be_nested_str_weak(fabric_index_X3A), - /* K83 */ be_nested_str_weak(active_fabrics), - /* K84 */ be_nested_str_weak(get_fabric_index), - /* K85 */ be_nested_str_weak(set_timer), - /* K86 */ be_nested_str_weak(stop_iteration), - /* K87 */ be_nested_str_weak(MTR_X3A_X20RemoveFabric_X20fabric_X28), - /* K88 */ be_nested_str_weak(_X29_X20not_X20found), - /* K89 */ be_nested_str_weak(INVALID_ACTION), - /* K90 */ be_nested_str_weak(MTR_X3A_X20OpenCommissioningWindow_X28timeout_X3D_X25i_X2C_X20passcode_X3D_X25s_X2C_X20discriminator_X3D_X25i_X2C_X20iterations_X3D_X25i_X2C_X20salt_X3D_X25s_X29), - /* K91 */ be_nested_str_weak(INVALID_DATA_TYPE), - /* K92 */ be_nested_str_weak(MTR_X3A_X20wrong_X20size_X20for_X20PAKE_X20parameters), - /* K93 */ be_nested_str_weak(CONSTRAINT_ERROR), - /* K94 */ be_nested_str_weak(start_basic_commissioning), - /* K95 */ be_nested_str_weak(get_fabric), - /* K96 */ be_nested_str_weak(MTR_X3A_X20OpenBasicCommissioningWindow_X20commissioning_timeout_X3D), - /* K97 */ be_nested_str_weak(start_root_basic_commissioning), - /* K98 */ be_nested_str_weak(stop_basic_commissioning), - /* K99 */ be_nested_str_weak(invoke_request), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[713]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xB8160200, // 0001 GETNGBL R5 K1 - 0x88140B02, // 0002 GETMBR R5 R5 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x881C0704, // 0004 GETMBR R7 R3 K4 - 0x5422002F, // 0005 LDINT R8 48 - 0x1C200C08, // 0006 EQ R8 R6 R8 - 0x7822005C, // 0007 JMPF R8 #0065 - 0x1C200F05, // 0008 EQ R8 R7 K5 - 0x78220017, // 0009 JMPF R8 #0022 - 0x8C200506, // 000A GETMET R8 R2 K6 - 0x58280005, // 000B LDCONST R10 K5 - 0x542E0383, // 000C LDINT R11 900 - 0x7C200600, // 000D CALL R8 3 - 0x8C240506, // 000E GETMET R9 R2 K6 - 0x582C0007, // 000F LDCONST R11 K7 - 0x58300005, // 0010 LDCONST R12 K5 - 0x7C240600, // 0011 CALL R9 3 - 0x90061009, // 0012 SETMBR R1 K8 R9 - 0x8C280B09, // 0013 GETMET R10 R5 K9 - 0x7C280200, // 0014 CALL R10 1 - 0x8C2C150A, // 0015 GETMET R11 R10 K10 - 0x58340005, // 0016 LDCONST R13 K5 - 0x88380B0B, // 0017 GETMBR R14 R5 K11 - 0x583C0005, // 0018 LDCONST R15 K5 - 0x7C2C0800, // 0019 CALL R11 4 - 0x8C2C150A, // 001A GETMET R11 R10 K10 - 0x58340007, // 001B LDCONST R13 K7 - 0x88380B0C, // 001C GETMBR R14 R5 K12 - 0x583C000D, // 001D LDCONST R15 K13 - 0x7C2C0800, // 001E CALL R11 4 - 0x900E0907, // 001F SETMBR R3 K4 K7 - 0x80041400, // 0020 RET 1 R10 - 0x70020041, // 0021 JMP #0064 - 0x1C200F0E, // 0022 EQ R8 R7 K14 - 0x7822001A, // 0023 JMPF R8 #003F - 0x8C200506, // 0024 GETMET R8 R2 K6 - 0x58280005, // 0025 LDCONST R10 K5 - 0x7C200400, // 0026 CALL R8 2 - 0x8C240506, // 0027 GETMET R9 R2 K6 - 0x582C0007, // 0028 LDCONST R11 K7 - 0x5830000F, // 0029 LDCONST R12 K15 - 0x7C240600, // 002A CALL R9 3 - 0x8C280506, // 002B GETMET R10 R2 K6 - 0x5830000E, // 002C LDCONST R12 K14 - 0x58340005, // 002D LDCONST R13 K5 - 0x7C280600, // 002E CALL R10 3 - 0x9006100A, // 002F SETMBR R1 K8 R10 - 0x8C2C0B09, // 0030 GETMET R11 R5 K9 - 0x7C2C0200, // 0031 CALL R11 1 - 0x8C30170A, // 0032 GETMET R12 R11 K10 - 0x58380005, // 0033 LDCONST R14 K5 - 0x883C0B0B, // 0034 GETMBR R15 R5 K11 - 0x58400005, // 0035 LDCONST R16 K5 - 0x7C300800, // 0036 CALL R12 4 - 0x8C30170A, // 0037 GETMET R12 R11 K10 - 0x58380007, // 0038 LDCONST R14 K7 - 0x883C0B0C, // 0039 GETMBR R15 R5 K12 - 0x5840000D, // 003A LDCONST R16 K13 - 0x7C300800, // 003B CALL R12 4 - 0x900E0910, // 003C SETMBR R3 K4 K16 - 0x80041600, // 003D RET 1 R11 - 0x70020024, // 003E JMP #0064 - 0x54220003, // 003F LDINT R8 4 - 0x1C200E08, // 0040 EQ R8 R7 R8 - 0x78220021, // 0041 JMPF R8 #0064 - 0x8C200111, // 0042 GETMET R8 R0 K17 - 0x5C280600, // 0043 MOVE R10 R3 - 0x7C200400, // 0044 CALL R8 2 - 0x88200312, // 0045 GETMBR R8 R1 K18 - 0x7822001B, // 0046 JMPF R8 #0063 - 0x90061105, // 0047 SETMBR R1 K8 K5 - 0x88200312, // 0048 GETMBR R8 R1 K18 - 0x8C201113, // 0049 GETMET R8 R8 K19 - 0x7C200200, // 004A CALL R8 1 - 0x8C200314, // 004B GETMET R8 R1 K20 - 0x7C200200, // 004C CALL R8 1 - 0x8C200315, // 004D GETMET R8 R1 K21 - 0x7C200200, // 004E CALL R8 1 - 0x8C200B09, // 004F GETMET R8 R5 K9 - 0x7C200200, // 0050 CALL R8 1 - 0x8C24110A, // 0051 GETMET R9 R8 K10 - 0x582C0005, // 0052 LDCONST R11 K5 - 0x88300B0B, // 0053 GETMBR R12 R5 K11 - 0x58340005, // 0054 LDCONST R13 K5 - 0x7C240800, // 0055 CALL R9 4 - 0x8C24110A, // 0056 GETMET R9 R8 K10 - 0x582C0007, // 0057 LDCONST R11 K7 - 0x88300B0C, // 0058 GETMBR R12 R5 K12 - 0x5834000D, // 0059 LDCONST R13 K13 - 0x7C240800, // 005A CALL R9 4 - 0x54260004, // 005B LDINT R9 5 - 0x900E0809, // 005C SETMBR R3 K4 R9 - 0x88240116, // 005D GETMBR R9 R0 K22 - 0x8C241317, // 005E GETMET R9 R9 K23 - 0x5C2C0200, // 005F MOVE R11 R1 - 0x7C240400, // 0060 CALL R9 2 - 0x80041000, // 0061 RET 1 R8 - 0x70020000, // 0062 JMP #0064 - 0xB0063119, // 0063 RAISE 1 K24 K25 - 0x70020261, // 0064 JMP #02C7 - 0x5422003D, // 0065 LDINT R8 62 - 0x1C200C08, // 0066 EQ R8 R6 R8 - 0x782201C2, // 0067 JMPF R8 #022B - 0x1C200F0E, // 0068 EQ R8 R7 K14 - 0x7822001D, // 0069 JMPF R8 #0088 - 0x8C200506, // 006A GETMET R8 R2 K6 - 0x58280005, // 006B LDCONST R10 K5 - 0x7C200400, // 006C CALL R8 2 - 0x20241107, // 006D NE R9 R8 K7 - 0x78260006, // 006E JMPF R9 #0076 - 0x2024110E, // 006F NE R9 R8 K14 - 0x78260004, // 0070 JMPF R9 #0076 - 0xB8260200, // 0071 GETNGBL R9 K1 - 0x8824131B, // 0072 GETMBR R9 R9 K27 - 0x900E3409, // 0073 SETMBR R3 K26 R9 - 0x4C240000, // 0074 LDNIL R9 - 0x80041200, // 0075 RET 1 R9 - 0x8C240B09, // 0076 GETMET R9 R5 K9 - 0x7C240200, // 0077 CALL R9 1 - 0x8C28130A, // 0078 GETMET R10 R9 K10 - 0x58300005, // 0079 LDCONST R12 K5 - 0x88340B1C, // 007A GETMBR R13 R5 K28 - 0x1C381107, // 007B EQ R14 R8 K7 - 0x783A0003, // 007C JMPF R14 #0081 - 0xB83A0200, // 007D GETNGBL R14 K1 - 0x8C381D1D, // 007E GETMET R14 R14 K29 - 0x7C380200, // 007F CALL R14 1 - 0x70020002, // 0080 JMP #0084 - 0xB83A0200, // 0081 GETNGBL R14 K1 - 0x8C381D1E, // 0082 GETMET R14 R14 K30 - 0x7C380200, // 0083 CALL R14 1 - 0x7C280800, // 0084 CALL R10 4 - 0x900E0910, // 0085 SETMBR R3 K4 K16 - 0x80041200, // 0086 RET 1 R9 - 0x700201A1, // 0087 JMP #022A - 0x1C200F05, // 0088 EQ R8 R7 K5 - 0x7822003C, // 0089 JMPF R8 #00C7 - 0x8C200506, // 008A GETMET R8 R2 K6 - 0x58280005, // 008B LDCONST R10 K5 - 0x7C200400, // 008C CALL R8 2 - 0x6024000C, // 008D GETGBL R9 G12 - 0x5C281000, // 008E MOVE R10 R8 - 0x7C240200, // 008F CALL R9 1 - 0x542A001F, // 0090 LDINT R10 32 - 0x2024120A, // 0091 NE R9 R9 R10 - 0x78260001, // 0092 JMPF R9 #0095 - 0x4C240000, // 0093 LDNIL R9 - 0x80041200, // 0094 RET 1 R9 - 0x900E0907, // 0095 SETMBR R3 K4 K7 - 0x8C240B09, // 0096 GETMET R9 R5 K9 - 0x7C240200, // 0097 CALL R9 1 - 0x8C28130A, // 0098 GETMET R10 R9 K10 - 0x58300007, // 0099 LDCONST R12 K7 - 0x88340B1C, // 009A GETMBR R13 R5 K28 - 0xB83A0200, // 009B GETNGBL R14 K1 - 0x8C381D1F, // 009C GETMET R14 R14 K31 - 0x7C380200, // 009D CALL R14 1 - 0x7C280800, // 009E CALL R10 4 - 0x8C28130A, // 009F GETMET R10 R9 K10 - 0x5830000E, // 00A0 LDCONST R12 K14 - 0x88340B20, // 00A1 GETMBR R13 R5 K32 - 0x5C381000, // 00A2 MOVE R14 R8 - 0x7C280800, // 00A3 CALL R10 4 - 0x8C28130A, // 00A4 GETMET R10 R9 K10 - 0x58300010, // 00A5 LDCONST R12 K16 - 0x88340B21, // 00A6 GETMBR R13 R5 K33 - 0xB83A4400, // 00A7 GETNGBL R14 K34 - 0x8C381D23, // 00A8 GETMET R14 R14 K35 - 0x7C380200, // 00A9 CALL R14 1 - 0x7C280800, // 00AA CALL R10 4 - 0x8C281324, // 00AB GETMET R10 R9 K36 - 0x7C280200, // 00AC CALL R10 1 - 0x8C2C0325, // 00AD GETMET R11 R1 K37 - 0x7C2C0200, // 00AE CALL R11 1 - 0x0030140B, // 00AF ADD R12 R10 R11 - 0x8C340926, // 00B0 GETMET R13 R4 K38 - 0x7C340200, // 00B1 CALL R13 1 - 0x8C341B27, // 00B2 GETMET R13 R13 K39 - 0xB83E0200, // 00B3 GETNGBL R15 K1 - 0x8C3C1F28, // 00B4 GETMET R15 R15 K40 - 0x7C3C0200, // 00B5 CALL R15 1 - 0x5C401800, // 00B6 MOVE R16 R12 - 0x7C340600, // 00B7 CALL R13 3 - 0x8C380B09, // 00B8 GETMET R14 R5 K9 - 0x7C380200, // 00B9 CALL R14 1 - 0x8C3C1D0A, // 00BA GETMET R15 R14 K10 - 0x58440005, // 00BB LDCONST R17 K5 - 0x88480B1C, // 00BC GETMBR R18 R5 K28 - 0x5C4C1400, // 00BD MOVE R19 R10 - 0x7C3C0800, // 00BE CALL R15 4 - 0x8C3C1D0A, // 00BF GETMET R15 R14 K10 - 0x58440007, // 00C0 LDCONST R17 K7 - 0x88480B20, // 00C1 GETMBR R18 R5 K32 - 0x5C4C1A00, // 00C2 MOVE R19 R13 - 0x7C3C0800, // 00C3 CALL R15 4 - 0x900E0907, // 00C4 SETMBR R3 K4 K7 - 0x80041C00, // 00C5 RET 1 R14 - 0x70020162, // 00C6 JMP #022A - 0x54220003, // 00C7 LDINT R8 4 - 0x1C200E08, // 00C8 EQ R8 R7 R8 - 0x7822003C, // 00C9 JMPF R8 #0107 - 0x8C200111, // 00CA GETMET R8 R0 K17 - 0x5C280600, // 00CB MOVE R10 R3 - 0x7C200400, // 00CC CALL R8 2 - 0x8C200506, // 00CD GETMET R8 R2 K6 - 0x58280005, // 00CE LDCONST R10 K5 - 0x7C200400, // 00CF CALL R8 2 - 0x6024000C, // 00D0 GETGBL R9 G12 - 0x5C281000, // 00D1 MOVE R10 R8 - 0x7C240200, // 00D2 CALL R9 1 - 0x542A001F, // 00D3 LDINT R10 32 - 0x2024120A, // 00D4 NE R9 R9 R10 - 0x78260001, // 00D5 JMPF R9 #00D8 - 0x4C240000, // 00D6 LDNIL R9 - 0x80041200, // 00D7 RET 1 R9 - 0x8C240506, // 00D8 GETMET R9 R2 K6 - 0x582C0007, // 00D9 LDCONST R11 K7 - 0x50300000, // 00DA LDBOOL R12 0 0 - 0x7C240600, // 00DB CALL R9 3 - 0x8C280329, // 00DC GETMET R10 R1 K41 - 0x7C280200, // 00DD CALL R10 1 - 0x8C2C0B09, // 00DE GETMET R11 R5 K9 - 0x7C2C0200, // 00DF CALL R11 1 - 0x8C30170A, // 00E0 GETMET R12 R11 K10 - 0x58380007, // 00E1 LDCONST R14 K7 - 0x883C0B1C, // 00E2 GETMBR R15 R5 K28 - 0x5C401400, // 00E3 MOVE R16 R10 - 0x7C300800, // 00E4 CALL R12 4 - 0x8C30170A, // 00E5 GETMET R12 R11 K10 - 0x5838000E, // 00E6 LDCONST R14 K14 - 0x883C0B20, // 00E7 GETMBR R15 R5 K32 - 0x5C401000, // 00E8 MOVE R16 R8 - 0x7C300800, // 00E9 CALL R12 4 - 0x8C301724, // 00EA GETMET R12 R11 K36 - 0x7C300200, // 00EB CALL R12 1 - 0x8C340325, // 00EC GETMET R13 R1 K37 - 0x7C340200, // 00ED CALL R13 1 - 0x0034180D, // 00EE ADD R13 R12 R13 - 0x8C380926, // 00EF GETMET R14 R4 K38 - 0x7C380200, // 00F0 CALL R14 1 - 0x8C381D27, // 00F1 GETMET R14 R14 K39 - 0xB8420200, // 00F2 GETNGBL R16 K1 - 0x8C402128, // 00F3 GETMET R16 R16 K40 - 0x7C400200, // 00F4 CALL R16 1 - 0x5C441A00, // 00F5 MOVE R17 R13 - 0x7C380600, // 00F6 CALL R14 3 - 0x8C3C0B09, // 00F7 GETMET R15 R5 K9 - 0x7C3C0200, // 00F8 CALL R15 1 - 0x8C401F0A, // 00F9 GETMET R16 R15 K10 - 0x58480005, // 00FA LDCONST R18 K5 - 0x884C0B1C, // 00FB GETMBR R19 R5 K28 - 0x5C501800, // 00FC MOVE R20 R12 - 0x7C400800, // 00FD CALL R16 4 - 0x8C401F0A, // 00FE GETMET R16 R15 K10 - 0x58480007, // 00FF LDCONST R18 K7 - 0x884C0B20, // 0100 GETMBR R19 R5 K32 - 0x5C501C00, // 0101 MOVE R20 R14 - 0x7C400800, // 0102 CALL R16 4 - 0x54420004, // 0103 LDINT R16 5 - 0x900E0810, // 0104 SETMBR R3 K4 R16 - 0x80041E00, // 0105 RET 1 R15 - 0x70020122, // 0106 JMP #022A - 0x5422000A, // 0107 LDINT R8 11 - 0x1C200E08, // 0108 EQ R8 R7 R8 - 0x7822000B, // 0109 JMPF R8 #0116 - 0x8C200506, // 010A GETMET R8 R2 K6 - 0x58280005, // 010B LDCONST R10 K5 - 0x7C200400, // 010C CALL R8 2 - 0x8C24032A, // 010D GETMET R9 R1 K42 - 0x5C2C1000, // 010E MOVE R11 R8 - 0x7C240400, // 010F CALL R9 2 - 0xB8260200, // 0110 GETNGBL R9 K1 - 0x8824132B, // 0111 GETMBR R9 R9 K43 - 0x900E3409, // 0112 SETMBR R3 K26 R9 - 0x4C240000, // 0113 LDNIL R9 - 0x80041200, // 0114 RET 1 R9 - 0x70020113, // 0115 JMP #022A - 0x54220005, // 0116 LDINT R8 6 - 0x1C200E08, // 0117 EQ R8 R7 R8 - 0x782200B9, // 0118 JMPF R8 #01D3 - 0xB8224400, // 0119 GETNGBL R8 K34 - 0x8C20112C, // 011A GETMET R8 R8 K44 - 0x60280008, // 011B GETGBL R10 G8 - 0x5C2C0400, // 011C MOVE R11 R2 - 0x7C280200, // 011D CALL R10 1 - 0x002A5A0A, // 011E ADD R10 K45 R10 - 0x542E0003, // 011F LDINT R11 4 - 0x7C200600, // 0120 CALL R8 3 - 0x8C200506, // 0121 GETMET R8 R2 K6 - 0x58280005, // 0122 LDCONST R10 K5 - 0x7C200400, // 0123 CALL R8 2 - 0x8C240506, // 0124 GETMET R9 R2 K6 - 0x582C0007, // 0125 LDCONST R11 K7 - 0x7C240400, // 0126 CALL R9 2 - 0x6028000C, // 0127 GETGBL R10 G12 - 0x5C2C1200, // 0128 MOVE R11 R9 - 0x7C280200, // 0129 CALL R10 1 - 0x1C281505, // 012A EQ R10 R10 K5 - 0x782A0000, // 012B JMPF R10 #012D - 0x4C240000, // 012C LDNIL R9 - 0x8C280506, // 012D GETMET R10 R2 K6 - 0x5830000E, // 012E LDCONST R12 K14 - 0x7C280400, // 012F CALL R10 2 - 0x8C2C0506, // 0130 GETMET R11 R2 K6 - 0x58340010, // 0131 LDCONST R13 K16 - 0x7C2C0400, // 0132 CALL R11 2 - 0x8C300506, // 0133 GETMET R12 R2 K6 - 0x543A0003, // 0134 LDINT R14 4 - 0x7C300400, // 0135 CALL R12 2 - 0x8C34032E, // 0136 GETMET R13 R1 K46 - 0x7C340200, // 0137 CALL R13 1 - 0x4C380000, // 0138 LDNIL R14 - 0x1C341A0E, // 0139 EQ R13 R13 R14 - 0x78360006, // 013A JMPF R13 #0142 - 0xB8364400, // 013B GETNGBL R13 K34 - 0x8C341B2C, // 013C GETMET R13 R13 K44 - 0x583C002F, // 013D LDCONST R15 K47 - 0x5840000E, // 013E LDCONST R16 K14 - 0x7C340600, // 013F CALL R13 3 - 0x4C340000, // 0140 LDNIL R13 - 0x80041A00, // 0141 RET 1 R13 - 0x88340116, // 0142 GETMBR R13 R0 K22 - 0x88341B30, // 0143 GETMBR R13 R13 K48 - 0x8C341B31, // 0144 GETMET R13 R13 K49 - 0x7C340200, // 0145 CALL R13 1 - 0x8C381B32, // 0146 GETMET R14 R13 K50 - 0x8C40032E, // 0147 GETMET R16 R1 K46 - 0x7C400200, // 0148 CALL R16 1 - 0x7C380400, // 0149 CALL R14 2 - 0x8C381B33, // 014A GETMET R14 R13 K51 - 0x5C401000, // 014B MOVE R16 R8 - 0x5C441200, // 014C MOVE R17 R9 - 0x7C380600, // 014D CALL R14 3 - 0x8C381B34, // 014E GETMET R14 R13 K52 - 0x5C401400, // 014F MOVE R16 R10 - 0x7C380400, // 0150 CALL R14 2 - 0x8C381B35, // 0151 GETMET R14 R13 K53 - 0x5C401600, // 0152 MOVE R16 R11 - 0x5C441800, // 0153 MOVE R17 R12 - 0x7C380600, // 0154 CALL R14 3 - 0x8C381B36, // 0155 GETMET R14 R13 K54 - 0x8C400337, // 0156 GETMET R16 R1 K55 - 0x7C400200, // 0157 CALL R16 1 - 0x7C380400, // 0158 CALL R14 2 - 0xB83A0200, // 0159 GETNGBL R14 K1 - 0x88381D02, // 015A GETMBR R14 R14 K2 - 0x8C381D38, // 015B GETMET R14 R14 K56 - 0x5C401000, // 015C MOVE R16 R8 - 0x7C380400, // 015D CALL R14 2 - 0x8C3C1D39, // 015E GETMET R15 R14 K57 - 0x54460005, // 015F LDINT R17 6 - 0x7C3C0400, // 0160 CALL R15 2 - 0x8C401F06, // 0161 GETMET R16 R15 K6 - 0x544A0014, // 0162 LDINT R18 21 - 0x7C400400, // 0163 CALL R16 2 - 0x8C441F06, // 0164 GETMET R17 R15 K6 - 0x544E0010, // 0165 LDINT R19 17 - 0x7C440400, // 0166 CALL R17 2 - 0x5C482000, // 0167 MOVE R18 R16 - 0x784A0001, // 0168 JMPF R18 #016B - 0x5C482200, // 0169 MOVE R18 R17 - 0x744A0006, // 016A JMPT R18 #0172 - 0xB84A4400, // 016B GETNGBL R18 K34 - 0x8C48252C, // 016C GETMET R18 R18 K44 - 0x5850003A, // 016D LDCONST R20 K58 - 0x5854000E, // 016E LDCONST R21 K14 - 0x7C480600, // 016F CALL R18 3 - 0x50480000, // 0170 LDBOOL R18 0 0 - 0x80042400, // 0171 RET 1 R18 - 0x60480004, // 0172 GETGBL R18 G4 - 0x5C4C2000, // 0173 MOVE R19 R16 - 0x7C480200, // 0174 CALL R18 1 - 0x1C48253B, // 0175 EQ R18 R18 K59 - 0x784A0007, // 0176 JMPF R18 #017F - 0xB84A7800, // 0177 GETNGBL R18 K60 - 0x8C48253D, // 0178 GETMET R18 R18 K61 - 0x5C502000, // 0179 MOVE R20 R16 - 0x7C480400, // 017A CALL R18 2 - 0x8C48253E, // 017B GETMET R18 R18 K62 - 0x7C480200, // 017C CALL R18 1 - 0x5C402400, // 017D MOVE R16 R18 - 0x70020002, // 017E JMP #0182 - 0x8C48213E, // 017F GETMET R18 R16 K62 - 0x7C480200, // 0180 CALL R18 1 - 0x5C402400, // 0181 MOVE R16 R18 - 0x60480004, // 0182 GETGBL R18 G4 - 0x5C4C2200, // 0183 MOVE R19 R17 - 0x7C480200, // 0184 CALL R18 1 - 0x1C48253B, // 0185 EQ R18 R18 K59 - 0x784A0007, // 0186 JMPF R18 #018F - 0xB84A7800, // 0187 GETNGBL R18 K60 - 0x8C48253D, // 0188 GETMET R18 R18 K61 - 0x5C502200, // 0189 MOVE R20 R17 - 0x7C480400, // 018A CALL R18 2 - 0x8C48253E, // 018B GETMET R18 R18 K62 - 0x7C480200, // 018C CALL R18 1 - 0x5C442400, // 018D MOVE R17 R18 - 0x70020002, // 018E JMP #0192 - 0x8C48233E, // 018F GETMET R18 R17 K62 - 0x7C480200, // 0190 CALL R18 1 - 0x5C442400, // 0191 MOVE R17 R18 - 0x8C48033F, // 0192 GETMET R18 R1 K63 - 0x7C480200, // 0193 CALL R18 1 - 0x404E0F40, // 0194 CONNECT R19 K7 K64 - 0x94482413, // 0195 GETIDX R18 R18 R19 - 0x60500015, // 0196 GETGBL R20 G21 - 0x7C500000, // 0197 CALL R20 0 - 0x8C502941, // 0198 GETMET R20 R20 K65 - 0x58580042, // 0199 LDCONST R22 K66 - 0x7C500400, // 019A CALL R20 2 - 0x5C4C2800, // 019B MOVE R19 R20 - 0x8C500943, // 019C GETMET R20 R4 K67 - 0x7C500200, // 019D CALL R20 1 - 0x8C542144, // 019E GETMET R21 R16 K68 - 0x7C540200, // 019F CALL R21 1 - 0x8C542B45, // 01A0 GETMET R21 R21 K69 - 0x7C540200, // 01A1 CALL R21 1 - 0x8C582946, // 01A2 GETMET R22 R20 K70 - 0x5C602400, // 01A3 MOVE R24 R18 - 0x5C642A00, // 01A4 MOVE R25 R21 - 0x5C682600, // 01A5 MOVE R26 R19 - 0x546E0007, // 01A6 LDINT R27 8 - 0x7C580A00, // 01A7 CALL R22 5 - 0x885C0312, // 01A8 GETMBR R23 R1 K18 - 0x785E0001, // 01A9 JMPF R23 #01AC - 0x885C0312, // 01AA GETMBR R23 R1 K18 - 0x70020001, // 01AB JMP #01AE - 0x885C0116, // 01AC GETMBR R23 R0 K22 - 0x885C2F47, // 01AD GETMBR R23 R23 K71 - 0x8C601B48, // 01AE GETMET R24 R13 K72 - 0x5C682000, // 01AF MOVE R26 R16 - 0x5C6C2200, // 01B0 MOVE R27 R17 - 0x5C702C00, // 01B1 MOVE R28 R22 - 0x5C742E00, // 01B2 MOVE R29 R23 - 0x7C600A00, // 01B3 CALL R24 5 - 0x8C601B49, // 01B4 GETMET R24 R13 K73 - 0x7C600200, // 01B5 CALL R24 1 - 0x88600116, // 01B6 GETMBR R24 R0 K22 - 0x8C60314A, // 01B7 GETMET R24 R24 K74 - 0x5C681A00, // 01B8 MOVE R26 R13 - 0x7C600400, // 01B9 CALL R24 2 - 0x8C60034B, // 01BA GETMET R24 R1 K75 - 0x7C600200, // 01BB CALL R24 1 - 0x78620002, // 01BC JMPF R24 #01C0 - 0x8C60034C, // 01BD GETMET R24 R1 K76 - 0x546A003B, // 01BE LDINT R26 60 - 0x7C600400, // 01BF CALL R24 2 - 0x8C601B4D, // 01C0 GETMET R24 R13 K77 - 0x7C600200, // 01C1 CALL R24 1 - 0x8C600B09, // 01C2 GETMET R24 R5 K9 - 0x7C600200, // 01C3 CALL R24 1 - 0x8C64310A, // 01C4 GETMET R25 R24 K10 - 0x586C0005, // 01C5 LDCONST R27 K5 - 0x88700B0B, // 01C6 GETMBR R28 R5 K11 - 0xB8760200, // 01C7 GETNGBL R29 K1 - 0x88743B2B, // 01C8 GETMBR R29 R29 K43 - 0x7C640800, // 01C9 CALL R25 4 - 0x8C64310A, // 01CA GETMET R25 R24 K10 - 0x586C0007, // 01CB LDCONST R27 K7 - 0x88700B0B, // 01CC GETMBR R28 R5 K11 - 0x58740007, // 01CD LDCONST R29 K7 - 0x7C640800, // 01CE CALL R25 4 - 0x54660007, // 01CF LDINT R25 8 - 0x900E0819, // 01D0 SETMBR R3 K4 R25 - 0x80043000, // 01D1 RET 1 R24 - 0x70020056, // 01D2 JMP #022A - 0x54220008, // 01D3 LDINT R8 9 - 0x1C200E08, // 01D4 EQ R8 R7 R8 - 0x7822001E, // 01D5 JMPF R8 #01F5 - 0x8C200506, // 01D6 GETMET R8 R2 K6 - 0x58280005, // 01D7 LDCONST R10 K5 - 0x7C200400, // 01D8 CALL R8 2 - 0x8C24034E, // 01D9 GETMET R9 R1 K78 - 0x5C2C1000, // 01DA MOVE R11 R8 - 0x7C240400, // 01DB CALL R9 2 - 0xB8264400, // 01DC GETNGBL R9 K34 - 0x8C24132C, // 01DD GETMET R9 R9 K44 - 0x602C0018, // 01DE GETGBL R11 G24 - 0x5830004F, // 01DF LDCONST R12 K79 - 0x88340312, // 01E0 GETMBR R13 R1 K18 - 0x8C341B50, // 01E1 GETMET R13 R13 K80 - 0x7C340200, // 01E2 CALL R13 1 - 0x8C341B44, // 01E3 GETMET R13 R13 K68 - 0x7C340200, // 01E4 CALL R13 1 - 0x8C341B45, // 01E5 GETMET R13 R13 K69 - 0x7C340200, // 01E6 CALL R13 1 - 0x8C341B51, // 01E7 GETMET R13 R13 K81 - 0x7C340200, // 01E8 CALL R13 1 - 0x60380008, // 01E9 GETGBL R14 G8 - 0x5C3C1000, // 01EA MOVE R15 R8 - 0x7C380200, // 01EB CALL R14 1 - 0x7C2C0600, // 01EC CALL R11 3 - 0x58300010, // 01ED LDCONST R12 K16 - 0x7C240600, // 01EE CALL R9 3 - 0xB8260200, // 01EF GETNGBL R9 K1 - 0x8824132B, // 01F0 GETMBR R9 R9 K43 - 0x900E3409, // 01F1 SETMBR R3 K26 R9 - 0x4C240000, // 01F2 LDNIL R9 - 0x80041200, // 01F3 RET 1 R9 - 0x70020034, // 01F4 JMP #022A - 0x54220009, // 01F5 LDINT R8 10 - 0x1C200E08, // 01F6 EQ R8 R7 R8 - 0x78220031, // 01F7 JMPF R8 #022A - 0x8C200506, // 01F8 GETMET R8 R2 K6 - 0x58280005, // 01F9 LDCONST R10 K5 - 0x7C200400, // 01FA CALL R8 2 - 0x60240008, // 01FB GETGBL R9 G8 - 0x5C281000, // 01FC MOVE R10 R8 - 0x7C240200, // 01FD CALL R9 1 - 0x0026A409, // 01FE ADD R9 K82 R9 - 0x900E5809, // 01FF SETMBR R3 K44 R9 - 0x60240010, // 0200 GETGBL R9 G16 - 0x88280116, // 0201 GETMBR R10 R0 K22 - 0x88281530, // 0202 GETMBR R10 R10 K48 - 0x8C281553, // 0203 GETMET R10 R10 K83 - 0x7C280200, // 0204 CALL R10 1 - 0x7C240200, // 0205 CALL R9 1 - 0xA8020010, // 0206 EXBLK 0 #0218 - 0x5C281200, // 0207 MOVE R10 R9 - 0x7C280000, // 0208 CALL R10 0 - 0x8C2C1554, // 0209 GETMET R11 R10 K84 - 0x7C2C0200, // 020A CALL R11 1 - 0x1C2C1608, // 020B EQ R11 R11 R8 - 0x782E0008, // 020C JMPF R11 #0216 - 0xB82E4400, // 020D GETNGBL R11 K34 - 0x8C2C1755, // 020E GETMET R11 R11 K85 - 0x543607CF, // 020F LDINT R13 2000 - 0x84380000, // 0210 CLOSURE R14 P0 - 0x7C2C0600, // 0211 CALL R11 3 - 0x502C0200, // 0212 LDBOOL R11 1 0 - 0xA0000000, // 0213 CLOSE R0 - 0xA8040001, // 0214 EXBLK 1 1 - 0x80041600, // 0215 RET 1 R11 - 0xA0240000, // 0216 CLOSE R9 - 0x7001FFEE, // 0217 JMP #0207 - 0x58240056, // 0218 LDCONST R9 K86 - 0xAC240200, // 0219 CATCH R9 1 0 - 0xB0080000, // 021A RAISE 2 R0 R0 - 0xB8264400, // 021B GETNGBL R9 K34 - 0x8C24132C, // 021C GETMET R9 R9 K44 - 0x602C0008, // 021D GETGBL R11 G8 - 0x5C301000, // 021E MOVE R12 R8 - 0x7C2C0200, // 021F CALL R11 1 - 0x002EAE0B, // 0220 ADD R11 K87 R11 - 0x002C1758, // 0221 ADD R11 R11 K88 - 0x5830000E, // 0222 LDCONST R12 K14 - 0x7C240600, // 0223 CALL R9 3 - 0xB8260200, // 0224 GETNGBL R9 K1 - 0x88241359, // 0225 GETMBR R9 R9 K89 - 0x900E3409, // 0226 SETMBR R3 K26 R9 - 0x4C240000, // 0227 LDNIL R9 - 0xA0000000, // 0228 CLOSE R0 - 0x80041200, // 0229 RET 1 R9 - 0x7002009B, // 022A JMP #02C7 - 0x5422003B, // 022B LDINT R8 60 - 0x1C200C08, // 022C EQ R8 R6 R8 - 0x78220085, // 022D JMPF R8 #02B4 - 0x1C200F05, // 022E EQ R8 R7 K5 - 0x78220065, // 022F JMPF R8 #0296 - 0x8C200506, // 0230 GETMET R8 R2 K6 - 0x58280005, // 0231 LDCONST R10 K5 - 0x7C200400, // 0232 CALL R8 2 - 0x8C240506, // 0233 GETMET R9 R2 K6 - 0x582C0007, // 0234 LDCONST R11 K7 - 0x7C240400, // 0235 CALL R9 2 - 0x8C280506, // 0236 GETMET R10 R2 K6 - 0x5830000E, // 0237 LDCONST R12 K14 - 0x7C280400, // 0238 CALL R10 2 - 0x8C2C0506, // 0239 GETMET R11 R2 K6 - 0x58340010, // 023A LDCONST R13 K16 - 0x7C2C0400, // 023B CALL R11 2 - 0x8C300506, // 023C GETMET R12 R2 K6 - 0x543A0003, // 023D LDINT R14 4 - 0x7C300400, // 023E CALL R12 2 - 0xB8364400, // 023F GETNGBL R13 K34 - 0x8C341B2C, // 0240 GETMET R13 R13 K44 - 0x603C0018, // 0241 GETGBL R15 G24 - 0x5840005A, // 0242 LDCONST R16 K90 - 0x5C441000, // 0243 MOVE R17 R8 - 0x8C481351, // 0244 GETMET R18 R9 K81 - 0x7C480200, // 0245 CALL R18 1 - 0x5C4C1400, // 0246 MOVE R19 R10 - 0x5C501600, // 0247 MOVE R20 R11 - 0x8C541951, // 0248 GETMET R21 R12 K81 - 0x7C540200, // 0249 CALL R21 1 - 0x7C3C0C00, // 024A CALL R15 6 - 0x54420003, // 024B LDINT R16 4 - 0x7C340600, // 024C CALL R13 3 - 0x4C340000, // 024D LDNIL R13 - 0x1C34100D, // 024E EQ R13 R8 R13 - 0x7436000B, // 024F JMPT R13 #025C - 0x4C340000, // 0250 LDNIL R13 - 0x1C34120D, // 0251 EQ R13 R9 R13 - 0x74360008, // 0252 JMPT R13 #025C - 0x4C340000, // 0253 LDNIL R13 - 0x1C34140D, // 0254 EQ R13 R10 R13 - 0x74360005, // 0255 JMPT R13 #025C - 0x4C340000, // 0256 LDNIL R13 - 0x1C34160D, // 0257 EQ R13 R11 R13 - 0x74360002, // 0258 JMPT R13 #025C - 0x4C340000, // 0259 LDNIL R13 - 0x1C34180D, // 025A EQ R13 R12 R13 - 0x78360005, // 025B JMPF R13 #0262 - 0xB8360200, // 025C GETNGBL R13 K1 - 0x88341B5B, // 025D GETMBR R13 R13 K91 - 0x900E340D, // 025E SETMBR R3 K26 R13 - 0x4C340000, // 025F LDNIL R13 - 0xA0000000, // 0260 CLOSE R0 - 0x80041A00, // 0261 RET 1 R13 - 0x6034000C, // 0262 GETGBL R13 G12 - 0x5C381200, // 0263 MOVE R14 R9 - 0x7C340200, // 0264 CALL R13 1 - 0x543A001F, // 0265 LDINT R14 32 - 0x543E0040, // 0266 LDINT R15 65 - 0x00381C0F, // 0267 ADD R14 R14 R15 - 0x20341A0E, // 0268 NE R13 R13 R14 - 0x7436000B, // 0269 JMPT R13 #0276 - 0x6034000C, // 026A GETGBL R13 G12 - 0x5C381800, // 026B MOVE R14 R12 - 0x7C340200, // 026C CALL R13 1 - 0x543A000F, // 026D LDINT R14 16 - 0x14341A0E, // 026E LT R13 R13 R14 - 0x74360005, // 026F JMPT R13 #0276 - 0x6034000C, // 0270 GETGBL R13 G12 - 0x5C381800, // 0271 MOVE R14 R12 - 0x7C340200, // 0272 CALL R13 1 - 0x543A001F, // 0273 LDINT R14 32 - 0x24341A0E, // 0274 GT R13 R13 R14 - 0x7836000A, // 0275 JMPF R13 #0281 - 0xB8364400, // 0276 GETNGBL R13 K34 - 0x8C341B2C, // 0277 GETMET R13 R13 K44 - 0x583C005C, // 0278 LDCONST R15 K92 - 0x5840000E, // 0279 LDCONST R16 K14 - 0x7C340600, // 027A CALL R13 3 - 0xB8360200, // 027B GETNGBL R13 K1 - 0x88341B5D, // 027C GETMBR R13 R13 K93 - 0x900E340D, // 027D SETMBR R3 K26 R13 - 0x4C340000, // 027E LDNIL R13 - 0xA0000000, // 027F CLOSE R0 - 0x80041A00, // 0280 RET 1 R13 - 0x5436001E, // 0281 LDINT R13 31 - 0x40360A0D, // 0282 CONNECT R13 K5 R13 - 0x9434120D, // 0283 GETIDX R13 R9 R13 - 0x543A001F, // 0284 LDINT R14 32 - 0x40381D40, // 0285 CONNECT R14 R14 K64 - 0x9438120E, // 0286 GETIDX R14 R9 R14 - 0x883C0116, // 0287 GETMBR R15 R0 K22 - 0x8C3C1F5E, // 0288 GETMET R15 R15 K94 - 0x5C441000, // 0289 MOVE R17 R8 - 0x5C481600, // 028A MOVE R18 R11 - 0x5C4C1400, // 028B MOVE R19 R10 - 0x5C501800, // 028C MOVE R20 R12 - 0x5C541A00, // 028D MOVE R21 R13 - 0x5C581C00, // 028E MOVE R22 R14 - 0x8C5C035F, // 028F GETMET R23 R1 K95 - 0x7C5C0200, // 0290 CALL R23 1 - 0x7C3C1000, // 0291 CALL R15 8 - 0x503C0200, // 0292 LDBOOL R15 1 0 - 0xA0000000, // 0293 CLOSE R0 - 0x80041E00, // 0294 RET 1 R15 - 0x7002001C, // 0295 JMP #02B3 - 0x1C200F07, // 0296 EQ R8 R7 K7 - 0x78220012, // 0297 JMPF R8 #02AB - 0x8C200506, // 0298 GETMET R8 R2 K6 - 0x58280005, // 0299 LDCONST R10 K5 - 0x7C200400, // 029A CALL R8 2 - 0xB8264400, // 029B GETNGBL R9 K34 - 0x8C24132C, // 029C GETMET R9 R9 K44 - 0x602C0008, // 029D GETGBL R11 G8 - 0x5C301000, // 029E MOVE R12 R8 - 0x7C2C0200, // 029F CALL R11 1 - 0x002EC00B, // 02A0 ADD R11 K96 R11 - 0x58300010, // 02A1 LDCONST R12 K16 - 0x7C240600, // 02A2 CALL R9 3 - 0x88240116, // 02A3 GETMBR R9 R0 K22 - 0x8C241361, // 02A4 GETMET R9 R9 K97 - 0x5C2C1000, // 02A5 MOVE R11 R8 - 0x7C240400, // 02A6 CALL R9 2 - 0x50240200, // 02A7 LDBOOL R9 1 0 - 0xA0000000, // 02A8 CLOSE R0 - 0x80041200, // 02A9 RET 1 R9 - 0x70020007, // 02AA JMP #02B3 - 0x1C200F0E, // 02AB EQ R8 R7 K14 - 0x78220005, // 02AC JMPF R8 #02B3 - 0x88200116, // 02AD GETMBR R8 R0 K22 - 0x8C201162, // 02AE GETMET R8 R8 K98 - 0x7C200200, // 02AF CALL R8 1 - 0x50200200, // 02B0 LDBOOL R8 1 0 - 0xA0000000, // 02B1 CLOSE R0 - 0x80041000, // 02B2 RET 1 R8 - 0x70020012, // 02B3 JMP #02C7 - 0x54220029, // 02B4 LDINT R8 42 - 0x1C200C08, // 02B5 EQ R8 R6 R8 - 0x78220005, // 02B6 JMPF R8 #02BD - 0x1C200F05, // 02B7 EQ R8 R7 K5 - 0x78220002, // 02B8 JMPF R8 #02BC - 0x50200200, // 02B9 LDBOOL R8 1 0 - 0xA0000000, // 02BA CLOSE R0 - 0x80041000, // 02BB RET 1 R8 - 0x70020009, // 02BC JMP #02C7 - 0x60200003, // 02BD GETGBL R8 G3 - 0x5C240000, // 02BE MOVE R9 R0 - 0x7C200200, // 02BF CALL R8 1 - 0x8C201163, // 02C0 GETMET R8 R8 K99 - 0x5C280200, // 02C1 MOVE R10 R1 - 0x5C2C0400, // 02C2 MOVE R11 R2 - 0x5C300600, // 02C3 MOVE R12 R3 - 0x7C200800, // 02C4 CALL R8 4 - 0xA0000000, // 02C5 CLOSE R0 - 0x80041000, // 02C6 RET 1 R8 - 0xA0000000, // 02C7 CLOSE R0 - 0x80000000, // 02C8 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -2061,6 +1196,871 @@ be_local_closure(Matter_Plugin_Root_write_attribute, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Root_invoke_request, /* name */ + be_nested_proto( + 30, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 1, /* has sup protos */ + ( &(const struct bproto*[ 1]) { + be_nested_proto( + 3, /* nstack */ + 0, /* argc */ + 0, /* varg */ + 1, /* has upvals */ + ( &(const bupvaldesc[ 2]) { /* upvals */ + be_local_const_upval(1, 0), + be_local_const_upval(1, 10), + }), + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(device), + /* K1 */ be_nested_str_weak(remove_fabric), + }), + be_str_weak(_anonymous_), + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0x68000000, // 0000 GETUPV R0 U0 + 0x88000100, // 0001 GETMBR R0 R0 K0 + 0x8C000101, // 0002 GETMET R0 R0 K1 + 0x68080001, // 0003 GETUPV R2 U1 + 0x7C000400, // 0004 CALL R0 2 + 0x80000000, // 0005 RET 0 + }) + ), + }), + 1, /* has constants */ + ( &(const bvalue[100]) { /* constants */ + /* K0 */ be_nested_str_weak(crypto), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(command), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(findsubval), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str_weak(_breadcrumb), + /* K9 */ be_nested_str_weak(Matter_TLV_struct), + /* K10 */ be_nested_str_weak(add_TLV), + /* K11 */ be_nested_str_weak(U1), + /* K12 */ be_nested_str_weak(UTF1), + /* K13 */ be_nested_str_weak(), + /* K14 */ be_const_int(2), + /* K15 */ be_nested_str_weak(XX), + /* K16 */ be_const_int(3), + /* K17 */ be_nested_str_weak(ack_request), + /* K18 */ be_nested_str_weak(_fabric), + /* K19 */ be_nested_str_weak(fabric_completed), + /* K20 */ be_nested_str_weak(set_no_expiration), + /* K21 */ be_nested_str_weak(save), + /* K22 */ be_nested_str_weak(device), + /* K23 */ be_nested_str_weak(start_commissioning_complete_deferred), + /* K24 */ be_nested_str_weak(context_error), + /* K25 */ be_nested_str_weak(CommissioningComplete_X3A_X20no_X20fabric_X20attached), + /* K26 */ be_nested_str_weak(status), + /* K27 */ be_nested_str_weak(UNSUPPORTED_COMMAND), + /* K28 */ be_nested_str_weak(B2), + /* K29 */ be_nested_str_weak(DAC_Cert_FFF1_8000), + /* K30 */ be_nested_str_weak(PAI_Cert_FFF1), + /* K31 */ be_nested_str_weak(CD_FFF1_8000), + /* K32 */ be_nested_str_weak(B1), + /* K33 */ be_nested_str_weak(U4), + /* K34 */ be_nested_str_weak(tasmota), + /* K35 */ be_nested_str_weak(rtc_utc), + /* K36 */ be_nested_str_weak(tlv2raw), + /* K37 */ be_nested_str_weak(get_ac), + /* K38 */ be_nested_str_weak(EC_P256), + /* K39 */ be_nested_str_weak(ecdsa_sign_sha256), + /* K40 */ be_nested_str_weak(DAC_Priv_FFF1_8000), + /* K41 */ be_nested_str_weak(gen_CSR), + /* K42 */ be_nested_str_weak(set_temp_ca), + /* K43 */ be_nested_str_weak(SUCCESS), + /* K44 */ be_nested_str_weak(log), + /* K45 */ be_nested_str_weak(MTR_X3A_X20AddNoc_X20Args_X3D), + /* K46 */ be_nested_str_weak(get_temp_ca), + /* K47 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20AdNOC_X20without_X20CA), + /* K48 */ be_nested_str_weak(sessions), + /* K49 */ be_nested_str_weak(create_fabric), + /* K50 */ be_nested_str_weak(set_ca), + /* K51 */ be_nested_str_weak(set_noc_icac), + /* K52 */ be_nested_str_weak(set_ipk_epoch_key), + /* K53 */ be_nested_str_weak(set_admin_subject_vendor), + /* K54 */ be_nested_str_weak(set_pk), + /* K55 */ be_nested_str_weak(get_pk), + /* K56 */ be_nested_str_weak(parse), + /* K57 */ be_nested_str_weak(findsub), + /* K58 */ be_nested_str_weak(MTR_X3A_X20Error_X3A_X20no_X20fabricid_X20nor_X20deviceid_X20in_X20NOC_X20certificate), + /* K59 */ be_nested_str_weak(int), + /* K60 */ be_nested_str_weak(int64), + /* K61 */ be_nested_str_weak(fromu32), + /* K62 */ be_nested_str_weak(tobytes), + /* K63 */ be_nested_str_weak(get_temp_ca_pub), + /* K64 */ be_const_int(2147483647), + /* K65 */ be_nested_str_weak(fromstring), + /* K66 */ be_nested_str_weak(CompressedFabric), + /* K67 */ be_nested_str_weak(HKDF_SHA256), + /* K68 */ be_nested_str_weak(copy), + /* K69 */ be_nested_str_weak(reverse), + /* K70 */ be_nested_str_weak(derive), + /* K71 */ be_nested_str_weak(commissioning_admin_fabric), + /* K72 */ be_nested_str_weak(set_fabric_device), + /* K73 */ be_nested_str_weak(fabric_candidate), + /* K74 */ be_nested_str_weak(start_operational_discovery_deferred), + /* K75 */ be_nested_str_weak(is_PASE), + /* K76 */ be_nested_str_weak(set_expire_in_seconds), + /* K77 */ be_nested_str_weak(log_new_fabric), + /* K78 */ be_nested_str_weak(set_fabric_label), + /* K79 */ be_nested_str_weak(MTR_X3A_X20_X2E_X20_X20_X20_X20_X20_X20_X20_X20_X20_X20Update_X20fabric_X20_X27_X25s_X27_X20label_X3D_X27_X25s_X27), + /* K80 */ be_nested_str_weak(get_fabric_id), + /* K81 */ be_nested_str_weak(tohex), + /* K82 */ be_nested_str_weak(fabric_index_X3A), + /* K83 */ be_nested_str_weak(active_fabrics), + /* K84 */ be_nested_str_weak(get_fabric_index), + /* K85 */ be_nested_str_weak(set_timer), + /* K86 */ be_nested_str_weak(stop_iteration), + /* K87 */ be_nested_str_weak(MTR_X3A_X20RemoveFabric_X20fabric_X28), + /* K88 */ be_nested_str_weak(_X29_X20not_X20found), + /* K89 */ be_nested_str_weak(INVALID_ACTION), + /* K90 */ be_nested_str_weak(MTR_X3A_X20OpenCommissioningWindow_X28timeout_X3D_X25i_X2C_X20passcode_X3D_X25s_X2C_X20discriminator_X3D_X25i_X2C_X20iterations_X3D_X25i_X2C_X20salt_X3D_X25s_X29), + /* K91 */ be_nested_str_weak(INVALID_DATA_TYPE), + /* K92 */ be_nested_str_weak(MTR_X3A_X20wrong_X20size_X20for_X20PAKE_X20parameters), + /* K93 */ be_nested_str_weak(CONSTRAINT_ERROR), + /* K94 */ be_nested_str_weak(start_basic_commissioning), + /* K95 */ be_nested_str_weak(get_fabric), + /* K96 */ be_nested_str_weak(MTR_X3A_X20OpenBasicCommissioningWindow_X20commissioning_timeout_X3D), + /* K97 */ be_nested_str_weak(start_root_basic_commissioning), + /* K98 */ be_nested_str_weak(stop_basic_commissioning), + /* K99 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[713]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x5422002F, // 0005 LDINT R8 48 + 0x1C200C08, // 0006 EQ R8 R6 R8 + 0x7822005C, // 0007 JMPF R8 #0065 + 0x1C200F05, // 0008 EQ R8 R7 K5 + 0x78220017, // 0009 JMPF R8 #0022 + 0x8C200506, // 000A GETMET R8 R2 K6 + 0x58280005, // 000B LDCONST R10 K5 + 0x542E0383, // 000C LDINT R11 900 + 0x7C200600, // 000D CALL R8 3 + 0x8C240506, // 000E GETMET R9 R2 K6 + 0x582C0007, // 000F LDCONST R11 K7 + 0x58300005, // 0010 LDCONST R12 K5 + 0x7C240600, // 0011 CALL R9 3 + 0x90061009, // 0012 SETMBR R1 K8 R9 + 0x8C280B09, // 0013 GETMET R10 R5 K9 + 0x7C280200, // 0014 CALL R10 1 + 0x8C2C150A, // 0015 GETMET R11 R10 K10 + 0x58340005, // 0016 LDCONST R13 K5 + 0x88380B0B, // 0017 GETMBR R14 R5 K11 + 0x583C0005, // 0018 LDCONST R15 K5 + 0x7C2C0800, // 0019 CALL R11 4 + 0x8C2C150A, // 001A GETMET R11 R10 K10 + 0x58340007, // 001B LDCONST R13 K7 + 0x88380B0C, // 001C GETMBR R14 R5 K12 + 0x583C000D, // 001D LDCONST R15 K13 + 0x7C2C0800, // 001E CALL R11 4 + 0x900E0907, // 001F SETMBR R3 K4 K7 + 0x80041400, // 0020 RET 1 R10 + 0x70020041, // 0021 JMP #0064 + 0x1C200F0E, // 0022 EQ R8 R7 K14 + 0x7822001A, // 0023 JMPF R8 #003F + 0x8C200506, // 0024 GETMET R8 R2 K6 + 0x58280005, // 0025 LDCONST R10 K5 + 0x7C200400, // 0026 CALL R8 2 + 0x8C240506, // 0027 GETMET R9 R2 K6 + 0x582C0007, // 0028 LDCONST R11 K7 + 0x5830000F, // 0029 LDCONST R12 K15 + 0x7C240600, // 002A CALL R9 3 + 0x8C280506, // 002B GETMET R10 R2 K6 + 0x5830000E, // 002C LDCONST R12 K14 + 0x58340005, // 002D LDCONST R13 K5 + 0x7C280600, // 002E CALL R10 3 + 0x9006100A, // 002F SETMBR R1 K8 R10 + 0x8C2C0B09, // 0030 GETMET R11 R5 K9 + 0x7C2C0200, // 0031 CALL R11 1 + 0x8C30170A, // 0032 GETMET R12 R11 K10 + 0x58380005, // 0033 LDCONST R14 K5 + 0x883C0B0B, // 0034 GETMBR R15 R5 K11 + 0x58400005, // 0035 LDCONST R16 K5 + 0x7C300800, // 0036 CALL R12 4 + 0x8C30170A, // 0037 GETMET R12 R11 K10 + 0x58380007, // 0038 LDCONST R14 K7 + 0x883C0B0C, // 0039 GETMBR R15 R5 K12 + 0x5840000D, // 003A LDCONST R16 K13 + 0x7C300800, // 003B CALL R12 4 + 0x900E0910, // 003C SETMBR R3 K4 K16 + 0x80041600, // 003D RET 1 R11 + 0x70020024, // 003E JMP #0064 + 0x54220003, // 003F LDINT R8 4 + 0x1C200E08, // 0040 EQ R8 R7 R8 + 0x78220021, // 0041 JMPF R8 #0064 + 0x8C200111, // 0042 GETMET R8 R0 K17 + 0x5C280600, // 0043 MOVE R10 R3 + 0x7C200400, // 0044 CALL R8 2 + 0x88200312, // 0045 GETMBR R8 R1 K18 + 0x7822001B, // 0046 JMPF R8 #0063 + 0x90061105, // 0047 SETMBR R1 K8 K5 + 0x88200312, // 0048 GETMBR R8 R1 K18 + 0x8C201113, // 0049 GETMET R8 R8 K19 + 0x7C200200, // 004A CALL R8 1 + 0x8C200314, // 004B GETMET R8 R1 K20 + 0x7C200200, // 004C CALL R8 1 + 0x8C200315, // 004D GETMET R8 R1 K21 + 0x7C200200, // 004E CALL R8 1 + 0x8C200B09, // 004F GETMET R8 R5 K9 + 0x7C200200, // 0050 CALL R8 1 + 0x8C24110A, // 0051 GETMET R9 R8 K10 + 0x582C0005, // 0052 LDCONST R11 K5 + 0x88300B0B, // 0053 GETMBR R12 R5 K11 + 0x58340005, // 0054 LDCONST R13 K5 + 0x7C240800, // 0055 CALL R9 4 + 0x8C24110A, // 0056 GETMET R9 R8 K10 + 0x582C0007, // 0057 LDCONST R11 K7 + 0x88300B0C, // 0058 GETMBR R12 R5 K12 + 0x5834000D, // 0059 LDCONST R13 K13 + 0x7C240800, // 005A CALL R9 4 + 0x54260004, // 005B LDINT R9 5 + 0x900E0809, // 005C SETMBR R3 K4 R9 + 0x88240116, // 005D GETMBR R9 R0 K22 + 0x8C241317, // 005E GETMET R9 R9 K23 + 0x5C2C0200, // 005F MOVE R11 R1 + 0x7C240400, // 0060 CALL R9 2 + 0x80041000, // 0061 RET 1 R8 + 0x70020000, // 0062 JMP #0064 + 0xB0063119, // 0063 RAISE 1 K24 K25 + 0x70020261, // 0064 JMP #02C7 + 0x5422003D, // 0065 LDINT R8 62 + 0x1C200C08, // 0066 EQ R8 R6 R8 + 0x782201C2, // 0067 JMPF R8 #022B + 0x1C200F0E, // 0068 EQ R8 R7 K14 + 0x7822001D, // 0069 JMPF R8 #0088 + 0x8C200506, // 006A GETMET R8 R2 K6 + 0x58280005, // 006B LDCONST R10 K5 + 0x7C200400, // 006C CALL R8 2 + 0x20241107, // 006D NE R9 R8 K7 + 0x78260006, // 006E JMPF R9 #0076 + 0x2024110E, // 006F NE R9 R8 K14 + 0x78260004, // 0070 JMPF R9 #0076 + 0xB8260200, // 0071 GETNGBL R9 K1 + 0x8824131B, // 0072 GETMBR R9 R9 K27 + 0x900E3409, // 0073 SETMBR R3 K26 R9 + 0x4C240000, // 0074 LDNIL R9 + 0x80041200, // 0075 RET 1 R9 + 0x8C240B09, // 0076 GETMET R9 R5 K9 + 0x7C240200, // 0077 CALL R9 1 + 0x8C28130A, // 0078 GETMET R10 R9 K10 + 0x58300005, // 0079 LDCONST R12 K5 + 0x88340B1C, // 007A GETMBR R13 R5 K28 + 0x1C381107, // 007B EQ R14 R8 K7 + 0x783A0003, // 007C JMPF R14 #0081 + 0xB83A0200, // 007D GETNGBL R14 K1 + 0x8C381D1D, // 007E GETMET R14 R14 K29 + 0x7C380200, // 007F CALL R14 1 + 0x70020002, // 0080 JMP #0084 + 0xB83A0200, // 0081 GETNGBL R14 K1 + 0x8C381D1E, // 0082 GETMET R14 R14 K30 + 0x7C380200, // 0083 CALL R14 1 + 0x7C280800, // 0084 CALL R10 4 + 0x900E0910, // 0085 SETMBR R3 K4 K16 + 0x80041200, // 0086 RET 1 R9 + 0x700201A1, // 0087 JMP #022A + 0x1C200F05, // 0088 EQ R8 R7 K5 + 0x7822003C, // 0089 JMPF R8 #00C7 + 0x8C200506, // 008A GETMET R8 R2 K6 + 0x58280005, // 008B LDCONST R10 K5 + 0x7C200400, // 008C CALL R8 2 + 0x6024000C, // 008D GETGBL R9 G12 + 0x5C281000, // 008E MOVE R10 R8 + 0x7C240200, // 008F CALL R9 1 + 0x542A001F, // 0090 LDINT R10 32 + 0x2024120A, // 0091 NE R9 R9 R10 + 0x78260001, // 0092 JMPF R9 #0095 + 0x4C240000, // 0093 LDNIL R9 + 0x80041200, // 0094 RET 1 R9 + 0x900E0907, // 0095 SETMBR R3 K4 K7 + 0x8C240B09, // 0096 GETMET R9 R5 K9 + 0x7C240200, // 0097 CALL R9 1 + 0x8C28130A, // 0098 GETMET R10 R9 K10 + 0x58300007, // 0099 LDCONST R12 K7 + 0x88340B1C, // 009A GETMBR R13 R5 K28 + 0xB83A0200, // 009B GETNGBL R14 K1 + 0x8C381D1F, // 009C GETMET R14 R14 K31 + 0x7C380200, // 009D CALL R14 1 + 0x7C280800, // 009E CALL R10 4 + 0x8C28130A, // 009F GETMET R10 R9 K10 + 0x5830000E, // 00A0 LDCONST R12 K14 + 0x88340B20, // 00A1 GETMBR R13 R5 K32 + 0x5C381000, // 00A2 MOVE R14 R8 + 0x7C280800, // 00A3 CALL R10 4 + 0x8C28130A, // 00A4 GETMET R10 R9 K10 + 0x58300010, // 00A5 LDCONST R12 K16 + 0x88340B21, // 00A6 GETMBR R13 R5 K33 + 0xB83A4400, // 00A7 GETNGBL R14 K34 + 0x8C381D23, // 00A8 GETMET R14 R14 K35 + 0x7C380200, // 00A9 CALL R14 1 + 0x7C280800, // 00AA CALL R10 4 + 0x8C281324, // 00AB GETMET R10 R9 K36 + 0x7C280200, // 00AC CALL R10 1 + 0x8C2C0325, // 00AD GETMET R11 R1 K37 + 0x7C2C0200, // 00AE CALL R11 1 + 0x0030140B, // 00AF ADD R12 R10 R11 + 0x8C340926, // 00B0 GETMET R13 R4 K38 + 0x7C340200, // 00B1 CALL R13 1 + 0x8C341B27, // 00B2 GETMET R13 R13 K39 + 0xB83E0200, // 00B3 GETNGBL R15 K1 + 0x8C3C1F28, // 00B4 GETMET R15 R15 K40 + 0x7C3C0200, // 00B5 CALL R15 1 + 0x5C401800, // 00B6 MOVE R16 R12 + 0x7C340600, // 00B7 CALL R13 3 + 0x8C380B09, // 00B8 GETMET R14 R5 K9 + 0x7C380200, // 00B9 CALL R14 1 + 0x8C3C1D0A, // 00BA GETMET R15 R14 K10 + 0x58440005, // 00BB LDCONST R17 K5 + 0x88480B1C, // 00BC GETMBR R18 R5 K28 + 0x5C4C1400, // 00BD MOVE R19 R10 + 0x7C3C0800, // 00BE CALL R15 4 + 0x8C3C1D0A, // 00BF GETMET R15 R14 K10 + 0x58440007, // 00C0 LDCONST R17 K7 + 0x88480B20, // 00C1 GETMBR R18 R5 K32 + 0x5C4C1A00, // 00C2 MOVE R19 R13 + 0x7C3C0800, // 00C3 CALL R15 4 + 0x900E0907, // 00C4 SETMBR R3 K4 K7 + 0x80041C00, // 00C5 RET 1 R14 + 0x70020162, // 00C6 JMP #022A + 0x54220003, // 00C7 LDINT R8 4 + 0x1C200E08, // 00C8 EQ R8 R7 R8 + 0x7822003C, // 00C9 JMPF R8 #0107 + 0x8C200111, // 00CA GETMET R8 R0 K17 + 0x5C280600, // 00CB MOVE R10 R3 + 0x7C200400, // 00CC CALL R8 2 + 0x8C200506, // 00CD GETMET R8 R2 K6 + 0x58280005, // 00CE LDCONST R10 K5 + 0x7C200400, // 00CF CALL R8 2 + 0x6024000C, // 00D0 GETGBL R9 G12 + 0x5C281000, // 00D1 MOVE R10 R8 + 0x7C240200, // 00D2 CALL R9 1 + 0x542A001F, // 00D3 LDINT R10 32 + 0x2024120A, // 00D4 NE R9 R9 R10 + 0x78260001, // 00D5 JMPF R9 #00D8 + 0x4C240000, // 00D6 LDNIL R9 + 0x80041200, // 00D7 RET 1 R9 + 0x8C240506, // 00D8 GETMET R9 R2 K6 + 0x582C0007, // 00D9 LDCONST R11 K7 + 0x50300000, // 00DA LDBOOL R12 0 0 + 0x7C240600, // 00DB CALL R9 3 + 0x8C280329, // 00DC GETMET R10 R1 K41 + 0x7C280200, // 00DD CALL R10 1 + 0x8C2C0B09, // 00DE GETMET R11 R5 K9 + 0x7C2C0200, // 00DF CALL R11 1 + 0x8C30170A, // 00E0 GETMET R12 R11 K10 + 0x58380007, // 00E1 LDCONST R14 K7 + 0x883C0B1C, // 00E2 GETMBR R15 R5 K28 + 0x5C401400, // 00E3 MOVE R16 R10 + 0x7C300800, // 00E4 CALL R12 4 + 0x8C30170A, // 00E5 GETMET R12 R11 K10 + 0x5838000E, // 00E6 LDCONST R14 K14 + 0x883C0B20, // 00E7 GETMBR R15 R5 K32 + 0x5C401000, // 00E8 MOVE R16 R8 + 0x7C300800, // 00E9 CALL R12 4 + 0x8C301724, // 00EA GETMET R12 R11 K36 + 0x7C300200, // 00EB CALL R12 1 + 0x8C340325, // 00EC GETMET R13 R1 K37 + 0x7C340200, // 00ED CALL R13 1 + 0x0034180D, // 00EE ADD R13 R12 R13 + 0x8C380926, // 00EF GETMET R14 R4 K38 + 0x7C380200, // 00F0 CALL R14 1 + 0x8C381D27, // 00F1 GETMET R14 R14 K39 + 0xB8420200, // 00F2 GETNGBL R16 K1 + 0x8C402128, // 00F3 GETMET R16 R16 K40 + 0x7C400200, // 00F4 CALL R16 1 + 0x5C441A00, // 00F5 MOVE R17 R13 + 0x7C380600, // 00F6 CALL R14 3 + 0x8C3C0B09, // 00F7 GETMET R15 R5 K9 + 0x7C3C0200, // 00F8 CALL R15 1 + 0x8C401F0A, // 00F9 GETMET R16 R15 K10 + 0x58480005, // 00FA LDCONST R18 K5 + 0x884C0B1C, // 00FB GETMBR R19 R5 K28 + 0x5C501800, // 00FC MOVE R20 R12 + 0x7C400800, // 00FD CALL R16 4 + 0x8C401F0A, // 00FE GETMET R16 R15 K10 + 0x58480007, // 00FF LDCONST R18 K7 + 0x884C0B20, // 0100 GETMBR R19 R5 K32 + 0x5C501C00, // 0101 MOVE R20 R14 + 0x7C400800, // 0102 CALL R16 4 + 0x54420004, // 0103 LDINT R16 5 + 0x900E0810, // 0104 SETMBR R3 K4 R16 + 0x80041E00, // 0105 RET 1 R15 + 0x70020122, // 0106 JMP #022A + 0x5422000A, // 0107 LDINT R8 11 + 0x1C200E08, // 0108 EQ R8 R7 R8 + 0x7822000B, // 0109 JMPF R8 #0116 + 0x8C200506, // 010A GETMET R8 R2 K6 + 0x58280005, // 010B LDCONST R10 K5 + 0x7C200400, // 010C CALL R8 2 + 0x8C24032A, // 010D GETMET R9 R1 K42 + 0x5C2C1000, // 010E MOVE R11 R8 + 0x7C240400, // 010F CALL R9 2 + 0xB8260200, // 0110 GETNGBL R9 K1 + 0x8824132B, // 0111 GETMBR R9 R9 K43 + 0x900E3409, // 0112 SETMBR R3 K26 R9 + 0x4C240000, // 0113 LDNIL R9 + 0x80041200, // 0114 RET 1 R9 + 0x70020113, // 0115 JMP #022A + 0x54220005, // 0116 LDINT R8 6 + 0x1C200E08, // 0117 EQ R8 R7 R8 + 0x782200B9, // 0118 JMPF R8 #01D3 + 0xB8224400, // 0119 GETNGBL R8 K34 + 0x8C20112C, // 011A GETMET R8 R8 K44 + 0x60280008, // 011B GETGBL R10 G8 + 0x5C2C0400, // 011C MOVE R11 R2 + 0x7C280200, // 011D CALL R10 1 + 0x002A5A0A, // 011E ADD R10 K45 R10 + 0x542E0003, // 011F LDINT R11 4 + 0x7C200600, // 0120 CALL R8 3 + 0x8C200506, // 0121 GETMET R8 R2 K6 + 0x58280005, // 0122 LDCONST R10 K5 + 0x7C200400, // 0123 CALL R8 2 + 0x8C240506, // 0124 GETMET R9 R2 K6 + 0x582C0007, // 0125 LDCONST R11 K7 + 0x7C240400, // 0126 CALL R9 2 + 0x6028000C, // 0127 GETGBL R10 G12 + 0x5C2C1200, // 0128 MOVE R11 R9 + 0x7C280200, // 0129 CALL R10 1 + 0x1C281505, // 012A EQ R10 R10 K5 + 0x782A0000, // 012B JMPF R10 #012D + 0x4C240000, // 012C LDNIL R9 + 0x8C280506, // 012D GETMET R10 R2 K6 + 0x5830000E, // 012E LDCONST R12 K14 + 0x7C280400, // 012F CALL R10 2 + 0x8C2C0506, // 0130 GETMET R11 R2 K6 + 0x58340010, // 0131 LDCONST R13 K16 + 0x7C2C0400, // 0132 CALL R11 2 + 0x8C300506, // 0133 GETMET R12 R2 K6 + 0x543A0003, // 0134 LDINT R14 4 + 0x7C300400, // 0135 CALL R12 2 + 0x8C34032E, // 0136 GETMET R13 R1 K46 + 0x7C340200, // 0137 CALL R13 1 + 0x4C380000, // 0138 LDNIL R14 + 0x1C341A0E, // 0139 EQ R13 R13 R14 + 0x78360006, // 013A JMPF R13 #0142 + 0xB8364400, // 013B GETNGBL R13 K34 + 0x8C341B2C, // 013C GETMET R13 R13 K44 + 0x583C002F, // 013D LDCONST R15 K47 + 0x5840000E, // 013E LDCONST R16 K14 + 0x7C340600, // 013F CALL R13 3 + 0x4C340000, // 0140 LDNIL R13 + 0x80041A00, // 0141 RET 1 R13 + 0x88340116, // 0142 GETMBR R13 R0 K22 + 0x88341B30, // 0143 GETMBR R13 R13 K48 + 0x8C341B31, // 0144 GETMET R13 R13 K49 + 0x7C340200, // 0145 CALL R13 1 + 0x8C381B32, // 0146 GETMET R14 R13 K50 + 0x8C40032E, // 0147 GETMET R16 R1 K46 + 0x7C400200, // 0148 CALL R16 1 + 0x7C380400, // 0149 CALL R14 2 + 0x8C381B33, // 014A GETMET R14 R13 K51 + 0x5C401000, // 014B MOVE R16 R8 + 0x5C441200, // 014C MOVE R17 R9 + 0x7C380600, // 014D CALL R14 3 + 0x8C381B34, // 014E GETMET R14 R13 K52 + 0x5C401400, // 014F MOVE R16 R10 + 0x7C380400, // 0150 CALL R14 2 + 0x8C381B35, // 0151 GETMET R14 R13 K53 + 0x5C401600, // 0152 MOVE R16 R11 + 0x5C441800, // 0153 MOVE R17 R12 + 0x7C380600, // 0154 CALL R14 3 + 0x8C381B36, // 0155 GETMET R14 R13 K54 + 0x8C400337, // 0156 GETMET R16 R1 K55 + 0x7C400200, // 0157 CALL R16 1 + 0x7C380400, // 0158 CALL R14 2 + 0xB83A0200, // 0159 GETNGBL R14 K1 + 0x88381D02, // 015A GETMBR R14 R14 K2 + 0x8C381D38, // 015B GETMET R14 R14 K56 + 0x5C401000, // 015C MOVE R16 R8 + 0x7C380400, // 015D CALL R14 2 + 0x8C3C1D39, // 015E GETMET R15 R14 K57 + 0x54460005, // 015F LDINT R17 6 + 0x7C3C0400, // 0160 CALL R15 2 + 0x8C401F06, // 0161 GETMET R16 R15 K6 + 0x544A0014, // 0162 LDINT R18 21 + 0x7C400400, // 0163 CALL R16 2 + 0x8C441F06, // 0164 GETMET R17 R15 K6 + 0x544E0010, // 0165 LDINT R19 17 + 0x7C440400, // 0166 CALL R17 2 + 0x5C482000, // 0167 MOVE R18 R16 + 0x784A0001, // 0168 JMPF R18 #016B + 0x5C482200, // 0169 MOVE R18 R17 + 0x744A0006, // 016A JMPT R18 #0172 + 0xB84A4400, // 016B GETNGBL R18 K34 + 0x8C48252C, // 016C GETMET R18 R18 K44 + 0x5850003A, // 016D LDCONST R20 K58 + 0x5854000E, // 016E LDCONST R21 K14 + 0x7C480600, // 016F CALL R18 3 + 0x50480000, // 0170 LDBOOL R18 0 0 + 0x80042400, // 0171 RET 1 R18 + 0x60480004, // 0172 GETGBL R18 G4 + 0x5C4C2000, // 0173 MOVE R19 R16 + 0x7C480200, // 0174 CALL R18 1 + 0x1C48253B, // 0175 EQ R18 R18 K59 + 0x784A0007, // 0176 JMPF R18 #017F + 0xB84A7800, // 0177 GETNGBL R18 K60 + 0x8C48253D, // 0178 GETMET R18 R18 K61 + 0x5C502000, // 0179 MOVE R20 R16 + 0x7C480400, // 017A CALL R18 2 + 0x8C48253E, // 017B GETMET R18 R18 K62 + 0x7C480200, // 017C CALL R18 1 + 0x5C402400, // 017D MOVE R16 R18 + 0x70020002, // 017E JMP #0182 + 0x8C48213E, // 017F GETMET R18 R16 K62 + 0x7C480200, // 0180 CALL R18 1 + 0x5C402400, // 0181 MOVE R16 R18 + 0x60480004, // 0182 GETGBL R18 G4 + 0x5C4C2200, // 0183 MOVE R19 R17 + 0x7C480200, // 0184 CALL R18 1 + 0x1C48253B, // 0185 EQ R18 R18 K59 + 0x784A0007, // 0186 JMPF R18 #018F + 0xB84A7800, // 0187 GETNGBL R18 K60 + 0x8C48253D, // 0188 GETMET R18 R18 K61 + 0x5C502200, // 0189 MOVE R20 R17 + 0x7C480400, // 018A CALL R18 2 + 0x8C48253E, // 018B GETMET R18 R18 K62 + 0x7C480200, // 018C CALL R18 1 + 0x5C442400, // 018D MOVE R17 R18 + 0x70020002, // 018E JMP #0192 + 0x8C48233E, // 018F GETMET R18 R17 K62 + 0x7C480200, // 0190 CALL R18 1 + 0x5C442400, // 0191 MOVE R17 R18 + 0x8C48033F, // 0192 GETMET R18 R1 K63 + 0x7C480200, // 0193 CALL R18 1 + 0x404E0F40, // 0194 CONNECT R19 K7 K64 + 0x94482413, // 0195 GETIDX R18 R18 R19 + 0x60500015, // 0196 GETGBL R20 G21 + 0x7C500000, // 0197 CALL R20 0 + 0x8C502941, // 0198 GETMET R20 R20 K65 + 0x58580042, // 0199 LDCONST R22 K66 + 0x7C500400, // 019A CALL R20 2 + 0x5C4C2800, // 019B MOVE R19 R20 + 0x8C500943, // 019C GETMET R20 R4 K67 + 0x7C500200, // 019D CALL R20 1 + 0x8C542144, // 019E GETMET R21 R16 K68 + 0x7C540200, // 019F CALL R21 1 + 0x8C542B45, // 01A0 GETMET R21 R21 K69 + 0x7C540200, // 01A1 CALL R21 1 + 0x8C582946, // 01A2 GETMET R22 R20 K70 + 0x5C602400, // 01A3 MOVE R24 R18 + 0x5C642A00, // 01A4 MOVE R25 R21 + 0x5C682600, // 01A5 MOVE R26 R19 + 0x546E0007, // 01A6 LDINT R27 8 + 0x7C580A00, // 01A7 CALL R22 5 + 0x885C0312, // 01A8 GETMBR R23 R1 K18 + 0x785E0001, // 01A9 JMPF R23 #01AC + 0x885C0312, // 01AA GETMBR R23 R1 K18 + 0x70020001, // 01AB JMP #01AE + 0x885C0116, // 01AC GETMBR R23 R0 K22 + 0x885C2F47, // 01AD GETMBR R23 R23 K71 + 0x8C601B48, // 01AE GETMET R24 R13 K72 + 0x5C682000, // 01AF MOVE R26 R16 + 0x5C6C2200, // 01B0 MOVE R27 R17 + 0x5C702C00, // 01B1 MOVE R28 R22 + 0x5C742E00, // 01B2 MOVE R29 R23 + 0x7C600A00, // 01B3 CALL R24 5 + 0x8C601B49, // 01B4 GETMET R24 R13 K73 + 0x7C600200, // 01B5 CALL R24 1 + 0x88600116, // 01B6 GETMBR R24 R0 K22 + 0x8C60314A, // 01B7 GETMET R24 R24 K74 + 0x5C681A00, // 01B8 MOVE R26 R13 + 0x7C600400, // 01B9 CALL R24 2 + 0x8C60034B, // 01BA GETMET R24 R1 K75 + 0x7C600200, // 01BB CALL R24 1 + 0x78620002, // 01BC JMPF R24 #01C0 + 0x8C60034C, // 01BD GETMET R24 R1 K76 + 0x546A003B, // 01BE LDINT R26 60 + 0x7C600400, // 01BF CALL R24 2 + 0x8C601B4D, // 01C0 GETMET R24 R13 K77 + 0x7C600200, // 01C1 CALL R24 1 + 0x8C600B09, // 01C2 GETMET R24 R5 K9 + 0x7C600200, // 01C3 CALL R24 1 + 0x8C64310A, // 01C4 GETMET R25 R24 K10 + 0x586C0005, // 01C5 LDCONST R27 K5 + 0x88700B0B, // 01C6 GETMBR R28 R5 K11 + 0xB8760200, // 01C7 GETNGBL R29 K1 + 0x88743B2B, // 01C8 GETMBR R29 R29 K43 + 0x7C640800, // 01C9 CALL R25 4 + 0x8C64310A, // 01CA GETMET R25 R24 K10 + 0x586C0007, // 01CB LDCONST R27 K7 + 0x88700B0B, // 01CC GETMBR R28 R5 K11 + 0x58740007, // 01CD LDCONST R29 K7 + 0x7C640800, // 01CE CALL R25 4 + 0x54660007, // 01CF LDINT R25 8 + 0x900E0819, // 01D0 SETMBR R3 K4 R25 + 0x80043000, // 01D1 RET 1 R24 + 0x70020056, // 01D2 JMP #022A + 0x54220008, // 01D3 LDINT R8 9 + 0x1C200E08, // 01D4 EQ R8 R7 R8 + 0x7822001E, // 01D5 JMPF R8 #01F5 + 0x8C200506, // 01D6 GETMET R8 R2 K6 + 0x58280005, // 01D7 LDCONST R10 K5 + 0x7C200400, // 01D8 CALL R8 2 + 0x8C24034E, // 01D9 GETMET R9 R1 K78 + 0x5C2C1000, // 01DA MOVE R11 R8 + 0x7C240400, // 01DB CALL R9 2 + 0xB8264400, // 01DC GETNGBL R9 K34 + 0x8C24132C, // 01DD GETMET R9 R9 K44 + 0x602C0018, // 01DE GETGBL R11 G24 + 0x5830004F, // 01DF LDCONST R12 K79 + 0x88340312, // 01E0 GETMBR R13 R1 K18 + 0x8C341B50, // 01E1 GETMET R13 R13 K80 + 0x7C340200, // 01E2 CALL R13 1 + 0x8C341B44, // 01E3 GETMET R13 R13 K68 + 0x7C340200, // 01E4 CALL R13 1 + 0x8C341B45, // 01E5 GETMET R13 R13 K69 + 0x7C340200, // 01E6 CALL R13 1 + 0x8C341B51, // 01E7 GETMET R13 R13 K81 + 0x7C340200, // 01E8 CALL R13 1 + 0x60380008, // 01E9 GETGBL R14 G8 + 0x5C3C1000, // 01EA MOVE R15 R8 + 0x7C380200, // 01EB CALL R14 1 + 0x7C2C0600, // 01EC CALL R11 3 + 0x58300010, // 01ED LDCONST R12 K16 + 0x7C240600, // 01EE CALL R9 3 + 0xB8260200, // 01EF GETNGBL R9 K1 + 0x8824132B, // 01F0 GETMBR R9 R9 K43 + 0x900E3409, // 01F1 SETMBR R3 K26 R9 + 0x4C240000, // 01F2 LDNIL R9 + 0x80041200, // 01F3 RET 1 R9 + 0x70020034, // 01F4 JMP #022A + 0x54220009, // 01F5 LDINT R8 10 + 0x1C200E08, // 01F6 EQ R8 R7 R8 + 0x78220031, // 01F7 JMPF R8 #022A + 0x8C200506, // 01F8 GETMET R8 R2 K6 + 0x58280005, // 01F9 LDCONST R10 K5 + 0x7C200400, // 01FA CALL R8 2 + 0x60240008, // 01FB GETGBL R9 G8 + 0x5C281000, // 01FC MOVE R10 R8 + 0x7C240200, // 01FD CALL R9 1 + 0x0026A409, // 01FE ADD R9 K82 R9 + 0x900E5809, // 01FF SETMBR R3 K44 R9 + 0x60240010, // 0200 GETGBL R9 G16 + 0x88280116, // 0201 GETMBR R10 R0 K22 + 0x88281530, // 0202 GETMBR R10 R10 K48 + 0x8C281553, // 0203 GETMET R10 R10 K83 + 0x7C280200, // 0204 CALL R10 1 + 0x7C240200, // 0205 CALL R9 1 + 0xA8020010, // 0206 EXBLK 0 #0218 + 0x5C281200, // 0207 MOVE R10 R9 + 0x7C280000, // 0208 CALL R10 0 + 0x8C2C1554, // 0209 GETMET R11 R10 K84 + 0x7C2C0200, // 020A CALL R11 1 + 0x1C2C1608, // 020B EQ R11 R11 R8 + 0x782E0008, // 020C JMPF R11 #0216 + 0xB82E4400, // 020D GETNGBL R11 K34 + 0x8C2C1755, // 020E GETMET R11 R11 K85 + 0x543607CF, // 020F LDINT R13 2000 + 0x84380000, // 0210 CLOSURE R14 P0 + 0x7C2C0600, // 0211 CALL R11 3 + 0x502C0200, // 0212 LDBOOL R11 1 0 + 0xA0000000, // 0213 CLOSE R0 + 0xA8040001, // 0214 EXBLK 1 1 + 0x80041600, // 0215 RET 1 R11 + 0xA0240000, // 0216 CLOSE R9 + 0x7001FFEE, // 0217 JMP #0207 + 0x58240056, // 0218 LDCONST R9 K86 + 0xAC240200, // 0219 CATCH R9 1 0 + 0xB0080000, // 021A RAISE 2 R0 R0 + 0xB8264400, // 021B GETNGBL R9 K34 + 0x8C24132C, // 021C GETMET R9 R9 K44 + 0x602C0008, // 021D GETGBL R11 G8 + 0x5C301000, // 021E MOVE R12 R8 + 0x7C2C0200, // 021F CALL R11 1 + 0x002EAE0B, // 0220 ADD R11 K87 R11 + 0x002C1758, // 0221 ADD R11 R11 K88 + 0x5830000E, // 0222 LDCONST R12 K14 + 0x7C240600, // 0223 CALL R9 3 + 0xB8260200, // 0224 GETNGBL R9 K1 + 0x88241359, // 0225 GETMBR R9 R9 K89 + 0x900E3409, // 0226 SETMBR R3 K26 R9 + 0x4C240000, // 0227 LDNIL R9 + 0xA0000000, // 0228 CLOSE R0 + 0x80041200, // 0229 RET 1 R9 + 0x7002009B, // 022A JMP #02C7 + 0x5422003B, // 022B LDINT R8 60 + 0x1C200C08, // 022C EQ R8 R6 R8 + 0x78220085, // 022D JMPF R8 #02B4 + 0x1C200F05, // 022E EQ R8 R7 K5 + 0x78220065, // 022F JMPF R8 #0296 + 0x8C200506, // 0230 GETMET R8 R2 K6 + 0x58280005, // 0231 LDCONST R10 K5 + 0x7C200400, // 0232 CALL R8 2 + 0x8C240506, // 0233 GETMET R9 R2 K6 + 0x582C0007, // 0234 LDCONST R11 K7 + 0x7C240400, // 0235 CALL R9 2 + 0x8C280506, // 0236 GETMET R10 R2 K6 + 0x5830000E, // 0237 LDCONST R12 K14 + 0x7C280400, // 0238 CALL R10 2 + 0x8C2C0506, // 0239 GETMET R11 R2 K6 + 0x58340010, // 023A LDCONST R13 K16 + 0x7C2C0400, // 023B CALL R11 2 + 0x8C300506, // 023C GETMET R12 R2 K6 + 0x543A0003, // 023D LDINT R14 4 + 0x7C300400, // 023E CALL R12 2 + 0xB8364400, // 023F GETNGBL R13 K34 + 0x8C341B2C, // 0240 GETMET R13 R13 K44 + 0x603C0018, // 0241 GETGBL R15 G24 + 0x5840005A, // 0242 LDCONST R16 K90 + 0x5C441000, // 0243 MOVE R17 R8 + 0x8C481351, // 0244 GETMET R18 R9 K81 + 0x7C480200, // 0245 CALL R18 1 + 0x5C4C1400, // 0246 MOVE R19 R10 + 0x5C501600, // 0247 MOVE R20 R11 + 0x8C541951, // 0248 GETMET R21 R12 K81 + 0x7C540200, // 0249 CALL R21 1 + 0x7C3C0C00, // 024A CALL R15 6 + 0x54420003, // 024B LDINT R16 4 + 0x7C340600, // 024C CALL R13 3 + 0x4C340000, // 024D LDNIL R13 + 0x1C34100D, // 024E EQ R13 R8 R13 + 0x7436000B, // 024F JMPT R13 #025C + 0x4C340000, // 0250 LDNIL R13 + 0x1C34120D, // 0251 EQ R13 R9 R13 + 0x74360008, // 0252 JMPT R13 #025C + 0x4C340000, // 0253 LDNIL R13 + 0x1C34140D, // 0254 EQ R13 R10 R13 + 0x74360005, // 0255 JMPT R13 #025C + 0x4C340000, // 0256 LDNIL R13 + 0x1C34160D, // 0257 EQ R13 R11 R13 + 0x74360002, // 0258 JMPT R13 #025C + 0x4C340000, // 0259 LDNIL R13 + 0x1C34180D, // 025A EQ R13 R12 R13 + 0x78360005, // 025B JMPF R13 #0262 + 0xB8360200, // 025C GETNGBL R13 K1 + 0x88341B5B, // 025D GETMBR R13 R13 K91 + 0x900E340D, // 025E SETMBR R3 K26 R13 + 0x4C340000, // 025F LDNIL R13 + 0xA0000000, // 0260 CLOSE R0 + 0x80041A00, // 0261 RET 1 R13 + 0x6034000C, // 0262 GETGBL R13 G12 + 0x5C381200, // 0263 MOVE R14 R9 + 0x7C340200, // 0264 CALL R13 1 + 0x543A001F, // 0265 LDINT R14 32 + 0x543E0040, // 0266 LDINT R15 65 + 0x00381C0F, // 0267 ADD R14 R14 R15 + 0x20341A0E, // 0268 NE R13 R13 R14 + 0x7436000B, // 0269 JMPT R13 #0276 + 0x6034000C, // 026A GETGBL R13 G12 + 0x5C381800, // 026B MOVE R14 R12 + 0x7C340200, // 026C CALL R13 1 + 0x543A000F, // 026D LDINT R14 16 + 0x14341A0E, // 026E LT R13 R13 R14 + 0x74360005, // 026F JMPT R13 #0276 + 0x6034000C, // 0270 GETGBL R13 G12 + 0x5C381800, // 0271 MOVE R14 R12 + 0x7C340200, // 0272 CALL R13 1 + 0x543A001F, // 0273 LDINT R14 32 + 0x24341A0E, // 0274 GT R13 R13 R14 + 0x7836000A, // 0275 JMPF R13 #0281 + 0xB8364400, // 0276 GETNGBL R13 K34 + 0x8C341B2C, // 0277 GETMET R13 R13 K44 + 0x583C005C, // 0278 LDCONST R15 K92 + 0x5840000E, // 0279 LDCONST R16 K14 + 0x7C340600, // 027A CALL R13 3 + 0xB8360200, // 027B GETNGBL R13 K1 + 0x88341B5D, // 027C GETMBR R13 R13 K93 + 0x900E340D, // 027D SETMBR R3 K26 R13 + 0x4C340000, // 027E LDNIL R13 + 0xA0000000, // 027F CLOSE R0 + 0x80041A00, // 0280 RET 1 R13 + 0x5436001E, // 0281 LDINT R13 31 + 0x40360A0D, // 0282 CONNECT R13 K5 R13 + 0x9434120D, // 0283 GETIDX R13 R9 R13 + 0x543A001F, // 0284 LDINT R14 32 + 0x40381D40, // 0285 CONNECT R14 R14 K64 + 0x9438120E, // 0286 GETIDX R14 R9 R14 + 0x883C0116, // 0287 GETMBR R15 R0 K22 + 0x8C3C1F5E, // 0288 GETMET R15 R15 K94 + 0x5C441000, // 0289 MOVE R17 R8 + 0x5C481600, // 028A MOVE R18 R11 + 0x5C4C1400, // 028B MOVE R19 R10 + 0x5C501800, // 028C MOVE R20 R12 + 0x5C541A00, // 028D MOVE R21 R13 + 0x5C581C00, // 028E MOVE R22 R14 + 0x8C5C035F, // 028F GETMET R23 R1 K95 + 0x7C5C0200, // 0290 CALL R23 1 + 0x7C3C1000, // 0291 CALL R15 8 + 0x503C0200, // 0292 LDBOOL R15 1 0 + 0xA0000000, // 0293 CLOSE R0 + 0x80041E00, // 0294 RET 1 R15 + 0x7002001C, // 0295 JMP #02B3 + 0x1C200F07, // 0296 EQ R8 R7 K7 + 0x78220012, // 0297 JMPF R8 #02AB + 0x8C200506, // 0298 GETMET R8 R2 K6 + 0x58280005, // 0299 LDCONST R10 K5 + 0x7C200400, // 029A CALL R8 2 + 0xB8264400, // 029B GETNGBL R9 K34 + 0x8C24132C, // 029C GETMET R9 R9 K44 + 0x602C0008, // 029D GETGBL R11 G8 + 0x5C301000, // 029E MOVE R12 R8 + 0x7C2C0200, // 029F CALL R11 1 + 0x002EC00B, // 02A0 ADD R11 K96 R11 + 0x58300010, // 02A1 LDCONST R12 K16 + 0x7C240600, // 02A2 CALL R9 3 + 0x88240116, // 02A3 GETMBR R9 R0 K22 + 0x8C241361, // 02A4 GETMET R9 R9 K97 + 0x5C2C1000, // 02A5 MOVE R11 R8 + 0x7C240400, // 02A6 CALL R9 2 + 0x50240200, // 02A7 LDBOOL R9 1 0 + 0xA0000000, // 02A8 CLOSE R0 + 0x80041200, // 02A9 RET 1 R9 + 0x70020007, // 02AA JMP #02B3 + 0x1C200F0E, // 02AB EQ R8 R7 K14 + 0x78220005, // 02AC JMPF R8 #02B3 + 0x88200116, // 02AD GETMBR R8 R0 K22 + 0x8C201162, // 02AE GETMET R8 R8 K98 + 0x7C200200, // 02AF CALL R8 1 + 0x50200200, // 02B0 LDBOOL R8 1 0 + 0xA0000000, // 02B1 CLOSE R0 + 0x80041000, // 02B2 RET 1 R8 + 0x70020012, // 02B3 JMP #02C7 + 0x54220029, // 02B4 LDINT R8 42 + 0x1C200C08, // 02B5 EQ R8 R6 R8 + 0x78220005, // 02B6 JMPF R8 #02BD + 0x1C200F05, // 02B7 EQ R8 R7 K5 + 0x78220002, // 02B8 JMPF R8 #02BC + 0x50200200, // 02B9 LDBOOL R8 1 0 + 0xA0000000, // 02BA CLOSE R0 + 0x80041000, // 02BB RET 1 R8 + 0x70020009, // 02BC JMP #02C7 + 0x60200003, // 02BD GETGBL R8 G3 + 0x5C240000, // 02BE MOVE R9 R0 + 0x7C200200, // 02BF CALL R8 1 + 0x8C201163, // 02C0 GETMET R8 R8 K99 + 0x5C280200, // 02C1 MOVE R10 R1 + 0x5C2C0400, // 02C2 MOVE R11 R2 + 0x5C300600, // 02C3 MOVE R12 R3 + 0x7C200800, // 02C4 CALL R8 4 + 0xA0000000, // 02C5 CLOSE R0 + 0x80041000, // 02C6 RET 1 R8 + 0xA0000000, // 02C7 CLOSE R0 + 0x80000000, // 02C8 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin_Root ********************************************************************/ @@ -2070,14 +2070,89 @@ be_local_class(Matter_Plugin_Root, &be_class_Matter_Plugin, be_nested_map(7, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(invoke_request, 2), be_const_closure(Matter_Plugin_Root_invoke_request_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Root_X20node) }, - { be_const_key_weak(CLUSTERS, 6), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(13, + { be_const_key_weak(read_attribute, 1), be_const_closure(Matter_Plugin_Root_read_attribute_closure) }, + { be_const_key_weak(invoke_request, 6), be_const_closure(Matter_Plugin_Root_invoke_request_closure) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(root) }, + { be_const_key_weak(TYPES, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(22, -1), be_const_int(1) }, + })) ) } )) }, + { be_const_key_weak(write_attribute, -1), be_const_closure(Matter_Plugin_Root_write_attribute_closure) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Root_X20node) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(15, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(60, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + })) ) } )) }, + { be_const_key_int(31, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(2), + be_const_int(3), + be_const_int(4), + })) ) } )) }, + { be_const_key_int(62, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + })) ) } )) }, + { be_const_key_int(48, 9), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(5, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + })) ) } )) }, + { be_const_key_int(49, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(3), + be_const_int(4), + be_const_int(65532), + })) ) } )) }, + { be_const_key_int(50, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(51, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(8), + })) ) } )) }, { be_const_key_int(52, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(0, ( (struct bvalue*) &(const bvalue[]) { + })) ) } )) }, + { be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(63, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(0, + ( (struct bvalue*) &(const bvalue[]) { })) ) } )) }, { be_const_key_int(40, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(15, @@ -2098,33 +2173,17 @@ be_local_class(Matter_Plugin_Root, be_const_int(18), be_const_int(19), })) ) } )) }, - { be_const_key_int(62, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(6, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(1), - be_const_int(2), - be_const_int(3), - be_const_int(4), - be_const_int(5), - })) ) } )) }, - { be_const_key_int(63, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(0, - ( (struct bvalue*) &(const bvalue[]) { - })) ) } )) }, - { be_const_key_int(56, 6), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(56, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(3, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), be_const_int(1), be_const_int(7), })) ) } )) }, - { be_const_key_int(44, 7), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(3, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(1), - be_const_int(2), + be_const_int(17), })) ) } )) }, { be_const_key_int(43, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(2, @@ -2132,58 +2191,14 @@ be_local_class(Matter_Plugin_Root, be_const_int(0), be_const_int(1), })) ) } )) }, - { be_const_key_int(31, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(4, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(2), - be_const_int(3), - be_const_int(4), - })) ) } )) }, - { be_const_key_int(60, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(44, 8), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(3, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), be_const_int(1), be_const_int(2), })) ) } )) }, - { be_const_key_int(48, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(5, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(1), - be_const_int(2), - be_const_int(3), - be_const_int(4), })) ) } )) }, - { be_const_key_int(49, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(3, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(3), - be_const_int(4), - be_const_int(65532), - })) ) } )) }, - { be_const_key_int(50, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(0, - ( (struct bvalue*) &(const bvalue[]) { - })) ) } )) }, - { be_const_key_int(51, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(4, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(1), - be_const_int(2), - be_const_int(8), - })) ) } )) }, - })) ) } )) }, - { be_const_key_weak(TYPES, 5), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(22, -1), be_const_int(1) }, - })) ) } )) }, - { be_const_key_weak(write_attribute, -1), be_const_closure(Matter_Plugin_Root_write_attribute_closure) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(root) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Root_read_attribute_closure) }, })), be_str_weak(Matter_Plugin_Root) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Aggregator.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Aggregator.h similarity index 92% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Aggregator.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Aggregator.h index f681758cc..af4ea7333 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Aggregator.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Aggregator.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Aggregator.h */ +/* Solidification of Matter_Plugin_2_Aggregator.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -106,14 +106,14 @@ be_local_class(Matter_Plugin_Aggregator, &be_class_Matter_Plugin, be_nested_map(4, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(NAME, 3), be_nested_str_weak(Aggregator) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(aggregator) }, - { be_const_key_weak(TYPES, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(14, -1), be_const_int(1) }, })) ) } )) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Aggregator_read_attribute_closure) }, + { be_const_key_weak(TYPE, 3), be_nested_str_weak(aggregator) }, + { be_const_key_weak(read_attribute, 0), be_const_closure(Matter_Plugin_Aggregator_read_attribute_closure) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Aggregator) }, })), be_str_weak(Matter_Plugin_Aggregator) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_HTTP.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Bridge_HTTP.h similarity index 96% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_HTTP.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Bridge_HTTP.h index 32305eea5..418f03eae 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_HTTP.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Bridge_HTTP.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_HTTP.h */ +/* Solidification of Matter_Plugin_2_Bridge_HTTP.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -226,125 +226,6 @@ void be_load_GetOptionReader_class(bvm *vm) { extern const bclass be_class_Matter_Plugin_Bridge_HTTP; -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_HTTP_init, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(init), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(ARG_HTTP), - /* K3 */ be_nested_str_weak(http_remote), - /* K4 */ be_nested_str_weak(device), - /* K5 */ be_nested_str_weak(register_http_remote), - /* K6 */ be_nested_str_weak(PROBE_TIMEOUT), - /* K7 */ be_nested_str_weak(register_cmd_cb), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[20]) { /* code */ - 0x60100003, // 0000 GETGBL R4 G3 - 0x5C140000, // 0001 MOVE R5 R0 - 0x7C100200, // 0002 CALL R4 1 - 0x8C100900, // 0003 GETMET R4 R4 K0 - 0x5C180200, // 0004 MOVE R6 R1 - 0x5C1C0400, // 0005 MOVE R7 R2 - 0x5C200600, // 0006 MOVE R8 R3 - 0x7C100800, // 0007 CALL R4 4 - 0x8C100701, // 0008 GETMET R4 R3 K1 - 0x88180102, // 0009 GETMBR R6 R0 K2 - 0x7C100400, // 000A CALL R4 2 - 0x88140104, // 000B GETMBR R5 R0 K4 - 0x8C140B05, // 000C GETMET R5 R5 K5 - 0x5C1C0800, // 000D MOVE R7 R4 - 0x88200106, // 000E GETMBR R8 R0 K6 - 0x7C140600, // 000F CALL R5 3 - 0x90020605, // 0010 SETMBR R0 K3 R5 - 0x8C140107, // 0011 GETMET R5 R0 K7 - 0x7C140200, // 0012 CALL R5 1 - 0x80000000, // 0013 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: every_250ms -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_HTTP_every_250ms, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(http_remote), - /* K1 */ be_nested_str_weak(scheduler), - }), - be_str_weak(every_250ms), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x80000000, // 0003 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: web_value_onoff -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_HTTP_web_value_onoff, /* name */ - be_nested_proto( - 3, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(_X3Cb_X3EOn_X3C_X2Fb_X3E), - /* K1 */ be_nested_str_weak(Off), - /* K2 */ be_nested_str_weak(), - }), - be_str_weak(web_value_onoff), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x4C080000, // 0000 LDNIL R2 - 0x20080202, // 0001 NE R2 R1 R2 - 0x780A0004, // 0002 JMPF R2 #0008 - 0x78060001, // 0003 JMPF R1 #0006 - 0x58080000, // 0004 LDCONST R2 K0 - 0x70020000, // 0005 JMP #0007 - 0x58080001, // 0006 LDCONST R2 K1 - 0x70020000, // 0007 JMP #0009 - 0x58080002, // 0008 LDCONST R2 K2 - 0x80040400, // 0009 RET 1 R2 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: call_remote_sync ********************************************************************/ @@ -426,11 +307,123 @@ be_local_closure(Matter_Plugin_Bridge_HTTP_call_remote_sync, /* name */ /******************************************************************** -** Solidified function: update_shadow +** Solidified function: web_value_onoff ********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_HTTP_update_shadow, /* name */ +be_local_closure(Matter_Plugin_Bridge_HTTP_web_value_onoff, /* name */ be_nested_proto( - 7, /* nstack */ + 3, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(_X3Cb_X3EOn_X3C_X2Fb_X3E), + /* K1 */ be_nested_str_weak(Off), + /* K2 */ be_nested_str_weak(), + }), + be_str_weak(web_value_onoff), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x4C080000, // 0000 LDNIL R2 + 0x20080202, // 0001 NE R2 R1 R2 + 0x780A0004, // 0002 JMPF R2 #0008 + 0x78060001, // 0003 JMPF R1 #0006 + 0x58080000, // 0004 LDCONST R2 K0 + 0x70020000, // 0005 JMP #0007 + 0x58080001, // 0006 LDCONST R2 K1 + 0x70020000, // 0007 JMP #0009 + 0x58080002, // 0008 LDCONST R2 K2 + 0x80040400, // 0009 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_http_response +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_HTTP_parse_http_response, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(http_remote), + /* K2 */ be_nested_str_weak(device_is_alive), + /* K3 */ be_nested_str_weak(device), + /* K4 */ be_nested_str_weak(tick), + /* K5 */ be_nested_str_weak(json), + /* K6 */ be_nested_str_weak(load), + /* K7 */ be_nested_str_weak(contains), + /* K8 */ be_nested_str_weak(StatusSNS), + /* K9 */ be_nested_str_weak(StatusSTS), + /* K10 */ be_nested_str_weak(StatusSHT), + /* K11 */ be_nested_str_weak(parse_update), + }), + be_str_weak(parse_http_response), + &be_const_str_solidified, + ( &(const binstruction[39]) { /* code */ + 0x24100300, // 0000 GT R4 R1 K0 + 0x78120023, // 0001 JMPF R4 #0026 + 0x88100101, // 0002 GETMBR R4 R0 K1 + 0x8C100902, // 0003 GETMET R4 R4 K2 + 0x50180200, // 0004 LDBOOL R6 1 0 + 0x7C100400, // 0005 CALL R4 2 + 0x88100103, // 0006 GETMBR R4 R0 K3 + 0x88100904, // 0007 GETMBR R4 R4 K4 + 0xA4160A00, // 0008 IMPORT R5 K5 + 0x8C180B06, // 0009 GETMET R6 R5 K6 + 0x5C200400, // 000A MOVE R8 R2 + 0x7C180400, // 000B CALL R6 2 + 0x4C1C0000, // 000C LDNIL R7 + 0x781A0017, // 000D JMPF R6 #0026 + 0x8C200D07, // 000E GETMET R8 R6 K7 + 0x58280008, // 000F LDCONST R10 K8 + 0x7C200400, // 0010 CALL R8 2 + 0x78220002, // 0011 JMPF R8 #0015 + 0x94180D08, // 0012 GETIDX R6 R6 K8 + 0x541E0007, // 0013 LDINT R7 8 + 0x7002000C, // 0014 JMP #0022 + 0x8C200D07, // 0015 GETMET R8 R6 K7 + 0x58280009, // 0016 LDCONST R10 K9 + 0x7C200400, // 0017 CALL R8 2 + 0x78220002, // 0018 JMPF R8 #001C + 0x94180D09, // 0019 GETIDX R6 R6 K9 + 0x541E000A, // 001A LDINT R7 11 + 0x70020005, // 001B JMP #0022 + 0x8C200D07, // 001C GETMET R8 R6 K7 + 0x5828000A, // 001D LDCONST R10 K10 + 0x7C200400, // 001E CALL R8 2 + 0x78220001, // 001F JMPF R8 #0022 + 0x94180D09, // 0020 GETIDX R6 R6 K9 + 0x541E000C, // 0021 LDINT R7 13 + 0x8C20010B, // 0022 GETMET R8 R0 K11 + 0x5C280C00, // 0023 MOVE R10 R6 + 0x5C2C0E00, // 0024 MOVE R11 R7 + 0x7C200600, // 0025 CALL R8 3 + 0x80000000, // 0026 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: web_values +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_HTTP_web_values, /* name */ + be_nested_proto( + 5, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -439,29 +432,25 @@ be_local_closure(Matter_Plugin_Bridge_HTTP_update_shadow, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(tick), - /* K1 */ be_nested_str_weak(device), - /* K2 */ be_nested_str_weak(call_remote_sync), - /* K3 */ be_nested_str_weak(UPDATE_CMD), - /* K4 */ be_nested_str_weak(parse_http_response), - /* K5 */ be_const_int(1), + /* K0 */ be_nested_str_weak(webserver), + /* K1 */ be_nested_str_weak(web_values_prefix), + /* K2 */ be_nested_str_weak(content_send), + /* K3 */ be_nested_str_weak(_X26lt_X3B_X2D_X2D_X20_X28), + /* K4 */ be_nested_str_weak(DISPLAY_NAME), + /* K5 */ be_nested_str_weak(_X29_X20_X2D_X2D_X26gt_X3B), }), - be_str_weak(update_shadow), + be_str_weak(web_values), &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x88040101, // 0000 GETMBR R1 R0 K1 - 0x88040300, // 0001 GETMBR R1 R1 K0 - 0x90020001, // 0002 SETMBR R0 K0 R1 - 0x8C040102, // 0003 GETMET R1 R0 K2 - 0x880C0103, // 0004 GETMBR R3 R0 K3 - 0x7C040400, // 0005 CALL R1 2 - 0x78060004, // 0006 JMPF R1 #000C - 0x8C080104, // 0007 GETMET R2 R0 K4 - 0x58100005, // 0008 LDCONST R4 K5 - 0x5C140200, // 0009 MOVE R5 R1 - 0x88180103, // 000A GETMBR R6 R0 K3 - 0x7C080800, // 000B CALL R2 4 - 0x80000000, // 000C RET 0 + ( &(const binstruction[ 9]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080101, // 0001 GETMET R2 R0 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x88100104, // 0004 GETMBR R4 R0 K4 + 0x00120604, // 0005 ADD R4 K3 R4 + 0x00100905, // 0006 ADD R4 R4 K5 + 0x7C080400, // 0007 CALL R2 2 + 0x80000000, // 0008 RET 0 }) ) ); @@ -493,6 +482,58 @@ be_local_closure(Matter_Plugin_Bridge_HTTP_is_local_device, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_HTTP_init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(ARG_HTTP), + /* K3 */ be_nested_str_weak(http_remote), + /* K4 */ be_nested_str_weak(device), + /* K5 */ be_nested_str_weak(register_http_remote), + /* K6 */ be_nested_str_weak(PROBE_TIMEOUT), + /* K7 */ be_nested_str_weak(register_cmd_cb), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x60100003, // 0000 GETGBL R4 G3 + 0x5C140000, // 0001 MOVE R5 R0 + 0x7C100200, // 0002 CALL R4 1 + 0x8C100900, // 0003 GETMET R4 R4 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x5C1C0400, // 0005 MOVE R7 R2 + 0x5C200600, // 0006 MOVE R8 R3 + 0x7C100800, // 0007 CALL R4 4 + 0x8C100701, // 0008 GETMET R4 R3 K1 + 0x88180102, // 0009 GETMBR R6 R0 K2 + 0x7C100400, // 000A CALL R4 2 + 0x88140104, // 000B GETMBR R5 R0 K4 + 0x8C140B05, // 000C GETMET R5 R5 K5 + 0x5C1C0800, // 000D MOVE R7 R4 + 0x88200106, // 000E GETMBR R8 R0 K6 + 0x7C140600, // 000F CALL R5 3 + 0x90020605, // 0010 SETMBR R0 K3 R5 + 0x8C140107, // 0011 GETMET R5 R0 K7 + 0x7C140200, // 0012 CALL R5 1 + 0x80000000, // 0013 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: parse_update ********************************************************************/ @@ -517,51 +558,6 @@ be_local_closure(Matter_Plugin_Bridge_HTTP_parse_update, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: web_values_prefix -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_HTTP_web_values_prefix, /* name */ - be_nested_proto( - 10, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str_weak(webserver), - /* K1 */ be_nested_str_weak(get_name), - /* K2 */ be_nested_str_weak(content_send), - /* K3 */ be_nested_str_weak(PREFIX), - /* K4 */ be_nested_str_weak(html_escape), - /* K5 */ be_nested_str_weak(), - }), - be_str_weak(web_values_prefix), - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080101, // 0001 GETMET R2 R0 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x8C0C0302, // 0003 GETMET R3 R1 K2 - 0x60140018, // 0004 GETGBL R5 G24 - 0x88180103, // 0005 GETMBR R6 R0 K3 - 0x780A0003, // 0006 JMPF R2 #000B - 0x8C1C0304, // 0007 GETMET R7 R1 K4 - 0x5C240400, // 0008 MOVE R9 R2 - 0x7C1C0400, // 0009 CALL R7 2 - 0x70020000, // 000A JMP #000C - 0x581C0005, // 000B LDCONST R7 K5 - 0x7C140400, // 000C CALL R5 2 - 0x7C0C0400, // 000D CALL R3 2 - 0x80000000, // 000E RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -723,11 +719,11 @@ be_local_closure(Matter_Plugin_Bridge_HTTP_read_attribute, /* name */ /******************************************************************** -** Solidified function: web_values +** Solidified function: web_values_prefix ********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_HTTP_web_values, /* name */ +be_local_closure(Matter_Plugin_Bridge_HTTP_web_values_prefix, /* name */ be_nested_proto( - 5, /* nstack */ + 10, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -737,99 +733,30 @@ be_local_closure(Matter_Plugin_Bridge_HTTP_web_values, /* name */ 1, /* has constants */ ( &(const bvalue[ 6]) { /* constants */ /* K0 */ be_nested_str_weak(webserver), - /* K1 */ be_nested_str_weak(web_values_prefix), + /* K1 */ be_nested_str_weak(get_name), /* K2 */ be_nested_str_weak(content_send), - /* K3 */ be_nested_str_weak(_X26lt_X3B_X2D_X2D_X20_X28), - /* K4 */ be_nested_str_weak(NAME), - /* K5 */ be_nested_str_weak(_X29_X20_X2D_X2D_X26gt_X3B), + /* K3 */ be_nested_str_weak(PREFIX), + /* K4 */ be_nested_str_weak(html_escape), + /* K5 */ be_nested_str_weak(), }), - be_str_weak(web_values), + be_str_weak(web_values_prefix), &be_const_str_solidified, - ( &(const binstruction[ 9]) { /* code */ + ( &(const binstruction[15]) { /* code */ 0xA4060000, // 0000 IMPORT R1 K0 0x8C080101, // 0001 GETMET R2 R0 K1 0x7C080200, // 0002 CALL R2 1 - 0x8C080302, // 0003 GETMET R2 R1 K2 - 0x88100104, // 0004 GETMBR R4 R0 K4 - 0x00120604, // 0005 ADD R4 K3 R4 - 0x00100905, // 0006 ADD R4 R4 K5 - 0x7C080400, // 0007 CALL R2 2 - 0x80000000, // 0008 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: parse_http_response -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_HTTP_parse_http_response, /* name */ - be_nested_proto( - 12, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str_weak(http_remote), - /* K2 */ be_nested_str_weak(device_is_alive), - /* K3 */ be_nested_str_weak(device), - /* K4 */ be_nested_str_weak(tick), - /* K5 */ be_nested_str_weak(json), - /* K6 */ be_nested_str_weak(load), - /* K7 */ be_nested_str_weak(contains), - /* K8 */ be_nested_str_weak(StatusSNS), - /* K9 */ be_nested_str_weak(StatusSTS), - /* K10 */ be_nested_str_weak(StatusSHT), - /* K11 */ be_nested_str_weak(parse_update), - }), - be_str_weak(parse_http_response), - &be_const_str_solidified, - ( &(const binstruction[39]) { /* code */ - 0x24100300, // 0000 GT R4 R1 K0 - 0x78120023, // 0001 JMPF R4 #0026 - 0x88100101, // 0002 GETMBR R4 R0 K1 - 0x8C100902, // 0003 GETMET R4 R4 K2 - 0x50180200, // 0004 LDBOOL R6 1 0 - 0x7C100400, // 0005 CALL R4 2 - 0x88100103, // 0006 GETMBR R4 R0 K3 - 0x88100904, // 0007 GETMBR R4 R4 K4 - 0xA4160A00, // 0008 IMPORT R5 K5 - 0x8C180B06, // 0009 GETMET R6 R5 K6 - 0x5C200400, // 000A MOVE R8 R2 - 0x7C180400, // 000B CALL R6 2 - 0x4C1C0000, // 000C LDNIL R7 - 0x781A0017, // 000D JMPF R6 #0026 - 0x8C200D07, // 000E GETMET R8 R6 K7 - 0x58280008, // 000F LDCONST R10 K8 - 0x7C200400, // 0010 CALL R8 2 - 0x78220002, // 0011 JMPF R8 #0015 - 0x94180D08, // 0012 GETIDX R6 R6 K8 - 0x541E0007, // 0013 LDINT R7 8 - 0x7002000C, // 0014 JMP #0022 - 0x8C200D07, // 0015 GETMET R8 R6 K7 - 0x58280009, // 0016 LDCONST R10 K9 - 0x7C200400, // 0017 CALL R8 2 - 0x78220002, // 0018 JMPF R8 #001C - 0x94180D09, // 0019 GETIDX R6 R6 K9 - 0x541E000A, // 001A LDINT R7 11 - 0x70020005, // 001B JMP #0022 - 0x8C200D07, // 001C GETMET R8 R6 K7 - 0x5828000A, // 001D LDCONST R10 K10 - 0x7C200400, // 001E CALL R8 2 - 0x78220001, // 001F JMPF R8 #0022 - 0x94180D09, // 0020 GETIDX R6 R6 K9 - 0x541E000C, // 0021 LDINT R7 13 - 0x8C20010B, // 0022 GETMET R8 R0 K11 - 0x5C280C00, // 0023 MOVE R10 R6 - 0x5C2C0E00, // 0024 MOVE R11 R7 - 0x7C200600, // 0025 CALL R8 3 - 0x80000000, // 0026 RET 0 + 0x8C0C0302, // 0003 GETMET R3 R1 K2 + 0x60140018, // 0004 GETGBL R5 G24 + 0x88180103, // 0005 GETMBR R6 R0 K3 + 0x780A0003, // 0006 JMPF R2 #000B + 0x8C1C0304, // 0007 GETMET R7 R1 K4 + 0x5C240400, // 0008 MOVE R9 R2 + 0x7C1C0400, // 0009 CALL R7 2 + 0x70020000, // 000A JMP #000C + 0x581C0005, // 000B LDCONST R7 K5 + 0x7C140400, // 000C CALL R5 2 + 0x7C0C0400, // 000D CALL R3 2 + 0x80000000, // 000E RET 0 }) ) ); @@ -899,6 +826,79 @@ be_local_closure(Matter_Plugin_Bridge_HTTP_register_cmd_cb, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_HTTP_update_shadow, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(tick), + /* K1 */ be_nested_str_weak(device), + /* K2 */ be_nested_str_weak(call_remote_sync), + /* K3 */ be_nested_str_weak(UPDATE_CMD), + /* K4 */ be_nested_str_weak(parse_http_response), + /* K5 */ be_const_int(1), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x88040101, // 0000 GETMBR R1 R0 K1 + 0x88040300, // 0001 GETMBR R1 R1 K0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x8C040102, // 0003 GETMET R1 R0 K2 + 0x880C0103, // 0004 GETMBR R3 R0 K3 + 0x7C040400, // 0005 CALL R1 2 + 0x78060004, // 0006 JMPF R1 #000C + 0x8C080104, // 0007 GETMET R2 R0 K4 + 0x58100005, // 0008 LDCONST R4 K5 + 0x5C140200, // 0009 MOVE R5 R1 + 0x88180103, // 000A GETMBR R6 R0 K3 + 0x7C080800, // 000B CALL R2 4 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: every_250ms +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_HTTP_every_250ms, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(http_remote), + /* K1 */ be_nested_str_weak(scheduler), + }), + be_str_weak(every_250ms), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x7C040200, // 0002 CALL R1 1 + 0x80000000, // 0003 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin_Bridge_HTTP ********************************************************************/ @@ -906,35 +906,31 @@ extern const bclass be_class_Matter_Plugin_Device; be_local_class(Matter_Plugin_Bridge_HTTP, 1, &be_class_Matter_Plugin_Device, - be_nested_map(24, + be_nested_map(23, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ARG_HTTP, 23), be_nested_str_weak(url) }, - { be_const_key_weak(register_cmd_cb, 11), be_const_closure(Matter_Plugin_Bridge_HTTP_register_cmd_cb_closure) }, - { be_const_key_weak(SYNC_TIMEOUT, -1), be_const_int(500) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_init_closure) }, - { be_const_key_weak(http_remote, -1), be_const_var(0) }, - { be_const_key_weak(GetOptionReader, 1), be_const_class(be_class_GetOptionReader) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak() }, - { be_const_key_weak(CLUSTERS, 21), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(0, - ( (struct bmapnode*) &(const bmapnode[]) { - })) ) } )) }, - { be_const_key_weak(every_250ms, 12), be_const_closure(Matter_Plugin_Bridge_HTTP_every_250ms_closure) }, - { be_const_key_weak(PREFIX, -1), be_nested_str_weak(_X7C_X20_X3Ci_X3E_X25s_X3C_X2Fi_X3E_X20) }, - { be_const_key_weak(web_value_onoff, 7), be_const_closure(Matter_Plugin_Bridge_HTTP_web_value_onoff_closure) }, - { be_const_key_weak(parse_http_response, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_parse_http_response_closure) }, - { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_web_values_closure) }, - { be_const_key_weak(TYPE, 20), be_nested_str_weak() }, { be_const_key_weak(UPDATE_CMD, -1), be_nested_str_weak(Status_X2011) }, - { be_const_key_weak(ARG, 14), be_nested_str_weak() }, - { be_const_key_weak(is_local_device, 19), be_const_closure(Matter_Plugin_Bridge_HTTP_is_local_device_closure) }, - { be_const_key_weak(web_values_prefix, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_web_values_prefix_closure) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_read_attribute_closure) }, - { be_const_key_weak(parse_update, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_parse_update_closure) }, - { be_const_key_weak(update_shadow, 22), be_const_closure(Matter_Plugin_Bridge_HTTP_update_shadow_closure) }, - { be_const_key_weak(call_remote_sync, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_call_remote_sync_closure) }, - { be_const_key_weak(PROBE_TIMEOUT, -1), be_const_int(1700) }, + { be_const_key_weak(every_250ms, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_every_250ms_closure) }, + { be_const_key_weak(ARG, -1), be_nested_str_weak() }, + { be_const_key_weak(call_remote_sync, 22), be_const_closure(Matter_Plugin_Bridge_HTTP_call_remote_sync_closure) }, + { be_const_key_weak(web_value_onoff, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_web_value_onoff_closure) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_update_shadow_closure) }, { be_const_key_weak(UPDATE_TIME, -1), be_const_int(3000) }, + { be_const_key_weak(GetOptionReader, 5), be_const_class(be_class_GetOptionReader) }, + { be_const_key_weak(parse_http_response, 21), be_const_closure(Matter_Plugin_Bridge_HTTP_parse_http_response_closure) }, + { be_const_key_weak(parse_update, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_parse_update_closure) }, + { be_const_key_weak(SYNC_TIMEOUT, 18), be_const_int(500) }, + { be_const_key_weak(is_local_device, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_is_local_device_closure) }, + { be_const_key_weak(PREFIX, 17), be_nested_str_weak(_X7C_X20_X3Ci_X3E_X25s_X3C_X2Fi_X3E_X20) }, + { be_const_key_weak(http_remote, 1), be_const_var(0) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_init_closure) }, + { be_const_key_weak(ARG_HTTP, -1), be_nested_str_weak(url) }, + { be_const_key_weak(DISPLAY_NAME, 9), be_nested_str_weak() }, + { be_const_key_weak(web_values_prefix, 19), be_const_closure(Matter_Plugin_Bridge_HTTP_web_values_prefix_closure) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_read_attribute_closure) }, + { be_const_key_weak(PROBE_TIMEOUT, -1), be_const_int(1700) }, + { be_const_key_weak(register_cmd_cb, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_register_cmd_cb_closure) }, + { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_HTTP_web_values_closure) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak() }, })), be_str_weak(Matter_Plugin_Bridge_HTTP) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Light0.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Light0.h new file mode 100644 index 000000000..bd25d7a01 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Light0.h @@ -0,0 +1,511 @@ +/* Solidification of Matter_Plugin_2_Light0.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Light0; + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_read_attribute, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(attribute), + /* K4 */ be_nested_str_weak(update_shadow_lazy), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(set), + /* K7 */ be_nested_str_weak(BOOL), + /* K8 */ be_nested_str_weak(shadow_onoff), + /* K9 */ be_nested_str_weak(U4), + /* K10 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[45]) { /* code */ + 0xB8120000, // 0000 GETNGBL R4 K0 + 0x88100901, // 0001 GETMBR R4 R4 K1 + 0x88140502, // 0002 GETMBR R5 R2 K2 + 0x88180503, // 0003 GETMBR R6 R2 K3 + 0x541E0005, // 0004 LDINT R7 6 + 0x1C1C0A07, // 0005 EQ R7 R5 R7 + 0x781E001B, // 0006 JMPF R7 #0023 + 0x8C1C0104, // 0007 GETMET R7 R0 K4 + 0x7C1C0200, // 0008 CALL R7 1 + 0x1C1C0D05, // 0009 EQ R7 R6 K5 + 0x781E0005, // 000A JMPF R7 #0011 + 0x8C1C0706, // 000B GETMET R7 R3 K6 + 0x88240907, // 000C GETMBR R9 R4 K7 + 0x88280108, // 000D GETMBR R10 R0 K8 + 0x7C1C0600, // 000E CALL R7 3 + 0x80040E00, // 000F RET 1 R7 + 0x70020010, // 0010 JMP #0022 + 0x541EFFFB, // 0011 LDINT R7 65532 + 0x1C1C0C07, // 0012 EQ R7 R6 R7 + 0x781E0005, // 0013 JMPF R7 #001A + 0x8C1C0706, // 0014 GETMET R7 R3 K6 + 0x88240909, // 0015 GETMBR R9 R4 K9 + 0x58280005, // 0016 LDCONST R10 K5 + 0x7C1C0600, // 0017 CALL R7 3 + 0x80040E00, // 0018 RET 1 R7 + 0x70020007, // 0019 JMP #0022 + 0x541EFFFC, // 001A LDINT R7 65533 + 0x1C1C0C07, // 001B EQ R7 R6 R7 + 0x781E0004, // 001C JMPF R7 #0022 + 0x8C1C0706, // 001D GETMET R7 R3 K6 + 0x88240909, // 001E GETMBR R9 R4 K9 + 0x542A0003, // 001F LDINT R10 4 + 0x7C1C0600, // 0020 CALL R7 3 + 0x80040E00, // 0021 RET 1 R7 + 0x70020008, // 0022 JMP #002C + 0x601C0003, // 0023 GETGBL R7 G3 + 0x5C200000, // 0024 MOVE R8 R0 + 0x7C1C0200, // 0025 CALL R7 1 + 0x8C1C0F0A, // 0026 GETMET R7 R7 K10 + 0x5C240200, // 0027 MOVE R9 R1 + 0x5C280400, // 0028 MOVE R10 R2 + 0x5C2C0600, // 0029 MOVE R11 R3 + 0x7C1C0800, // 002A CALL R7 4 + 0x80040E00, // 002B RET 1 R7 + 0x80000000, // 002C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_onoff +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_set_onoff, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(VIRTUAL), + /* K1 */ be_nested_str_weak(light), + /* K2 */ be_nested_str_weak(set), + /* K3 */ be_nested_str_weak(power), + /* K4 */ be_nested_str_weak(update_shadow), + /* K5 */ be_nested_str_weak(shadow_onoff), + /* K6 */ be_nested_str_weak(attribute_updated), + /* K7 */ be_const_int(0), + }), + be_str_weak(set_onoff), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x740A0008, // 0001 JMPT R2 #000B + 0xA40A0200, // 0002 IMPORT R2 K1 + 0x8C0C0502, // 0003 GETMET R3 R2 K2 + 0x60140013, // 0004 GETGBL R5 G19 + 0x7C140000, // 0005 CALL R5 0 + 0x98160601, // 0006 SETIDX R5 K3 R1 + 0x7C0C0400, // 0007 CALL R3 2 + 0x8C0C0104, // 0008 GETMET R3 R0 K4 + 0x7C0C0200, // 0009 CALL R3 1 + 0x70020007, // 000A JMP #0013 + 0x88080105, // 000B GETMBR R2 R0 K5 + 0x20080202, // 000C NE R2 R1 R2 + 0x780A0004, // 000D JMPF R2 #0013 + 0x8C080106, // 000E GETMET R2 R0 K6 + 0x54120005, // 000F LDINT R4 6 + 0x58140007, // 0010 LDCONST R5 K7 + 0x7C080600, // 0011 CALL R2 3 + 0x90020A01, // 0012 SETMBR R0 K5 R1 + 0x80000000, // 0013 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_virtual +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_update_virtual, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(find), + /* K1 */ be_nested_str_weak(Power), + /* K2 */ be_nested_str_weak(set_onoff), + /* K3 */ be_nested_str_weak(update_virtual), + }), + be_str_weak(update_virtual), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x8C080300, // 0000 GETMET R2 R1 K0 + 0x58100001, // 0001 LDCONST R4 K1 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x200C0403, // 0004 NE R3 R2 R3 + 0x780E0004, // 0005 JMPF R3 #000B + 0x8C0C0102, // 0006 GETMET R3 R0 K2 + 0x60140017, // 0007 GETGBL R5 G23 + 0x5C180400, // 0008 MOVE R6 R2 + 0x7C140200, // 0009 CALL R5 1 + 0x7C0C0400, // 000A CALL R3 2 + 0x600C0003, // 000B GETGBL R3 G3 + 0x5C100000, // 000C MOVE R4 R0 + 0x7C0C0200, // 000D CALL R3 1 + 0x8C0C0703, // 000E GETMET R3 R3 K3 + 0x5C140200, // 000F MOVE R5 R1 + 0x7C0C0400, // 0010 CALL R3 2 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(shadow_onoff), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x60100003, // 0000 GETGBL R4 G3 + 0x5C140000, // 0001 MOVE R5 R0 + 0x7C100200, // 0002 CALL R4 1 + 0x8C100900, // 0003 GETMET R4 R4 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x5C1C0400, // 0005 MOVE R7 R2 + 0x5C200600, // 0006 MOVE R8 R3 + 0x7C100800, // 0007 CALL R4 4 + 0x50100000, // 0008 LDBOOL R4 0 0 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_update_shadow, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(VIRTUAL), + /* K1 */ be_nested_str_weak(light), + /* K2 */ be_nested_str_weak(get), + /* K3 */ be_nested_str_weak(find), + /* K4 */ be_nested_str_weak(power), + /* K5 */ be_nested_str_weak(shadow_onoff), + /* K6 */ be_nested_str_weak(attribute_updated), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(update_shadow), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[26]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x74060011, // 0001 JMPT R1 #0014 + 0xA4060200, // 0002 IMPORT R1 K1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x7C080200, // 0004 CALL R2 1 + 0x4C0C0000, // 0005 LDNIL R3 + 0x200C0403, // 0006 NE R3 R2 R3 + 0x780E000B, // 0007 JMPF R3 #0014 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140004, // 0009 LDCONST R5 K4 + 0x4C180000, // 000A LDNIL R6 + 0x7C0C0600, // 000B CALL R3 3 + 0x88100105, // 000C GETMBR R4 R0 K5 + 0x20100604, // 000D NE R4 R3 R4 + 0x78120004, // 000E JMPF R4 #0014 + 0x8C100106, // 000F GETMET R4 R0 K6 + 0x541A0005, // 0010 LDINT R6 6 + 0x581C0007, // 0011 LDCONST R7 K7 + 0x7C100600, // 0012 CALL R4 3 + 0x90020A03, // 0013 SETMBR R0 K5 R3 + 0x60040003, // 0014 GETGBL R1 G3 + 0x5C080000, // 0015 MOVE R2 R0 + 0x7C040200, // 0016 CALL R1 1 + 0x8C040308, // 0017 GETMET R1 R1 K8 + 0x7C040200, // 0018 CALL R1 1 + 0x80000000, // 0019 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_invoke_request, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(light), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(command), + /* K5 */ be_nested_str_weak(update_shadow_lazy), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(set_onoff), + /* K8 */ be_nested_str_weak(publish_command), + /* K9 */ be_nested_str_weak(Power), + /* K10 */ be_const_int(1), + /* K11 */ be_const_int(2), + /* K12 */ be_nested_str_weak(shadow_onoff), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[53]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x54220005, // 0005 LDINT R8 6 + 0x1C200C08, // 0006 EQ R8 R6 R8 + 0x7822002B, // 0007 JMPF R8 #0034 + 0x8C200105, // 0008 GETMET R8 R0 K5 + 0x7C200200, // 0009 CALL R8 1 + 0x1C200F06, // 000A EQ R8 R7 K6 + 0x78220009, // 000B JMPF R8 #0016 + 0x8C200107, // 000C GETMET R8 R0 K7 + 0x50280000, // 000D LDBOOL R10 0 0 + 0x7C200400, // 000E CALL R8 2 + 0x8C200108, // 000F GETMET R8 R0 K8 + 0x58280009, // 0010 LDCONST R10 K9 + 0x582C0006, // 0011 LDCONST R11 K6 + 0x7C200600, // 0012 CALL R8 3 + 0x50200200, // 0013 LDBOOL R8 1 0 + 0x80041000, // 0014 RET 1 R8 + 0x7002001D, // 0015 JMP #0034 + 0x1C200F0A, // 0016 EQ R8 R7 K10 + 0x78220009, // 0017 JMPF R8 #0022 + 0x8C200107, // 0018 GETMET R8 R0 K7 + 0x50280200, // 0019 LDBOOL R10 1 0 + 0x7C200400, // 001A CALL R8 2 + 0x8C200108, // 001B GETMET R8 R0 K8 + 0x58280009, // 001C LDCONST R10 K9 + 0x582C000A, // 001D LDCONST R11 K10 + 0x7C200600, // 001E CALL R8 3 + 0x50200200, // 001F LDBOOL R8 1 0 + 0x80041000, // 0020 RET 1 R8 + 0x70020011, // 0021 JMP #0034 + 0x1C200F0B, // 0022 EQ R8 R7 K11 + 0x7822000F, // 0023 JMPF R8 #0034 + 0x8C200107, // 0024 GETMET R8 R0 K7 + 0x8828010C, // 0025 GETMBR R10 R0 K12 + 0x782A0000, // 0026 JMPF R10 #0028 + 0x50280001, // 0027 LDBOOL R10 0 1 + 0x50280200, // 0028 LDBOOL R10 1 0 + 0x7C200400, // 0029 CALL R8 2 + 0x8C200108, // 002A GETMET R8 R0 K8 + 0x58280009, // 002B LDCONST R10 K9 + 0x882C010C, // 002C GETMBR R11 R0 K12 + 0x782E0001, // 002D JMPF R11 #0030 + 0x582C000A, // 002E LDCONST R11 K10 + 0x70020000, // 002F JMP #0031 + 0x582C0006, // 0030 LDCONST R11 K6 + 0x7C200600, // 0031 CALL R8 3 + 0x50200200, // 0032 LDBOOL R8 1 0 + 0x80041000, // 0033 RET 1 R8 + 0x80000000, // 0034 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_val_i +********************************************************************/ +be_local_closure(Matter_Plugin_Light0_find_val_i, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 4, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_const_class(be_class_Matter_Plugin_Light0), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(find_key_i), + /* K3 */ be_nested_str_weak(find), + }), + be_str_weak(find_val_i), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x58080000, // 0000 LDCONST R2 K0 + 0xB80E0200, // 0001 GETNGBL R3 K1 + 0x8C0C0702, // 0002 GETMET R3 R3 K2 + 0x5C140000, // 0003 MOVE R5 R0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x7C0C0600, // 0005 CALL R3 3 + 0x8C100103, // 0006 GETMET R4 R0 K3 + 0x5C180600, // 0007 MOVE R6 R3 + 0x7C100400, // 0008 CALL R4 2 + 0x80040800, // 0009 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Light0 +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Device; +be_local_class(Matter_Plugin_Light0, + 1, + &be_class_Matter_Plugin_Device, + be_nested_map(14, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(read_attribute, 9), be_const_closure(Matter_Plugin_Light0_read_attribute_closure) }, + { be_const_key_weak(UPDATE_TIME, 4), be_const_int(250) }, + { be_const_key_weak(update_virtual, 1), be_const_closure(Matter_Plugin_Light0_update_virtual_closure) }, + { be_const_key_weak(UPDATE_COMMANDS, 13), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Power), + })) ) } )) }, + { be_const_key_weak(find_val_i, -1), be_const_static_closure(Matter_Plugin_Light0_find_val_i_closure) }, + { be_const_key_weak(init, 11), be_const_closure(Matter_Plugin_Light0_init_closure) }, + { be_const_key_weak(set_onoff, 12), be_const_closure(Matter_Plugin_Light0_set_onoff_closure) }, + { be_const_key_weak(update_shadow, 8), be_const_closure(Matter_Plugin_Light0_update_shadow_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light0_invoke_request_closure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(256, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Light_X200_X20On) }, + { be_const_key_weak(shadow_onoff, -1), be_const_var(0) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(light0) }, + })), + be_str_weak(Matter_Plugin_Light0) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Light0_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Light0); + be_setglobal(vm, "Matter_Plugin_Light0"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_OnOff.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_OnOff.h similarity index 56% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_OnOff.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_OnOff.h index bf855e119..20ce2d258 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_OnOff.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_OnOff.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_OnOff.h */ +/* Solidification of Matter_Plugin_2_OnOff.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -7,51 +7,11 @@ extern const bclass be_class_Matter_Plugin_OnOff; /******************************************************************** -** Solidified function: set_onoff +** Solidified function: invoke_request ********************************************************************/ -be_local_closure(Matter_Plugin_OnOff_set_onoff, /* name */ +be_local_closure(Matter_Plugin_OnOff_invoke_request, /* name */ be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(set_power), - /* K2 */ be_nested_str_weak(tasmota_relay_index), - /* K3 */ be_const_int(1), - /* K4 */ be_nested_str_weak(update_shadow), - }), - be_str_weak(set_onoff), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0xB80A0000, // 0000 GETNGBL R2 K0 - 0x8C080501, // 0001 GETMET R2 R2 K1 - 0x88100102, // 0002 GETMBR R4 R0 K2 - 0x04100903, // 0003 SUB R4 R4 K3 - 0x60140017, // 0004 GETGBL R5 G23 - 0x5C180200, // 0005 MOVE R6 R1 - 0x7C140200, // 0006 CALL R5 1 - 0x7C080600, // 0007 CALL R2 3 - 0x8C080104, // 0008 GETMET R2 R0 K4 - 0x7C080200, // 0009 CALL R2 1 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_OnOff_init, /* name */ - be_nested_proto( - 9, /* nstack */ + 11, /* nstack */ 4, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -59,126 +19,75 @@ be_local_closure(Matter_Plugin_OnOff_init, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(init), - /* K1 */ be_nested_str_weak(shadow_onoff), + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(command), + /* K4 */ be_nested_str_weak(update_shadow_lazy), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(set_onoff), + /* K7 */ be_nested_str_weak(publish_command), + /* K8 */ be_nested_str_weak(Power), + /* K9 */ be_const_int(1), + /* K10 */ be_const_int(2), + /* K11 */ be_nested_str_weak(shadow_onoff), }), - be_str_weak(init), + be_str_weak(invoke_request), &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x60100003, // 0000 GETGBL R4 G3 - 0x5C140000, // 0001 MOVE R5 R0 - 0x7C100200, // 0002 CALL R4 1 - 0x8C100900, // 0003 GETMET R4 R4 K0 - 0x5C180200, // 0004 MOVE R6 R1 - 0x5C1C0400, // 0005 MOVE R7 R2 - 0x5C200600, // 0006 MOVE R8 R3 - 0x7C100800, // 0007 CALL R4 4 - 0x50100000, // 0008 LDBOOL R4 0 0 - 0x90020204, // 0009 SETMBR R0 K1 R4 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_OnOff_update_shadow, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(get_power), - /* K2 */ be_nested_str_weak(tasmota_relay_index), - /* K3 */ be_const_int(1), - /* K4 */ be_nested_str_weak(shadow_onoff), - /* K5 */ be_nested_str_weak(attribute_updated), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(update_shadow), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[29]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x880C0102, // 0002 GETMBR R3 R0 K2 - 0x040C0703, // 0003 SUB R3 R3 K3 - 0x7C040400, // 0004 CALL R1 2 - 0x4C080000, // 0005 LDNIL R2 - 0x20080202, // 0006 NE R2 R1 R2 - 0x780A000E, // 0007 JMPF R2 #0017 - 0x88080104, // 0008 GETMBR R2 R0 K4 - 0x4C0C0000, // 0009 LDNIL R3 - 0x20080403, // 000A NE R2 R2 R3 - 0x780A0009, // 000B JMPF R2 #0016 - 0x88080104, // 000C GETMBR R2 R0 K4 - 0x600C0017, // 000D GETGBL R3 G23 - 0x5C100200, // 000E MOVE R4 R1 - 0x7C0C0200, // 000F CALL R3 1 - 0x20080403, // 0010 NE R2 R2 R3 - 0x780A0003, // 0011 JMPF R2 #0016 - 0x8C080105, // 0012 GETMET R2 R0 K5 - 0x54120005, // 0013 LDINT R4 6 - 0x58140006, // 0014 LDCONST R5 K6 - 0x7C080600, // 0015 CALL R2 3 - 0x90020801, // 0016 SETMBR R0 K4 R1 - 0x60080003, // 0017 GETGBL R2 G3 - 0x5C0C0000, // 0018 MOVE R3 R0 - 0x7C080200, // 0019 CALL R2 1 - 0x8C080507, // 001A GETMET R2 R2 K7 - 0x7C080200, // 001B CALL R2 1 - 0x80000000, // 001C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: parse_configuration -********************************************************************/ -be_local_closure(Matter_Plugin_OnOff_parse_configuration, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota_relay_index), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(ARG), - /* K3 */ be_const_int(1), - /* K4 */ be_const_int(0), - }), - be_str_weak(parse_configuration), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x60080009, // 0000 GETGBL R2 G9 - 0x8C0C0301, // 0001 GETMET R3 R1 K1 - 0x88140102, // 0002 GETMBR R5 R0 K2 - 0x58180003, // 0003 LDCONST R6 K3 - 0x7C0C0600, // 0004 CALL R3 3 - 0x7C080200, // 0005 CALL R2 1 - 0x90020002, // 0006 SETMBR R0 K0 R2 - 0x88080100, // 0007 GETMBR R2 R0 K0 - 0x18080504, // 0008 LE R2 R2 K4 - 0x780A0000, // 0009 JMPF R2 #000B - 0x90020103, // 000A SETMBR R0 K0 K3 - 0x80000000, // 000B RET 0 + ( &(const binstruction[52]) { /* code */ + 0xB8120000, // 0000 GETNGBL R4 K0 + 0x88100901, // 0001 GETMBR R4 R4 K1 + 0x88140702, // 0002 GETMBR R5 R3 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x541E0005, // 0004 LDINT R7 6 + 0x1C1C0A07, // 0005 EQ R7 R5 R7 + 0x781E002B, // 0006 JMPF R7 #0033 + 0x8C1C0104, // 0007 GETMET R7 R0 K4 + 0x7C1C0200, // 0008 CALL R7 1 + 0x1C1C0D05, // 0009 EQ R7 R6 K5 + 0x781E0009, // 000A JMPF R7 #0015 + 0x8C1C0106, // 000B GETMET R7 R0 K6 + 0x50240000, // 000C LDBOOL R9 0 0 + 0x7C1C0400, // 000D CALL R7 2 + 0x8C1C0107, // 000E GETMET R7 R0 K7 + 0x58240008, // 000F LDCONST R9 K8 + 0x58280005, // 0010 LDCONST R10 K5 + 0x7C1C0600, // 0011 CALL R7 3 + 0x501C0200, // 0012 LDBOOL R7 1 0 + 0x80040E00, // 0013 RET 1 R7 + 0x7002001D, // 0014 JMP #0033 + 0x1C1C0D09, // 0015 EQ R7 R6 K9 + 0x781E0009, // 0016 JMPF R7 #0021 + 0x8C1C0106, // 0017 GETMET R7 R0 K6 + 0x50240200, // 0018 LDBOOL R9 1 0 + 0x7C1C0400, // 0019 CALL R7 2 + 0x8C1C0107, // 001A GETMET R7 R0 K7 + 0x58240008, // 001B LDCONST R9 K8 + 0x58280009, // 001C LDCONST R10 K9 + 0x7C1C0600, // 001D CALL R7 3 + 0x501C0200, // 001E LDBOOL R7 1 0 + 0x80040E00, // 001F RET 1 R7 + 0x70020011, // 0020 JMP #0033 + 0x1C1C0D0A, // 0021 EQ R7 R6 K10 + 0x781E000F, // 0022 JMPF R7 #0033 + 0x8C1C0106, // 0023 GETMET R7 R0 K6 + 0x8824010B, // 0024 GETMBR R9 R0 K11 + 0x78260000, // 0025 JMPF R9 #0027 + 0x50240001, // 0026 LDBOOL R9 0 1 + 0x50240200, // 0027 LDBOOL R9 1 0 + 0x7C1C0400, // 0028 CALL R7 2 + 0x8C1C0107, // 0029 GETMET R7 R0 K7 + 0x58240008, // 002A LDCONST R9 K8 + 0x8828010B, // 002B GETMBR R10 R0 K11 + 0x782A0001, // 002C JMPF R10 #002F + 0x58280009, // 002D LDCONST R10 K9 + 0x70020000, // 002E JMP #0030 + 0x58280005, // 002F LDCONST R10 K5 + 0x7C1C0600, // 0030 CALL R7 3 + 0x501C0200, // 0031 LDBOOL R7 1 0 + 0x80040E00, // 0032 RET 1 R7 + 0x80000000, // 0033 RET 0 }) ) ); @@ -266,76 +175,86 @@ be_local_closure(Matter_Plugin_OnOff_read_attribute, /* name */ /******************************************************************** -** Solidified function: invoke_request +** Solidified function: parse_configuration ********************************************************************/ -be_local_closure(Matter_Plugin_OnOff_invoke_request, /* name */ +be_local_closure(Matter_Plugin_OnOff_parse_configuration, /* name */ be_nested_proto( - 10, /* nstack */ - 4, /* argc */ + 7, /* nstack */ + 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(TLV), - /* K2 */ be_nested_str_weak(cluster), - /* K3 */ be_nested_str_weak(command), - /* K4 */ be_nested_str_weak(update_shadow_lazy), - /* K5 */ be_const_int(0), - /* K6 */ be_nested_str_weak(set_onoff), - /* K7 */ be_nested_str_weak(update_shadow), - /* K8 */ be_const_int(1), - /* K9 */ be_const_int(2), - /* K10 */ be_nested_str_weak(shadow_onoff), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota_relay_index), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(ARG), + /* K3 */ be_const_int(1), + /* K4 */ be_const_int(0), }), - be_str_weak(invoke_request), + be_str_weak(parse_configuration), &be_const_str_solidified, - ( &(const binstruction[42]) { /* code */ - 0xB8120000, // 0000 GETNGBL R4 K0 - 0x88100901, // 0001 GETMBR R4 R4 K1 - 0x88140702, // 0002 GETMBR R5 R3 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x541E0005, // 0004 LDINT R7 6 - 0x1C1C0A07, // 0005 EQ R7 R5 R7 - 0x781E0021, // 0006 JMPF R7 #0029 - 0x8C1C0104, // 0007 GETMET R7 R0 K4 - 0x7C1C0200, // 0008 CALL R7 1 - 0x1C1C0D05, // 0009 EQ R7 R6 K5 - 0x781E0007, // 000A JMPF R7 #0013 - 0x8C1C0106, // 000B GETMET R7 R0 K6 - 0x50240000, // 000C LDBOOL R9 0 0 - 0x7C1C0400, // 000D CALL R7 2 - 0x8C1C0107, // 000E GETMET R7 R0 K7 - 0x7C1C0200, // 000F CALL R7 1 - 0x501C0200, // 0010 LDBOOL R7 1 0 - 0x80040E00, // 0011 RET 1 R7 - 0x70020015, // 0012 JMP #0029 - 0x1C1C0D08, // 0013 EQ R7 R6 K8 - 0x781E0007, // 0014 JMPF R7 #001D - 0x8C1C0106, // 0015 GETMET R7 R0 K6 - 0x50240200, // 0016 LDBOOL R9 1 0 - 0x7C1C0400, // 0017 CALL R7 2 - 0x8C1C0107, // 0018 GETMET R7 R0 K7 - 0x7C1C0200, // 0019 CALL R7 1 - 0x501C0200, // 001A LDBOOL R7 1 0 - 0x80040E00, // 001B RET 1 R7 - 0x7002000B, // 001C JMP #0029 - 0x1C1C0D09, // 001D EQ R7 R6 K9 - 0x781E0009, // 001E JMPF R7 #0029 - 0x8C1C0106, // 001F GETMET R7 R0 K6 - 0x8824010A, // 0020 GETMBR R9 R0 K10 - 0x78260000, // 0021 JMPF R9 #0023 - 0x50240001, // 0022 LDBOOL R9 0 1 - 0x50240200, // 0023 LDBOOL R9 1 0 - 0x7C1C0400, // 0024 CALL R7 2 - 0x8C1C0107, // 0025 GETMET R7 R0 K7 - 0x7C1C0200, // 0026 CALL R7 1 - 0x501C0200, // 0027 LDBOOL R7 1 0 - 0x80040E00, // 0028 RET 1 R7 - 0x80000000, // 0029 RET 0 + ( &(const binstruction[12]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x8C0C0301, // 0001 GETMET R3 R1 K1 + 0x88140102, // 0002 GETMBR R5 R0 K2 + 0x58180003, // 0003 LDCONST R6 K3 + 0x7C0C0600, // 0004 CALL R3 3 + 0x7C080200, // 0005 CALL R2 1 + 0x90020002, // 0006 SETMBR R0 K0 R2 + 0x88080100, // 0007 GETMBR R2 R0 K0 + 0x18080504, // 0008 LE R2 R2 K4 + 0x780A0000, // 0009 JMPF R2 #000B + 0x90020103, // 000A SETMBR R0 K0 K3 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_virtual +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_update_virtual, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(find), + /* K1 */ be_nested_str_weak(Power), + /* K2 */ be_nested_str_weak(set_onoff), + /* K3 */ be_nested_str_weak(update_virtual), + }), + be_str_weak(update_virtual), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x8C080300, // 0000 GETMET R2 R1 K0 + 0x58100001, // 0001 LDCONST R4 K1 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x200C0403, // 0004 NE R3 R2 R3 + 0x780E0004, // 0005 JMPF R3 #000B + 0x8C0C0102, // 0006 GETMET R3 R0 K2 + 0x60140017, // 0007 GETGBL R5 G23 + 0x5C180400, // 0008 MOVE R6 R2 + 0x7C140200, // 0009 CALL R5 1 + 0x7C0C0400, // 000A CALL R3 2 + 0x600C0003, // 000B GETGBL R3 G3 + 0x5C100000, // 000C MOVE R4 R0 + 0x7C0C0200, // 000D CALL R3 1 + 0x8C0C0703, // 000E GETMET R3 R3 K3 + 0x5C140200, // 000F MOVE R5 R1 + 0x7C0C0400, // 0010 CALL R3 2 + 0x80000000, // 0011 RET 0 }) ) ); @@ -369,6 +288,158 @@ be_local_closure(Matter_Plugin_OnOff__X3Clambda_X3E, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: set_onoff +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_set_onoff, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(VIRTUAL), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(set_power), + /* K3 */ be_nested_str_weak(tasmota_relay_index), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(update_shadow), + /* K6 */ be_nested_str_weak(shadow_onoff), + /* K7 */ be_nested_str_weak(attribute_updated), + /* K8 */ be_const_int(0), + }), + be_str_weak(set_onoff), + &be_const_str_solidified, + ( &(const binstruction[22]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x740A000A, // 0001 JMPT R2 #000D + 0xB80A0200, // 0002 GETNGBL R2 K1 + 0x8C080502, // 0003 GETMET R2 R2 K2 + 0x88100103, // 0004 GETMBR R4 R0 K3 + 0x04100904, // 0005 SUB R4 R4 K4 + 0x60140017, // 0006 GETGBL R5 G23 + 0x5C180200, // 0007 MOVE R6 R1 + 0x7C140200, // 0008 CALL R5 1 + 0x7C080600, // 0009 CALL R2 3 + 0x8C080105, // 000A GETMET R2 R0 K5 + 0x7C080200, // 000B CALL R2 1 + 0x70020007, // 000C JMP #0015 + 0x88080106, // 000D GETMBR R2 R0 K6 + 0x20080202, // 000E NE R2 R1 R2 + 0x780A0004, // 000F JMPF R2 #0015 + 0x8C080107, // 0010 GETMET R2 R0 K7 + 0x54120005, // 0011 LDINT R4 6 + 0x58140008, // 0012 LDCONST R5 K8 + 0x7C080600, // 0013 CALL R2 3 + 0x90020C01, // 0014 SETMBR R0 K6 R1 + 0x80000000, // 0015 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_update_shadow, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(VIRTUAL), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(get_power), + /* K3 */ be_nested_str_weak(tasmota_relay_index), + /* K4 */ be_const_int(1), + /* K5 */ be_nested_str_weak(shadow_onoff), + /* K6 */ be_nested_str_weak(attribute_updated), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(update_shadow), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x74060012, // 0001 JMPT R1 #0015 + 0xB8060200, // 0002 GETNGBL R1 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x880C0103, // 0004 GETMBR R3 R0 K3 + 0x040C0704, // 0005 SUB R3 R3 K4 + 0x7C040400, // 0006 CALL R1 2 + 0x4C080000, // 0007 LDNIL R2 + 0x20080202, // 0008 NE R2 R1 R2 + 0x780A000A, // 0009 JMPF R2 #0015 + 0x88080105, // 000A GETMBR R2 R0 K5 + 0x600C0017, // 000B GETGBL R3 G23 + 0x5C100200, // 000C MOVE R4 R1 + 0x7C0C0200, // 000D CALL R3 1 + 0x20080403, // 000E NE R2 R2 R3 + 0x780A0003, // 000F JMPF R2 #0014 + 0x8C080106, // 0010 GETMET R2 R0 K6 + 0x54120005, // 0011 LDINT R4 6 + 0x58140007, // 0012 LDCONST R5 K7 + 0x7C080600, // 0013 CALL R2 3 + 0x90020A01, // 0014 SETMBR R0 K5 R1 + 0x60040003, // 0015 GETGBL R1 G3 + 0x5C080000, // 0016 MOVE R2 R0 + 0x7C040200, // 0017 CALL R1 1 + 0x8C040308, // 0018 GETMET R1 R1 K8 + 0x7C040200, // 0019 CALL R1 1 + 0x80000000, // 001A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_OnOff_init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(shadow_onoff), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x60100003, // 0000 GETGBL R4 G3 + 0x5C140000, // 0001 MOVE R5 R0 + 0x7C100200, // 0002 CALL R4 1 + 0x8C100900, // 0003 GETMET R4 R4 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x5C1C0400, // 0005 MOVE R7 R2 + 0x5C200600, // 0006 MOVE R8 R3 + 0x7C100800, // 0007 CALL R4 4 + 0x50100000, // 0008 LDBOOL R4 0 0 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin_OnOff ********************************************************************/ @@ -376,19 +447,22 @@ extern const bclass be_class_Matter_Plugin_Device; be_local_class(Matter_Plugin_OnOff, 2, &be_class_Matter_Plugin_Device, - be_nested_map(16, + be_nested_map(18, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(shadow_onoff, 4), be_const_var(1) }, - { be_const_key_weak(tasmota_relay_index, 12), be_const_var(0) }, - { be_const_key_weak(set_onoff, -1), be_const_closure(Matter_Plugin_OnOff_set_onoff_closure) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_OnOff_init_closure) }, - { be_const_key_weak(ARG_TYPE, -1), be_const_static_closure(Matter_Plugin_OnOff__X3Clambda_X3E_closure) }, - { be_const_key_weak(update_shadow, 15), be_const_closure(Matter_Plugin_OnOff_update_shadow_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Relay) }, - { be_const_key_weak(ARG, -1), be_nested_str_weak(relay) }, { be_const_key_weak(UPDATE_TIME, -1), be_const_int(250) }, - { be_const_key_weak(CLUSTERS, 14), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(TYPE, -1), be_nested_str_weak(relay) }, + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(266, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(UPDATE_COMMANDS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Power), + })) ) } )) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(3, @@ -397,17 +471,68 @@ be_local_class(Matter_Plugin_OnOff, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(TYPES, 9), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(266, -1), be_const_int(2) }, })) ) } )) }, { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_OnOff_invoke_request_closure) }, - { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Relay_X3Cx_X3E_X20number) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(relay) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_OnOff_read_attribute_closure) }, - { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_OnOff_parse_configuration_closure) }, + { be_const_key_weak(read_attribute, 16), be_const_closure(Matter_Plugin_OnOff_read_attribute_closure) }, + { be_const_key_weak(parse_configuration, 13), be_const_closure(Matter_Plugin_OnOff_parse_configuration_closure) }, + { be_const_key_weak(update_virtual, -1), be_const_closure(Matter_Plugin_OnOff_update_virtual_closure) }, + { be_const_key_weak(DISPLAY_NAME, 14), be_nested_str_weak(Relay) }, + { be_const_key_weak(ARG_TYPE, 12), be_const_static_closure(Matter_Plugin_OnOff__X3Clambda_X3E_closure) }, + { be_const_key_weak(ARG, -1), be_nested_str_weak(relay) }, + { be_const_key_weak(shadow_onoff, -1), be_const_var(0) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_OnOff_update_shadow_closure) }, + { be_const_key_weak(ARG_HINT, 11), be_nested_str_weak(Relay_X3Cx_X3E_X20number) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_OnOff_init_closure) }, + { be_const_key_weak(set_onoff, -1), be_const_closure(Matter_Plugin_OnOff_set_onoff_closure) }, + { be_const_key_weak(tasmota_relay_index, -1), be_const_var(1) }, })), be_str_weak(Matter_Plugin_OnOff) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Sensor.h similarity index 55% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Sensor.h index 85a316317..adb3bf9c8 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Sensor.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Sensor.h */ +/* Solidification of Matter_Plugin_2_Sensor.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -7,23 +7,106 @@ extern const bclass be_class_Matter_Plugin_Sensor; /******************************************************************** -** Solidified function: value_changed +** Solidified function: update_virtual ********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_value_changed, /* name */ +be_local_closure(Matter_Plugin_Sensor_update_virtual, /* name */ be_nested_proto( - 2, /* nstack */ + 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(value_changed), + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(find), + /* K1 */ be_nested_str_weak(JSON_NAME), + /* K2 */ be_nested_str_weak(bool), + /* K3 */ be_nested_str_weak(shadow_value), + /* K4 */ be_nested_str_weak(value_changed), + /* K5 */ be_nested_str_weak(update_virtual), + }), + be_str_weak(update_virtual), &be_const_str_solidified, - ( &(const binstruction[ 1]) { /* code */ - 0x80000000, // 0000 RET 0 + ( &(const binstruction[28]) { /* code */ + 0x8C080300, // 0000 GETMET R2 R1 K0 + 0x88100101, // 0001 GETMBR R4 R0 K1 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x200C0403, // 0004 NE R3 R2 R3 + 0x780E000E, // 0005 JMPF R3 #0015 + 0x600C0004, // 0006 GETGBL R3 G4 + 0x5C100400, // 0007 MOVE R4 R2 + 0x7C0C0200, // 0008 CALL R3 1 + 0x1C0C0702, // 0009 EQ R3 R3 K2 + 0x780E0003, // 000A JMPF R3 #000F + 0x600C0009, // 000B GETGBL R3 G9 + 0x5C100400, // 000C MOVE R4 R2 + 0x7C0C0200, // 000D CALL R3 1 + 0x5C080600, // 000E MOVE R2 R3 + 0x880C0103, // 000F GETMBR R3 R0 K3 + 0x200C0602, // 0010 NE R3 R3 R2 + 0x780E0002, // 0011 JMPF R3 #0015 + 0x8C0C0104, // 0012 GETMET R3 R0 K4 + 0x7C0C0200, // 0013 CALL R3 1 + 0x90020602, // 0014 SETMBR R0 K3 R2 + 0x600C0003, // 0015 GETGBL R3 G3 + 0x5C100000, // 0016 MOVE R4 R0 + 0x7C0C0200, // 0017 CALL R3 1 + 0x8C0C0705, // 0018 GETMET R3 R3 K5 + 0x5C140200, // 0019 MOVE R5 R1 + 0x7C0C0400, // 001A CALL R3 2 + 0x80000000, // 001B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse_sensors +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_parse_sensors, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota_sensor_matcher), + /* K1 */ be_nested_str_weak(pre_value), + /* K2 */ be_nested_str_weak(match), + /* K3 */ be_nested_str_weak(shadow_value), + /* K4 */ be_nested_str_weak(value_changed), + }), + be_str_weak(parse_sensors), + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A0010, // 0001 JMPF R2 #0013 + 0x8C080101, // 0002 GETMET R2 R0 K1 + 0x6010000A, // 0003 GETGBL R4 G10 + 0x88140100, // 0004 GETMBR R5 R0 K0 + 0x8C140B02, // 0005 GETMET R5 R5 K2 + 0x5C1C0200, // 0006 MOVE R7 R1 + 0x7C140400, // 0007 CALL R5 2 + 0x7C100200, // 0008 CALL R4 1 + 0x7C080400, // 0009 CALL R2 2 + 0x4C0C0000, // 000A LDNIL R3 + 0x200C0403, // 000B NE R3 R2 R3 + 0x780E0005, // 000C JMPF R3 #0013 + 0x880C0103, // 000D GETMBR R3 R0 K3 + 0x200C0403, // 000E NE R3 R2 R3 + 0x780E0002, // 000F JMPF R3 #0013 + 0x8C0C0104, // 0010 GETMET R3 R0 K4 + 0x7C0C0200, // 0011 CALL R3 1 + 0x90020602, // 0012 SETMBR R0 K3 R2 + 0x80000000, // 0013 RET 0 }) ) ); @@ -74,56 +157,6 @@ be_local_closure(Matter_Plugin_Sensor_parse_configuration, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: parse_sensors -********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_parse_sensors, /* name */ - be_nested_proto( - 8, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota_sensor_matcher), - /* K1 */ be_nested_str_weak(pre_value), - /* K2 */ be_nested_str_weak(match), - /* K3 */ be_nested_str_weak(shadow_value), - /* K4 */ be_nested_str_weak(value_changed), - }), - be_str_weak(parse_sensors), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A0011, // 0001 JMPF R2 #0014 - 0x8C080101, // 0002 GETMET R2 R0 K1 - 0x6010000A, // 0003 GETGBL R4 G10 - 0x88140100, // 0004 GETMBR R5 R0 K0 - 0x8C140B02, // 0005 GETMET R5 R5 K2 - 0x5C1C0200, // 0006 MOVE R7 R1 - 0x7C140400, // 0007 CALL R5 2 - 0x7C100200, // 0008 CALL R4 1 - 0x7C080400, // 0009 CALL R2 2 - 0x4C0C0000, // 000A LDNIL R3 - 0x200C0403, // 000B NE R3 R2 R3 - 0x780E0006, // 000C JMPF R3 #0014 - 0x880C0103, // 000D GETMBR R3 R0 K3 - 0x200C0403, // 000E NE R3 R2 R3 - 0x780E0002, // 000F JMPF R3 #0013 - 0x8C0C0104, // 0010 GETMET R3 R0 K4 - 0x5C140400, // 0011 MOVE R5 R2 - 0x7C0C0400, // 0012 CALL R3 2 - 0x90020602, // 0013 SETMBR R0 K3 R2 - 0x80000000, // 0014 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: pre_value ********************************************************************/ @@ -148,6 +181,71 @@ be_local_closure(Matter_Plugin_Sensor_pre_value, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: append_state_json +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_append_state_json, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(shadow_value), + /* K1 */ be_nested_str_weak(null), + /* K2 */ be_nested_str_weak(_X2C_X22_X25s_X22_X3A_X25s), + /* K3 */ be_nested_str_weak(JSON_NAME), + }), + be_str_weak(append_state_json), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x4C080000, // 0001 LDNIL R2 + 0x20040202, // 0002 NE R1 R1 R2 + 0x78060001, // 0003 JMPF R1 #0006 + 0x88040100, // 0004 GETMBR R1 R0 K0 + 0x70020000, // 0005 JMP #0007 + 0x58040001, // 0006 LDCONST R1 K1 + 0x60080018, // 0007 GETGBL R2 G24 + 0x580C0002, // 0008 LDCONST R3 K2 + 0x88100103, // 0009 GETMBR R4 R0 K3 + 0x5C140200, // 000A MOVE R5 R1 + 0x7C080600, // 000B CALL R2 3 + 0x80040400, // 000C RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_value_changed, /* name */ + be_nested_proto( + 1, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 1]) { /* code */ + 0x80000000, // 0000 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin_Sensor ********************************************************************/ @@ -155,18 +253,21 @@ extern const bclass be_class_Matter_Plugin_Device; be_local_class(Matter_Plugin_Sensor, 3, &be_class_Matter_Plugin_Device, - be_nested_map(10, + be_nested_map(13, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(tasmota_sensor_matcher, -1), be_const_var(1) }, + { be_const_key_weak(ARG, 1), be_nested_str_weak(filter) }, { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Sensor_value_changed_closure) }, - { be_const_key_weak(ARG, -1), be_nested_str_weak(filter) }, - { be_const_key_weak(shadow_value, -1), be_const_var(2) }, - { be_const_key_weak(UPDATE_TIME, 7), be_const_int(5000) }, - { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Filter_X20pattern) }, - { be_const_key_weak(parse_sensors, 4), be_const_closure(Matter_Plugin_Sensor_parse_sensors_closure) }, - { be_const_key_weak(tasmota_sensor_filter, 8), be_const_var(0) }, - { be_const_key_weak(pre_value, -1), be_const_closure(Matter_Plugin_Sensor_pre_value_closure) }, - { be_const_key_weak(parse_configuration, 2), be_const_closure(Matter_Plugin_Sensor_parse_configuration_closure) }, + { be_const_key_weak(update_virtual, -1), be_const_closure(Matter_Plugin_Sensor_update_virtual_closure) }, + { be_const_key_weak(ARG_HINT, 8), be_nested_str_weak(Filter_X20pattern) }, + { be_const_key_weak(tasmota_sensor_matcher, -1), be_const_var(1) }, + { be_const_key_weak(parse_sensors, -1), be_const_closure(Matter_Plugin_Sensor_parse_sensors_closure) }, + { be_const_key_weak(JSON_NAME, -1), be_nested_str_weak() }, + { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_Sensor_parse_configuration_closure) }, + { be_const_key_weak(pre_value, 12), be_const_closure(Matter_Plugin_Sensor_pre_value_closure) }, + { be_const_key_weak(append_state_json, -1), be_const_closure(Matter_Plugin_Sensor_append_state_json_closure) }, + { be_const_key_weak(shadow_value, 9), be_const_var(2) }, + { be_const_key_weak(UPDATE_TIME, -1), be_const_int(5000) }, + { be_const_key_weak(tasmota_sensor_filter, -1), be_const_var(0) }, })), be_str_weak(Matter_Plugin_Sensor) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Shutter.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Shutter.h similarity index 91% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Shutter.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Shutter.h index f071d2f26..30f6d8348 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Shutter.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_2_Shutter.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Shutter.h */ +/* Solidification of Matter_Plugin_2_Shutter.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,6 +6,211 @@ extern const bclass be_class_Matter_Plugin_Shutter; +/******************************************************************** +** Solidified function: parse_configuration +********************************************************************/ +be_local_closure(Matter_Plugin_Shutter_parse_configuration, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota_shutter_index), + /* K1 */ be_nested_str_weak(find), + /* K2 */ be_nested_str_weak(ARG), + /* K3 */ be_const_int(0), + /* K4 */ be_nested_str_weak(shadow_shutter_inverted), + }), + be_str_weak(parse_configuration), + &be_const_str_solidified, + ( &(const binstruction[12]) { /* code */ + 0x8C080301, // 0000 GETMET R2 R1 K1 + 0x88100102, // 0001 GETMBR R4 R0 K2 + 0x7C080400, // 0002 CALL R2 2 + 0x90020002, // 0003 SETMBR R0 K0 R2 + 0x88080100, // 0004 GETMBR R2 R0 K0 + 0x4C0C0000, // 0005 LDNIL R3 + 0x1C080403, // 0006 EQ R2 R2 R3 + 0x780A0000, // 0007 JMPF R2 #0009 + 0x90020103, // 0008 SETMBR R0 K0 K3 + 0x5409FFFE, // 0009 LDINT R2 -1 + 0x90020802, // 000A SETMBR R0 K4 R2 + 0x80000000, // 000B RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Shutter_invoke_request, /* name */ + be_nested_proto( + 14, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[24]) { /* constants */ + /* K0 */ be_nested_str_weak(light), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(command), + /* K5 */ be_nested_str_weak(update_shadow_lazy), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(cmd), + /* K9 */ be_nested_str_weak(ShutterStopOpen), + /* K10 */ be_nested_str_weak(tasmota_shutter_index), + /* K11 */ be_const_int(1), + /* K12 */ be_nested_str_weak(update_shadow), + /* K13 */ be_nested_str_weak(ShutterStopClose), + /* K14 */ be_const_int(2), + /* K15 */ be_nested_str_weak(ShutterStop), + /* K16 */ be_nested_str_weak(log), + /* K17 */ be_nested_str_weak(MTR_X3A_X20Tilt_X20_X3D_X20), + /* K18 */ be_nested_str_weak(findsubval), + /* K19 */ be_nested_str_weak(shadow_shutter_inverted), + /* K20 */ be_nested_str_weak(ShutterPosition), + /* K21 */ be_nested_str_weak(_X20), + /* K22 */ be_nested_str_weak(pos_X25_X3A), + /* K23 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[116]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x54220101, // 0005 LDINT R8 258 + 0x1C200C08, // 0006 EQ R8 R6 R8 + 0x78220061, // 0007 JMPF R8 #006A + 0x8C200105, // 0008 GETMET R8 R0 K5 + 0x7C200200, // 0009 CALL R8 1 + 0x1C200F06, // 000A EQ R8 R7 K6 + 0x7822000D, // 000B JMPF R8 #001A + 0xB8220E00, // 000C GETNGBL R8 K7 + 0x8C201108, // 000D GETMET R8 R8 K8 + 0x60280008, // 000E GETGBL R10 G8 + 0x882C010A, // 000F GETMBR R11 R0 K10 + 0x002C170B, // 0010 ADD R11 R11 K11 + 0x7C280200, // 0011 CALL R10 1 + 0x002A120A, // 0012 ADD R10 K9 R10 + 0x502C0200, // 0013 LDBOOL R11 1 0 + 0x7C200600, // 0014 CALL R8 3 + 0x8C20010C, // 0015 GETMET R8 R0 K12 + 0x7C200200, // 0016 CALL R8 1 + 0x50200200, // 0017 LDBOOL R8 1 0 + 0x80041000, // 0018 RET 1 R8 + 0x7002004E, // 0019 JMP #0069 + 0x1C200F0B, // 001A EQ R8 R7 K11 + 0x7822000D, // 001B JMPF R8 #002A + 0xB8220E00, // 001C GETNGBL R8 K7 + 0x8C201108, // 001D GETMET R8 R8 K8 + 0x60280008, // 001E GETGBL R10 G8 + 0x882C010A, // 001F GETMBR R11 R0 K10 + 0x002C170B, // 0020 ADD R11 R11 K11 + 0x7C280200, // 0021 CALL R10 1 + 0x002A1A0A, // 0022 ADD R10 K13 R10 + 0x502C0200, // 0023 LDBOOL R11 1 0 + 0x7C200600, // 0024 CALL R8 3 + 0x8C20010C, // 0025 GETMET R8 R0 K12 + 0x7C200200, // 0026 CALL R8 1 + 0x50200200, // 0027 LDBOOL R8 1 0 + 0x80041000, // 0028 RET 1 R8 + 0x7002003E, // 0029 JMP #0069 + 0x1C200F0E, // 002A EQ R8 R7 K14 + 0x7822000D, // 002B JMPF R8 #003A + 0xB8220E00, // 002C GETNGBL R8 K7 + 0x8C201108, // 002D GETMET R8 R8 K8 + 0x60280008, // 002E GETGBL R10 G8 + 0x882C010A, // 002F GETMBR R11 R0 K10 + 0x002C170B, // 0030 ADD R11 R11 K11 + 0x7C280200, // 0031 CALL R10 1 + 0x002A1E0A, // 0032 ADD R10 K15 R10 + 0x502C0200, // 0033 LDBOOL R11 1 0 + 0x7C200600, // 0034 CALL R8 3 + 0x8C20010C, // 0035 GETMET R8 R0 K12 + 0x7C200200, // 0036 CALL R8 1 + 0x50200200, // 0037 LDBOOL R8 1 0 + 0x80041000, // 0038 RET 1 R8 + 0x7002002E, // 0039 JMP #0069 + 0x54220004, // 003A LDINT R8 5 + 0x1C200E08, // 003B EQ R8 R7 R8 + 0x7822002B, // 003C JMPF R8 #0069 + 0xB8220E00, // 003D GETNGBL R8 K7 + 0x8C201110, // 003E GETMET R8 R8 K16 + 0x60280008, // 003F GETGBL R10 G8 + 0x5C2C0400, // 0040 MOVE R11 R2 + 0x7C280200, // 0041 CALL R10 1 + 0x002A220A, // 0042 ADD R10 K17 R10 + 0x582C000E, // 0043 LDCONST R11 K14 + 0x7C200600, // 0044 CALL R8 3 + 0x8C200512, // 0045 GETMET R8 R2 K18 + 0x58280006, // 0046 LDCONST R10 K6 + 0x7C200400, // 0047 CALL R8 2 + 0x4C240000, // 0048 LDNIL R9 + 0x20241009, // 0049 NE R9 R8 R9 + 0x7826001B, // 004A JMPF R9 #0067 + 0x54260063, // 004B LDINT R9 100 + 0x0C201009, // 004C DIV R8 R8 R9 + 0x88240113, // 004D GETMBR R9 R0 K19 + 0x1C241306, // 004E EQ R9 R9 K6 + 0x78260001, // 004F JMPF R9 #0052 + 0x54260063, // 0050 LDINT R9 100 + 0x04201208, // 0051 SUB R8 R9 R8 + 0xB8260E00, // 0052 GETNGBL R9 K7 + 0x8C241308, // 0053 GETMET R9 R9 K8 + 0x602C0008, // 0054 GETGBL R11 G8 + 0x8830010A, // 0055 GETMBR R12 R0 K10 + 0x0030190B, // 0056 ADD R12 R12 K11 + 0x7C2C0200, // 0057 CALL R11 1 + 0x002E280B, // 0058 ADD R11 K20 R11 + 0x002C1715, // 0059 ADD R11 R11 K21 + 0x60300008, // 005A GETGBL R12 G8 + 0x5C341000, // 005B MOVE R13 R8 + 0x7C300200, // 005C CALL R12 1 + 0x002C160C, // 005D ADD R11 R11 R12 + 0x50300200, // 005E LDBOOL R12 1 0 + 0x7C240600, // 005F CALL R9 3 + 0x60240008, // 0060 GETGBL R9 G8 + 0x5C281000, // 0061 MOVE R10 R8 + 0x7C240200, // 0062 CALL R9 1 + 0x00262C09, // 0063 ADD R9 K22 R9 + 0x900E2009, // 0064 SETMBR R3 K16 R9 + 0x8C24010C, // 0065 GETMET R9 R0 K12 + 0x7C240200, // 0066 CALL R9 1 + 0x50240200, // 0067 LDBOOL R9 1 0 + 0x80041200, // 0068 RET 1 R9 + 0x70020008, // 0069 JMP #0073 + 0x60200003, // 006A GETGBL R8 G3 + 0x5C240000, // 006B MOVE R9 R0 + 0x7C200200, // 006C CALL R8 1 + 0x8C201117, // 006D GETMET R8 R8 K23 + 0x5C280200, // 006E MOVE R10 R1 + 0x5C2C0400, // 006F MOVE R11 R2 + 0x5C300600, // 0070 MOVE R12 R3 + 0x7C200800, // 0071 CALL R8 4 + 0x80041000, // 0072 RET 1 R8 + 0x80000000, // 0073 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -200,6 +405,33 @@ be_local_closure(Matter_Plugin_Shutter_read_attribute, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: +********************************************************************/ +be_local_closure(Matter_Plugin_Shutter__X3Clambda_X3E, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040009, // 0000 GETGBL R1 G9 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: parse_sensors ********************************************************************/ @@ -289,264 +521,6 @@ be_local_closure(Matter_Plugin_Shutter_parse_sensors, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_Shutter_update_shadow, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(update_inverted), - /* K1 */ be_nested_str_weak(tasmota), - /* K2 */ be_nested_str_weak(cmd), - /* K3 */ be_nested_str_weak(ShutterPosition), - /* K4 */ be_nested_str_weak(tasmota_shutter_index), - /* K5 */ be_const_int(1), - /* K6 */ be_nested_str_weak(parse_sensors), - /* K7 */ be_nested_str_weak(update_shadow), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0xB8060200, // 0002 GETNGBL R1 K1 - 0x8C040302, // 0003 GETMET R1 R1 K2 - 0x600C0008, // 0004 GETGBL R3 G8 - 0x88100104, // 0005 GETMBR R4 R0 K4 - 0x00100905, // 0006 ADD R4 R4 K5 - 0x7C0C0200, // 0007 CALL R3 1 - 0x000E0603, // 0008 ADD R3 K3 R3 - 0x50100200, // 0009 LDBOOL R4 1 0 - 0x7C040600, // 000A CALL R1 3 - 0x78060002, // 000B JMPF R1 #000F - 0x8C080106, // 000C GETMET R2 R0 K6 - 0x5C100200, // 000D MOVE R4 R1 - 0x7C080400, // 000E CALL R2 2 - 0x60080003, // 000F GETGBL R2 G3 - 0x5C0C0000, // 0010 MOVE R3 R0 - 0x7C080200, // 0011 CALL R2 1 - 0x8C080507, // 0012 GETMET R2 R2 K7 - 0x7C080200, // 0013 CALL R2 1 - 0x80000000, // 0014 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Shutter_invoke_request, /* name */ - be_nested_proto( - 14, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[24]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(command), - /* K5 */ be_nested_str_weak(update_shadow_lazy), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(tasmota), - /* K8 */ be_nested_str_weak(cmd), - /* K9 */ be_nested_str_weak(ShutterStopOpen), - /* K10 */ be_nested_str_weak(tasmota_shutter_index), - /* K11 */ be_const_int(1), - /* K12 */ be_nested_str_weak(update_shadow), - /* K13 */ be_nested_str_weak(ShutterStopClose), - /* K14 */ be_const_int(2), - /* K15 */ be_nested_str_weak(ShutterStop), - /* K16 */ be_nested_str_weak(log), - /* K17 */ be_nested_str_weak(MTR_X3A_X20Tilt_X20_X3D_X20), - /* K18 */ be_nested_str_weak(findsubval), - /* K19 */ be_nested_str_weak(shadow_shutter_inverted), - /* K20 */ be_nested_str_weak(ShutterPosition), - /* K21 */ be_nested_str_weak(_X20), - /* K22 */ be_nested_str_weak(pos_X25_X3A), - /* K23 */ be_nested_str_weak(invoke_request), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[116]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xB8160200, // 0001 GETNGBL R5 K1 - 0x88140B02, // 0002 GETMBR R5 R5 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x881C0704, // 0004 GETMBR R7 R3 K4 - 0x54220101, // 0005 LDINT R8 258 - 0x1C200C08, // 0006 EQ R8 R6 R8 - 0x78220061, // 0007 JMPF R8 #006A - 0x8C200105, // 0008 GETMET R8 R0 K5 - 0x7C200200, // 0009 CALL R8 1 - 0x1C200F06, // 000A EQ R8 R7 K6 - 0x7822000D, // 000B JMPF R8 #001A - 0xB8220E00, // 000C GETNGBL R8 K7 - 0x8C201108, // 000D GETMET R8 R8 K8 - 0x60280008, // 000E GETGBL R10 G8 - 0x882C010A, // 000F GETMBR R11 R0 K10 - 0x002C170B, // 0010 ADD R11 R11 K11 - 0x7C280200, // 0011 CALL R10 1 - 0x002A120A, // 0012 ADD R10 K9 R10 - 0x502C0200, // 0013 LDBOOL R11 1 0 - 0x7C200600, // 0014 CALL R8 3 - 0x8C20010C, // 0015 GETMET R8 R0 K12 - 0x7C200200, // 0016 CALL R8 1 - 0x50200200, // 0017 LDBOOL R8 1 0 - 0x80041000, // 0018 RET 1 R8 - 0x7002004E, // 0019 JMP #0069 - 0x1C200F0B, // 001A EQ R8 R7 K11 - 0x7822000D, // 001B JMPF R8 #002A - 0xB8220E00, // 001C GETNGBL R8 K7 - 0x8C201108, // 001D GETMET R8 R8 K8 - 0x60280008, // 001E GETGBL R10 G8 - 0x882C010A, // 001F GETMBR R11 R0 K10 - 0x002C170B, // 0020 ADD R11 R11 K11 - 0x7C280200, // 0021 CALL R10 1 - 0x002A1A0A, // 0022 ADD R10 K13 R10 - 0x502C0200, // 0023 LDBOOL R11 1 0 - 0x7C200600, // 0024 CALL R8 3 - 0x8C20010C, // 0025 GETMET R8 R0 K12 - 0x7C200200, // 0026 CALL R8 1 - 0x50200200, // 0027 LDBOOL R8 1 0 - 0x80041000, // 0028 RET 1 R8 - 0x7002003E, // 0029 JMP #0069 - 0x1C200F0E, // 002A EQ R8 R7 K14 - 0x7822000D, // 002B JMPF R8 #003A - 0xB8220E00, // 002C GETNGBL R8 K7 - 0x8C201108, // 002D GETMET R8 R8 K8 - 0x60280008, // 002E GETGBL R10 G8 - 0x882C010A, // 002F GETMBR R11 R0 K10 - 0x002C170B, // 0030 ADD R11 R11 K11 - 0x7C280200, // 0031 CALL R10 1 - 0x002A1E0A, // 0032 ADD R10 K15 R10 - 0x502C0200, // 0033 LDBOOL R11 1 0 - 0x7C200600, // 0034 CALL R8 3 - 0x8C20010C, // 0035 GETMET R8 R0 K12 - 0x7C200200, // 0036 CALL R8 1 - 0x50200200, // 0037 LDBOOL R8 1 0 - 0x80041000, // 0038 RET 1 R8 - 0x7002002E, // 0039 JMP #0069 - 0x54220004, // 003A LDINT R8 5 - 0x1C200E08, // 003B EQ R8 R7 R8 - 0x7822002B, // 003C JMPF R8 #0069 - 0xB8220E00, // 003D GETNGBL R8 K7 - 0x8C201110, // 003E GETMET R8 R8 K16 - 0x60280008, // 003F GETGBL R10 G8 - 0x5C2C0400, // 0040 MOVE R11 R2 - 0x7C280200, // 0041 CALL R10 1 - 0x002A220A, // 0042 ADD R10 K17 R10 - 0x582C000E, // 0043 LDCONST R11 K14 - 0x7C200600, // 0044 CALL R8 3 - 0x8C200512, // 0045 GETMET R8 R2 K18 - 0x58280006, // 0046 LDCONST R10 K6 - 0x7C200400, // 0047 CALL R8 2 - 0x4C240000, // 0048 LDNIL R9 - 0x20241009, // 0049 NE R9 R8 R9 - 0x7826001B, // 004A JMPF R9 #0067 - 0x54260063, // 004B LDINT R9 100 - 0x0C201009, // 004C DIV R8 R8 R9 - 0x88240113, // 004D GETMBR R9 R0 K19 - 0x1C241306, // 004E EQ R9 R9 K6 - 0x78260001, // 004F JMPF R9 #0052 - 0x54260063, // 0050 LDINT R9 100 - 0x04201208, // 0051 SUB R8 R9 R8 - 0xB8260E00, // 0052 GETNGBL R9 K7 - 0x8C241308, // 0053 GETMET R9 R9 K8 - 0x602C0008, // 0054 GETGBL R11 G8 - 0x8830010A, // 0055 GETMBR R12 R0 K10 - 0x0030190B, // 0056 ADD R12 R12 K11 - 0x7C2C0200, // 0057 CALL R11 1 - 0x002E280B, // 0058 ADD R11 K20 R11 - 0x002C1715, // 0059 ADD R11 R11 K21 - 0x60300008, // 005A GETGBL R12 G8 - 0x5C341000, // 005B MOVE R13 R8 - 0x7C300200, // 005C CALL R12 1 - 0x002C160C, // 005D ADD R11 R11 R12 - 0x50300200, // 005E LDBOOL R12 1 0 - 0x7C240600, // 005F CALL R9 3 - 0x60240008, // 0060 GETGBL R9 G8 - 0x5C281000, // 0061 MOVE R10 R8 - 0x7C240200, // 0062 CALL R9 1 - 0x00262C09, // 0063 ADD R9 K22 R9 - 0x900E2009, // 0064 SETMBR R3 K16 R9 - 0x8C24010C, // 0065 GETMET R9 R0 K12 - 0x7C240200, // 0066 CALL R9 1 - 0x50240200, // 0067 LDBOOL R9 1 0 - 0x80041200, // 0068 RET 1 R9 - 0x70020008, // 0069 JMP #0073 - 0x60200003, // 006A GETGBL R8 G3 - 0x5C240000, // 006B MOVE R9 R0 - 0x7C200200, // 006C CALL R8 1 - 0x8C201117, // 006D GETMET R8 R8 K23 - 0x5C280200, // 006E MOVE R10 R1 - 0x5C2C0400, // 006F MOVE R11 R2 - 0x5C300600, // 0070 MOVE R12 R3 - 0x7C200800, // 0071 CALL R8 4 - 0x80041000, // 0072 RET 1 R8 - 0x80000000, // 0073 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: parse_configuration -********************************************************************/ -be_local_closure(Matter_Plugin_Shutter_parse_configuration, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota_shutter_index), - /* K1 */ be_nested_str_weak(find), - /* K2 */ be_nested_str_weak(ARG), - /* K3 */ be_const_int(0), - /* K4 */ be_nested_str_weak(shadow_shutter_inverted), - }), - be_str_weak(parse_configuration), - &be_const_str_solidified, - ( &(const binstruction[12]) { /* code */ - 0x8C080301, // 0000 GETMET R2 R1 K1 - 0x88100102, // 0001 GETMBR R4 R0 K2 - 0x7C080400, // 0002 CALL R2 2 - 0x90020002, // 0003 SETMBR R0 K0 R2 - 0x88080100, // 0004 GETMBR R2 R0 K0 - 0x4C0C0000, // 0005 LDNIL R3 - 0x1C080403, // 0006 EQ R2 R2 R3 - 0x780A0000, // 0007 JMPF R2 #0009 - 0x90020103, // 0008 SETMBR R0 K0 K3 - 0x5409FFFE, // 0009 LDINT R2 -1 - 0x90020802, // 000A SETMBR R0 K4 R2 - 0x80000000, // 000B RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: update_inverted ********************************************************************/ @@ -620,26 +594,52 @@ be_local_closure(Matter_Plugin_Shutter_update_inverted, /* name */ /******************************************************************** -** Solidified function: +** Solidified function: update_shadow ********************************************************************/ -be_local_closure(Matter_Plugin_Shutter__X3Clambda_X3E, /* name */ +be_local_closure(Matter_Plugin_Shutter_update_shadow, /* name */ be_nested_proto( - 3, /* nstack */ + 5, /* nstack */ 1, /* argc */ - 0, /* varg */ + 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(_X3Clambda_X3E), + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(update_inverted), + /* K1 */ be_nested_str_weak(tasmota), + /* K2 */ be_nested_str_weak(cmd), + /* K3 */ be_nested_str_weak(ShutterPosition), + /* K4 */ be_nested_str_weak(tasmota_shutter_index), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str_weak(parse_sensors), + /* K7 */ be_nested_str_weak(update_shadow), + }), + be_str_weak(update_shadow), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040009, // 0000 GETGBL R1 G9 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x80040200, // 0003 RET 1 R1 + ( &(const binstruction[21]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0xB8060200, // 0002 GETNGBL R1 K1 + 0x8C040302, // 0003 GETMET R1 R1 K2 + 0x600C0008, // 0004 GETGBL R3 G8 + 0x88100104, // 0005 GETMBR R4 R0 K4 + 0x00100905, // 0006 ADD R4 R4 K5 + 0x7C0C0200, // 0007 CALL R3 1 + 0x000E0603, // 0008 ADD R3 K3 R3 + 0x50100200, // 0009 LDBOOL R4 1 0 + 0x7C040600, // 000A CALL R1 3 + 0x78060002, // 000B JMPF R1 #000F + 0x8C080106, // 000C GETMET R2 R0 K6 + 0x5C100200, // 000D MOVE R4 R1 + 0x7C080400, // 000E CALL R2 2 + 0x60080003, // 000F GETGBL R2 G3 + 0x5C0C0000, // 0010 MOVE R3 R0 + 0x7C080200, // 0011 CALL R2 1 + 0x8C080507, // 0012 GETMET R2 R2 K7 + 0x7C080200, // 0013 CALL R2 1 + 0x80000000, // 0014 RET 0 }) ) ); @@ -651,20 +651,20 @@ be_local_closure(Matter_Plugin_Shutter__X3Clambda_X3E, /* name */ ********************************************************************/ extern const bclass be_class_Matter_Plugin_Device; be_local_class(Matter_Plugin_Shutter, - 6, + 5, &be_class_Matter_Plugin_Device, - be_nested_map(19, + be_nested_map(18, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, 4), be_const_closure(Matter_Plugin_Shutter_read_attribute_closure) }, - { be_const_key_weak(shadow_shutter_pos, 18), be_const_var(1) }, - { be_const_key_weak(tasmota_shutter_index, -1), be_const_var(0) }, - { be_const_key_weak(parse_sensors, -1), be_const_closure(Matter_Plugin_Shutter_parse_sensors_closure) }, - { be_const_key_weak(shadow_shutter_direction, -1), be_const_var(4) }, - { be_const_key_weak(shadow_shutter_target, -1), be_const_var(2) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Shutter_invoke_request_closure) }, - { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Relay_X3Cx_X3E_X20number) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(shadow_shutter_inverted, -1), be_const_var(4) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(shutter) }, + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(514, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(shadow_shutter_target, -1), be_const_var(2) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(258, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(10, @@ -680,21 +680,68 @@ be_local_class(Matter_Plugin_Shutter, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(update_shadow, 5), be_const_closure(Matter_Plugin_Shutter_update_shadow_closure) }, - { be_const_key_weak(NAME, 6), be_nested_str_weak(Shutter) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(shutter) }, - { be_const_key_weak(shadow_shutter_inverted, -1), be_const_var(5) }, - { be_const_key_weak(ARG, 7), be_nested_str_weak(shutter) }, - { be_const_key_weak(shadow_shutter_tilt, 8), be_const_var(3) }, - { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_Shutter_parse_configuration_closure) }, - { be_const_key_weak(update_inverted, -1), be_const_closure(Matter_Plugin_Shutter_update_inverted_closure) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(invoke_request, 3), be_const_closure(Matter_Plugin_Shutter_invoke_request_closure) }, + { be_const_key_weak(read_attribute, 11), be_const_closure(Matter_Plugin_Shutter_read_attribute_closure) }, + { be_const_key_weak(parse_configuration, 14), be_const_closure(Matter_Plugin_Shutter_parse_configuration_closure) }, + { be_const_key_weak(shadow_shutter_pos, -1), be_const_var(1) }, + { be_const_key_weak(ARG, 13), be_nested_str_weak(shutter) }, { be_const_key_weak(ARG_TYPE, -1), be_const_static_closure(Matter_Plugin_Shutter__X3Clambda_X3E_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(514, -1), be_const_int(2) }, - })) ) } )) }, + { be_const_key_weak(parse_sensors, -1), be_const_closure(Matter_Plugin_Shutter_parse_sensors_closure) }, + { be_const_key_weak(update_inverted, -1), be_const_closure(Matter_Plugin_Shutter_update_inverted_closure) }, + { be_const_key_weak(ARG_HINT, 16), be_nested_str_weak(Relay_X3Cx_X3E_X20number) }, + { be_const_key_weak(update_shadow, 0), be_const_closure(Matter_Plugin_Shutter_update_shadow_closure) }, + { be_const_key_weak(tasmota_shutter_index, -1), be_const_var(0) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Shutter) }, + { be_const_key_weak(shadow_shutter_direction, -1), be_const_var(3) }, })), be_str_weak(Matter_Plugin_Shutter) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light0.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Bridge_Light0.h similarity index 80% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light0.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Bridge_Light0.h index 635323adf..c0eb08bcd 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light0.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Bridge_Light0.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Light0.h */ +/* Solidification of Matter_Plugin_3_Bridge_Light0.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,33 +6,6 @@ extern const bclass be_class_Matter_Plugin_Bridge_Light0; -/******************************************************************** -** Solidified function: -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_Light0__X3Clambda_X3E, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 0, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(_X3Clambda_X3E), - &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040009, // 0000 GETGBL R1 G9 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x80040200, // 0003 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: set_onoff ********************************************************************/ @@ -214,6 +187,33 @@ be_local_closure(Matter_Plugin_Bridge_Light0_read_attribute, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_Light0__X3Clambda_X3E, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040009, // 0000 GETGBL R1 G9 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: parse_update ********************************************************************/ @@ -293,7 +293,7 @@ be_local_closure(Matter_Plugin_Bridge_Light0_parse_update, /* name */ ********************************************************************/ be_local_closure(Matter_Plugin_Bridge_Light0_invoke_request, /* name */ be_nested_proto( - 10, /* nstack */ + 11, /* nstack */ 4, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -301,54 +301,72 @@ be_local_closure(Matter_Plugin_Bridge_Light0_invoke_request, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ + ( &(const bvalue[11]) { /* constants */ /* K0 */ be_nested_str_weak(matter), /* K1 */ be_nested_str_weak(TLV), /* K2 */ be_nested_str_weak(cluster), /* K3 */ be_nested_str_weak(command), /* K4 */ be_const_int(0), /* K5 */ be_nested_str_weak(set_onoff), - /* K6 */ be_const_int(1), - /* K7 */ be_const_int(2), - /* K8 */ be_nested_str_weak(shadow_onoff), + /* K6 */ be_nested_str_weak(publish_command), + /* K7 */ be_nested_str_weak(Power), + /* K8 */ be_const_int(1), + /* K9 */ be_const_int(2), + /* K10 */ be_nested_str_weak(shadow_onoff), }), be_str_weak(invoke_request), &be_const_str_solidified, - ( &(const binstruction[34]) { /* code */ + ( &(const binstruction[50]) { /* code */ 0xB8120000, // 0000 GETNGBL R4 K0 0x88100901, // 0001 GETMBR R4 R4 K1 0x88140702, // 0002 GETMBR R5 R3 K2 0x88180703, // 0003 GETMBR R6 R3 K3 0x541E0005, // 0004 LDINT R7 6 0x1C1C0A07, // 0005 EQ R7 R5 R7 - 0x781E0019, // 0006 JMPF R7 #0021 + 0x781E0029, // 0006 JMPF R7 #0031 0x1C1C0D04, // 0007 EQ R7 R6 K4 - 0x781E0005, // 0008 JMPF R7 #000F + 0x781E0009, // 0008 JMPF R7 #0013 0x8C1C0105, // 0009 GETMET R7 R0 K5 0x50240000, // 000A LDBOOL R9 0 0 0x7C1C0400, // 000B CALL R7 2 - 0x501C0200, // 000C LDBOOL R7 1 0 - 0x80040E00, // 000D RET 1 R7 - 0x70020011, // 000E JMP #0021 - 0x1C1C0D06, // 000F EQ R7 R6 K6 - 0x781E0005, // 0010 JMPF R7 #0017 - 0x8C1C0105, // 0011 GETMET R7 R0 K5 - 0x50240200, // 0012 LDBOOL R9 1 0 - 0x7C1C0400, // 0013 CALL R7 2 - 0x501C0200, // 0014 LDBOOL R7 1 0 - 0x80040E00, // 0015 RET 1 R7 - 0x70020009, // 0016 JMP #0021 - 0x1C1C0D07, // 0017 EQ R7 R6 K7 - 0x781E0007, // 0018 JMPF R7 #0021 - 0x8C1C0105, // 0019 GETMET R7 R0 K5 - 0x88240108, // 001A GETMBR R9 R0 K8 - 0x78260000, // 001B JMPF R9 #001D - 0x50240001, // 001C LDBOOL R9 0 1 - 0x50240200, // 001D LDBOOL R9 1 0 - 0x7C1C0400, // 001E CALL R7 2 - 0x501C0200, // 001F LDBOOL R7 1 0 - 0x80040E00, // 0020 RET 1 R7 - 0x80000000, // 0021 RET 0 + 0x8C1C0106, // 000C GETMET R7 R0 K6 + 0x58240007, // 000D LDCONST R9 K7 + 0x58280004, // 000E LDCONST R10 K4 + 0x7C1C0600, // 000F CALL R7 3 + 0x501C0200, // 0010 LDBOOL R7 1 0 + 0x80040E00, // 0011 RET 1 R7 + 0x7002001D, // 0012 JMP #0031 + 0x1C1C0D08, // 0013 EQ R7 R6 K8 + 0x781E0009, // 0014 JMPF R7 #001F + 0x8C1C0105, // 0015 GETMET R7 R0 K5 + 0x50240200, // 0016 LDBOOL R9 1 0 + 0x7C1C0400, // 0017 CALL R7 2 + 0x8C1C0106, // 0018 GETMET R7 R0 K6 + 0x58240007, // 0019 LDCONST R9 K7 + 0x58280008, // 001A LDCONST R10 K8 + 0x7C1C0600, // 001B CALL R7 3 + 0x501C0200, // 001C LDBOOL R7 1 0 + 0x80040E00, // 001D RET 1 R7 + 0x70020011, // 001E JMP #0031 + 0x1C1C0D09, // 001F EQ R7 R6 K9 + 0x781E000F, // 0020 JMPF R7 #0031 + 0x8C1C0105, // 0021 GETMET R7 R0 K5 + 0x8824010A, // 0022 GETMBR R9 R0 K10 + 0x78260000, // 0023 JMPF R9 #0025 + 0x50240001, // 0024 LDBOOL R9 0 1 + 0x50240200, // 0025 LDBOOL R9 1 0 + 0x7C1C0400, // 0026 CALL R7 2 + 0x8C1C0106, // 0027 GETMET R7 R0 K6 + 0x58240007, // 0028 LDCONST R9 K7 + 0x8828010A, // 0029 GETMBR R10 R0 K10 + 0x782A0001, // 002A JMPF R10 #002D + 0x58280008, // 002B LDCONST R10 K8 + 0x70020000, // 002C JMP #002E + 0x58280004, // 002D LDCONST R10 K4 + 0x7C1C0600, // 002E CALL R7 3 + 0x501C0200, // 002F LDBOOL R7 1 0 + 0x80040E00, // 0030 RET 1 R7 + 0x80000000, // 0031 RET 0 }) ) ); @@ -460,17 +478,20 @@ be_local_class(Matter_Plugin_Bridge_Light0, &be_class_Matter_Plugin_Bridge_HTTP, be_nested_map(16, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ARG_TYPE, 5), be_const_static_closure(Matter_Plugin_Bridge_Light0__X3Clambda_X3E_closure) }, + { be_const_key_weak(shadow_onoff, 5), be_const_var(1) }, { be_const_key_weak(tasmota_relay_index, 4), be_const_var(0) }, { be_const_key_weak(set_onoff, -1), be_const_closure(Matter_Plugin_Bridge_Light0_set_onoff_closure) }, { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Bridge_Light0_init_closure) }, - { be_const_key_weak(web_values_prefix, 12), be_const_closure(Matter_Plugin_Bridge_Light0_web_values_prefix_closure) }, - { be_const_key_weak(web_values, 14), be_const_closure(Matter_Plugin_Bridge_Light0_web_values_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Light_X200_X20On) }, + { be_const_key_weak(web_values_prefix, 9), be_const_closure(Matter_Plugin_Bridge_Light0_web_values_prefix_closure) }, + { be_const_key_weak(web_values, 15), be_const_closure(Matter_Plugin_Bridge_Light0_web_values_closure) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_light0) }, { be_const_key_weak(ARG, -1), be_nested_str_weak(relay) }, { be_const_key_weak(parse_update, -1), be_const_closure(Matter_Plugin_Bridge_Light0_parse_update_closure) }, - { be_const_key_weak(CLUSTERS, 15), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Power_X3Cx_X3E_X20number) }, + { be_const_key_weak(read_attribute, 12), be_const_closure(Matter_Plugin_Bridge_Light0_read_attribute_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Bridge_Light0_invoke_request_closure) }, + { be_const_key_weak(CLUSTERS, 14), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(3, @@ -479,17 +500,62 @@ be_local_class(Matter_Plugin_Bridge_Light0, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(read_attribute, 9), be_const_closure(Matter_Plugin_Bridge_Light0_read_attribute_closure) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Bridge_Light0_invoke_request_closure) }, - { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Power_X3Cx_X3E_X20number) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_light0) }, - { be_const_key_weak(shadow_onoff, -1), be_const_var(1) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(DISPLAY_NAME, 6), be_nested_str_weak(Light_X200_X20On) }, { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(256, -1), be_const_int(2) }, })) ) } )) }, + { be_const_key_weak(ARG_TYPE, -1), be_const_static_closure(Matter_Plugin_Bridge_Light0__X3Clambda_X3E_closure) }, })), be_str_weak(Matter_Plugin_Bridge_Light0) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Bridge_Sensor.h similarity index 96% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Bridge_Sensor.h index 5f19a1916..4079b20bd 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Bridge_Sensor.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Sensor.h */ +/* Solidification of Matter_Plugin_3_Bridge_Sensor.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -63,8 +63,8 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_parse_configuration, /* name */ ********************************************************************/ be_local_closure(Matter_Plugin_Bridge_Sensor_value_changed, /* name */ be_nested_proto( - 2, /* nstack */ - 2, /* argc */ + 1, /* nstack */ + 1, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -160,10 +160,10 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_parse_update, /* name */ }), be_str_weak(parse_update), &be_const_str_solidified, - ( &(const binstruction[36]) { /* code */ + ( &(const binstruction[35]) { /* code */ 0x540E0007, // 0000 LDINT R3 8 0x1C0C0403, // 0001 EQ R3 R2 R3 - 0x780E001F, // 0002 JMPF R3 #0023 + 0x780E001E, // 0002 JMPF R3 #0022 0x8C0C0300, // 0003 GETMET R3 R1 K0 0x58140001, // 0004 LDCONST R5 K1 0x7C0C0400, // 0005 CALL R3 2 @@ -177,7 +177,7 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_parse_update, /* name */ 0x940C0303, // 000D GETIDX R3 R1 K3 0x90020803, // 000E SETMBR R0 K4 R3 0x880C0105, // 000F GETMBR R3 R0 K5 - 0x780E0011, // 0010 JMPF R3 #0023 + 0x780E0010, // 0010 JMPF R3 #0022 0x8C0C0106, // 0011 GETMET R3 R0 K6 0x6014000A, // 0012 GETGBL R5 G10 0x88180105, // 0013 GETMBR R6 R0 K5 @@ -188,15 +188,14 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_parse_update, /* name */ 0x7C0C0400, // 0018 CALL R3 2 0x4C100000, // 0019 LDNIL R4 0x20100604, // 001A NE R4 R3 R4 - 0x78120006, // 001B JMPF R4 #0023 + 0x78120005, // 001B JMPF R4 #0022 0x88100108, // 001C GETMBR R4 R0 K8 0x20100604, // 001D NE R4 R3 R4 0x78120002, // 001E JMPF R4 #0022 0x8C100109, // 001F GETMET R4 R0 K9 - 0x5C180600, // 0020 MOVE R6 R3 - 0x7C100400, // 0021 CALL R4 2 - 0x90021003, // 0022 SETMBR R0 K8 R3 - 0x80000000, // 0023 RET 0 + 0x7C100200, // 0020 CALL R4 1 + 0x90021003, // 0021 SETMBR R0 K8 R3 + 0x80000000, // 0022 RET 0 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Light1.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Light1.h new file mode 100644 index 000000000..2d227550a --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Light1.h @@ -0,0 +1,663 @@ +/* Solidification of Matter_Plugin_3_Light1.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Light1; + +/******************************************************************** +** Solidified function: set_bri +********************************************************************/ +be_local_closure(Matter_Plugin_Light1_set_bri, /* name */ + be_nested_proto( + 11, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(VIRTUAL), + /* K2 */ be_nested_str_weak(light), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(scale_uint), + /* K5 */ be_nested_str_weak(set), + /* K6 */ be_nested_str_weak(bri), + /* K7 */ be_nested_str_weak(power), + /* K8 */ be_nested_str_weak(update_shadow), + /* K9 */ be_nested_str_weak(shadow_onoff), + /* K10 */ be_nested_str_weak(attribute_updated), + /* K11 */ be_nested_str_weak(shadow_bri), + }), + be_str_weak(set_bri), + &be_const_str_solidified, + ( &(const binstruction[65]) { /* code */ + 0x140C0300, // 0000 LT R3 R1 K0 + 0x780E0000, // 0001 JMPF R3 #0003 + 0x58040000, // 0002 LDCONST R1 K0 + 0x540E00FD, // 0003 LDINT R3 254 + 0x240C0203, // 0004 GT R3 R1 R3 + 0x780E0000, // 0005 JMPF R3 #0007 + 0x540600FD, // 0006 LDINT R1 254 + 0x4C0C0000, // 0007 LDNIL R3 + 0x200C0403, // 0008 NE R3 R2 R3 + 0x780E0003, // 0009 JMPF R3 #000E + 0x600C0017, // 000A GETGBL R3 G23 + 0x5C100400, // 000B MOVE R4 R2 + 0x7C0C0200, // 000C CALL R3 1 + 0x70020000, // 000D JMP #000F + 0x4C0C0000, // 000E LDNIL R3 + 0x5C080600, // 000F MOVE R2 R3 + 0x880C0101, // 0010 GETMBR R3 R0 K1 + 0x740E001A, // 0011 JMPT R3 #002D + 0xA40E0400, // 0012 IMPORT R3 K2 + 0xB8120600, // 0013 GETNGBL R4 K3 + 0x8C100904, // 0014 GETMET R4 R4 K4 + 0x5C180200, // 0015 MOVE R6 R1 + 0x581C0000, // 0016 LDCONST R7 K0 + 0x542200FD, // 0017 LDINT R8 254 + 0x58240000, // 0018 LDCONST R9 K0 + 0x542A00FE, // 0019 LDINT R10 255 + 0x7C100C00, // 001A CALL R4 6 + 0x4C140000, // 001B LDNIL R5 + 0x1C140405, // 001C EQ R5 R2 R5 + 0x78160005, // 001D JMPF R5 #0024 + 0x8C140705, // 001E GETMET R5 R3 K5 + 0x601C0013, // 001F GETGBL R7 G19 + 0x7C1C0000, // 0020 CALL R7 0 + 0x981E0C04, // 0021 SETIDX R7 K6 R4 + 0x7C140400, // 0022 CALL R5 2 + 0x70020005, // 0023 JMP #002A + 0x8C140705, // 0024 GETMET R5 R3 K5 + 0x601C0013, // 0025 GETGBL R7 G19 + 0x7C1C0000, // 0026 CALL R7 0 + 0x981E0C04, // 0027 SETIDX R7 K6 R4 + 0x981E0E02, // 0028 SETIDX R7 K7 R2 + 0x7C140400, // 0029 CALL R5 2 + 0x8C140108, // 002A GETMET R5 R0 K8 + 0x7C140200, // 002B CALL R5 1 + 0x70020012, // 002C JMP #0040 + 0x4C0C0000, // 002D LDNIL R3 + 0x200C0403, // 002E NE R3 R2 R3 + 0x780E0007, // 002F JMPF R3 #0038 + 0x880C0109, // 0030 GETMBR R3 R0 K9 + 0x200C0403, // 0031 NE R3 R2 R3 + 0x780E0004, // 0032 JMPF R3 #0038 + 0x8C0C010A, // 0033 GETMET R3 R0 K10 + 0x54160005, // 0034 LDINT R5 6 + 0x58180000, // 0035 LDCONST R6 K0 + 0x7C0C0600, // 0036 CALL R3 3 + 0x90021202, // 0037 SETMBR R0 K9 R2 + 0x880C010B, // 0038 GETMBR R3 R0 K11 + 0x200C0203, // 0039 NE R3 R1 R3 + 0x780E0004, // 003A JMPF R3 #0040 + 0x8C0C010A, // 003B GETMET R3 R0 K10 + 0x54160007, // 003C LDINT R5 8 + 0x58180000, // 003D LDCONST R6 K0 + 0x7C0C0600, // 003E CALL R3 3 + 0x90021601, // 003F SETMBR R0 K11 R1 + 0x80000000, // 0040 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Light1_init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(shadow_bri), + /* K2 */ be_const_int(0), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x60100003, // 0000 GETGBL R4 G3 + 0x5C140000, // 0001 MOVE R5 R0 + 0x7C100200, // 0002 CALL R4 1 + 0x8C100900, // 0003 GETMET R4 R4 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x5C1C0400, // 0005 MOVE R7 R2 + 0x5C200600, // 0006 MOVE R8 R3 + 0x7C100800, // 0007 CALL R4 4 + 0x90020302, // 0008 SETMBR R0 K1 K2 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Light1_update_shadow, /* name */ + be_nested_proto( + 11, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_nested_str_weak(VIRTUAL), + /* K1 */ be_nested_str_weak(light), + /* K2 */ be_nested_str_weak(get), + /* K3 */ be_nested_str_weak(find), + /* K4 */ be_nested_str_weak(bri), + /* K5 */ be_nested_str_weak(tasmota), + /* K6 */ be_nested_str_weak(scale_uint), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(shadow_bri), + /* K9 */ be_nested_str_weak(attribute_updated), + /* K10 */ be_nested_str_weak(update_shadow), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[38]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x7406001D, // 0001 JMPT R1 #0020 + 0xA4060200, // 0002 IMPORT R1 K1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x7C080200, // 0004 CALL R2 1 + 0x4C0C0000, // 0005 LDNIL R3 + 0x200C0403, // 0006 NE R3 R2 R3 + 0x780E0017, // 0007 JMPF R3 #0020 + 0x8C0C0503, // 0008 GETMET R3 R2 K3 + 0x58140004, // 0009 LDCONST R5 K4 + 0x4C180000, // 000A LDNIL R6 + 0x7C0C0600, // 000B CALL R3 3 + 0x4C100000, // 000C LDNIL R4 + 0x20100604, // 000D NE R4 R3 R4 + 0x78120010, // 000E JMPF R4 #0020 + 0xB8120A00, // 000F GETNGBL R4 K5 + 0x8C100906, // 0010 GETMET R4 R4 K6 + 0x5C180600, // 0011 MOVE R6 R3 + 0x581C0007, // 0012 LDCONST R7 K7 + 0x542200FE, // 0013 LDINT R8 255 + 0x58240007, // 0014 LDCONST R9 K7 + 0x542A00FD, // 0015 LDINT R10 254 + 0x7C100C00, // 0016 CALL R4 6 + 0x5C0C0800, // 0017 MOVE R3 R4 + 0x88100108, // 0018 GETMBR R4 R0 K8 + 0x20100604, // 0019 NE R4 R3 R4 + 0x78120004, // 001A JMPF R4 #0020 + 0x8C100109, // 001B GETMET R4 R0 K9 + 0x541A0007, // 001C LDINT R6 8 + 0x581C0007, // 001D LDCONST R7 K7 + 0x7C100600, // 001E CALL R4 3 + 0x90021003, // 001F SETMBR R0 K8 R3 + 0x60040003, // 0020 GETGBL R1 G3 + 0x5C080000, // 0021 MOVE R2 R0 + 0x7C040200, // 0022 CALL R1 1 + 0x8C04030A, // 0023 GETMET R1 R1 K10 + 0x7C040200, // 0024 CALL R1 1 + 0x80000000, // 0025 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Light1_read_attribute, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(attribute), + /* K4 */ be_nested_str_weak(update_shadow_lazy), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(set), + /* K7 */ be_nested_str_weak(U1), + /* K8 */ be_nested_str_weak(shadow_bri), + /* K9 */ be_const_int(2), + /* K10 */ be_const_int(3), + /* K11 */ be_nested_str_weak(U4), + /* K12 */ be_const_int(1), + /* K13 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[79]) { /* code */ + 0xB8120000, // 0000 GETNGBL R4 K0 + 0x88100901, // 0001 GETMBR R4 R4 K1 + 0x88140502, // 0002 GETMBR R5 R2 K2 + 0x88180503, // 0003 GETMBR R6 R2 K3 + 0x541E0007, // 0004 LDINT R7 8 + 0x1C1C0A07, // 0005 EQ R7 R5 R7 + 0x781E003D, // 0006 JMPF R7 #0045 + 0x8C1C0104, // 0007 GETMET R7 R0 K4 + 0x7C1C0200, // 0008 CALL R7 1 + 0x1C1C0D05, // 0009 EQ R7 R6 K5 + 0x781E0005, // 000A JMPF R7 #0011 + 0x8C1C0706, // 000B GETMET R7 R3 K6 + 0x88240907, // 000C GETMBR R9 R4 K7 + 0x88280108, // 000D GETMBR R10 R0 K8 + 0x7C1C0600, // 000E CALL R7 3 + 0x80040E00, // 000F RET 1 R7 + 0x70020032, // 0010 JMP #0044 + 0x1C1C0D09, // 0011 EQ R7 R6 K9 + 0x781E0005, // 0012 JMPF R7 #0019 + 0x8C1C0706, // 0013 GETMET R7 R3 K6 + 0x88240907, // 0014 GETMBR R9 R4 K7 + 0x58280005, // 0015 LDCONST R10 K5 + 0x7C1C0600, // 0016 CALL R7 3 + 0x80040E00, // 0017 RET 1 R7 + 0x7002002A, // 0018 JMP #0044 + 0x1C1C0D0A, // 0019 EQ R7 R6 K10 + 0x781E0005, // 001A JMPF R7 #0021 + 0x8C1C0706, // 001B GETMET R7 R3 K6 + 0x88240907, // 001C GETMBR R9 R4 K7 + 0x542A00FD, // 001D LDINT R10 254 + 0x7C1C0600, // 001E CALL R7 3 + 0x80040E00, // 001F RET 1 R7 + 0x70020022, // 0020 JMP #0044 + 0x541E000E, // 0021 LDINT R7 15 + 0x1C1C0C07, // 0022 EQ R7 R6 R7 + 0x781E0005, // 0023 JMPF R7 #002A + 0x8C1C0706, // 0024 GETMET R7 R3 K6 + 0x88240907, // 0025 GETMBR R9 R4 K7 + 0x58280005, // 0026 LDCONST R10 K5 + 0x7C1C0600, // 0027 CALL R7 3 + 0x80040E00, // 0028 RET 1 R7 + 0x70020019, // 0029 JMP #0044 + 0x541E0010, // 002A LDINT R7 17 + 0x1C1C0C07, // 002B EQ R7 R6 R7 + 0x781E0005, // 002C JMPF R7 #0033 + 0x8C1C0706, // 002D GETMET R7 R3 K6 + 0x88240907, // 002E GETMBR R9 R4 K7 + 0x88280108, // 002F GETMBR R10 R0 K8 + 0x7C1C0600, // 0030 CALL R7 3 + 0x80040E00, // 0031 RET 1 R7 + 0x70020010, // 0032 JMP #0044 + 0x541EFFFB, // 0033 LDINT R7 65532 + 0x1C1C0C07, // 0034 EQ R7 R6 R7 + 0x781E0005, // 0035 JMPF R7 #003C + 0x8C1C0706, // 0036 GETMET R7 R3 K6 + 0x8824090B, // 0037 GETMBR R9 R4 K11 + 0x5828000C, // 0038 LDCONST R10 K12 + 0x7C1C0600, // 0039 CALL R7 3 + 0x80040E00, // 003A RET 1 R7 + 0x70020007, // 003B JMP #0044 + 0x541EFFFC, // 003C LDINT R7 65533 + 0x1C1C0C07, // 003D EQ R7 R6 R7 + 0x781E0004, // 003E JMPF R7 #0044 + 0x8C1C0706, // 003F GETMET R7 R3 K6 + 0x8824090B, // 0040 GETMBR R9 R4 K11 + 0x542A0004, // 0041 LDINT R10 5 + 0x7C1C0600, // 0042 CALL R7 3 + 0x80040E00, // 0043 RET 1 R7 + 0x70020008, // 0044 JMP #004E + 0x601C0003, // 0045 GETGBL R7 G3 + 0x5C200000, // 0046 MOVE R8 R0 + 0x7C1C0200, // 0047 CALL R7 1 + 0x8C1C0F0D, // 0048 GETMET R7 R7 K13 + 0x5C240200, // 0049 MOVE R9 R1 + 0x5C280400, // 004A MOVE R10 R2 + 0x5C2C0600, // 004B MOVE R11 R3 + 0x7C1C0800, // 004C CALL R7 4 + 0x80040E00, // 004D RET 1 R7 + 0x80000000, // 004E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_virtual +********************************************************************/ +be_local_closure(Matter_Plugin_Light1_update_virtual, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(find), + /* K1 */ be_nested_str_weak(Power), + /* K2 */ be_nested_str_weak(Bri), + /* K3 */ be_nested_str_weak(set_bri), + /* K4 */ be_nested_str_weak(update_virtual), + }), + be_str_weak(update_virtual), + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x8C080300, // 0000 GETMET R2 R1 K0 + 0x58100001, // 0001 LDCONST R4 K1 + 0x7C080400, // 0002 CALL R2 2 + 0x8C0C0300, // 0003 GETMET R3 R1 K0 + 0x58140002, // 0004 LDCONST R5 K2 + 0x7C0C0400, // 0005 CALL R3 2 + 0x4C100000, // 0006 LDNIL R4 + 0x20100604, // 0007 NE R4 R3 R4 + 0x78120006, // 0008 JMPF R4 #0010 + 0x8C100103, // 0009 GETMET R4 R0 K3 + 0x60180009, // 000A GETGBL R6 G9 + 0x5C1C0600, // 000B MOVE R7 R3 + 0x7C180200, // 000C CALL R6 1 + 0x5C1C0400, // 000D MOVE R7 R2 + 0x7C100600, // 000E CALL R4 3 + 0x80000800, // 000F RET 0 + 0x60100003, // 0010 GETGBL R4 G3 + 0x5C140000, // 0011 MOVE R5 R0 + 0x7C100200, // 0012 CALL R4 1 + 0x8C100904, // 0013 GETMET R4 R4 K4 + 0x5C180200, // 0014 MOVE R6 R1 + 0x7C100400, // 0015 CALL R4 2 + 0x80000000, // 0016 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Light1_invoke_request, /* name */ + be_nested_proto( + 22, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[21]) { /* constants */ + /* K0 */ be_nested_str_weak(light), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(command), + /* K5 */ be_nested_str_weak(update_shadow_lazy), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(findsubval), + /* K8 */ be_nested_str_weak(set_bri), + /* K9 */ be_nested_str_weak(log), + /* K10 */ be_nested_str_weak(bri_X3A), + /* K11 */ be_nested_str_weak(publish_command), + /* K12 */ be_nested_str_weak(Bri), + /* K13 */ be_nested_str_weak(Dimmer), + /* K14 */ be_nested_str_weak(tasmota), + /* K15 */ be_nested_str_weak(scale_uint), + /* K16 */ be_const_int(1), + /* K17 */ be_const_int(2), + /* K18 */ be_const_int(3), + /* K19 */ be_nested_str_weak(Power), + /* K20 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[119]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x54220007, // 0005 LDINT R8 8 + 0x1C200C08, // 0006 EQ R8 R6 R8 + 0x78220064, // 0007 JMPF R8 #006D + 0x8C200105, // 0008 GETMET R8 R0 K5 + 0x7C200200, // 0009 CALL R8 1 + 0x1C200F06, // 000A EQ R8 R7 K6 + 0x7822001A, // 000B JMPF R8 #0027 + 0x8C200507, // 000C GETMET R8 R2 K7 + 0x58280006, // 000D LDCONST R10 K6 + 0x7C200400, // 000E CALL R8 2 + 0x8C240108, // 000F GETMET R9 R0 K8 + 0x5C2C1000, // 0010 MOVE R11 R8 + 0x7C240400, // 0011 CALL R9 2 + 0x60240008, // 0012 GETGBL R9 G8 + 0x5C281000, // 0013 MOVE R10 R8 + 0x7C240200, // 0014 CALL R9 1 + 0x00261409, // 0015 ADD R9 K10 R9 + 0x900E1209, // 0016 SETMBR R3 K9 R9 + 0x8C24010B, // 0017 GETMET R9 R0 K11 + 0x582C000C, // 0018 LDCONST R11 K12 + 0x5C301000, // 0019 MOVE R12 R8 + 0x5834000D, // 001A LDCONST R13 K13 + 0xB83A1C00, // 001B GETNGBL R14 K14 + 0x8C381D0F, // 001C GETMET R14 R14 K15 + 0x5C401000, // 001D MOVE R16 R8 + 0x58440006, // 001E LDCONST R17 K6 + 0x544A00FD, // 001F LDINT R18 254 + 0x584C0006, // 0020 LDCONST R19 K6 + 0x54520063, // 0021 LDINT R20 100 + 0x7C380C00, // 0022 CALL R14 6 + 0x7C240A00, // 0023 CALL R9 5 + 0x50240200, // 0024 LDBOOL R9 1 0 + 0x80041200, // 0025 RET 1 R9 + 0x70020044, // 0026 JMP #006C + 0x1C200F10, // 0027 EQ R8 R7 K16 + 0x78220002, // 0028 JMPF R8 #002C + 0x50200200, // 0029 LDBOOL R8 1 0 + 0x80041000, // 002A RET 1 R8 + 0x7002003F, // 002B JMP #006C + 0x1C200F11, // 002C EQ R8 R7 K17 + 0x78220002, // 002D JMPF R8 #0031 + 0x50200200, // 002E LDBOOL R8 1 0 + 0x80041000, // 002F RET 1 R8 + 0x7002003A, // 0030 JMP #006C + 0x1C200F12, // 0031 EQ R8 R7 K18 + 0x78220002, // 0032 JMPF R8 #0036 + 0x50200200, // 0033 LDBOOL R8 1 0 + 0x80041000, // 0034 RET 1 R8 + 0x70020035, // 0035 JMP #006C + 0x54220003, // 0036 LDINT R8 4 + 0x1C200E08, // 0037 EQ R8 R7 R8 + 0x78220021, // 0038 JMPF R8 #005B + 0x8C200507, // 0039 GETMET R8 R2 K7 + 0x58280006, // 003A LDCONST R10 K6 + 0x7C200400, // 003B CALL R8 2 + 0x24241106, // 003C GT R9 R8 K6 + 0x8C280108, // 003D GETMET R10 R0 K8 + 0x5C301000, // 003E MOVE R12 R8 + 0x5C341200, // 003F MOVE R13 R9 + 0x7C280600, // 0040 CALL R10 3 + 0x60280008, // 0041 GETGBL R10 G8 + 0x5C2C1000, // 0042 MOVE R11 R8 + 0x7C280200, // 0043 CALL R10 1 + 0x002A140A, // 0044 ADD R10 K10 R10 + 0x900E120A, // 0045 SETMBR R3 K9 R10 + 0x8C28010B, // 0046 GETMET R10 R0 K11 + 0x5830000C, // 0047 LDCONST R12 K12 + 0x5C341000, // 0048 MOVE R13 R8 + 0x5838000D, // 0049 LDCONST R14 K13 + 0xB83E1C00, // 004A GETNGBL R15 K14 + 0x8C3C1F0F, // 004B GETMET R15 R15 K15 + 0x5C441000, // 004C MOVE R17 R8 + 0x58480006, // 004D LDCONST R18 K6 + 0x544E00FD, // 004E LDINT R19 254 + 0x58500006, // 004F LDCONST R20 K6 + 0x54560063, // 0050 LDINT R21 100 + 0x7C3C0C00, // 0051 CALL R15 6 + 0x58400013, // 0052 LDCONST R16 K19 + 0x78260001, // 0053 JMPF R9 #0056 + 0x58440010, // 0054 LDCONST R17 K16 + 0x70020000, // 0055 JMP #0057 + 0x58440006, // 0056 LDCONST R17 K6 + 0x7C280E00, // 0057 CALL R10 7 + 0x50280200, // 0058 LDBOOL R10 1 0 + 0x80041400, // 0059 RET 1 R10 + 0x70020010, // 005A JMP #006C + 0x54220004, // 005B LDINT R8 5 + 0x1C200E08, // 005C EQ R8 R7 R8 + 0x78220002, // 005D JMPF R8 #0061 + 0x50200200, // 005E LDBOOL R8 1 0 + 0x80041000, // 005F RET 1 R8 + 0x7002000A, // 0060 JMP #006C + 0x54220005, // 0061 LDINT R8 6 + 0x1C200E08, // 0062 EQ R8 R7 R8 + 0x78220002, // 0063 JMPF R8 #0067 + 0x50200200, // 0064 LDBOOL R8 1 0 + 0x80041000, // 0065 RET 1 R8 + 0x70020004, // 0066 JMP #006C + 0x54220006, // 0067 LDINT R8 7 + 0x1C200E08, // 0068 EQ R8 R7 R8 + 0x78220001, // 0069 JMPF R8 #006C + 0x50200200, // 006A LDBOOL R8 1 0 + 0x80041000, // 006B RET 1 R8 + 0x70020008, // 006C JMP #0076 + 0x60200003, // 006D GETGBL R8 G3 + 0x5C240000, // 006E MOVE R9 R0 + 0x7C200200, // 006F CALL R8 1 + 0x8C201114, // 0070 GETMET R8 R8 K20 + 0x5C280200, // 0071 MOVE R10 R1 + 0x5C2C0400, // 0072 MOVE R11 R2 + 0x5C300600, // 0073 MOVE R12 R3 + 0x7C200800, // 0074 CALL R8 4 + 0x80041000, // 0075 RET 1 R8 + 0x80000000, // 0076 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Light1 +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Light0; +be_local_class(Matter_Plugin_Light1, + 1, + &be_class_Matter_Plugin_Light0, + be_nested_map(12, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light1_invoke_request_closure) }, + { be_const_key_weak(shadow_bri, 7), be_const_var(0) }, + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(257, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(UPDATE_COMMANDS, 4), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(2, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Power), + be_nested_str_weak(Bri), + })) ) } )) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light1_init_closure) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Light1_update_shadow_closure) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Light1_read_attribute_closure) }, + { be_const_key_weak(TYPE, 5), be_nested_str_weak(light1) }, + { be_const_key_weak(update_virtual, -1), be_const_closure(Matter_Plugin_Light1_update_virtual_closure) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Light_X201_X20Dimmer) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(7, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(29, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(8, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(2), + be_const_int(3), + be_const_int(15), + be_const_int(17), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(set_bri, 0), be_const_closure(Matter_Plugin_Light1_set_bri_closure) }, + })), + be_str_weak(Matter_Plugin_Light1) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Light1_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Light1); + be_setglobal(vm, "Matter_Plugin_Light1"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Contact.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Contact.h similarity index 55% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Contact.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Contact.h index 00e5c533c..7a33f6a30 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Contact.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Contact.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Sensor_Contact.h */ +/* Solidification of Matter_Plugin_3_Sensor_Contact.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -7,26 +7,32 @@ extern const bclass be_class_Matter_Plugin_Sensor_Contact; /******************************************************************** -** Solidified function: +** Solidified function: append_state_json ********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_Contact__X3Clambda_X3E, /* name */ +be_local_closure(Matter_Plugin_Sensor_Contact_append_state_json, /* name */ be_nested_proto( - 3, /* nstack */ + 5, /* nstack */ 1, /* argc */ - 0, /* varg */ + 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(_X3Clambda_X3E), + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_X2C_X22Contact_X22_X3A_X25s), + /* K1 */ be_nested_str_weak(shadow_contact), + }), + be_str_weak(append_state_json), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040009, // 0000 GETGBL R1 G9 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x80040200, // 0003 RET 1 R1 + ( &(const binstruction[ 7]) { /* code */ + 0x60040018, // 0000 GETGBL R1 G24 + 0x58080000, // 0001 LDCONST R2 K0 + 0x600C0009, // 0002 GETGBL R3 G9 + 0x88100101, // 0003 GETMBR R4 R0 K1 + 0x7C0C0200, // 0004 CALL R3 1 + 0x7C040400, // 0005 CALL R1 2 + 0x80040200, // 0006 RET 1 R1 }) ) ); @@ -74,6 +80,200 @@ be_local_closure(Matter_Plugin_Sensor_Contact_parse_configuration, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Contact_update_shadow, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(update_shadow), + /* K1 */ be_nested_str_weak(json), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(cmd), + /* K4 */ be_nested_str_weak(Status_X208), + /* K5 */ be_nested_str_weak(load), + /* K6 */ be_nested_str_weak(find), + /* K7 */ be_nested_str_weak(Switch), + /* K8 */ be_nested_str_weak(tasmota_switch_index), + /* K9 */ be_nested_str_weak(ON), + /* K10 */ be_nested_str_weak(shadow_contact), + /* K11 */ be_nested_str_weak(attribute_updated), + /* K12 */ be_const_int(0), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[38]) { /* code */ + 0x60040003, // 0000 GETGBL R1 G3 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x8C040300, // 0003 GETMET R1 R1 K0 + 0x7C040200, // 0004 CALL R1 1 + 0xA4060200, // 0005 IMPORT R1 K1 + 0xB80A0400, // 0006 GETNGBL R2 K2 + 0x8C080503, // 0007 GETMET R2 R2 K3 + 0x58100004, // 0008 LDCONST R4 K4 + 0x50140200, // 0009 LDBOOL R5 1 0 + 0x7C080600, // 000A CALL R2 3 + 0x4C0C0000, // 000B LDNIL R3 + 0x200C0403, // 000C NE R3 R2 R3 + 0x780E0016, // 000D JMPF R3 #0025 + 0x8C0C0305, // 000E GETMET R3 R1 K5 + 0x5C140400, // 000F MOVE R5 R2 + 0x7C0C0400, // 0010 CALL R3 2 + 0x4C100000, // 0011 LDNIL R4 + 0x20100604, // 0012 NE R4 R3 R4 + 0x78120010, // 0013 JMPF R4 #0025 + 0x50100000, // 0014 LDBOOL R4 0 0 + 0x8C140706, // 0015 GETMET R5 R3 K6 + 0x601C0008, // 0016 GETGBL R7 G8 + 0x88200108, // 0017 GETMBR R8 R0 K8 + 0x7C1C0200, // 0018 CALL R7 1 + 0x001E0E07, // 0019 ADD R7 K7 R7 + 0x7C140400, // 001A CALL R5 2 + 0x1C140B09, // 001B EQ R5 R5 K9 + 0x5C100A00, // 001C MOVE R4 R5 + 0x8814010A, // 001D GETMBR R5 R0 K10 + 0x20140A04, // 001E NE R5 R5 R4 + 0x78160004, // 001F JMPF R5 #0025 + 0x8C14010B, // 0020 GETMET R5 R0 K11 + 0x541E0044, // 0021 LDINT R7 69 + 0x5820000C, // 0022 LDCONST R8 K12 + 0x7C140600, // 0023 CALL R5 3 + 0x90021404, // 0024 SETMBR R0 K10 R4 + 0x80000000, // 0025 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_virtual +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Contact_update_virtual, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(find), + /* K1 */ be_nested_str_weak(Contact), + /* K2 */ be_nested_str_weak(shadow_contact), + /* K3 */ be_nested_str_weak(attribute_updated), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(update_virtual), + }), + be_str_weak(update_virtual), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x8C080300, // 0000 GETMET R2 R1 K0 + 0x58100001, // 0001 LDCONST R4 K1 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x200C0403, // 0004 NE R3 R2 R3 + 0x780E000B, // 0005 JMPF R3 #0012 + 0x600C0017, // 0006 GETGBL R3 G23 + 0x5C100400, // 0007 MOVE R4 R2 + 0x7C0C0200, // 0008 CALL R3 1 + 0x5C080600, // 0009 MOVE R2 R3 + 0x880C0102, // 000A GETMBR R3 R0 K2 + 0x200C0602, // 000B NE R3 R3 R2 + 0x780E0004, // 000C JMPF R3 #0012 + 0x8C0C0103, // 000D GETMET R3 R0 K3 + 0x54160044, // 000E LDINT R5 69 + 0x58180004, // 000F LDCONST R6 K4 + 0x7C0C0600, // 0010 CALL R3 3 + 0x90020402, // 0011 SETMBR R0 K2 R2 + 0x600C0003, // 0012 GETGBL R3 G3 + 0x5C100000, // 0013 MOVE R4 R0 + 0x7C0C0200, // 0014 CALL R3 1 + 0x8C0C0705, // 0015 GETMET R3 R3 K5 + 0x5C140200, // 0016 MOVE R5 R1 + 0x7C0C0400, // 0017 CALL R3 2 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Contact__X3Clambda_X3E, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040009, // 0000 GETGBL R1 G9 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Contact_init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(shadow_contact), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x60100003, // 0000 GETGBL R4 G3 + 0x5C140000, // 0001 MOVE R5 R0 + 0x7C100200, // 0002 CALL R4 1 + 0x8C100900, // 0003 GETMET R4 R4 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x5C1C0400, // 0005 MOVE R7 R2 + 0x5C200600, // 0006 MOVE R8 R3 + 0x7C100800, // 0007 CALL R4 4 + 0x50100000, // 0008 LDBOOL R4 0 0 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -163,88 +363,6 @@ be_local_closure(Matter_Plugin_Sensor_Contact_read_attribute, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_Contact_update_shadow, /* name */ - be_nested_proto( - 9, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(update_shadow), - /* K1 */ be_nested_str_weak(json), - /* K2 */ be_nested_str_weak(tasmota), - /* K3 */ be_nested_str_weak(cmd), - /* K4 */ be_nested_str_weak(Status_X208), - /* K5 */ be_nested_str_weak(load), - /* K6 */ be_nested_str_weak(find), - /* K7 */ be_nested_str_weak(Switch), - /* K8 */ be_nested_str_weak(tasmota_switch_index), - /* K9 */ be_nested_str_weak(ON), - /* K10 */ be_nested_str_weak(shadow_contact), - /* K11 */ be_nested_str_weak(attribute_updated), - /* K12 */ be_const_int(0), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[45]) { /* code */ - 0x60040003, // 0000 GETGBL R1 G3 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x8C040300, // 0003 GETMET R1 R1 K0 - 0x7C040200, // 0004 CALL R1 1 - 0xA4060200, // 0005 IMPORT R1 K1 - 0xB80A0400, // 0006 GETNGBL R2 K2 - 0x8C080503, // 0007 GETMET R2 R2 K3 - 0x58100004, // 0008 LDCONST R4 K4 - 0x50140200, // 0009 LDBOOL R5 1 0 - 0x7C080600, // 000A CALL R2 3 - 0x4C0C0000, // 000B LDNIL R3 - 0x200C0403, // 000C NE R3 R2 R3 - 0x780E001D, // 000D JMPF R3 #002C - 0x8C0C0305, // 000E GETMET R3 R1 K5 - 0x5C140400, // 000F MOVE R5 R2 - 0x7C0C0400, // 0010 CALL R3 2 - 0x4C100000, // 0011 LDNIL R4 - 0x20100604, // 0012 NE R4 R3 R4 - 0x78120017, // 0013 JMPF R4 #002C - 0x50100000, // 0014 LDBOOL R4 0 0 - 0x8C140706, // 0015 GETMET R5 R3 K6 - 0x601C0008, // 0016 GETGBL R7 G8 - 0x88200108, // 0017 GETMBR R8 R0 K8 - 0x7C1C0200, // 0018 CALL R7 1 - 0x001E0E07, // 0019 ADD R7 K7 R7 - 0x7C140400, // 001A CALL R5 2 - 0x1C140B09, // 001B EQ R5 R5 K9 - 0x5C100A00, // 001C MOVE R4 R5 - 0x8814010A, // 001D GETMBR R5 R0 K10 - 0x4C180000, // 001E LDNIL R6 - 0x20140A06, // 001F NE R5 R5 R6 - 0x78160009, // 0020 JMPF R5 #002B - 0x8814010A, // 0021 GETMBR R5 R0 K10 - 0x60180017, // 0022 GETGBL R6 G23 - 0x5C1C0800, // 0023 MOVE R7 R4 - 0x7C180200, // 0024 CALL R6 1 - 0x20140A06, // 0025 NE R5 R5 R6 - 0x78160003, // 0026 JMPF R5 #002B - 0x8C14010B, // 0027 GETMET R5 R0 K11 - 0x541E0044, // 0028 LDINT R7 69 - 0x5820000C, // 0029 LDCONST R8 K12 - 0x7C140600, // 002A CALL R5 3 - 0x90021404, // 002B SETMBR R0 K10 R4 - 0x80000000, // 002C RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Plugin_Sensor_Contact ********************************************************************/ @@ -252,35 +370,91 @@ extern const bclass be_class_Matter_Plugin_Device; be_local_class(Matter_Plugin_Sensor_Contact, 2, &be_class_Matter_Plugin_Device, - be_nested_map(13, + be_nested_map(17, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ARG, -1), be_nested_str_weak(switch) }, - { be_const_key_weak(shadow_contact, -1), be_const_var(1) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(contact) }, - { be_const_key_weak(ARG_TYPE, 5), be_const_static_closure(Matter_Plugin_Sensor_Contact__X3Clambda_X3E_closure) }, - { be_const_key_weak(UPDATE_TIME, -1), be_const_int(750) }, - { be_const_key_weak(ARG_HINT, 1), be_nested_str_weak(Switch_X3Cx_X3E_X20number) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Contact) }, - { be_const_key_weak(parse_configuration, 8), be_const_closure(Matter_Plugin_Sensor_Contact_parse_configuration_closure) }, - { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Sensor_Contact_update_shadow_closure) }, - { be_const_key_weak(tasmota_switch_index, 6), be_const_var(0) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(read_attribute, 12), be_const_closure(Matter_Plugin_Sensor_Contact_read_attribute_closure) }, + { be_const_key_weak(append_state_json, -1), be_const_closure(Matter_Plugin_Sensor_Contact_append_state_json_closure) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Switch_X3Cx_X3E_X20number) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Sensor_Contact_init_closure) }, + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(69, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(21, -1), be_const_int(1) }, + })) ) } )) }, + { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_Sensor_Contact_parse_configuration_closure) }, + { be_const_key_weak(shadow_contact, 16), be_const_var(1) }, + { be_const_key_weak(update_virtual, -1), be_const_closure(Matter_Plugin_Sensor_Contact_update_virtual_closure) }, + { be_const_key_weak(ARG, 7), be_nested_str_weak(switch) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(69, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(3, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(read_attribute, 4), be_const_closure(Matter_Plugin_Sensor_Contact_read_attribute_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(21, -1), be_const_int(1) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(tasmota_switch_index, -1), be_const_var(0) }, + { be_const_key_weak(DISPLAY_NAME, 0), be_nested_str_weak(Contact) }, + { be_const_key_weak(ARG_TYPE, 13), be_const_static_closure(Matter_Plugin_Sensor_Contact__X3Clambda_X3E_closure) }, + { be_const_key_weak(UPDATE_TIME, -1), be_const_int(750) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(contact) }, + { be_const_key_weak(UPDATE_COMMANDS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Contact), + })) ) } )) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Sensor_Contact_update_shadow_closure) }, })), be_str_weak(Matter_Plugin_Sensor_Contact) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Humidity.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Humidity.h similarity index 72% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Humidity.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Humidity.h index 77df755f2..f4e9ebc3a 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Humidity.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Humidity.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Sensor_Humidity.h */ +/* Solidification of Matter_Plugin_3_Sensor_Humidity.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,6 +6,37 @@ extern const bclass be_class_Matter_Plugin_Sensor_Humidity; +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Humidity_value_changed, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0404, // 0001 LDINT R3 1029 + 0x58100001, // 0002 LDCONST R4 K1 + 0x7C040600, // 0003 CALL R1 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -148,37 +179,6 @@ be_local_closure(Matter_Plugin_Sensor_Humidity_pre_value, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: value_changed -********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_Humidity_value_changed, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - }), - be_str_weak(value_changed), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x54120404, // 0001 LDINT R4 1029 - 0x58140001, // 0002 LDCONST R5 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Plugin_Sensor_Humidity ********************************************************************/ @@ -186,14 +186,58 @@ extern const bclass be_class_Matter_Plugin_Sensor; be_local_class(Matter_Plugin_Sensor_Humidity, 0, &be_class_Matter_Plugin_Sensor, - be_nested_map(7, + be_nested_map(9, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, 2), be_const_closure(Matter_Plugin_Sensor_Humidity_read_attribute_closure) }, - { be_const_key_weak(pre_value, 4), be_const_closure(Matter_Plugin_Sensor_Humidity_pre_value_closure) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Humidity) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(humidity) }, + { be_const_key_weak(TYPES, 8), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(1029, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(775, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(UPDATE_COMMANDS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Humidity), + })) ) } )) }, + { be_const_key_weak(value_changed, 7), be_const_closure(Matter_Plugin_Sensor_Humidity_value_changed_closure) }, + { be_const_key_weak(JSON_NAME, -1), be_nested_str_weak(Humidity) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Sensor_Humidity_read_attribute_closure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(1029, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), @@ -202,15 +246,25 @@ be_local_class(Matter_Plugin_Sensor_Humidity, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(TYPE, 6), be_nested_str_weak(humidity) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Humidity) }, - { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Sensor_Humidity_value_changed_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(775, -1), be_const_int(2) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(pre_value, -1), be_const_closure(Matter_Plugin_Sensor_Humidity_pre_value_closure) }, })), be_str_weak(Matter_Plugin_Sensor_Humidity) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Illuminance.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Illuminance.h similarity index 73% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Illuminance.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Illuminance.h index 6da510376..17b96ce22 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Illuminance.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Illuminance.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Sensor_Illuminance.h */ +/* Solidification of Matter_Plugin_3_Sensor_Illuminance.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,6 +6,37 @@ extern const bclass be_class_Matter_Plugin_Sensor_Illuminance; +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Illuminance_value_changed, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E03FF, // 0001 LDINT R3 1024 + 0x58100001, // 0002 LDCONST R4 K1 + 0x7C040600, // 0003 CALL R1 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -160,37 +191,6 @@ be_local_closure(Matter_Plugin_Sensor_Illuminance_pre_value, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: value_changed -********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_Illuminance_value_changed, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - }), - be_str_weak(value_changed), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x541203FF, // 0001 LDINT R4 1024 - 0x58140001, // 0002 LDCONST R5 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Plugin_Sensor_Illuminance ********************************************************************/ @@ -198,14 +198,65 @@ extern const bclass be_class_Matter_Plugin_Sensor; be_local_class(Matter_Plugin_Sensor_Illuminance, 0, &be_class_Matter_Plugin_Sensor, - be_nested_map(7, + be_nested_map(9, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, 2), be_const_closure(Matter_Plugin_Sensor_Illuminance_read_attribute_closure) }, - { be_const_key_weak(pre_value, 4), be_const_closure(Matter_Plugin_Sensor_Illuminance_pre_value_closure) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Illuminance) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(illuminance) }, + { be_const_key_weak(TYPES, 8), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(1024, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(262, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(UPDATE_COMMANDS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Illuminance), + })) ) } )) }, + { be_const_key_weak(value_changed, 7), be_const_closure(Matter_Plugin_Sensor_Illuminance_value_changed_closure) }, + { be_const_key_weak(JSON_NAME, -1), be_nested_str_weak(Illuminance) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Sensor_Illuminance_read_attribute_closure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(1024, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), @@ -214,15 +265,18 @@ be_local_class(Matter_Plugin_Sensor_Illuminance, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(TYPE, 6), be_nested_str_weak(illuminance) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Illuminance) }, - { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Sensor_Illuminance_value_changed_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(262, -1), be_const_int(2) }, })) ) } )) }, + { be_const_key_weak(pre_value, -1), be_const_closure(Matter_Plugin_Sensor_Illuminance_pre_value_closure) }, })), be_str_weak(Matter_Plugin_Sensor_Illuminance) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Occupancy.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Occupancy.h similarity index 59% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Occupancy.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Occupancy.h index 7d9f5f042..a2585b7a0 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Occupancy.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Occupancy.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Sensor_Occupancy.h */ +/* Solidification of Matter_Plugin_3_Sensor_Occupancy.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -7,26 +7,32 @@ extern const bclass be_class_Matter_Plugin_Sensor_Occupancy; /******************************************************************** -** Solidified function: +** Solidified function: append_state_json ********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_Occupancy__X3Clambda_X3E, /* name */ +be_local_closure(Matter_Plugin_Sensor_Occupancy_append_state_json, /* name */ be_nested_proto( - 3, /* nstack */ + 5, /* nstack */ 1, /* argc */ - 0, /* varg */ + 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ - 0, /* has constants */ - NULL, /* no const */ - be_str_weak(_X3Clambda_X3E), + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_X2C_X22Occupancy_X22_X3A_X25s), + /* K1 */ be_nested_str_weak(shadow_occupancy), + }), + be_str_weak(append_state_json), &be_const_str_solidified, - ( &(const binstruction[ 4]) { /* code */ - 0x60040009, // 0000 GETGBL R1 G9 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x80040200, // 0003 RET 1 R1 + ( &(const binstruction[ 7]) { /* code */ + 0x60040018, // 0000 GETGBL R1 G24 + 0x58080000, // 0001 LDCONST R2 K0 + 0x600C0009, // 0002 GETGBL R3 G9 + 0x88100101, // 0003 GETMBR R4 R0 K1 + 0x7C0C0200, // 0004 CALL R3 1 + 0x7C040400, // 0005 CALL R1 2 + 0x80040200, // 0006 RET 1 R1 }) ) ); @@ -74,6 +80,203 @@ be_local_closure(Matter_Plugin_Sensor_Occupancy_parse_configuration, /* name * /*******************************************************************/ +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Occupancy_update_shadow, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(update_shadow), + /* K1 */ be_nested_str_weak(Switch), + /* K2 */ be_nested_str_weak(tasmota_switch_index), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(cmd), + /* K5 */ be_nested_str_weak(Status_X208), + /* K6 */ be_nested_str_weak(find), + /* K7 */ be_nested_str_weak(StatusSNS), + /* K8 */ be_nested_str_weak(contains), + /* K9 */ be_nested_str_weak(ON), + /* K10 */ be_nested_str_weak(shadow_occupancy), + /* K11 */ be_nested_str_weak(attribute_updated), + /* K12 */ be_const_int(0), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[41]) { /* code */ + 0x60040003, // 0000 GETGBL R1 G3 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x8C040300, // 0003 GETMET R1 R1 K0 + 0x7C040200, // 0004 CALL R1 1 + 0x60040008, // 0005 GETGBL R1 G8 + 0x88080102, // 0006 GETMBR R2 R0 K2 + 0x7C040200, // 0007 CALL R1 1 + 0x00060201, // 0008 ADD R1 K1 R1 + 0xB80A0600, // 0009 GETNGBL R2 K3 + 0x8C080504, // 000A GETMET R2 R2 K4 + 0x58100005, // 000B LDCONST R4 K5 + 0x50140200, // 000C LDBOOL R5 1 0 + 0x7C080600, // 000D CALL R2 3 + 0x4C0C0000, // 000E LDNIL R3 + 0x200C0403, // 000F NE R3 R2 R3 + 0x780E0003, // 0010 JMPF R3 #0015 + 0x8C0C0506, // 0011 GETMET R3 R2 K6 + 0x58140007, // 0012 LDCONST R5 K7 + 0x7C0C0400, // 0013 CALL R3 2 + 0x5C080600, // 0014 MOVE R2 R3 + 0x4C0C0000, // 0015 LDNIL R3 + 0x200C0403, // 0016 NE R3 R2 R3 + 0x780E000F, // 0017 JMPF R3 #0028 + 0x8C0C0508, // 0018 GETMET R3 R2 K8 + 0x5C140200, // 0019 MOVE R5 R1 + 0x7C0C0400, // 001A CALL R3 2 + 0x780E000B, // 001B JMPF R3 #0028 + 0x8C0C0506, // 001C GETMET R3 R2 K6 + 0x5C140200, // 001D MOVE R5 R1 + 0x7C0C0400, // 001E CALL R3 2 + 0x1C0C0709, // 001F EQ R3 R3 K9 + 0x8810010A, // 0020 GETMBR R4 R0 K10 + 0x20100803, // 0021 NE R4 R4 R3 + 0x78120003, // 0022 JMPF R4 #0027 + 0x8C10010B, // 0023 GETMET R4 R0 K11 + 0x541A0405, // 0024 LDINT R6 1030 + 0x581C000C, // 0025 LDCONST R7 K12 + 0x7C100600, // 0026 CALL R4 3 + 0x90021403, // 0027 SETMBR R0 K10 R3 + 0x80000000, // 0028 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_virtual +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Occupancy_update_virtual, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str_weak(find), + /* K1 */ be_nested_str_weak(Occupancy), + /* K2 */ be_nested_str_weak(shadow_occupancy), + /* K3 */ be_nested_str_weak(attribute_updated), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(update_virtual), + }), + be_str_weak(update_virtual), + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x8C080300, // 0000 GETMET R2 R1 K0 + 0x58100001, // 0001 LDCONST R4 K1 + 0x7C080400, // 0002 CALL R2 2 + 0x4C0C0000, // 0003 LDNIL R3 + 0x200C0403, // 0004 NE R3 R2 R3 + 0x780E000B, // 0005 JMPF R3 #0012 + 0x600C0017, // 0006 GETGBL R3 G23 + 0x5C100400, // 0007 MOVE R4 R2 + 0x7C0C0200, // 0008 CALL R3 1 + 0x5C080600, // 0009 MOVE R2 R3 + 0x880C0102, // 000A GETMBR R3 R0 K2 + 0x200C0602, // 000B NE R3 R3 R2 + 0x780E0004, // 000C JMPF R3 #0012 + 0x8C0C0103, // 000D GETMET R3 R0 K3 + 0x54160405, // 000E LDINT R5 1030 + 0x58180004, // 000F LDCONST R6 K4 + 0x7C0C0600, // 0010 CALL R3 3 + 0x90020402, // 0011 SETMBR R0 K2 R2 + 0x600C0003, // 0012 GETGBL R3 G3 + 0x5C100000, // 0013 MOVE R4 R0 + 0x7C0C0200, // 0014 CALL R3 1 + 0x8C0C0705, // 0015 GETMET R3 R3 K5 + 0x5C140200, // 0016 MOVE R5 R1 + 0x7C0C0400, // 0017 CALL R3 2 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Occupancy__X3Clambda_X3E, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 0, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 0, /* has constants */ + NULL, /* no const */ + be_str_weak(_X3Clambda_X3E), + &be_const_str_solidified, + ( &(const binstruction[ 4]) { /* code */ + 0x60040009, // 0000 GETGBL R1 G9 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x80040200, // 0003 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Occupancy_init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(shadow_occupancy), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x60100003, // 0000 GETGBL R4 G3 + 0x5C140000, // 0001 MOVE R5 R0 + 0x7C100200, // 0002 CALL R4 1 + 0x8C100900, // 0003 GETMET R4 R4 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x5C1C0400, // 0005 MOVE R7 R2 + 0x5C200600, // 0006 MOVE R8 R3 + 0x7C100800, // 0007 CALL R4 4 + 0x50100000, // 0008 LDBOOL R4 0 0 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -181,84 +384,6 @@ be_local_closure(Matter_Plugin_Sensor_Occupancy_read_attribute, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_Occupancy_update_shadow, /* name */ - be_nested_proto( - 8, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(update_shadow), - /* K1 */ be_nested_str_weak(Switch), - /* K2 */ be_nested_str_weak(tasmota_switch_index), - /* K3 */ be_nested_str_weak(tasmota), - /* K4 */ be_nested_str_weak(cmd), - /* K5 */ be_nested_str_weak(Status_X208), - /* K6 */ be_nested_str_weak(find), - /* K7 */ be_nested_str_weak(StatusSNS), - /* K8 */ be_nested_str_weak(contains), - /* K9 */ be_nested_str_weak(ON), - /* K10 */ be_nested_str_weak(shadow_occupancy), - /* K11 */ be_nested_str_weak(attribute_updated), - /* K12 */ be_const_int(0), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[41]) { /* code */ - 0x60040003, // 0000 GETGBL R1 G3 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x8C040300, // 0003 GETMET R1 R1 K0 - 0x7C040200, // 0004 CALL R1 1 - 0x60040008, // 0005 GETGBL R1 G8 - 0x88080102, // 0006 GETMBR R2 R0 K2 - 0x7C040200, // 0007 CALL R1 1 - 0x00060201, // 0008 ADD R1 K1 R1 - 0xB80A0600, // 0009 GETNGBL R2 K3 - 0x8C080504, // 000A GETMET R2 R2 K4 - 0x58100005, // 000B LDCONST R4 K5 - 0x50140200, // 000C LDBOOL R5 1 0 - 0x7C080600, // 000D CALL R2 3 - 0x4C0C0000, // 000E LDNIL R3 - 0x200C0403, // 000F NE R3 R2 R3 - 0x780E0003, // 0010 JMPF R3 #0015 - 0x8C0C0506, // 0011 GETMET R3 R2 K6 - 0x58140007, // 0012 LDCONST R5 K7 - 0x7C0C0400, // 0013 CALL R3 2 - 0x5C080600, // 0014 MOVE R2 R3 - 0x4C0C0000, // 0015 LDNIL R3 - 0x200C0403, // 0016 NE R3 R2 R3 - 0x780E000F, // 0017 JMPF R3 #0028 - 0x8C0C0508, // 0018 GETMET R3 R2 K8 - 0x5C140200, // 0019 MOVE R5 R1 - 0x7C0C0400, // 001A CALL R3 2 - 0x780E000B, // 001B JMPF R3 #0028 - 0x8C0C0506, // 001C GETMET R3 R2 K6 - 0x5C140200, // 001D MOVE R5 R1 - 0x7C0C0400, // 001E CALL R3 2 - 0x1C0C0709, // 001F EQ R3 R3 K9 - 0x8810010A, // 0020 GETMBR R4 R0 K10 - 0x20100803, // 0021 NE R4 R4 R3 - 0x78120003, // 0022 JMPF R4 #0027 - 0x8C10010B, // 0023 GETMET R4 R0 K11 - 0x541A0405, // 0024 LDINT R6 1030 - 0x581C000C, // 0025 LDCONST R7 K12 - 0x7C100600, // 0026 CALL R4 3 - 0x90021403, // 0027 SETMBR R0 K10 R3 - 0x80000000, // 0028 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Plugin_Sensor_Occupancy ********************************************************************/ @@ -266,22 +391,63 @@ extern const bclass be_class_Matter_Plugin_Device; be_local_class(Matter_Plugin_Sensor_Occupancy, 2, &be_class_Matter_Plugin_Device, - be_nested_map(13, + be_nested_map(17, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ARG, -1), be_nested_str_weak(switch) }, - { be_const_key_weak(ARG_TYPE, -1), be_const_static_closure(Matter_Plugin_Sensor_Occupancy__X3Clambda_X3E_closure) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(occupancy) }, - { be_const_key_weak(ARG_HINT, 1), be_nested_str_weak(Switch_X3Cx_X3E_X20number) }, - { be_const_key_weak(UPDATE_TIME, -1), be_const_int(750) }, - { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_Sensor_Occupancy_parse_configuration_closure) }, - { be_const_key_weak(tasmota_switch_index, -1), be_const_var(0) }, - { be_const_key_weak(shadow_occupancy, 8), be_const_var(1) }, - { be_const_key_weak(update_shadow, 5), be_const_closure(Matter_Plugin_Sensor_Occupancy_update_shadow_closure) }, - { be_const_key_weak(NAME, 6), be_nested_str_weak(Occupancy) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(read_attribute, 12), be_const_closure(Matter_Plugin_Sensor_Occupancy_read_attribute_closure) }, + { be_const_key_weak(append_state_json, -1), be_const_closure(Matter_Plugin_Sensor_Occupancy_append_state_json_closure) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Switch_X3Cx_X3E_X20number) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Sensor_Occupancy_init_closure) }, + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(1030, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(263, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_Sensor_Occupancy_parse_configuration_closure) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Sensor_Occupancy_update_shadow_closure) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Occupancy) }, + { be_const_key_weak(ARG, 16), be_nested_str_weak(switch) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(1030, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), @@ -290,13 +456,28 @@ be_local_class(Matter_Plugin_Sensor_Occupancy, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(read_attribute, 4), be_const_closure(Matter_Plugin_Sensor_Occupancy_read_attribute_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(263, -1), be_const_int(2) }, })) ) } )) }, + { be_const_key_weak(tasmota_switch_index, -1), be_const_var(0) }, + { be_const_key_weak(UPDATE_TIME, 0), be_const_int(750) }, + { be_const_key_weak(shadow_occupancy, 13), be_const_var(1) }, + { be_const_key_weak(ARG_TYPE, 7), be_const_static_closure(Matter_Plugin_Sensor_Occupancy__X3Clambda_X3E_closure) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(occupancy) }, + { be_const_key_weak(UPDATE_COMMANDS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Occupancy), + })) ) } )) }, + { be_const_key_weak(update_virtual, -1), be_const_closure(Matter_Plugin_Sensor_Occupancy_update_virtual_closure) }, })), be_str_weak(Matter_Plugin_Sensor_Occupancy) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_OnOff.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_OnOff.h similarity index 72% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_OnOff.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_OnOff.h index 98a98f080..4bb8243a0 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_OnOff.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_OnOff.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Sensor_OnOff.h */ +/* Solidification of Matter_Plugin_3_Sensor_OnOff.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -33,6 +33,84 @@ be_local_closure(Matter_Plugin_Sensor_OnOff__X3Clambda_X3E, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_OnOff_update_shadow, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(update_shadow), + /* K1 */ be_nested_str_weak(Switch), + /* K2 */ be_nested_str_weak(tasmota_switch_index), + /* K3 */ be_nested_str_weak(tasmota), + /* K4 */ be_nested_str_weak(cmd), + /* K5 */ be_nested_str_weak(Status_X208), + /* K6 */ be_nested_str_weak(find), + /* K7 */ be_nested_str_weak(StatusSNS), + /* K8 */ be_nested_str_weak(contains), + /* K9 */ be_nested_str_weak(ON), + /* K10 */ be_nested_str_weak(shadow_onoff), + /* K11 */ be_nested_str_weak(attribute_updated), + /* K12 */ be_const_int(0), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[41]) { /* code */ + 0x60040003, // 0000 GETGBL R1 G3 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x8C040300, // 0003 GETMET R1 R1 K0 + 0x7C040200, // 0004 CALL R1 1 + 0x60040008, // 0005 GETGBL R1 G8 + 0x88080102, // 0006 GETMBR R2 R0 K2 + 0x7C040200, // 0007 CALL R1 1 + 0x00060201, // 0008 ADD R1 K1 R1 + 0xB80A0600, // 0009 GETNGBL R2 K3 + 0x8C080504, // 000A GETMET R2 R2 K4 + 0x58100005, // 000B LDCONST R4 K5 + 0x50140200, // 000C LDBOOL R5 1 0 + 0x7C080600, // 000D CALL R2 3 + 0x4C0C0000, // 000E LDNIL R3 + 0x200C0403, // 000F NE R3 R2 R3 + 0x780E0003, // 0010 JMPF R3 #0015 + 0x8C0C0506, // 0011 GETMET R3 R2 K6 + 0x58140007, // 0012 LDCONST R5 K7 + 0x7C0C0400, // 0013 CALL R3 2 + 0x5C080600, // 0014 MOVE R2 R3 + 0x4C0C0000, // 0015 LDNIL R3 + 0x200C0403, // 0016 NE R3 R2 R3 + 0x780E000F, // 0017 JMPF R3 #0028 + 0x8C0C0508, // 0018 GETMET R3 R2 K8 + 0x5C140200, // 0019 MOVE R5 R1 + 0x7C0C0400, // 001A CALL R3 2 + 0x780E000B, // 001B JMPF R3 #0028 + 0x8C0C0506, // 001C GETMET R3 R2 K6 + 0x5C140200, // 001D MOVE R5 R1 + 0x7C0C0400, // 001E CALL R3 2 + 0x1C0C0709, // 001F EQ R3 R3 K9 + 0x8810010A, // 0020 GETMBR R4 R0 K10 + 0x20100803, // 0021 NE R4 R4 R3 + 0x78120003, // 0022 JMPF R4 #0027 + 0x8C10010B, // 0023 GETMET R4 R0 K11 + 0x541A0005, // 0024 LDINT R6 6 + 0x581C000C, // 0025 LDCONST R7 K12 + 0x7C100600, // 0026 CALL R4 3 + 0x90021403, // 0027 SETMBR R0 K10 R3 + 0x80000000, // 0028 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: parse_configuration ********************************************************************/ @@ -155,11 +233,11 @@ be_local_closure(Matter_Plugin_Sensor_OnOff_read_attribute, /* name */ /******************************************************************** -** Solidified function: update_shadow +** Solidified function: append_state_json ********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_OnOff_update_shadow, /* name */ +be_local_closure(Matter_Plugin_Sensor_OnOff_append_state_json, /* name */ be_nested_proto( - 8, /* nstack */ + 5, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -167,65 +245,20 @@ be_local_closure(Matter_Plugin_Sensor_OnOff_update_shadow, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(update_shadow), - /* K1 */ be_nested_str_weak(Switch), - /* K2 */ be_nested_str_weak(tasmota_switch_index), - /* K3 */ be_nested_str_weak(tasmota), - /* K4 */ be_nested_str_weak(cmd), - /* K5 */ be_nested_str_weak(Status_X208), - /* K6 */ be_nested_str_weak(find), - /* K7 */ be_nested_str_weak(StatusSNS), - /* K8 */ be_nested_str_weak(contains), - /* K9 */ be_nested_str_weak(ON), - /* K10 */ be_nested_str_weak(shadow_onoff), - /* K11 */ be_nested_str_weak(attribute_updated), - /* K12 */ be_const_int(0), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(_X2C_X22OnOff_X22_X3A_X25s), + /* K1 */ be_nested_str_weak(shadow_onoff), }), - be_str_weak(update_shadow), + be_str_weak(append_state_json), &be_const_str_solidified, - ( &(const binstruction[41]) { /* code */ - 0x60040003, // 0000 GETGBL R1 G3 - 0x5C080000, // 0001 MOVE R2 R0 - 0x7C040200, // 0002 CALL R1 1 - 0x8C040300, // 0003 GETMET R1 R1 K0 - 0x7C040200, // 0004 CALL R1 1 - 0x60040008, // 0005 GETGBL R1 G8 - 0x88080102, // 0006 GETMBR R2 R0 K2 - 0x7C040200, // 0007 CALL R1 1 - 0x00060201, // 0008 ADD R1 K1 R1 - 0xB80A0600, // 0009 GETNGBL R2 K3 - 0x8C080504, // 000A GETMET R2 R2 K4 - 0x58100005, // 000B LDCONST R4 K5 - 0x50140200, // 000C LDBOOL R5 1 0 - 0x7C080600, // 000D CALL R2 3 - 0x4C0C0000, // 000E LDNIL R3 - 0x200C0403, // 000F NE R3 R2 R3 - 0x780E0003, // 0010 JMPF R3 #0015 - 0x8C0C0506, // 0011 GETMET R3 R2 K6 - 0x58140007, // 0012 LDCONST R5 K7 - 0x7C0C0400, // 0013 CALL R3 2 - 0x5C080600, // 0014 MOVE R2 R3 - 0x4C0C0000, // 0015 LDNIL R3 - 0x200C0403, // 0016 NE R3 R2 R3 - 0x780E000F, // 0017 JMPF R3 #0028 - 0x8C0C0508, // 0018 GETMET R3 R2 K8 - 0x5C140200, // 0019 MOVE R5 R1 - 0x7C0C0400, // 001A CALL R3 2 - 0x780E000B, // 001B JMPF R3 #0028 - 0x8C0C0506, // 001C GETMET R3 R2 K6 - 0x5C140200, // 001D MOVE R5 R1 - 0x7C0C0400, // 001E CALL R3 2 - 0x1C0C0709, // 001F EQ R3 R3 K9 - 0x8810010A, // 0020 GETMBR R4 R0 K10 - 0x20100803, // 0021 NE R4 R4 R3 - 0x78120003, // 0022 JMPF R4 #0027 - 0x8C10010B, // 0023 GETMET R4 R0 K11 - 0x541A0005, // 0024 LDINT R6 6 - 0x581C000C, // 0025 LDCONST R7 K12 - 0x7C100600, // 0026 CALL R4 3 - 0x90021403, // 0027 SETMBR R0 K10 R3 - 0x80000000, // 0028 RET 0 + ( &(const binstruction[ 7]) { /* code */ + 0x60040018, // 0000 GETGBL R1 G24 + 0x58080000, // 0001 LDCONST R2 K0 + 0x600C0009, // 0002 GETGBL R3 G9 + 0x88100101, // 0003 GETMBR R4 R0 K1 + 0x7C0C0200, // 0004 CALL R3 1 + 0x7C040400, // 0005 CALL R1 2 + 0x80040200, // 0006 RET 1 R1 }) ) ); @@ -239,20 +272,10 @@ extern const bclass be_class_Matter_Plugin_Device; be_local_class(Matter_Plugin_Sensor_OnOff, 2, &be_class_Matter_Plugin_Device, - be_nested_map(13, + be_nested_map(14, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ARG, 8), be_nested_str_weak(switch) }, - { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Switch_X3Cx_X3E_X20number) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(onoff) }, - { be_const_key_weak(ARG_TYPE, 1), be_const_static_closure(Matter_Plugin_Sensor_OnOff__X3Clambda_X3E_closure) }, - { be_const_key_weak(UPDATE_TIME, -1), be_const_int(750) }, - { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Sensor_OnOff_update_shadow_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(OnOff_X20Sensor) }, - { be_const_key_weak(parse_configuration, 5), be_const_closure(Matter_Plugin_Sensor_OnOff_parse_configuration_closure) }, - { be_const_key_weak(shadow_onoff, -1), be_const_var(1) }, - { be_const_key_weak(tasmota_switch_index, 6), be_const_var(0) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, + { be_const_key_weak(CLUSTERS, 8), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(3, @@ -261,13 +284,72 @@ be_local_class(Matter_Plugin_Sensor_OnOff, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(read_attribute, 4), be_const_closure(Matter_Plugin_Sensor_OnOff_read_attribute_closure) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(ARG, -1), be_nested_str_weak(switch) }, + { be_const_key_weak(UPDATE_TIME, 4), be_const_int(750) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(onoff) }, + { be_const_key_weak(append_state_json, 12), be_const_closure(Matter_Plugin_Sensor_OnOff_append_state_json_closure) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(OnOff_X20Sensor) }, + { be_const_key_weak(shadow_onoff, -1), be_const_var(1) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Sensor_OnOff_update_shadow_closure) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Sensor_OnOff_read_attribute_closure) }, + { be_const_key_weak(parse_configuration, -1), be_const_closure(Matter_Plugin_Sensor_OnOff_parse_configuration_closure) }, { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(2128, -1), be_const_int(2) }, })) ) } )) }, + { be_const_key_weak(ARG_HINT, 9), be_nested_str_weak(Switch_X3Cx_X3E_X20number) }, + { be_const_key_weak(tasmota_switch_index, 13), be_const_var(0) }, + { be_const_key_weak(ARG_TYPE, -1), be_const_static_closure(Matter_Plugin_Sensor_OnOff__X3Clambda_X3E_closure) }, })), be_str_weak(Matter_Plugin_Sensor_OnOff) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Pressure.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Pressure.h similarity index 72% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Pressure.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Pressure.h index 02d98c5fc..bcd8a036f 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Pressure.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Pressure.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Sensor_Pressure.h */ +/* Solidification of Matter_Plugin_3_Sensor_Pressure.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,6 +6,37 @@ extern const bclass be_class_Matter_Plugin_Sensor_Pressure; +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Pressure_value_changed, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0402, // 0001 LDINT R3 1027 + 0x58100001, // 0002 LDCONST R4 K1 + 0x7C040600, // 0003 CALL R1 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -147,37 +178,6 @@ be_local_closure(Matter_Plugin_Sensor_Pressure_pre_value, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: value_changed -********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_Pressure_value_changed, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - }), - be_str_weak(value_changed), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x54120402, // 0001 LDINT R4 1027 - 0x58140001, // 0002 LDCONST R5 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Plugin_Sensor_Pressure ********************************************************************/ @@ -185,13 +185,38 @@ extern const bclass be_class_Matter_Plugin_Sensor; be_local_class(Matter_Plugin_Sensor_Pressure, 0, &be_class_Matter_Plugin_Sensor, - be_nested_map(7, + be_nested_map(9, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, 2), be_const_closure(Matter_Plugin_Sensor_Pressure_read_attribute_closure) }, - { be_const_key_weak(pre_value, 4), be_const_closure(Matter_Plugin_Sensor_Pressure_pre_value_closure) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Pressure) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(pressure) }, + { be_const_key_weak(TYPES, 8), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(773, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(UPDATE_COMMANDS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Pressure), + })) ) } )) }, + { be_const_key_weak(value_changed, 7), be_const_closure(Matter_Plugin_Sensor_Pressure_value_changed_closure) }, + { be_const_key_weak(JSON_NAME, -1), be_nested_str_weak(Pressure) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Sensor_Pressure_read_attribute_closure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, { be_const_key_int(1027, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, ( (struct bvalue*) &(const bvalue[]) { @@ -201,15 +226,44 @@ be_local_class(Matter_Plugin_Sensor_Pressure, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), })) ) } )) }, - { be_const_key_weak(TYPE, 6), be_nested_str_weak(pressure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Pressure) }, - { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Sensor_Pressure_value_changed_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(773, -1), be_const_int(2) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(pre_value, -1), be_const_closure(Matter_Plugin_Sensor_Pressure_pre_value_closure) }, })), be_str_weak(Matter_Plugin_Sensor_Pressure) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Temp.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Temp.h similarity index 74% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Temp.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Temp.h index 4213f69d3..a28ac1196 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Sensor_Temp.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_Sensor_Temp.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Sensor_Temp.h */ +/* Solidification of Matter_Plugin_3_Sensor_Temp.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,6 +6,37 @@ extern const bclass be_class_Matter_Plugin_Sensor_Temp; +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Sensor_Temp_value_changed, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0401, // 0001 LDINT R3 1026 + 0x58100001, // 0002 LDCONST R4 K1 + 0x7C040600, // 0003 CALL R1 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -160,37 +191,6 @@ be_local_closure(Matter_Plugin_Sensor_Temp_pre_value, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: value_changed -********************************************************************/ -be_local_closure(Matter_Plugin_Sensor_Temp_value_changed, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - }), - be_str_weak(value_changed), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x54120401, // 0001 LDINT R4 1026 - 0x58140001, // 0002 LDCONST R5 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Plugin_Sensor_Temp ********************************************************************/ @@ -198,12 +198,25 @@ extern const bclass be_class_Matter_Plugin_Sensor; be_local_class(Matter_Plugin_Sensor_Temp, 0, &be_class_Matter_Plugin_Sensor, - be_nested_map(7, + be_nested_map(9, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(read_attribute, 2), be_const_closure(Matter_Plugin_Sensor_Temp_read_attribute_closure) }, - { be_const_key_weak(pre_value, 4), be_const_closure(Matter_Plugin_Sensor_Temp_pre_value_closure) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Temperature) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(temperature) }, + { be_const_key_weak(TYPES, 8), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(770, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(UPDATE_COMMANDS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(1, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Temperature), + })) ) } )) }, + { be_const_key_weak(value_changed, 7), be_const_closure(Matter_Plugin_Sensor_Temp_value_changed_closure) }, + { be_const_key_weak(JSON_NAME, -1), be_nested_str_weak(Temperature) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Sensor_Temp_read_attribute_closure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(1026, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, @@ -214,15 +227,56 @@ be_local_class(Matter_Plugin_Sensor_Temp, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(TYPE, 6), be_nested_str_weak(temperature) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Temperature) }, - { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Sensor_Temp_value_changed_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(770, -1), be_const_int(2) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(pre_value, -1), be_const_closure(Matter_Plugin_Sensor_Temp_pre_value_closure) }, })), be_str_weak(Matter_Plugin_Sensor_Temp) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_ShutterTilt.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_ShutterTilt.h similarity index 87% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_ShutterTilt.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_ShutterTilt.h index bfd316679..c661121a9 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_ShutterTilt.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_3_ShutterTilt.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_ShutterTilt.h */ +/* Solidification of Matter_Plugin_3_ShutterTilt.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -76,132 +76,6 @@ be_local_closure(Matter_Plugin_ShutterTilt_update_tilt_min_max, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_ShutterTilt_invoke_request, /* name */ - be_nested_proto( - 18, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[23]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(command), - /* K5 */ be_nested_str_weak(update_shadow_lazy), - /* K6 */ be_nested_str_weak(findsubval), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str_weak(update_tilt_min_max), - /* K9 */ be_nested_str_weak(tilt_min), - /* K10 */ be_nested_str_weak(tilt_max), - /* K11 */ be_nested_str_weak(tasmota), - /* K12 */ be_nested_str_weak(scale_uint), - /* K13 */ be_nested_str_weak(cmd), - /* K14 */ be_nested_str_weak(ShutterTilt), - /* K15 */ be_nested_str_weak(tasmota_shutter_index), - /* K16 */ be_const_int(1), - /* K17 */ be_nested_str_weak(_X20), - /* K18 */ be_nested_str_weak(update_shadow), - /* K19 */ be_nested_str_weak(log), - /* K20 */ be_nested_str_weak(tilt_X25_X3A), - /* K21 */ be_nested_str_weak(tilt_X25_X28no_tilt_support_X29_X3A), - /* K22 */ be_nested_str_weak(invoke_request), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[79]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xB8160200, // 0001 GETNGBL R5 K1 - 0x88140B02, // 0002 GETMBR R5 R5 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x881C0704, // 0004 GETMBR R7 R3 K4 - 0x54220101, // 0005 LDINT R8 258 - 0x1C200C08, // 0006 EQ R8 R6 R8 - 0x7822003D, // 0007 JMPF R8 #0046 - 0x8C200105, // 0008 GETMET R8 R0 K5 - 0x7C200200, // 0009 CALL R8 1 - 0x54220007, // 000A LDINT R8 8 - 0x1C200E08, // 000B EQ R8 R7 R8 - 0x78220038, // 000C JMPF R8 #0046 - 0x8C200506, // 000D GETMET R8 R2 K6 - 0x58280007, // 000E LDCONST R10 K7 - 0x7C200400, // 000F CALL R8 2 - 0x4C240000, // 0010 LDNIL R9 - 0x20241009, // 0011 NE R9 R8 R9 - 0x78260030, // 0012 JMPF R9 #0044 - 0x8C240108, // 0013 GETMET R9 R0 K8 - 0x7C240200, // 0014 CALL R9 1 - 0x88240109, // 0015 GETMBR R9 R0 K9 - 0x4C280000, // 0016 LDNIL R10 - 0x2024120A, // 0017 NE R9 R9 R10 - 0x78260025, // 0018 JMPF R9 #003F - 0x8824010A, // 0019 GETMBR R9 R0 K10 - 0x4C280000, // 001A LDNIL R10 - 0x2024120A, // 001B NE R9 R9 R10 - 0x78260021, // 001C JMPF R9 #003F - 0x88240109, // 001D GETMBR R9 R0 K9 - 0xB82A1600, // 001E GETNGBL R10 K11 - 0x8C28150C, // 001F GETMET R10 R10 K12 - 0x5C301000, // 0020 MOVE R12 R8 - 0x58340007, // 0021 LDCONST R13 K7 - 0x543A270F, // 0022 LDINT R14 10000 - 0x583C0007, // 0023 LDCONST R15 K7 - 0x8840010A, // 0024 GETMBR R16 R0 K10 - 0x88440109, // 0025 GETMBR R17 R0 K9 - 0x04402011, // 0026 SUB R16 R16 R17 - 0x7C280C00, // 0027 CALL R10 6 - 0x0024120A, // 0028 ADD R9 R9 R10 - 0xB82A1600, // 0029 GETNGBL R10 K11 - 0x8C28150D, // 002A GETMET R10 R10 K13 - 0x60300008, // 002B GETGBL R12 G8 - 0x8834010F, // 002C GETMBR R13 R0 K15 - 0x00341B10, // 002D ADD R13 R13 K16 - 0x7C300200, // 002E CALL R12 1 - 0x00321C0C, // 002F ADD R12 K14 R12 - 0x00301911, // 0030 ADD R12 R12 K17 - 0x60340008, // 0031 GETGBL R13 G8 - 0x5C381200, // 0032 MOVE R14 R9 - 0x7C340200, // 0033 CALL R13 1 - 0x0030180D, // 0034 ADD R12 R12 R13 - 0x50340000, // 0035 LDBOOL R13 0 0 - 0x7C280600, // 0036 CALL R10 3 - 0x8C280112, // 0037 GETMET R10 R0 K18 - 0x7C280200, // 0038 CALL R10 1 - 0x60280008, // 0039 GETGBL R10 G8 - 0x5C2C1000, // 003A MOVE R11 R8 - 0x7C280200, // 003B CALL R10 1 - 0x002A280A, // 003C ADD R10 K20 R10 - 0x900E260A, // 003D SETMBR R3 K19 R10 - 0x70020004, // 003E JMP #0044 - 0x60240008, // 003F GETGBL R9 G8 - 0x5C281000, // 0040 MOVE R10 R8 - 0x7C240200, // 0041 CALL R9 1 - 0x00262A09, // 0042 ADD R9 K21 R9 - 0x900E2609, // 0043 SETMBR R3 K19 R9 - 0x50240200, // 0044 LDBOOL R9 1 0 - 0x80041200, // 0045 RET 1 R9 - 0x60200003, // 0046 GETGBL R8 G3 - 0x5C240000, // 0047 MOVE R9 R0 - 0x7C200200, // 0048 CALL R8 1 - 0x8C201116, // 0049 GETMET R8 R8 K22 - 0x5C280200, // 004A MOVE R10 R1 - 0x5C2C0400, // 004B MOVE R11 R2 - 0x5C300600, // 004C MOVE R12 R3 - 0x7C200800, // 004D CALL R8 4 - 0x80041000, // 004E RET 1 R8 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -423,35 +297,220 @@ be_local_closure(Matter_Plugin_ShutterTilt_parse_sensors, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_ShutterTilt_invoke_request, /* name */ + be_nested_proto( + 18, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[23]) { /* constants */ + /* K0 */ be_nested_str_weak(light), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(command), + /* K5 */ be_nested_str_weak(update_shadow_lazy), + /* K6 */ be_nested_str_weak(findsubval), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(update_tilt_min_max), + /* K9 */ be_nested_str_weak(tilt_min), + /* K10 */ be_nested_str_weak(tilt_max), + /* K11 */ be_nested_str_weak(tasmota), + /* K12 */ be_nested_str_weak(scale_uint), + /* K13 */ be_nested_str_weak(cmd), + /* K14 */ be_nested_str_weak(ShutterTilt), + /* K15 */ be_nested_str_weak(tasmota_shutter_index), + /* K16 */ be_const_int(1), + /* K17 */ be_nested_str_weak(_X20), + /* K18 */ be_nested_str_weak(update_shadow), + /* K19 */ be_nested_str_weak(log), + /* K20 */ be_nested_str_weak(tilt_X25_X3A), + /* K21 */ be_nested_str_weak(tilt_X25_X28no_tilt_support_X29_X3A), + /* K22 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[79]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x54220101, // 0005 LDINT R8 258 + 0x1C200C08, // 0006 EQ R8 R6 R8 + 0x7822003D, // 0007 JMPF R8 #0046 + 0x8C200105, // 0008 GETMET R8 R0 K5 + 0x7C200200, // 0009 CALL R8 1 + 0x54220007, // 000A LDINT R8 8 + 0x1C200E08, // 000B EQ R8 R7 R8 + 0x78220038, // 000C JMPF R8 #0046 + 0x8C200506, // 000D GETMET R8 R2 K6 + 0x58280007, // 000E LDCONST R10 K7 + 0x7C200400, // 000F CALL R8 2 + 0x4C240000, // 0010 LDNIL R9 + 0x20241009, // 0011 NE R9 R8 R9 + 0x78260030, // 0012 JMPF R9 #0044 + 0x8C240108, // 0013 GETMET R9 R0 K8 + 0x7C240200, // 0014 CALL R9 1 + 0x88240109, // 0015 GETMBR R9 R0 K9 + 0x4C280000, // 0016 LDNIL R10 + 0x2024120A, // 0017 NE R9 R9 R10 + 0x78260025, // 0018 JMPF R9 #003F + 0x8824010A, // 0019 GETMBR R9 R0 K10 + 0x4C280000, // 001A LDNIL R10 + 0x2024120A, // 001B NE R9 R9 R10 + 0x78260021, // 001C JMPF R9 #003F + 0x88240109, // 001D GETMBR R9 R0 K9 + 0xB82A1600, // 001E GETNGBL R10 K11 + 0x8C28150C, // 001F GETMET R10 R10 K12 + 0x5C301000, // 0020 MOVE R12 R8 + 0x58340007, // 0021 LDCONST R13 K7 + 0x543A270F, // 0022 LDINT R14 10000 + 0x583C0007, // 0023 LDCONST R15 K7 + 0x8840010A, // 0024 GETMBR R16 R0 K10 + 0x88440109, // 0025 GETMBR R17 R0 K9 + 0x04402011, // 0026 SUB R16 R16 R17 + 0x7C280C00, // 0027 CALL R10 6 + 0x0024120A, // 0028 ADD R9 R9 R10 + 0xB82A1600, // 0029 GETNGBL R10 K11 + 0x8C28150D, // 002A GETMET R10 R10 K13 + 0x60300008, // 002B GETGBL R12 G8 + 0x8834010F, // 002C GETMBR R13 R0 K15 + 0x00341B10, // 002D ADD R13 R13 K16 + 0x7C300200, // 002E CALL R12 1 + 0x00321C0C, // 002F ADD R12 K14 R12 + 0x00301911, // 0030 ADD R12 R12 K17 + 0x60340008, // 0031 GETGBL R13 G8 + 0x5C381200, // 0032 MOVE R14 R9 + 0x7C340200, // 0033 CALL R13 1 + 0x0030180D, // 0034 ADD R12 R12 R13 + 0x50340000, // 0035 LDBOOL R13 0 0 + 0x7C280600, // 0036 CALL R10 3 + 0x8C280112, // 0037 GETMET R10 R0 K18 + 0x7C280200, // 0038 CALL R10 1 + 0x60280008, // 0039 GETGBL R10 G8 + 0x5C2C1000, // 003A MOVE R11 R8 + 0x7C280200, // 003B CALL R10 1 + 0x002A280A, // 003C ADD R10 K20 R10 + 0x900E260A, // 003D SETMBR R3 K19 R10 + 0x70020004, // 003E JMP #0044 + 0x60240008, // 003F GETGBL R9 G8 + 0x5C281000, // 0040 MOVE R10 R8 + 0x7C240200, // 0041 CALL R9 1 + 0x00262A09, // 0042 ADD R9 K21 R9 + 0x900E2609, // 0043 SETMBR R3 K19 R9 + 0x50240200, // 0044 LDBOOL R9 1 0 + 0x80041200, // 0045 RET 1 R9 + 0x60200003, // 0046 GETGBL R8 G3 + 0x5C240000, // 0047 MOVE R9 R0 + 0x7C200200, // 0048 CALL R8 1 + 0x8C201116, // 0049 GETMET R8 R8 K22 + 0x5C280200, // 004A MOVE R10 R1 + 0x5C2C0400, // 004B MOVE R11 R2 + 0x5C300600, // 004C MOVE R12 R3 + 0x7C200800, // 004D CALL R8 4 + 0x80041000, // 004E RET 1 R8 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin_ShutterTilt ********************************************************************/ extern const bclass be_class_Matter_Plugin_Shutter; be_local_class(Matter_Plugin_ShutterTilt, - 2, + 3, &be_class_Matter_Plugin_Shutter, - be_nested_map(9, + be_nested_map(10, ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(update_tilt_min_max, -1), be_const_closure(Matter_Plugin_ShutterTilt_update_tilt_min_max_closure) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Shutter_X20_X2B_X20Tilt) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_ShutterTilt_read_attribute_closure) }, { be_const_key_weak(TYPE, -1), be_nested_str_weak(shutter_X2Btilt) }, - { be_const_key_weak(update_tilt_min_max, 0), be_const_closure(Matter_Plugin_ShutterTilt_update_tilt_min_max_closure) }, - { be_const_key_weak(parse_sensors, 7), be_const_closure(Matter_Plugin_ShutterTilt_parse_sensors_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Shutter_X20_X2B_X20Tilt) }, { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, + be_const_map( * be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(258, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(4, + be_const_list( * be_nested_list(14, ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(5), + be_const_int(7), + be_const_int(10), + be_const_int(11), + be_const_int(13), + be_const_int(14), + be_const_int(23), + be_const_int(65532), + be_const_int(65533), be_const_int(7), be_const_int(12), be_const_int(15), be_const_int(65532), })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(tilt_min, 8), be_const_var(1) }, + { be_const_key_weak(parse_sensors, -1), be_const_closure(Matter_Plugin_ShutterTilt_parse_sensors_closure) }, { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_ShutterTilt_invoke_request_closure) }, - { be_const_key_weak(tilt_min, 2), be_const_var(0) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_ShutterTilt_read_attribute_closure) }, - { be_const_key_weak(tilt_max, -1), be_const_var(1) }, + { be_const_key_weak(shadow_shutter_tilt, -1), be_const_var(0) }, + { be_const_key_weak(tilt_max, 3), be_const_var(2) }, })), be_str_weak(Matter_Plugin_ShutterTilt) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light1.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Light1.h similarity index 70% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light1.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Light1.h index e14326c29..8cdf671bf 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light1.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Light1.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Light1.h */ +/* Solidification of Matter_Plugin_4_Bridge_Light1.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -11,7 +11,7 @@ extern const bclass be_class_Matter_Plugin_Bridge_Light1; ********************************************************************/ be_local_closure(Matter_Plugin_Bridge_Light1_invoke_request, /* name */ be_nested_proto( - 12, /* nstack */ + 21, /* nstack */ 4, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -19,7 +19,7 @@ be_local_closure(Matter_Plugin_Bridge_Light1_invoke_request, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[14]) { /* constants */ + ( &(const bvalue[20]) { /* constants */ /* K0 */ be_nested_str_weak(matter), /* K1 */ be_nested_str_weak(TLV), /* K2 */ be_nested_str_weak(cluster), @@ -29,24 +29,30 @@ be_local_closure(Matter_Plugin_Bridge_Light1_invoke_request, /* name */ /* K6 */ be_nested_str_weak(set_bri), /* K7 */ be_nested_str_weak(log), /* K8 */ be_nested_str_weak(bri_X3A), - /* K9 */ be_const_int(1), - /* K10 */ be_const_int(2), - /* K11 */ be_const_int(3), - /* K12 */ be_nested_str_weak(set_onoff), - /* K13 */ be_nested_str_weak(invoke_request), + /* K9 */ be_nested_str_weak(publish_command), + /* K10 */ be_nested_str_weak(Bri), + /* K11 */ be_nested_str_weak(tasmota), + /* K12 */ be_nested_str_weak(scale_uint), + /* K13 */ be_nested_str_weak(Dimmer), + /* K14 */ be_const_int(1), + /* K15 */ be_const_int(2), + /* K16 */ be_const_int(3), + /* K17 */ be_nested_str_weak(set_onoff), + /* K18 */ be_nested_str_weak(Power), + /* K19 */ be_nested_str_weak(invoke_request), }), be_str_weak(invoke_request), &be_const_str_solidified, - ( &(const binstruction[87]) { /* code */ + ( &(const binstruction[132]) { /* code */ 0xB8120000, // 0000 GETNGBL R4 K0 0x88100901, // 0001 GETMBR R4 R4 K1 0x88140702, // 0002 GETMBR R5 R3 K2 0x88180703, // 0003 GETMBR R6 R3 K3 0x541E0007, // 0004 LDINT R7 8 0x1C1C0A07, // 0005 EQ R7 R5 R7 - 0x781E0045, // 0006 JMPF R7 #004D + 0x781E0072, // 0006 JMPF R7 #007A 0x1C1C0D04, // 0007 EQ R7 R6 K4 - 0x781E000D, // 0008 JMPF R7 #0017 + 0x781E0021, // 0008 JMPF R7 #002B 0x8C1C0505, // 0009 GETMET R7 R2 K5 0x58240004, // 000A LDCONST R9 K4 0x7C1C0400, // 000B CALL R7 2 @@ -58,73 +64,118 @@ be_local_closure(Matter_Plugin_Bridge_Light1_invoke_request, /* name */ 0x7C200200, // 0011 CALL R8 1 0x00221008, // 0012 ADD R8 K8 R8 0x900E0E08, // 0013 SETMBR R3 K7 R8 - 0x50200200, // 0014 LDBOOL R8 1 0 - 0x80041000, // 0015 RET 1 R8 - 0x70020034, // 0016 JMP #004C - 0x1C1C0D09, // 0017 EQ R7 R6 K9 - 0x781E0002, // 0018 JMPF R7 #001C - 0x501C0200, // 0019 LDBOOL R7 1 0 - 0x80040E00, // 001A RET 1 R7 - 0x7002002F, // 001B JMP #004C - 0x1C1C0D0A, // 001C EQ R7 R6 K10 - 0x781E0002, // 001D JMPF R7 #0021 - 0x501C0200, // 001E LDBOOL R7 1 0 - 0x80040E00, // 001F RET 1 R7 - 0x7002002A, // 0020 JMP #004C - 0x1C1C0D0B, // 0021 EQ R7 R6 K11 - 0x781E0002, // 0022 JMPF R7 #0026 - 0x501C0200, // 0023 LDBOOL R7 1 0 - 0x80040E00, // 0024 RET 1 R7 - 0x70020025, // 0025 JMP #004C - 0x541E0003, // 0026 LDINT R7 4 - 0x1C1C0C07, // 0027 EQ R7 R6 R7 - 0x781E0011, // 0028 JMPF R7 #003B - 0x8C1C0505, // 0029 GETMET R7 R2 K5 - 0x58240004, // 002A LDCONST R9 K4 - 0x7C1C0400, // 002B CALL R7 2 - 0x8C200106, // 002C GETMET R8 R0 K6 - 0x5C280E00, // 002D MOVE R10 R7 - 0x7C200400, // 002E CALL R8 2 - 0x24200F04, // 002F GT R8 R7 K4 - 0x8C24010C, // 0030 GETMET R9 R0 K12 - 0x5C2C1000, // 0031 MOVE R11 R8 - 0x7C240400, // 0032 CALL R9 2 - 0x60240008, // 0033 GETGBL R9 G8 - 0x5C280E00, // 0034 MOVE R10 R7 - 0x7C240200, // 0035 CALL R9 1 - 0x00261009, // 0036 ADD R9 K8 R9 - 0x900E0E09, // 0037 SETMBR R3 K7 R9 - 0x50240200, // 0038 LDBOOL R9 1 0 - 0x80041200, // 0039 RET 1 R9 - 0x70020010, // 003A JMP #004C - 0x541E0004, // 003B LDINT R7 5 - 0x1C1C0C07, // 003C EQ R7 R6 R7 - 0x781E0002, // 003D JMPF R7 #0041 - 0x501C0200, // 003E LDBOOL R7 1 0 - 0x80040E00, // 003F RET 1 R7 - 0x7002000A, // 0040 JMP #004C - 0x541E0005, // 0041 LDINT R7 6 - 0x1C1C0C07, // 0042 EQ R7 R6 R7 - 0x781E0002, // 0043 JMPF R7 #0047 - 0x501C0200, // 0044 LDBOOL R7 1 0 - 0x80040E00, // 0045 RET 1 R7 - 0x70020004, // 0046 JMP #004C - 0x541E0006, // 0047 LDINT R7 7 - 0x1C1C0C07, // 0048 EQ R7 R6 R7 - 0x781E0001, // 0049 JMPF R7 #004C - 0x501C0200, // 004A LDBOOL R7 1 0 - 0x80040E00, // 004B RET 1 R7 - 0x70020008, // 004C JMP #0056 - 0x601C0003, // 004D GETGBL R7 G3 - 0x5C200000, // 004E MOVE R8 R0 - 0x7C1C0200, // 004F CALL R7 1 - 0x8C1C0F0D, // 0050 GETMET R7 R7 K13 - 0x5C240200, // 0051 MOVE R9 R1 - 0x5C280400, // 0052 MOVE R10 R2 - 0x5C2C0600, // 0053 MOVE R11 R3 - 0x7C1C0800, // 0054 CALL R7 4 - 0x80040E00, // 0055 RET 1 R7 - 0x80000000, // 0056 RET 0 + 0x8C200109, // 0014 GETMET R8 R0 K9 + 0x5828000A, // 0015 LDCONST R10 K10 + 0xB82E1600, // 0016 GETNGBL R11 K11 + 0x8C2C170C, // 0017 GETMET R11 R11 K12 + 0x5C340E00, // 0018 MOVE R13 R7 + 0x58380004, // 0019 LDCONST R14 K4 + 0x543E00FD, // 001A LDINT R15 254 + 0x58400004, // 001B LDCONST R16 K4 + 0x544600FE, // 001C LDINT R17 255 + 0x7C2C0C00, // 001D CALL R11 6 + 0x5830000D, // 001E LDCONST R12 K13 + 0xB8361600, // 001F GETNGBL R13 K11 + 0x8C341B0C, // 0020 GETMET R13 R13 K12 + 0x5C3C0E00, // 0021 MOVE R15 R7 + 0x58400004, // 0022 LDCONST R16 K4 + 0x544600FD, // 0023 LDINT R17 254 + 0x58480004, // 0024 LDCONST R18 K4 + 0x544E0063, // 0025 LDINT R19 100 + 0x7C340C00, // 0026 CALL R13 6 + 0x7C200A00, // 0027 CALL R8 5 + 0x50200200, // 0028 LDBOOL R8 1 0 + 0x80041000, // 0029 RET 1 R8 + 0x7002004D, // 002A JMP #0079 + 0x1C1C0D0E, // 002B EQ R7 R6 K14 + 0x781E0002, // 002C JMPF R7 #0030 + 0x501C0200, // 002D LDBOOL R7 1 0 + 0x80040E00, // 002E RET 1 R7 + 0x70020048, // 002F JMP #0079 + 0x1C1C0D0F, // 0030 EQ R7 R6 K15 + 0x781E0002, // 0031 JMPF R7 #0035 + 0x501C0200, // 0032 LDBOOL R7 1 0 + 0x80040E00, // 0033 RET 1 R7 + 0x70020043, // 0034 JMP #0079 + 0x1C1C0D10, // 0035 EQ R7 R6 K16 + 0x781E0002, // 0036 JMPF R7 #003A + 0x501C0200, // 0037 LDBOOL R7 1 0 + 0x80040E00, // 0038 RET 1 R7 + 0x7002003E, // 0039 JMP #0079 + 0x541E0003, // 003A LDINT R7 4 + 0x1C1C0C07, // 003B EQ R7 R6 R7 + 0x781E002A, // 003C JMPF R7 #0068 + 0x8C1C0505, // 003D GETMET R7 R2 K5 + 0x58240004, // 003E LDCONST R9 K4 + 0x7C1C0400, // 003F CALL R7 2 + 0x8C200106, // 0040 GETMET R8 R0 K6 + 0x5C280E00, // 0041 MOVE R10 R7 + 0x7C200400, // 0042 CALL R8 2 + 0x24200F04, // 0043 GT R8 R7 K4 + 0x8C240111, // 0044 GETMET R9 R0 K17 + 0x5C2C1000, // 0045 MOVE R11 R8 + 0x7C240400, // 0046 CALL R9 2 + 0x60240008, // 0047 GETGBL R9 G8 + 0x5C280E00, // 0048 MOVE R10 R7 + 0x7C240200, // 0049 CALL R9 1 + 0x00261009, // 004A ADD R9 K8 R9 + 0x900E0E09, // 004B SETMBR R3 K7 R9 + 0x8C240109, // 004C GETMET R9 R0 K9 + 0x582C000A, // 004D LDCONST R11 K10 + 0xB8321600, // 004E GETNGBL R12 K11 + 0x8C30190C, // 004F GETMET R12 R12 K12 + 0x5C380E00, // 0050 MOVE R14 R7 + 0x583C0004, // 0051 LDCONST R15 K4 + 0x544200FD, // 0052 LDINT R16 254 + 0x58440004, // 0053 LDCONST R17 K4 + 0x544A00FE, // 0054 LDINT R18 255 + 0x7C300C00, // 0055 CALL R12 6 + 0x5834000D, // 0056 LDCONST R13 K13 + 0xB83A1600, // 0057 GETNGBL R14 K11 + 0x8C381D0C, // 0058 GETMET R14 R14 K12 + 0x5C400E00, // 0059 MOVE R16 R7 + 0x58440004, // 005A LDCONST R17 K4 + 0x544A00FD, // 005B LDINT R18 254 + 0x584C0004, // 005C LDCONST R19 K4 + 0x54520063, // 005D LDINT R20 100 + 0x7C380C00, // 005E CALL R14 6 + 0x583C0012, // 005F LDCONST R15 K18 + 0x78220001, // 0060 JMPF R8 #0063 + 0x5840000E, // 0061 LDCONST R16 K14 + 0x70020000, // 0062 JMP #0064 + 0x58400004, // 0063 LDCONST R16 K4 + 0x7C240E00, // 0064 CALL R9 7 + 0x50240200, // 0065 LDBOOL R9 1 0 + 0x80041200, // 0066 RET 1 R9 + 0x70020010, // 0067 JMP #0079 + 0x541E0004, // 0068 LDINT R7 5 + 0x1C1C0C07, // 0069 EQ R7 R6 R7 + 0x781E0002, // 006A JMPF R7 #006E + 0x501C0200, // 006B LDBOOL R7 1 0 + 0x80040E00, // 006C RET 1 R7 + 0x7002000A, // 006D JMP #0079 + 0x541E0005, // 006E LDINT R7 6 + 0x1C1C0C07, // 006F EQ R7 R6 R7 + 0x781E0002, // 0070 JMPF R7 #0074 + 0x501C0200, // 0071 LDBOOL R7 1 0 + 0x80040E00, // 0072 RET 1 R7 + 0x70020004, // 0073 JMP #0079 + 0x541E0006, // 0074 LDINT R7 7 + 0x1C1C0C07, // 0075 EQ R7 R6 R7 + 0x781E0001, // 0076 JMPF R7 #0079 + 0x501C0200, // 0077 LDBOOL R7 1 0 + 0x80040E00, // 0078 RET 1 R7 + 0x70020008, // 0079 JMP #0083 + 0x601C0003, // 007A GETGBL R7 G3 + 0x5C200000, // 007B MOVE R8 R0 + 0x7C1C0200, // 007C CALL R7 1 + 0x8C1C0F13, // 007D GETMET R7 R7 K19 + 0x5C240200, // 007E MOVE R9 R1 + 0x5C280400, // 007F MOVE R10 R2 + 0x5C2C0600, // 0080 MOVE R11 R3 + 0x7C1C0800, // 0081 CALL R7 4 + 0x80040E00, // 0082 RET 1 R7 + 0x80000000, // 0083 RET 0 }) ) ); @@ -495,18 +546,28 @@ be_local_class(Matter_Plugin_Bridge_Light1, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(web_value_dimmer, -1), be_const_closure(Matter_Plugin_Bridge_Light1_web_value_dimmer_closure) }, { be_const_key_weak(parse_update, -1), be_const_closure(Matter_Plugin_Bridge_Light1_parse_update_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_light1) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Bridge_Light1_read_attribute_closure) }, + { be_const_key_weak(TYPES, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(257, -1), be_const_int(2) }, })) ) } )) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Bridge_Light1_read_attribute_closure) }, - { be_const_key_weak(TYPE, 2), be_nested_str_weak(http_light1) }, - { be_const_key_weak(shadow_bri, 8), be_const_var(0) }, + { be_const_key_weak(shadow_bri, -1), be_const_var(0) }, { be_const_key_weak(CLUSTERS, 5), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, + be_const_map( * be_nested_map(7, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(8, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(29, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(8, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(7, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), @@ -516,10 +577,55 @@ be_local_class(Matter_Plugin_Bridge_Light1, be_const_int(17), be_const_int(65532), be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, })) ) } )) }, { be_const_key_weak(set_bri, -1), be_const_closure(Matter_Plugin_Bridge_Light1_set_bri_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Light_X201_X20Dimmer) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Light_X201_X20Dimmer) }, { be_const_key_weak(web_values, 1), be_const_closure(Matter_Plugin_Bridge_Light1_web_values_closure) }, { be_const_key_weak(invoke_request, 0), be_const_closure(Matter_Plugin_Bridge_Light1_invoke_request_closure) }, })), diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_OnOff.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_OnOff.h similarity index 94% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_OnOff.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_OnOff.h index d4100d5c4..0e7f4e707 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_OnOff.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_OnOff.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_OnOff.h */ +/* Solidification of Matter_Plugin_4_Bridge_OnOff.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -64,10 +64,10 @@ be_local_class(Matter_Plugin_Bridge_OnOff, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(266, -1), be_const_int(2) }, })) ) } )) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Relay) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Relay) }, { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_OnOff_web_values_closure) }, { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(Relay_X3Cx_X3E_X20number) }, - { be_const_key_weak(TYPE, 1), be_nested_str_weak(http_relay) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_relay) }, })), be_str_weak(Matter_Plugin_Bridge_OnOff) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Contact.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Contact.h similarity index 85% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Contact.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Contact.h index 00465b9d9..ded960e54 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Contact.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Contact.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Sensor_Contact.h */ +/* Solidification of Matter_Plugin_4_Bridge_Sensor_Contact.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -344,29 +344,77 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Contact, { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Contact_init_closure) }, { be_const_key_weak(web_values_prefix, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Contact_web_values_prefix_closure) }, { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Contact_web_values_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Contact) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Contact) }, { be_const_key_weak(ARG, -1), be_nested_str_weak(switch) }, - { be_const_key_weak(UPDATE_TIME, 14), be_const_int(5000) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Contact_read_attribute_closure) }, - { be_const_key_weak(CLUSTERS, 11), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, + { be_const_key_weak(parse_update, 11), be_const_closure(Matter_Plugin_Bridge_Sensor_Contact_parse_update_closure) }, + { be_const_key_weak(read_attribute, 12), be_const_closure(Matter_Plugin_Bridge_Sensor_Contact_read_attribute_closure) }, + { be_const_key_weak(CLUSTERS, 9), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(69, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(69, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(3, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(TYPES, 12), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(UPDATE_TIME, -1), be_const_int(5000) }, + { be_const_key_weak(TYPES, 14), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(21, -1), be_const_int(1) }, })) ) } )) }, - { be_const_key_weak(tasmota_switch_index, 9), be_const_var(0) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_contact) }, - { be_const_key_weak(parse_update, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Contact_parse_update_closure) }, + { be_const_key_weak(TYPE, 6), be_nested_str_weak(http_contact) }, + { be_const_key_weak(tasmota_switch_index, -1), be_const_var(0) }, { be_const_key_weak(UPDATE_CMD, -1), be_nested_str_weak(Status_X208) }, })), be_str_weak(Matter_Plugin_Bridge_Sensor_Contact) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Humidity.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Humidity.h similarity index 79% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Humidity.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Humidity.h index 999d0b35d..6a2032b50 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Humidity.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Humidity.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Sensor_Humidity.h */ +/* Solidification of Matter_Plugin_4_Bridge_Sensor_Humidity.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -39,6 +39,37 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_Humidity_pre_value, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_Sensor_Humidity_value_changed, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0404, // 0001 LDINT R3 1029 + 0x58100001, // 0002 LDCONST R4 K1 + 0x7C040600, // 0003 CALL R1 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -148,37 +179,6 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_Humidity_read_attribute, /* name /*******************************************************************/ -/******************************************************************** -** Solidified function: value_changed -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_Sensor_Humidity_value_changed, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - }), - be_str_weak(value_changed), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x54120404, // 0001 LDINT R4 1029 - 0x58140001, // 0002 LDCONST R5 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: web_values ********************************************************************/ @@ -239,10 +239,50 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Humidity, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(pre_value, 1), be_const_closure(Matter_Plugin_Bridge_Sensor_Humidity_pre_value_closure) }, { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Humidity_web_values_closure) }, - { be_const_key_weak(CLUSTERS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(TYPES, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(1029, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(775, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(read_attribute, 7), be_const_closure(Matter_Plugin_Bridge_Sensor_Humidity_read_attribute_closure) }, + { be_const_key_weak(value_changed, 6), be_const_closure(Matter_Plugin_Bridge_Sensor_Humidity_value_changed_closure) }, + { be_const_key_weak(DISPLAY_NAME, 4), be_nested_str_weak(Humidity) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_humidity) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(1029, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), @@ -251,15 +291,23 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Humidity, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(read_attribute, 7), be_const_closure(Matter_Plugin_Bridge_Sensor_Humidity_read_attribute_closure) }, - { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Humidity_value_changed_closure) }, - { be_const_key_weak(TYPE, 4), be_nested_str_weak(http_humidity) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Humidity) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(775, -1), be_const_int(2) }, })) ) } )) }, })), be_str_weak(Matter_Plugin_Bridge_Sensor_Humidity) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Illuminance.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Illuminance.h similarity index 79% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Illuminance.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Illuminance.h index 894d2caaf..739e203bf 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Illuminance.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Illuminance.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Sensor_Illuminance.h */ +/* Solidification of Matter_Plugin_4_Bridge_Sensor_Illuminance.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -51,6 +51,37 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_Illuminance_pre_value, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_Sensor_Illuminance_value_changed, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E03FF, // 0001 LDINT R3 1024 + 0x58100001, // 0002 LDCONST R4 K1 + 0x7C040600, // 0003 CALL R1 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -160,37 +191,6 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_Illuminance_read_attribute, /* na /*******************************************************************/ -/******************************************************************** -** Solidified function: value_changed -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_Sensor_Illuminance_value_changed, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - }), - be_str_weak(value_changed), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x541203FF, // 0001 LDINT R4 1024 - 0x58140001, // 0002 LDCONST R5 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: web_values ********************************************************************/ @@ -243,10 +243,57 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Illuminance, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(pre_value, 1), be_const_closure(Matter_Plugin_Bridge_Sensor_Illuminance_pre_value_closure) }, { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Illuminance_web_values_closure) }, - { be_const_key_weak(CLUSTERS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(TYPES, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(1024, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(262, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(read_attribute, 7), be_const_closure(Matter_Plugin_Bridge_Sensor_Illuminance_read_attribute_closure) }, + { be_const_key_weak(value_changed, 6), be_const_closure(Matter_Plugin_Bridge_Sensor_Illuminance_value_changed_closure) }, + { be_const_key_weak(DISPLAY_NAME, 4), be_nested_str_weak(Illuminance) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_illuminance) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(1024, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), @@ -255,15 +302,16 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Illuminance, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(read_attribute, 7), be_const_closure(Matter_Plugin_Bridge_Sensor_Illuminance_read_attribute_closure) }, - { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Illuminance_value_changed_closure) }, - { be_const_key_weak(TYPE, 4), be_nested_str_weak(http_illuminance) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Illuminance) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(262, -1), be_const_int(2) }, })) ) } )) }, })), be_str_weak(Matter_Plugin_Bridge_Sensor_Illuminance) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Occupancy.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Occupancy.h similarity index 86% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Occupancy.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Occupancy.h index 9f232fc03..b19d193b9 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Occupancy.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Occupancy.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Sensor_Occupancy.h */ +/* Solidification of Matter_Plugin_4_Bridge_Sensor_Occupancy.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -357,18 +357,60 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Occupancy, be_nested_map(16, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(ARG_TYPE, 4), be_const_static_closure(Matter_Plugin_Bridge_Sensor_Occupancy__X3Clambda_X3E_closure) }, - { be_const_key_weak(ARG_HINT, 14), be_nested_str_weak(Switch_X3Cx_X3E_X20number) }, + { be_const_key_weak(ARG_HINT, 12), be_nested_str_weak(Switch_X3Cx_X3E_X20number) }, { be_const_key_weak(shadow_occupancy, -1), be_const_var(1) }, { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Occupancy_init_closure) }, { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Occupancy_web_values_closure) }, - { be_const_key_weak(UPDATE_TIME, -1), be_const_int(5000) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Occupancy) }, - { be_const_key_weak(ARG, -1), be_nested_str_weak(switch) }, - { be_const_key_weak(parse_update, 5), be_const_closure(Matter_Plugin_Bridge_Sensor_Occupancy_parse_update_closure) }, - { be_const_key_weak(CLUSTERS, 11), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Occupancy) }, + { be_const_key_weak(TYPES, 9), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(1030, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + { be_const_key_int(263, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(ARG, -1), be_nested_str_weak(switch) }, + { be_const_key_weak(parse_update, 14), be_const_closure(Matter_Plugin_Bridge_Sensor_Occupancy_parse_update_closure) }, + { be_const_key_weak(CLUSTERS, 11), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(1030, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, ( (struct bvalue*) &(const bvalue[]) { be_const_int(0), @@ -377,16 +419,22 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Occupancy, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(tasmota_switch_index, 9), be_const_var(0) }, - { be_const_key_weak(read_attribute, 12), be_const_closure(Matter_Plugin_Bridge_Sensor_Occupancy_read_attribute_closure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(263, -1), be_const_int(2) }, })) ) } )) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_occupancy) }, + { be_const_key_weak(tasmota_switch_index, 6), be_const_var(0) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Occupancy_read_attribute_closure) }, { be_const_key_weak(web_values_prefix, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Occupancy_web_values_prefix_closure) }, + { be_const_key_weak(TYPE, 5), be_nested_str_weak(http_occupancy) }, + { be_const_key_weak(UPDATE_TIME, -1), be_const_int(5000) }, { be_const_key_weak(UPDATE_CMD, 2), be_nested_str_weak(Status_X208) }, })), be_str_weak(Matter_Plugin_Bridge_Sensor_Occupancy) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Pressure.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Pressure.h similarity index 79% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Pressure.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Pressure.h index a72084820..63f96dae4 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Pressure.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Pressure.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Sensor_Pressure.h */ +/* Solidification of Matter_Plugin_4_Bridge_Sensor_Pressure.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -38,6 +38,37 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_Pressure_pre_value, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_Sensor_Pressure_value_changed, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0402, // 0001 LDINT R3 1027 + 0x58100001, // 0002 LDCONST R4 K1 + 0x7C040600, // 0003 CALL R1 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -147,37 +178,6 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_Pressure_read_attribute, /* name /*******************************************************************/ -/******************************************************************** -** Solidified function: value_changed -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_Sensor_Pressure_value_changed, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - }), - be_str_weak(value_changed), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x54120402, // 0001 LDINT R4 1027 - 0x58140001, // 0002 LDCONST R5 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: web_values ********************************************************************/ @@ -230,9 +230,30 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Pressure, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(pre_value, 1), be_const_closure(Matter_Plugin_Bridge_Sensor_Pressure_pre_value_closure) }, { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Pressure_web_values_closure) }, - { be_const_key_weak(CLUSTERS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(TYPES, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(773, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(read_attribute, 7), be_const_closure(Matter_Plugin_Bridge_Sensor_Pressure_read_attribute_closure) }, + { be_const_key_weak(value_changed, 6), be_const_closure(Matter_Plugin_Bridge_Sensor_Pressure_value_changed_closure) }, + { be_const_key_weak(DISPLAY_NAME, 4), be_nested_str_weak(Pressure) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_pressure) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, { be_const_key_int(1027, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, ( (struct bvalue*) &(const bvalue[]) { @@ -242,15 +263,42 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Pressure, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 0), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(read_attribute, 7), be_const_closure(Matter_Plugin_Bridge_Sensor_Pressure_read_attribute_closure) }, - { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Pressure_value_changed_closure) }, - { be_const_key_weak(TYPE, 4), be_nested_str_weak(http_pressure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Pressure) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(773, -1), be_const_int(2) }, })) ) } )) }, })), be_str_weak(Matter_Plugin_Bridge_Sensor_Pressure) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Temp.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Temp.h similarity index 80% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Temp.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Temp.h index ac392119c..44b133271 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Sensor_Temp.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Bridge_Sensor_Temp.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Sensor_Temp.h */ +/* Solidification of Matter_Plugin_4_Bridge_Sensor_Temp.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -51,6 +51,37 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_Temp_pre_value, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: value_changed +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_Sensor_Temp_value_changed, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str_weak(attribute_updated), + /* K1 */ be_const_int(0), + }), + be_str_weak(value_changed), + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x540E0401, // 0001 LDINT R3 1026 + 0x58100001, // 0002 LDCONST R4 K1 + 0x7C040600, // 0003 CALL R1 3 + 0x80000000, // 0004 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -157,37 +188,6 @@ be_local_closure(Matter_Plugin_Bridge_Sensor_Temp_read_attribute, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: value_changed -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_Sensor_Temp_value_changed, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(attribute_updated), - /* K1 */ be_const_int(0), - }), - be_str_weak(value_changed), - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x54120401, // 0001 LDINT R4 1026 - 0x58140001, // 0002 LDCONST R5 K1 - 0x7C080600, // 0003 CALL R2 3 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: web_values ********************************************************************/ @@ -248,8 +248,17 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Temp, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(pre_value, 1), be_const_closure(Matter_Plugin_Bridge_Sensor_Temp_pre_value_closure) }, { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Temp_web_values_closure) }, - { be_const_key_weak(CLUSTERS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + { be_const_key_weak(TYPES, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(770, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(read_attribute, 7), be_const_closure(Matter_Plugin_Bridge_Sensor_Temp_read_attribute_closure) }, + { be_const_key_weak(value_changed, 6), be_const_closure(Matter_Plugin_Bridge_Sensor_Temp_value_changed_closure) }, + { be_const_key_weak(DISPLAY_NAME, 4), be_nested_str_weak(Temperature) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_temperature) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(6, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(1026, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(5, @@ -260,15 +269,54 @@ be_local_class(Matter_Plugin_Bridge_Sensor_Temp, be_const_int(65532), be_const_int(65533), })) ) } )) }, + { be_const_key_int(5, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(3, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(29, 1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(read_attribute, 7), be_const_closure(Matter_Plugin_Bridge_Sensor_Temp_read_attribute_closure) }, - { be_const_key_weak(value_changed, -1), be_const_closure(Matter_Plugin_Bridge_Sensor_Temp_value_changed_closure) }, - { be_const_key_weak(TYPE, 4), be_nested_str_weak(http_temperature) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Temperature) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(770, -1), be_const_int(2) }, })) ) } )) }, })), be_str_weak(Matter_Plugin_Bridge_Sensor_Temp) diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light2.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Light2.h similarity index 59% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light2.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Light2.h index 8294b2afa..a52eb7229 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light2.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Light2.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Light2.h */ +/* Solidification of Matter_Plugin_4_Light2.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -6,6 +6,312 @@ extern const bclass be_class_Matter_Plugin_Light2; +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Light2_init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(shadow_ct), + /* K2 */ be_nested_str_weak(update_ct_minmax), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[13]) { /* code */ + 0x60100003, // 0000 GETGBL R4 G3 + 0x5C140000, // 0001 MOVE R5 R0 + 0x7C100200, // 0002 CALL R4 1 + 0x8C100900, // 0003 GETMET R4 R4 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x5C1C0400, // 0005 MOVE R7 R2 + 0x5C200600, // 0006 MOVE R8 R3 + 0x7C100800, // 0007 CALL R4 4 + 0x54120144, // 0008 LDINT R4 325 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x8C100102, // 000A GETMET R4 R0 K2 + 0x7C100200, // 000B CALL R4 1 + 0x80000000, // 000C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Light2_invoke_request, /* name */ + be_nested_proto( + 13, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(light), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(command), + /* K5 */ be_nested_str_weak(update_shadow_lazy), + /* K6 */ be_nested_str_weak(findsubval), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str_weak(set_ct), + /* K9 */ be_nested_str_weak(log), + /* K10 */ be_nested_str_weak(ct_X3A), + /* K11 */ be_nested_str_weak(publish_command), + /* K12 */ be_nested_str_weak(CT), + /* K13 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[59]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x542202FF, // 0005 LDINT R8 768 + 0x1C200C08, // 0006 EQ R8 R6 R8 + 0x78220028, // 0007 JMPF R8 #0031 + 0x8C200105, // 0008 GETMET R8 R0 K5 + 0x7C200200, // 0009 CALL R8 1 + 0x54220009, // 000A LDINT R8 10 + 0x1C200E08, // 000B EQ R8 R7 R8 + 0x78220011, // 000C JMPF R8 #001F + 0x8C200506, // 000D GETMET R8 R2 K6 + 0x58280007, // 000E LDCONST R10 K7 + 0x7C200400, // 000F CALL R8 2 + 0x8C240108, // 0010 GETMET R9 R0 K8 + 0x5C2C1000, // 0011 MOVE R11 R8 + 0x7C240400, // 0012 CALL R9 2 + 0x60240008, // 0013 GETGBL R9 G8 + 0x5C281000, // 0014 MOVE R10 R8 + 0x7C240200, // 0015 CALL R9 1 + 0x00261409, // 0016 ADD R9 K10 R9 + 0x900E1209, // 0017 SETMBR R3 K9 R9 + 0x8C24010B, // 0018 GETMET R9 R0 K11 + 0x582C000C, // 0019 LDCONST R11 K12 + 0x5C301000, // 001A MOVE R12 R8 + 0x7C240600, // 001B CALL R9 3 + 0x50240200, // 001C LDBOOL R9 1 0 + 0x80041200, // 001D RET 1 R9 + 0x70020010, // 001E JMP #0030 + 0x54220046, // 001F LDINT R8 71 + 0x1C200E08, // 0020 EQ R8 R7 R8 + 0x78220002, // 0021 JMPF R8 #0025 + 0x50200200, // 0022 LDBOOL R8 1 0 + 0x80041000, // 0023 RET 1 R8 + 0x7002000A, // 0024 JMP #0030 + 0x5422004A, // 0025 LDINT R8 75 + 0x1C200E08, // 0026 EQ R8 R7 R8 + 0x78220002, // 0027 JMPF R8 #002B + 0x50200200, // 0028 LDBOOL R8 1 0 + 0x80041000, // 0029 RET 1 R8 + 0x70020004, // 002A JMP #0030 + 0x5422004B, // 002B LDINT R8 76 + 0x1C200E08, // 002C EQ R8 R7 R8 + 0x78220001, // 002D JMPF R8 #0030 + 0x50200200, // 002E LDBOOL R8 1 0 + 0x80041000, // 002F RET 1 R8 + 0x70020008, // 0030 JMP #003A + 0x60200003, // 0031 GETGBL R8 G3 + 0x5C240000, // 0032 MOVE R9 R0 + 0x7C200200, // 0033 CALL R8 1 + 0x8C20110D, // 0034 GETMET R8 R8 K13 + 0x5C280200, // 0035 MOVE R10 R1 + 0x5C2C0400, // 0036 MOVE R11 R2 + 0x5C300600, // 0037 MOVE R12 R3 + 0x7C200800, // 0038 CALL R8 4 + 0x80041000, // 0039 RET 1 R8 + 0x80000000, // 003A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Light2_update_shadow, /* name */ + be_nested_proto( + 8, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str_weak(light), + /* K1 */ be_nested_str_weak(update_ct_minmax), + /* K2 */ be_nested_str_weak(update_shadow), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_nested_str_weak(find), + /* K5 */ be_nested_str_weak(ct), + /* K6 */ be_nested_str_weak(shadow_ct), + /* K7 */ be_nested_str_weak(attribute_updated), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[30]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080101, // 0001 GETMET R2 R0 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x60080003, // 0003 GETGBL R2 G3 + 0x5C0C0000, // 0004 MOVE R3 R0 + 0x7C080200, // 0005 CALL R2 1 + 0x8C080502, // 0006 GETMET R2 R2 K2 + 0x7C080200, // 0007 CALL R2 1 + 0x8C080303, // 0008 GETMET R2 R1 K3 + 0x7C080200, // 0009 CALL R2 1 + 0x4C0C0000, // 000A LDNIL R3 + 0x200C0403, // 000B NE R3 R2 R3 + 0x780E000F, // 000C JMPF R3 #001D + 0x8C0C0504, // 000D GETMET R3 R2 K4 + 0x58140005, // 000E LDCONST R5 K5 + 0x4C180000, // 000F LDNIL R6 + 0x7C0C0600, // 0010 CALL R3 3 + 0x4C100000, // 0011 LDNIL R4 + 0x1C100604, // 0012 EQ R4 R3 R4 + 0x78120000, // 0013 JMPF R4 #0015 + 0x880C0106, // 0014 GETMBR R3 R0 K6 + 0x88100106, // 0015 GETMBR R4 R0 K6 + 0x20100604, // 0016 NE R4 R3 R4 + 0x78120004, // 0017 JMPF R4 #001D + 0x8C100107, // 0018 GETMET R4 R0 K7 + 0x541A02FF, // 0019 LDINT R6 768 + 0x541E0006, // 001A LDINT R7 7 + 0x7C100600, // 001B CALL R4 3 + 0x90020C03, // 001C SETMBR R0 K6 R3 + 0x80000000, // 001D RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_virtual +********************************************************************/ +be_local_closure(Matter_Plugin_Light2_update_virtual, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(find), + /* K1 */ be_nested_str_weak(CT), + /* K2 */ be_nested_str_weak(set_ct), + /* K3 */ be_nested_str_weak(update_virtual), + }), + be_str_weak(update_virtual), + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x8C0C0300, // 0001 GETMET R3 R1 K0 + 0x58140001, // 0002 LDCONST R5 K1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x7C080200, // 0004 CALL R2 1 + 0x4C0C0000, // 0005 LDNIL R3 + 0x200C0403, // 0006 NE R3 R2 R3 + 0x780E0002, // 0007 JMPF R3 #000B + 0x8C0C0102, // 0008 GETMET R3 R0 K2 + 0x5C140400, // 0009 MOVE R5 R2 + 0x7C0C0400, // 000A CALL R3 2 + 0x600C0003, // 000B GETGBL R3 G3 + 0x5C100000, // 000C MOVE R4 R0 + 0x7C0C0200, // 000D CALL R3 1 + 0x8C0C0703, // 000E GETMET R3 R3 K3 + 0x5C140200, // 000F MOVE R5 R1 + 0x7C0C0400, // 0010 CALL R3 2 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_ct +********************************************************************/ +be_local_closure(Matter_Plugin_Light2_set_ct, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str_weak(ct_min), + /* K1 */ be_nested_str_weak(ct_max), + /* K2 */ be_nested_str_weak(VIRTUAL), + /* K3 */ be_nested_str_weak(light), + /* K4 */ be_nested_str_weak(set), + /* K5 */ be_nested_str_weak(ct), + /* K6 */ be_nested_str_weak(update_shadow), + /* K7 */ be_nested_str_weak(shadow_ct), + /* K8 */ be_nested_str_weak(attribute_updated), + }), + be_str_weak(set_ct), + &be_const_str_solidified, + ( &(const binstruction[28]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x14080202, // 0001 LT R2 R1 R2 + 0x780A0000, // 0002 JMPF R2 #0004 + 0x88040100, // 0003 GETMBR R1 R0 K0 + 0x88080101, // 0004 GETMBR R2 R0 K1 + 0x24080202, // 0005 GT R2 R1 R2 + 0x780A0000, // 0006 JMPF R2 #0008 + 0x88040101, // 0007 GETMBR R1 R0 K1 + 0x88080102, // 0008 GETMBR R2 R0 K2 + 0x740A0008, // 0009 JMPT R2 #0013 + 0xA40A0600, // 000A IMPORT R2 K3 + 0x8C0C0504, // 000B GETMET R3 R2 K4 + 0x60140013, // 000C GETGBL R5 G19 + 0x7C140000, // 000D CALL R5 0 + 0x98160A01, // 000E SETIDX R5 K5 R1 + 0x7C0C0400, // 000F CALL R3 2 + 0x8C0C0106, // 0010 GETMET R3 R0 K6 + 0x7C0C0200, // 0011 CALL R3 1 + 0x70020007, // 0012 JMP #001B + 0x88080107, // 0013 GETMBR R2 R0 K7 + 0x20080202, // 0014 NE R2 R1 R2 + 0x780A0004, // 0015 JMPF R2 #001B + 0x8C080108, // 0016 GETMET R2 R0 K8 + 0x541202FF, // 0017 LDINT R4 768 + 0x54160006, // 0018 LDINT R5 7 + 0x7C080600, // 0019 CALL R2 3 + 0x90020E01, // 001A SETMBR R0 K7 R1 + 0x80000000, // 001B RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -126,108 +432,6 @@ be_local_closure(Matter_Plugin_Light2_read_attribute, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_Light2_update_shadow, /* name */ - be_nested_proto( - 8, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(update_ct_minmax), - /* K2 */ be_nested_str_weak(update_shadow), - /* K3 */ be_nested_str_weak(get), - /* K4 */ be_nested_str_weak(find), - /* K5 */ be_nested_str_weak(ct), - /* K6 */ be_nested_str_weak(shadow_ct), - /* K7 */ be_nested_str_weak(attribute_updated), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[30]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080101, // 0001 GETMET R2 R0 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x60080003, // 0003 GETGBL R2 G3 - 0x5C0C0000, // 0004 MOVE R3 R0 - 0x7C080200, // 0005 CALL R2 1 - 0x8C080502, // 0006 GETMET R2 R2 K2 - 0x7C080200, // 0007 CALL R2 1 - 0x8C080303, // 0008 GETMET R2 R1 K3 - 0x7C080200, // 0009 CALL R2 1 - 0x4C0C0000, // 000A LDNIL R3 - 0x200C0403, // 000B NE R3 R2 R3 - 0x780E000F, // 000C JMPF R3 #001D - 0x8C0C0504, // 000D GETMET R3 R2 K4 - 0x58140005, // 000E LDCONST R5 K5 - 0x4C180000, // 000F LDNIL R6 - 0x7C0C0600, // 0010 CALL R3 3 - 0x4C100000, // 0011 LDNIL R4 - 0x1C100604, // 0012 EQ R4 R3 R4 - 0x78120000, // 0013 JMPF R4 #0015 - 0x880C0106, // 0014 GETMBR R3 R0 K6 - 0x88100106, // 0015 GETMBR R4 R0 K6 - 0x20100604, // 0016 NE R4 R3 R4 - 0x78120004, // 0017 JMPF R4 #001D - 0x8C100107, // 0018 GETMET R4 R0 K7 - 0x541A02FF, // 0019 LDINT R6 768 - 0x541E0006, // 001A LDINT R7 7 - 0x7C100600, // 001B CALL R4 3 - 0x90020C03, // 001C SETMBR R0 K6 R3 - 0x80000000, // 001D RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_Light2_init, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(init), - /* K1 */ be_nested_str_weak(shadow_ct), - /* K2 */ be_nested_str_weak(update_ct_minmax), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[13]) { /* code */ - 0x60100003, // 0000 GETGBL R4 G3 - 0x5C140000, // 0001 MOVE R5 R0 - 0x7C100200, // 0002 CALL R4 1 - 0x8C100900, // 0003 GETMET R4 R4 K0 - 0x5C180200, // 0004 MOVE R6 R1 - 0x5C1C0400, // 0005 MOVE R7 R2 - 0x5C200600, // 0006 MOVE R8 R3 - 0x7C100800, // 0007 CALL R4 4 - 0x54120144, // 0008 LDINT R4 325 - 0x90020204, // 0009 SETMBR R0 K1 R4 - 0x8C100102, // 000A GETMET R4 R0 K2 - 0x7C100200, // 000B CALL R4 1 - 0x80000000, // 000C RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: update_ct_minmax ********************************************************************/ @@ -271,113 +475,6 @@ be_local_closure(Matter_Plugin_Light2_update_ct_minmax, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Light2_invoke_request, /* name */ - be_nested_proto( - 13, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(command), - /* K5 */ be_nested_str_weak(update_shadow_lazy), - /* K6 */ be_nested_str_weak(findsubval), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str_weak(ct_min), - /* K9 */ be_nested_str_weak(ct_max), - /* K10 */ be_nested_str_weak(set), - /* K11 */ be_nested_str_weak(ct), - /* K12 */ be_nested_str_weak(update_shadow), - /* K13 */ be_nested_str_weak(log), - /* K14 */ be_nested_str_weak(ct_X3A), - /* K15 */ be_nested_str_weak(invoke_request), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[67]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xB8160200, // 0001 GETNGBL R5 K1 - 0x88140B02, // 0002 GETMBR R5 R5 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x881C0704, // 0004 GETMBR R7 R3 K4 - 0x542202FF, // 0005 LDINT R8 768 - 0x1C200C08, // 0006 EQ R8 R6 R8 - 0x78220030, // 0007 JMPF R8 #0039 - 0x8C200105, // 0008 GETMET R8 R0 K5 - 0x7C200200, // 0009 CALL R8 1 - 0x54220009, // 000A LDINT R8 10 - 0x1C200E08, // 000B EQ R8 R7 R8 - 0x78220019, // 000C JMPF R8 #0027 - 0x8C200506, // 000D GETMET R8 R2 K6 - 0x58280007, // 000E LDCONST R10 K7 - 0x7C200400, // 000F CALL R8 2 - 0x88240108, // 0010 GETMBR R9 R0 K8 - 0x14241009, // 0011 LT R9 R8 R9 - 0x78260000, // 0012 JMPF R9 #0014 - 0x88200108, // 0013 GETMBR R8 R0 K8 - 0x88240109, // 0014 GETMBR R9 R0 K9 - 0x24241009, // 0015 GT R9 R8 R9 - 0x78260000, // 0016 JMPF R9 #0018 - 0x88200109, // 0017 GETMBR R8 R0 K9 - 0x8C24090A, // 0018 GETMET R9 R4 K10 - 0x602C0013, // 0019 GETGBL R11 G19 - 0x7C2C0000, // 001A CALL R11 0 - 0x982E1608, // 001B SETIDX R11 K11 R8 - 0x7C240400, // 001C CALL R9 2 - 0x8C24010C, // 001D GETMET R9 R0 K12 - 0x7C240200, // 001E CALL R9 1 - 0x60240008, // 001F GETGBL R9 G8 - 0x5C281000, // 0020 MOVE R10 R8 - 0x7C240200, // 0021 CALL R9 1 - 0x00261C09, // 0022 ADD R9 K14 R9 - 0x900E1A09, // 0023 SETMBR R3 K13 R9 - 0x50240200, // 0024 LDBOOL R9 1 0 - 0x80041200, // 0025 RET 1 R9 - 0x70020010, // 0026 JMP #0038 - 0x54220046, // 0027 LDINT R8 71 - 0x1C200E08, // 0028 EQ R8 R7 R8 - 0x78220002, // 0029 JMPF R8 #002D - 0x50200200, // 002A LDBOOL R8 1 0 - 0x80041000, // 002B RET 1 R8 - 0x7002000A, // 002C JMP #0038 - 0x5422004A, // 002D LDINT R8 75 - 0x1C200E08, // 002E EQ R8 R7 R8 - 0x78220002, // 002F JMPF R8 #0033 - 0x50200200, // 0030 LDBOOL R8 1 0 - 0x80041000, // 0031 RET 1 R8 - 0x70020004, // 0032 JMP #0038 - 0x5422004B, // 0033 LDINT R8 76 - 0x1C200E08, // 0034 EQ R8 R7 R8 - 0x78220001, // 0035 JMPF R8 #0038 - 0x50200200, // 0036 LDBOOL R8 1 0 - 0x80041000, // 0037 RET 1 R8 - 0x70020008, // 0038 JMP #0042 - 0x60200003, // 0039 GETGBL R8 G3 - 0x5C240000, // 003A MOVE R9 R0 - 0x7C200200, // 003B CALL R8 1 - 0x8C20110F, // 003C GETMET R8 R8 K15 - 0x5C280200, // 003D MOVE R10 R1 - 0x5C2C0400, // 003E MOVE R11 R2 - 0x5C300600, // 003F MOVE R12 R3 - 0x7C200800, // 0040 CALL R8 4 - 0x80041000, // 0041 RET 1 R8 - 0x80000000, // 0042 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Matter_Plugin_Light2 ********************************************************************/ @@ -385,25 +482,97 @@ extern const bclass be_class_Matter_Plugin_Light1; be_local_class(Matter_Plugin_Light2, 3, &be_class_Matter_Plugin_Light1, - be_nested_map(12, + be_nested_map(15, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(ct_min, -1), be_const_var(1) }, - { be_const_key_weak(shadow_ct, 8), be_const_var(0) }, + { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light2_init_closure) }, + { be_const_key_weak(shadow_ct, -1), be_const_var(0) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light2_invoke_request_closure) }, + { be_const_key_weak(ct_max, -1), be_const_var(2) }, + { be_const_key_weak(update_shadow, 10), be_const_closure(Matter_Plugin_Light2_update_shadow_closure) }, + { be_const_key_weak(update_virtual, 8), be_const_closure(Matter_Plugin_Light2_update_virtual_closure) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Light_X202_X20CT) }, + { be_const_key_weak(set_ct, -1), be_const_closure(Matter_Plugin_Light2_set_ct_closure) }, { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { be_const_map( * be_nested_map(1, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(268, -1), be_const_int(2) }, })) ) } )) }, - { be_const_key_weak(ct_max, 7), be_const_var(2) }, - { be_const_key_weak(TYPE, 0), be_nested_str_weak(light2) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Light2_read_attribute_closure) }, - { be_const_key_weak(NAME, 5), be_nested_str_weak(Light_X202_X20CT) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light2_init_closure) }, - { be_const_key_weak(update_shadow, 4), be_const_closure(Matter_Plugin_Light2_update_shadow_closure) }, - { be_const_key_weak(update_ct_minmax, -1), be_const_closure(Matter_Plugin_Light2_update_ct_minmax_closure) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, + { be_const_key_weak(UPDATE_COMMANDS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Power), + be_nested_str_weak(Bri), + be_nested_str_weak(CT), + })) ) } )) }, + { be_const_key_weak(CLUSTERS, 14), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(8, ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(8, 7), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(2), + be_const_int(3), + be_const_int(15), + be_const_int(17), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(5, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, { be_const_key_int(768, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(7, ( (struct bvalue*) &(const bvalue[]) { @@ -416,7 +585,10 @@ be_local_class(Matter_Plugin_Light2, be_const_int(65533), })) ) } )) }, })) ) } )) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light2_invoke_request_closure) }, + { be_const_key_weak(update_ct_minmax, -1), be_const_closure(Matter_Plugin_Light2_update_ct_minmax_closure) }, + { be_const_key_weak(read_attribute, 11), be_const_closure(Matter_Plugin_Light2_read_attribute_closure) }, + { be_const_key_weak(ct_min, -1), be_const_var(1) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(light2) }, })), be_str_weak(Matter_Plugin_Light2) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Light3.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Light3.h new file mode 100644 index 000000000..538d02b80 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_4_Light3.h @@ -0,0 +1,785 @@ +/* Solidification of Matter_Plugin_4_Light3.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Light3; + +/******************************************************************** +** Solidified function: update_virtual +********************************************************************/ +be_local_closure(Matter_Plugin_Light3_update_virtual, /* name */ + be_nested_proto( + 8, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str_weak(find), + /* K1 */ be_nested_str_weak(Hue), + /* K2 */ be_nested_str_weak(Sat), + /* K3 */ be_nested_str_weak(set_hue_sat), + /* K4 */ be_nested_str_weak(update_virtual), + }), + be_str_weak(update_virtual), + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x60080009, // 0000 GETGBL R2 G9 + 0x8C0C0300, // 0001 GETMET R3 R1 K0 + 0x58140001, // 0002 LDCONST R5 K1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x7C080200, // 0004 CALL R2 1 + 0x600C0009, // 0005 GETGBL R3 G9 + 0x8C100300, // 0006 GETMET R4 R1 K0 + 0x58180002, // 0007 LDCONST R6 K2 + 0x7C100400, // 0008 CALL R4 2 + 0x7C0C0200, // 0009 CALL R3 1 + 0x4C100000, // 000A LDNIL R4 + 0x20100404, // 000B NE R4 R2 R4 + 0x74120002, // 000C JMPT R4 #0010 + 0x4C100000, // 000D LDNIL R4 + 0x20100604, // 000E NE R4 R3 R4 + 0x78120003, // 000F JMPF R4 #0014 + 0x8C100103, // 0010 GETMET R4 R0 K3 + 0x5C180400, // 0011 MOVE R6 R2 + 0x5C1C0600, // 0012 MOVE R7 R3 + 0x7C100600, // 0013 CALL R4 3 + 0x60100003, // 0014 GETGBL R4 G3 + 0x5C140000, // 0015 MOVE R5 R0 + 0x7C100200, // 0016 CALL R4 1 + 0x8C100904, // 0017 GETMET R4 R4 K4 + 0x5C180200, // 0018 MOVE R6 R1 + 0x7C100400, // 0019 CALL R4 2 + 0x80000000, // 001A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_hue_sat +********************************************************************/ +be_local_closure(Matter_Plugin_Light3_set_hue_sat, /* name */ + be_nested_proto( + 11, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str_weak(VIRTUAL), + /* K2 */ be_nested_str_weak(tasmota), + /* K3 */ be_nested_str_weak(scale_uint), + /* K4 */ be_nested_str_weak(light), + /* K5 */ be_nested_str_weak(set), + /* K6 */ be_nested_str_weak(hue), + /* K7 */ be_nested_str_weak(sat), + /* K8 */ be_nested_str_weak(update_shadow), + /* K9 */ be_nested_str_weak(shadow_hue), + /* K10 */ be_nested_str_weak(attribute_updated), + /* K11 */ be_nested_str_weak(shadow_sat), + /* K12 */ be_const_int(1), + }), + be_str_weak(set_hue_sat), + &be_const_str_solidified, + ( &(const binstruction[104]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0203, // 0001 NE R3 R1 R3 + 0x780E0006, // 0002 JMPF R3 #000A + 0x140C0300, // 0003 LT R3 R1 K0 + 0x780E0000, // 0004 JMPF R3 #0006 + 0x58040000, // 0005 LDCONST R1 K0 + 0x540E00FD, // 0006 LDINT R3 254 + 0x240C0203, // 0007 GT R3 R1 R3 + 0x780E0000, // 0008 JMPF R3 #000A + 0x540600FD, // 0009 LDINT R1 254 + 0x4C0C0000, // 000A LDNIL R3 + 0x200C0403, // 000B NE R3 R2 R3 + 0x780E0006, // 000C JMPF R3 #0014 + 0x140C0500, // 000D LT R3 R2 K0 + 0x780E0000, // 000E JMPF R3 #0010 + 0x58080000, // 000F LDCONST R2 K0 + 0x540E00FD, // 0010 LDINT R3 254 + 0x240C0403, // 0011 GT R3 R2 R3 + 0x780E0000, // 0012 JMPF R3 #0014 + 0x540A00FD, // 0013 LDINT R2 254 + 0x880C0101, // 0014 GETMBR R3 R0 K1 + 0x740E003A, // 0015 JMPT R3 #0051 + 0x4C0C0000, // 0016 LDNIL R3 + 0x200C0203, // 0017 NE R3 R1 R3 + 0x780E0008, // 0018 JMPF R3 #0022 + 0xB80E0400, // 0019 GETNGBL R3 K2 + 0x8C0C0703, // 001A GETMET R3 R3 K3 + 0x5C140200, // 001B MOVE R5 R1 + 0x58180000, // 001C LDCONST R6 K0 + 0x541E00FD, // 001D LDINT R7 254 + 0x58200000, // 001E LDCONST R8 K0 + 0x54260167, // 001F LDINT R9 360 + 0x7C0C0C00, // 0020 CALL R3 6 + 0x70020000, // 0021 JMP #0023 + 0x4C0C0000, // 0022 LDNIL R3 + 0x4C100000, // 0023 LDNIL R4 + 0x20100404, // 0024 NE R4 R2 R4 + 0x78120008, // 0025 JMPF R4 #002F + 0xB8120400, // 0026 GETNGBL R4 K2 + 0x8C100903, // 0027 GETMET R4 R4 K3 + 0x5C180400, // 0028 MOVE R6 R2 + 0x581C0000, // 0029 LDCONST R7 K0 + 0x542200FD, // 002A LDINT R8 254 + 0x58240000, // 002B LDCONST R9 K0 + 0x542A00FE, // 002C LDINT R10 255 + 0x7C100C00, // 002D CALL R4 6 + 0x70020000, // 002E JMP #0030 + 0x4C100000, // 002F LDNIL R4 + 0x4C140000, // 0030 LDNIL R5 + 0x20140605, // 0031 NE R5 R3 R5 + 0x7816000A, // 0032 JMPF R5 #003E + 0x4C140000, // 0033 LDNIL R5 + 0x20140805, // 0034 NE R5 R4 R5 + 0x78160007, // 0035 JMPF R5 #003E + 0xB8160800, // 0036 GETNGBL R5 K4 + 0x8C140B05, // 0037 GETMET R5 R5 K5 + 0x601C0013, // 0038 GETGBL R7 G19 + 0x7C1C0000, // 0039 CALL R7 0 + 0x981E0C03, // 003A SETIDX R7 K6 R3 + 0x981E0E04, // 003B SETIDX R7 K7 R4 + 0x7C140400, // 003C CALL R5 2 + 0x7002000F, // 003D JMP #004E + 0x4C140000, // 003E LDNIL R5 + 0x20140605, // 003F NE R5 R3 R5 + 0x78160006, // 0040 JMPF R5 #0048 + 0xB8160800, // 0041 GETNGBL R5 K4 + 0x8C140B05, // 0042 GETMET R5 R5 K5 + 0x601C0013, // 0043 GETGBL R7 G19 + 0x7C1C0000, // 0044 CALL R7 0 + 0x981E0C03, // 0045 SETIDX R7 K6 R3 + 0x7C140400, // 0046 CALL R5 2 + 0x70020005, // 0047 JMP #004E + 0xB8160800, // 0048 GETNGBL R5 K4 + 0x8C140B05, // 0049 GETMET R5 R5 K5 + 0x601C0013, // 004A GETGBL R7 G19 + 0x7C1C0000, // 004B CALL R7 0 + 0x981E0E04, // 004C SETIDX R7 K7 R4 + 0x7C140400, // 004D CALL R5 2 + 0x8C140108, // 004E GETMET R5 R0 K8 + 0x7C140200, // 004F CALL R5 1 + 0x70020015, // 0050 JMP #0067 + 0x4C0C0000, // 0051 LDNIL R3 + 0x200C0203, // 0052 NE R3 R1 R3 + 0x780E0007, // 0053 JMPF R3 #005C + 0x880C0109, // 0054 GETMBR R3 R0 K9 + 0x200C0203, // 0055 NE R3 R1 R3 + 0x780E0004, // 0056 JMPF R3 #005C + 0x8C0C010A, // 0057 GETMET R3 R0 K10 + 0x541602FF, // 0058 LDINT R5 768 + 0x58180000, // 0059 LDCONST R6 K0 + 0x7C0C0600, // 005A CALL R3 3 + 0x90021201, // 005B SETMBR R0 K9 R1 + 0x4C0C0000, // 005C LDNIL R3 + 0x200C0403, // 005D NE R3 R2 R3 + 0x780E0007, // 005E JMPF R3 #0067 + 0x880C010B, // 005F GETMBR R3 R0 K11 + 0x200C0403, // 0060 NE R3 R2 R3 + 0x780E0004, // 0061 JMPF R3 #0067 + 0x8C0C010A, // 0062 GETMET R3 R0 K10 + 0x541602FF, // 0063 LDINT R5 768 + 0x5818000C, // 0064 LDCONST R6 K12 + 0x7C0C0600, // 0065 CALL R3 3 + 0x90021602, // 0066 SETMBR R0 K11 R2 + 0x80000000, // 0067 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Light3_invoke_request, /* name */ + be_nested_proto( + 16, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[20]) { /* constants */ + /* K0 */ be_nested_str_weak(light), + /* K1 */ be_nested_str_weak(matter), + /* K2 */ be_nested_str_weak(TLV), + /* K3 */ be_nested_str_weak(cluster), + /* K4 */ be_nested_str_weak(command), + /* K5 */ be_nested_str_weak(update_shadow_lazy), + /* K6 */ be_const_int(0), + /* K7 */ be_nested_str_weak(findsubval), + /* K8 */ be_nested_str_weak(set_hue_sat), + /* K9 */ be_nested_str_weak(log), + /* K10 */ be_nested_str_weak(hue_X3A), + /* K11 */ be_nested_str_weak(publish_command), + /* K12 */ be_nested_str_weak(Hue), + /* K13 */ be_const_int(1), + /* K14 */ be_const_int(2), + /* K15 */ be_const_int(3), + /* K16 */ be_nested_str_weak(sat_X3A), + /* K17 */ be_nested_str_weak(Sat), + /* K18 */ be_nested_str_weak(_X20sat_X3A), + /* K19 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[122]) { /* code */ + 0xA4120000, // 0000 IMPORT R4 K0 + 0xB8160200, // 0001 GETNGBL R5 K1 + 0x88140B02, // 0002 GETMBR R5 R5 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x881C0704, // 0004 GETMBR R7 R3 K4 + 0x542202FF, // 0005 LDINT R8 768 + 0x1C200C08, // 0006 EQ R8 R6 R8 + 0x78220067, // 0007 JMPF R8 #0070 + 0x8C200105, // 0008 GETMET R8 R0 K5 + 0x7C200200, // 0009 CALL R8 1 + 0x1C200F06, // 000A EQ R8 R7 K6 + 0x78220012, // 000B JMPF R8 #001F + 0x8C200507, // 000C GETMET R8 R2 K7 + 0x58280006, // 000D LDCONST R10 K6 + 0x7C200400, // 000E CALL R8 2 + 0x8C240108, // 000F GETMET R9 R0 K8 + 0x5C2C1000, // 0010 MOVE R11 R8 + 0x4C300000, // 0011 LDNIL R12 + 0x7C240600, // 0012 CALL R9 3 + 0x60240008, // 0013 GETGBL R9 G8 + 0x5C281000, // 0014 MOVE R10 R8 + 0x7C240200, // 0015 CALL R9 1 + 0x00261409, // 0016 ADD R9 K10 R9 + 0x900E1209, // 0017 SETMBR R3 K9 R9 + 0x8C24010B, // 0018 GETMET R9 R0 K11 + 0x582C000C, // 0019 LDCONST R11 K12 + 0x5C301000, // 001A MOVE R12 R8 + 0x7C240600, // 001B CALL R9 3 + 0x50240200, // 001C LDBOOL R9 1 0 + 0x80041200, // 001D RET 1 R9 + 0x7002004F, // 001E JMP #006F + 0x1C200F0D, // 001F EQ R8 R7 K13 + 0x78220002, // 0020 JMPF R8 #0024 + 0x50200200, // 0021 LDBOOL R8 1 0 + 0x80041000, // 0022 RET 1 R8 + 0x7002004A, // 0023 JMP #006F + 0x1C200F0E, // 0024 EQ R8 R7 K14 + 0x78220002, // 0025 JMPF R8 #0029 + 0x50200200, // 0026 LDBOOL R8 1 0 + 0x80041000, // 0027 RET 1 R8 + 0x70020045, // 0028 JMP #006F + 0x1C200F0F, // 0029 EQ R8 R7 K15 + 0x78220012, // 002A JMPF R8 #003E + 0x8C200507, // 002B GETMET R8 R2 K7 + 0x58280006, // 002C LDCONST R10 K6 + 0x7C200400, // 002D CALL R8 2 + 0x8C240108, // 002E GETMET R9 R0 K8 + 0x4C2C0000, // 002F LDNIL R11 + 0x5C301000, // 0030 MOVE R12 R8 + 0x7C240600, // 0031 CALL R9 3 + 0x60240008, // 0032 GETGBL R9 G8 + 0x5C281000, // 0033 MOVE R10 R8 + 0x7C240200, // 0034 CALL R9 1 + 0x00262009, // 0035 ADD R9 K16 R9 + 0x900E1209, // 0036 SETMBR R3 K9 R9 + 0x8C24010B, // 0037 GETMET R9 R0 K11 + 0x582C0011, // 0038 LDCONST R11 K17 + 0x5C301000, // 0039 MOVE R12 R8 + 0x7C240600, // 003A CALL R9 3 + 0x50240200, // 003B LDBOOL R9 1 0 + 0x80041200, // 003C RET 1 R9 + 0x70020030, // 003D JMP #006F + 0x54220003, // 003E LDINT R8 4 + 0x1C200E08, // 003F EQ R8 R7 R8 + 0x78220002, // 0040 JMPF R8 #0044 + 0x50200200, // 0041 LDBOOL R8 1 0 + 0x80041000, // 0042 RET 1 R8 + 0x7002002A, // 0043 JMP #006F + 0x54220004, // 0044 LDINT R8 5 + 0x1C200E08, // 0045 EQ R8 R7 R8 + 0x78220002, // 0046 JMPF R8 #004A + 0x50200200, // 0047 LDBOOL R8 1 0 + 0x80041000, // 0048 RET 1 R8 + 0x70020024, // 0049 JMP #006F + 0x54220005, // 004A LDINT R8 6 + 0x1C200E08, // 004B EQ R8 R7 R8 + 0x7822001C, // 004C JMPF R8 #006A + 0x8C200507, // 004D GETMET R8 R2 K7 + 0x58280006, // 004E LDCONST R10 K6 + 0x7C200400, // 004F CALL R8 2 + 0x8C240507, // 0050 GETMET R9 R2 K7 + 0x582C000D, // 0051 LDCONST R11 K13 + 0x7C240400, // 0052 CALL R9 2 + 0x8C280108, // 0053 GETMET R10 R0 K8 + 0x5C301000, // 0054 MOVE R12 R8 + 0x5C341200, // 0055 MOVE R13 R9 + 0x7C280600, // 0056 CALL R10 3 + 0x60280008, // 0057 GETGBL R10 G8 + 0x5C2C1000, // 0058 MOVE R11 R8 + 0x7C280200, // 0059 CALL R10 1 + 0x002A140A, // 005A ADD R10 K10 R10 + 0x00281512, // 005B ADD R10 R10 K18 + 0x602C0008, // 005C GETGBL R11 G8 + 0x5C301200, // 005D MOVE R12 R9 + 0x7C2C0200, // 005E CALL R11 1 + 0x0028140B, // 005F ADD R10 R10 R11 + 0x900E120A, // 0060 SETMBR R3 K9 R10 + 0x8C28010B, // 0061 GETMET R10 R0 K11 + 0x5830000C, // 0062 LDCONST R12 K12 + 0x5C341000, // 0063 MOVE R13 R8 + 0x58380011, // 0064 LDCONST R14 K17 + 0x5C3C1200, // 0065 MOVE R15 R9 + 0x7C280A00, // 0066 CALL R10 5 + 0x50280200, // 0067 LDBOOL R10 1 0 + 0x80041400, // 0068 RET 1 R10 + 0x70020004, // 0069 JMP #006F + 0x54220046, // 006A LDINT R8 71 + 0x1C200E08, // 006B EQ R8 R7 R8 + 0x78220001, // 006C JMPF R8 #006F + 0x50200200, // 006D LDBOOL R8 1 0 + 0x80041000, // 006E RET 1 R8 + 0x70020008, // 006F JMP #0079 + 0x60200003, // 0070 GETGBL R8 G3 + 0x5C240000, // 0071 MOVE R9 R0 + 0x7C200200, // 0072 CALL R8 1 + 0x8C201113, // 0073 GETMET R8 R8 K19 + 0x5C280200, // 0074 MOVE R10 R1 + 0x5C2C0400, // 0075 MOVE R11 R2 + 0x5C300600, // 0076 MOVE R12 R3 + 0x7C200800, // 0077 CALL R8 4 + 0x80041000, // 0078 RET 1 R8 + 0x80000000, // 0079 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Matter_Plugin_Light3_init, /* name */ + be_nested_proto( + 9, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(init), + /* K1 */ be_nested_str_weak(shadow_hue), + /* K2 */ be_const_int(0), + /* K3 */ be_nested_str_weak(shadow_sat), + }), + be_str_weak(init), + &be_const_str_solidified, + ( &(const binstruction[11]) { /* code */ + 0x60100003, // 0000 GETGBL R4 G3 + 0x5C140000, // 0001 MOVE R5 R0 + 0x7C100200, // 0002 CALL R4 1 + 0x8C100900, // 0003 GETMET R4 R4 K0 + 0x5C180200, // 0004 MOVE R6 R1 + 0x5C1C0400, // 0005 MOVE R7 R2 + 0x5C200600, // 0006 MOVE R8 R3 + 0x7C100800, // 0007 CALL R4 4 + 0x90020302, // 0008 SETMBR R0 K1 K2 + 0x90020702, // 0009 SETMBR R0 K3 K2 + 0x80000000, // 000A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: update_shadow +********************************************************************/ +be_local_closure(Matter_Plugin_Light3_update_shadow, /* name */ + be_nested_proto( + 12, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str_weak(update_shadow), + /* K1 */ be_nested_str_weak(VIRTUAL), + /* K2 */ be_nested_str_weak(light), + /* K3 */ be_nested_str_weak(get), + /* K4 */ be_nested_str_weak(find), + /* K5 */ be_nested_str_weak(hue), + /* K6 */ be_nested_str_weak(sat), + /* K7 */ be_nested_str_weak(tasmota), + /* K8 */ be_nested_str_weak(scale_uint), + /* K9 */ be_const_int(0), + /* K10 */ be_nested_str_weak(shadow_hue), + /* K11 */ be_nested_str_weak(shadow_sat), + /* K12 */ be_nested_str_weak(attribute_updated), + /* K13 */ be_const_int(1), + }), + be_str_weak(update_shadow), + &be_const_str_solidified, + ( &(const binstruction[66]) { /* code */ + 0x60040003, // 0000 GETGBL R1 G3 + 0x5C080000, // 0001 MOVE R2 R0 + 0x7C040200, // 0002 CALL R1 1 + 0x8C040300, // 0003 GETMET R1 R1 K0 + 0x7C040200, // 0004 CALL R1 1 + 0x88040101, // 0005 GETMBR R1 R0 K1 + 0x74060039, // 0006 JMPT R1 #0041 + 0xA4060400, // 0007 IMPORT R1 K2 + 0x8C080303, // 0008 GETMET R2 R1 K3 + 0x7C080200, // 0009 CALL R2 1 + 0x4C0C0000, // 000A LDNIL R3 + 0x200C0403, // 000B NE R3 R2 R3 + 0x780E0033, // 000C JMPF R3 #0041 + 0x8C0C0504, // 000D GETMET R3 R2 K4 + 0x58140005, // 000E LDCONST R5 K5 + 0x4C180000, // 000F LDNIL R6 + 0x7C0C0600, // 0010 CALL R3 3 + 0x8C100504, // 0011 GETMET R4 R2 K4 + 0x58180006, // 0012 LDCONST R6 K6 + 0x4C1C0000, // 0013 LDNIL R7 + 0x7C100600, // 0014 CALL R4 3 + 0x4C140000, // 0015 LDNIL R5 + 0x20140605, // 0016 NE R5 R3 R5 + 0x78160009, // 0017 JMPF R5 #0022 + 0xB8160E00, // 0018 GETNGBL R5 K7 + 0x8C140B08, // 0019 GETMET R5 R5 K8 + 0x5C1C0600, // 001A MOVE R7 R3 + 0x58200009, // 001B LDCONST R8 K9 + 0x54260167, // 001C LDINT R9 360 + 0x58280009, // 001D LDCONST R10 K9 + 0x542E00FD, // 001E LDINT R11 254 + 0x7C140C00, // 001F CALL R5 6 + 0x5C0C0A00, // 0020 MOVE R3 R5 + 0x70020000, // 0021 JMP #0023 + 0x880C010A, // 0022 GETMBR R3 R0 K10 + 0x4C140000, // 0023 LDNIL R5 + 0x20140805, // 0024 NE R5 R4 R5 + 0x78160009, // 0025 JMPF R5 #0030 + 0xB8160E00, // 0026 GETNGBL R5 K7 + 0x8C140B08, // 0027 GETMET R5 R5 K8 + 0x5C1C0800, // 0028 MOVE R7 R4 + 0x58200009, // 0029 LDCONST R8 K9 + 0x542600FE, // 002A LDINT R9 255 + 0x58280009, // 002B LDCONST R10 K9 + 0x542E00FD, // 002C LDINT R11 254 + 0x7C140C00, // 002D CALL R5 6 + 0x5C100A00, // 002E MOVE R4 R5 + 0x70020000, // 002F JMP #0031 + 0x8810010B, // 0030 GETMBR R4 R0 K11 + 0x8814010A, // 0031 GETMBR R5 R0 K10 + 0x20140605, // 0032 NE R5 R3 R5 + 0x78160004, // 0033 JMPF R5 #0039 + 0x8C14010C, // 0034 GETMET R5 R0 K12 + 0x541E02FF, // 0035 LDINT R7 768 + 0x58200009, // 0036 LDCONST R8 K9 + 0x7C140600, // 0037 CALL R5 3 + 0x90021403, // 0038 SETMBR R0 K10 R3 + 0x8814010B, // 0039 GETMBR R5 R0 K11 + 0x20140805, // 003A NE R5 R4 R5 + 0x78160004, // 003B JMPF R5 #0041 + 0x8C14010C, // 003C GETMET R5 R0 K12 + 0x541E02FF, // 003D LDINT R7 768 + 0x5820000D, // 003E LDCONST R8 K13 + 0x7C140600, // 003F CALL R5 3 + 0x90021604, // 0040 SETMBR R0 K11 R4 + 0x80000000, // 0041 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: read_attribute +********************************************************************/ +be_local_closure(Matter_Plugin_Light3_read_attribute, /* name */ + be_nested_proto( + 12, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[13]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(attribute), + /* K4 */ be_nested_str_weak(update_shadow_lazy), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str_weak(set), + /* K7 */ be_nested_str_weak(U1), + /* K8 */ be_nested_str_weak(shadow_hue), + /* K9 */ be_const_int(1), + /* K10 */ be_nested_str_weak(shadow_sat), + /* K11 */ be_nested_str_weak(U4), + /* K12 */ be_nested_str_weak(read_attribute), + }), + be_str_weak(read_attribute), + &be_const_str_solidified, + ( &(const binstruction[107]) { /* code */ + 0xB8120000, // 0000 GETNGBL R4 K0 + 0x88100901, // 0001 GETMBR R4 R4 K1 + 0x88140502, // 0002 GETMBR R5 R2 K2 + 0x88180503, // 0003 GETMBR R6 R2 K3 + 0x541E02FF, // 0004 LDINT R7 768 + 0x1C1C0A07, // 0005 EQ R7 R5 R7 + 0x781E0059, // 0006 JMPF R7 #0061 + 0x8C1C0104, // 0007 GETMET R7 R0 K4 + 0x7C1C0200, // 0008 CALL R7 1 + 0x1C1C0D05, // 0009 EQ R7 R6 K5 + 0x781E0005, // 000A JMPF R7 #0011 + 0x8C1C0706, // 000B GETMET R7 R3 K6 + 0x88240907, // 000C GETMBR R9 R4 K7 + 0x88280108, // 000D GETMBR R10 R0 K8 + 0x7C1C0600, // 000E CALL R7 3 + 0x80040E00, // 000F RET 1 R7 + 0x7002004E, // 0010 JMP #0060 + 0x1C1C0D09, // 0011 EQ R7 R6 K9 + 0x781E0005, // 0012 JMPF R7 #0019 + 0x8C1C0706, // 0013 GETMET R7 R3 K6 + 0x88240907, // 0014 GETMBR R9 R4 K7 + 0x8828010A, // 0015 GETMBR R10 R0 K10 + 0x7C1C0600, // 0016 CALL R7 3 + 0x80040E00, // 0017 RET 1 R7 + 0x70020046, // 0018 JMP #0060 + 0x541E0006, // 0019 LDINT R7 7 + 0x1C1C0C07, // 001A EQ R7 R6 R7 + 0x781E0005, // 001B JMPF R7 #0022 + 0x8C1C0706, // 001C GETMET R7 R3 K6 + 0x88240907, // 001D GETMBR R9 R4 K7 + 0x58280005, // 001E LDCONST R10 K5 + 0x7C1C0600, // 001F CALL R7 3 + 0x80040E00, // 0020 RET 1 R7 + 0x7002003D, // 0021 JMP #0060 + 0x541E0007, // 0022 LDINT R7 8 + 0x1C1C0C07, // 0023 EQ R7 R6 R7 + 0x781E0005, // 0024 JMPF R7 #002B + 0x8C1C0706, // 0025 GETMET R7 R3 K6 + 0x88240907, // 0026 GETMBR R9 R4 K7 + 0x58280005, // 0027 LDCONST R10 K5 + 0x7C1C0600, // 0028 CALL R7 3 + 0x80040E00, // 0029 RET 1 R7 + 0x70020034, // 002A JMP #0060 + 0x541E000E, // 002B LDINT R7 15 + 0x1C1C0C07, // 002C EQ R7 R6 R7 + 0x781E0005, // 002D JMPF R7 #0034 + 0x8C1C0706, // 002E GETMET R7 R3 K6 + 0x88240907, // 002F GETMBR R9 R4 K7 + 0x58280005, // 0030 LDCONST R10 K5 + 0x7C1C0600, // 0031 CALL R7 3 + 0x80040E00, // 0032 RET 1 R7 + 0x7002002B, // 0033 JMP #0060 + 0x541E4000, // 0034 LDINT R7 16385 + 0x1C1C0C07, // 0035 EQ R7 R6 R7 + 0x781E0005, // 0036 JMPF R7 #003D + 0x8C1C0706, // 0037 GETMET R7 R3 K6 + 0x88240907, // 0038 GETMBR R9 R4 K7 + 0x58280005, // 0039 LDCONST R10 K5 + 0x7C1C0600, // 003A CALL R7 3 + 0x80040E00, // 003B RET 1 R7 + 0x70020022, // 003C JMP #0060 + 0x541E4009, // 003D LDINT R7 16394 + 0x1C1C0C07, // 003E EQ R7 R6 R7 + 0x781E0005, // 003F JMPF R7 #0046 + 0x8C1C0706, // 0040 GETMET R7 R3 K6 + 0x88240907, // 0041 GETMBR R9 R4 K7 + 0x58280009, // 0042 LDCONST R10 K9 + 0x7C1C0600, // 0043 CALL R7 3 + 0x80040E00, // 0044 RET 1 R7 + 0x70020019, // 0045 JMP #0060 + 0x541E000F, // 0046 LDINT R7 16 + 0x1C1C0C07, // 0047 EQ R7 R6 R7 + 0x781E0005, // 0048 JMPF R7 #004F + 0x8C1C0706, // 0049 GETMET R7 R3 K6 + 0x88240907, // 004A GETMBR R9 R4 K7 + 0x58280005, // 004B LDCONST R10 K5 + 0x7C1C0600, // 004C CALL R7 3 + 0x80040E00, // 004D RET 1 R7 + 0x70020010, // 004E JMP #0060 + 0x541EFFFB, // 004F LDINT R7 65532 + 0x1C1C0C07, // 0050 EQ R7 R6 R7 + 0x781E0005, // 0051 JMPF R7 #0058 + 0x8C1C0706, // 0052 GETMET R7 R3 K6 + 0x8824090B, // 0053 GETMBR R9 R4 K11 + 0x58280009, // 0054 LDCONST R10 K9 + 0x7C1C0600, // 0055 CALL R7 3 + 0x80040E00, // 0056 RET 1 R7 + 0x70020007, // 0057 JMP #0060 + 0x541EFFFC, // 0058 LDINT R7 65533 + 0x1C1C0C07, // 0059 EQ R7 R6 R7 + 0x781E0004, // 005A JMPF R7 #0060 + 0x8C1C0706, // 005B GETMET R7 R3 K6 + 0x8824090B, // 005C GETMBR R9 R4 K11 + 0x542A0004, // 005D LDINT R10 5 + 0x7C1C0600, // 005E CALL R7 3 + 0x80040E00, // 005F RET 1 R7 + 0x70020008, // 0060 JMP #006A + 0x601C0003, // 0061 GETGBL R7 G3 + 0x5C200000, // 0062 MOVE R8 R0 + 0x7C1C0200, // 0063 CALL R7 1 + 0x8C1C0F0C, // 0064 GETMET R7 R7 K12 + 0x5C240200, // 0065 MOVE R9 R1 + 0x5C280400, // 0066 MOVE R10 R2 + 0x5C2C0600, // 0067 MOVE R11 R3 + 0x7C1C0800, // 0068 CALL R7 4 + 0x80040E00, // 0069 RET 1 R7 + 0x80000000, // 006A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified class: Matter_Plugin_Light3 +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Light1; +be_local_class(Matter_Plugin_Light3, + 2, + &be_class_Matter_Plugin_Light1, + be_nested_map(13, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(shadow_hue, -1), be_const_var(0) }, + { be_const_key_weak(shadow_sat, -1), be_const_var(1) }, + { be_const_key_weak(update_virtual, 8), be_const_closure(Matter_Plugin_Light3_update_virtual_closure) }, + { be_const_key_weak(update_shadow, -1), be_const_closure(Matter_Plugin_Light3_update_shadow_closure) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Light3_read_attribute_closure) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light3_invoke_request_closure) }, + { be_const_key_weak(init, 9), be_const_closure(Matter_Plugin_Light3_init_closure) }, + { be_const_key_weak(set_hue_sat, 3), be_const_closure(Matter_Plugin_Light3_set_hue_sat_closure) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(light3) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Light_X203_X20RGB) }, + { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(8, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(8, 7), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(2), + be_const_int(3), + be_const_int(15), + be_const_int(17), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(5, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(768, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(9, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(7), + be_const_int(8), + be_const_int(15), + be_const_int(16385), + be_const_int(16394), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + })) ) } )) }, + { be_const_key_weak(UPDATE_COMMANDS, 4), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_nested_str_weak(Power), + be_nested_str_weak(Bri), + be_nested_str_weak(Hue), + be_nested_str_weak(Sat), + })) ) } )) }, + { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(269, -1), be_const_int(2) }, + })) ) } )) }, + })), + be_str_weak(Matter_Plugin_Light3) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Light3_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Light3); + be_setglobal(vm, "Matter_Plugin_Light3"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light2.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_5_Bridge_Light2.h similarity index 82% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light2.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_5_Bridge_Light2.h index 1dc7e126f..712aa9f6d 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light2.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_5_Bridge_Light2.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Light2.h */ +/* Solidification of Matter_Plugin_5_Bridge_Light2.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -260,7 +260,7 @@ be_local_closure(Matter_Plugin_Bridge_Light2_invoke_request, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ + ( &(const bvalue[14]) { /* constants */ /* K0 */ be_nested_str_weak(matter), /* K1 */ be_nested_str_weak(TLV), /* K2 */ be_nested_str_weak(cluster), @@ -272,21 +272,23 @@ be_local_closure(Matter_Plugin_Bridge_Light2_invoke_request, /* name */ /* K8 */ be_nested_str_weak(set_ct), /* K9 */ be_nested_str_weak(log), /* K10 */ be_nested_str_weak(ct_X3A), - /* K11 */ be_nested_str_weak(invoke_request), + /* K11 */ be_nested_str_weak(publish_command), + /* K12 */ be_nested_str_weak(CT), + /* K13 */ be_nested_str_weak(invoke_request), }), be_str_weak(invoke_request), &be_const_str_solidified, - ( &(const binstruction[60]) { /* code */ + ( &(const binstruction[64]) { /* code */ 0xB8120000, // 0000 GETNGBL R4 K0 0x88100901, // 0001 GETMBR R4 R4 K1 0x88140702, // 0002 GETMBR R5 R3 K2 0x88180703, // 0003 GETMBR R6 R3 K3 0x541E02FF, // 0004 LDINT R7 768 0x1C1C0A07, // 0005 EQ R7 R5 R7 - 0x781E002A, // 0006 JMPF R7 #0032 + 0x781E002E, // 0006 JMPF R7 #0036 0x541E0009, // 0007 LDINT R7 10 0x1C1C0C07, // 0008 EQ R7 R6 R7 - 0x781E0015, // 0009 JMPF R7 #0020 + 0x781E0019, // 0009 JMPF R7 #0024 0x8C1C0504, // 000A GETMET R7 R2 K4 0x58240005, // 000B LDCONST R9 K5 0x7C1C0400, // 000C CALL R7 2 @@ -306,80 +308,41 @@ be_local_closure(Matter_Plugin_Bridge_Light2_invoke_request, /* name */ 0x7C200200, // 001A CALL R8 1 0x00221408, // 001B ADD R8 K10 R8 0x900E1208, // 001C SETMBR R3 K9 R8 - 0x50200200, // 001D LDBOOL R8 1 0 - 0x80041000, // 001E RET 1 R8 - 0x70020010, // 001F JMP #0031 - 0x541E0046, // 0020 LDINT R7 71 - 0x1C1C0C07, // 0021 EQ R7 R6 R7 - 0x781E0002, // 0022 JMPF R7 #0026 - 0x501C0200, // 0023 LDBOOL R7 1 0 - 0x80040E00, // 0024 RET 1 R7 - 0x7002000A, // 0025 JMP #0031 - 0x541E004A, // 0026 LDINT R7 75 - 0x1C1C0C07, // 0027 EQ R7 R6 R7 - 0x781E0002, // 0028 JMPF R7 #002C - 0x501C0200, // 0029 LDBOOL R7 1 0 - 0x80040E00, // 002A RET 1 R7 - 0x70020004, // 002B JMP #0031 - 0x541E004B, // 002C LDINT R7 76 - 0x1C1C0C07, // 002D EQ R7 R6 R7 - 0x781E0001, // 002E JMPF R7 #0031 - 0x501C0200, // 002F LDBOOL R7 1 0 - 0x80040E00, // 0030 RET 1 R7 - 0x70020008, // 0031 JMP #003B - 0x601C0003, // 0032 GETGBL R7 G3 - 0x5C200000, // 0033 MOVE R8 R0 - 0x7C1C0200, // 0034 CALL R7 1 - 0x8C1C0F0B, // 0035 GETMET R7 R7 K11 - 0x5C240200, // 0036 MOVE R9 R1 - 0x5C280400, // 0037 MOVE R10 R2 - 0x5C2C0600, // 0038 MOVE R11 R3 - 0x7C1C0800, // 0039 CALL R7 4 - 0x80040E00, // 003A RET 1 R7 - 0x80000000, // 003B RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: update_ct_minmax -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_Light2_update_ct_minmax, /* name */ - be_nested_proto( - 4, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(tasmota), - /* K1 */ be_nested_str_weak(get_option), - /* K2 */ be_nested_str_weak(ct_min), - /* K3 */ be_nested_str_weak(ct_max), - }), - be_str_weak(update_ct_minmax), - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x540E0051, // 0002 LDINT R3 82 - 0x7C040400, // 0003 CALL R1 2 - 0x78060001, // 0004 JMPF R1 #0007 - 0x540A00C7, // 0005 LDINT R2 200 - 0x70020000, // 0006 JMP #0008 - 0x540A0098, // 0007 LDINT R2 153 - 0x90020402, // 0008 SETMBR R0 K2 R2 - 0x78060001, // 0009 JMPF R1 #000C - 0x540A017B, // 000A LDINT R2 380 - 0x70020000, // 000B JMP #000D - 0x540A01F3, // 000C LDINT R2 500 - 0x90020602, // 000D SETMBR R0 K3 R2 - 0x80000000, // 000E RET 0 + 0x8C20010B, // 001D GETMET R8 R0 K11 + 0x5828000C, // 001E LDCONST R10 K12 + 0x5C2C0E00, // 001F MOVE R11 R7 + 0x7C200600, // 0020 CALL R8 3 + 0x50200200, // 0021 LDBOOL R8 1 0 + 0x80041000, // 0022 RET 1 R8 + 0x70020010, // 0023 JMP #0035 + 0x541E0046, // 0024 LDINT R7 71 + 0x1C1C0C07, // 0025 EQ R7 R6 R7 + 0x781E0002, // 0026 JMPF R7 #002A + 0x501C0200, // 0027 LDBOOL R7 1 0 + 0x80040E00, // 0028 RET 1 R7 + 0x7002000A, // 0029 JMP #0035 + 0x541E004A, // 002A LDINT R7 75 + 0x1C1C0C07, // 002B EQ R7 R6 R7 + 0x781E0002, // 002C JMPF R7 #0030 + 0x501C0200, // 002D LDBOOL R7 1 0 + 0x80040E00, // 002E RET 1 R7 + 0x70020004, // 002F JMP #0035 + 0x541E004B, // 0030 LDINT R7 76 + 0x1C1C0C07, // 0031 EQ R7 R6 R7 + 0x781E0001, // 0032 JMPF R7 #0035 + 0x501C0200, // 0033 LDBOOL R7 1 0 + 0x80040E00, // 0034 RET 1 R7 + 0x70020008, // 0035 JMP #003F + 0x601C0003, // 0036 GETGBL R7 G3 + 0x5C200000, // 0037 MOVE R8 R0 + 0x7C1C0200, // 0038 CALL R7 1 + 0x8C1C0F0D, // 0039 GETMET R7 R7 K13 + 0x5C240200, // 003A MOVE R9 R1 + 0x5C280400, // 003B MOVE R10 R2 + 0x5C2C0600, // 003C MOVE R11 R3 + 0x7C1C0800, // 003D CALL R7 4 + 0x80040E00, // 003E RET 1 R7 + 0x80000000, // 003F RET 0 }) ) ); @@ -526,6 +489,49 @@ be_local_closure(Matter_Plugin_Bridge_Light2_read_attribute, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: update_ct_minmax +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_Light2_update_ct_minmax, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str_weak(tasmota), + /* K1 */ be_nested_str_weak(get_option), + /* K2 */ be_nested_str_weak(ct_min), + /* K3 */ be_nested_str_weak(ct_max), + }), + be_str_weak(update_ct_minmax), + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 + 0x540E0051, // 0002 LDINT R3 82 + 0x7C040400, // 0003 CALL R1 2 + 0x78060001, // 0004 JMPF R1 #0007 + 0x540A00C7, // 0005 LDINT R2 200 + 0x70020000, // 0006 JMP #0008 + 0x540A0098, // 0007 LDINT R2 153 + 0x90020402, // 0008 SETMBR R0 K2 R2 + 0x78060001, // 0009 JMPF R1 #000C + 0x540A017B, // 000A LDINT R2 380 + 0x70020000, // 000B JMP #000D + 0x540A01F3, // 000C LDINT R2 500 + 0x90020602, // 000D SETMBR R0 K3 R2 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified class: Matter_Plugin_Bridge_Light2 ********************************************************************/ @@ -536,12 +542,78 @@ be_local_class(Matter_Plugin_Bridge_Light2, be_nested_map(15, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Bridge_Light2_init_closure) }, - { be_const_key_weak(parse_update, 10), be_const_closure(Matter_Plugin_Bridge_Light2_parse_update_closure) }, + { be_const_key_weak(parse_update, 9), be_const_closure(Matter_Plugin_Bridge_Light2_parse_update_closure) }, { be_const_key_weak(web_values, 11), be_const_closure(Matter_Plugin_Bridge_Light2_web_values_closure) }, { be_const_key_weak(ct_max, -1), be_const_var(2) }, { be_const_key_weak(CLUSTERS, 14), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, + be_const_map( * be_nested_map(8, ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(8, 7), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(2), + be_const_int(3), + be_const_int(15), + be_const_int(17), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(5, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, { be_const_key_int(768, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(8, ( (struct bvalue*) &(const bvalue[]) { @@ -560,13 +632,13 @@ be_local_class(Matter_Plugin_Bridge_Light2, ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(268, -1), be_const_int(2) }, })) ) } )) }, - { be_const_key_weak(web_value_ct, -1), be_const_closure(Matter_Plugin_Bridge_Light2_web_value_ct_closure) }, + { be_const_key_weak(web_value_ct, 8), be_const_closure(Matter_Plugin_Bridge_Light2_web_value_ct_closure) }, { be_const_key_weak(set_ct, -1), be_const_closure(Matter_Plugin_Bridge_Light2_set_ct_closure) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Bridge_Light2_read_attribute_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Light_X202_X20CT) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Light_X202_X20CT) }, { be_const_key_weak(shadow_ct, -1), be_const_var(0) }, + { be_const_key_weak(update_ct_minmax, -1), be_const_closure(Matter_Plugin_Bridge_Light2_update_ct_minmax_closure) }, { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Bridge_Light2_invoke_request_closure) }, - { be_const_key_weak(update_ct_minmax, 8), be_const_closure(Matter_Plugin_Bridge_Light2_update_ct_minmax_closure) }, + { be_const_key_weak(read_attribute, 10), be_const_closure(Matter_Plugin_Bridge_Light2_read_attribute_closure) }, { be_const_key_weak(ct_min, -1), be_const_var(1) }, { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_light2) }, })), diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light3.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_5_Bridge_Light3.h similarity index 76% rename from lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light3.h rename to lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_5_Bridge_Light3.h index f5cd9c4ae..18cd5c467 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Bridge_Light3.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_5_Bridge_Light3.h @@ -1,4 +1,4 @@ -/* Solidification of Matter_Plugin_Bridge_Light3.h */ +/* Solidification of Matter_Plugin_5_Bridge_Light3.h */ /********************************************************************\ * Generated code, don't edit * \********************************************************************/ @@ -295,151 +295,6 @@ be_local_closure(Matter_Plugin_Bridge_Light3_web_value_RGB, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Bridge_Light3_invoke_request, /* name */ - be_nested_proto( - 12, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[16]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(TLV), - /* K2 */ be_nested_str_weak(cluster), - /* K3 */ be_nested_str_weak(command), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_str_weak(findsubval), - /* K6 */ be_nested_str_weak(set_hue), - /* K7 */ be_nested_str_weak(log), - /* K8 */ be_nested_str_weak(hue_X3A), - /* K9 */ be_const_int(1), - /* K10 */ be_const_int(2), - /* K11 */ be_const_int(3), - /* K12 */ be_nested_str_weak(set_sat), - /* K13 */ be_nested_str_weak(sat_X3A), - /* K14 */ be_nested_str_weak(_X20sat_X3A), - /* K15 */ be_nested_str_weak(invoke_request), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[105]) { /* code */ - 0xB8120000, // 0000 GETNGBL R4 K0 - 0x88100901, // 0001 GETMBR R4 R4 K1 - 0x88140702, // 0002 GETMBR R5 R3 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x541E02FF, // 0004 LDINT R7 768 - 0x1C1C0A07, // 0005 EQ R7 R5 R7 - 0x781E0057, // 0006 JMPF R7 #005F - 0x1C1C0D04, // 0007 EQ R7 R6 K4 - 0x781E000D, // 0008 JMPF R7 #0017 - 0x8C1C0505, // 0009 GETMET R7 R2 K5 - 0x58240004, // 000A LDCONST R9 K4 - 0x7C1C0400, // 000B CALL R7 2 - 0x8C200106, // 000C GETMET R8 R0 K6 - 0x5C280E00, // 000D MOVE R10 R7 - 0x7C200400, // 000E CALL R8 2 - 0x60200008, // 000F GETGBL R8 G8 - 0x5C240E00, // 0010 MOVE R9 R7 - 0x7C200200, // 0011 CALL R8 1 - 0x00221008, // 0012 ADD R8 K8 R8 - 0x900E0E08, // 0013 SETMBR R3 K7 R8 - 0x50200200, // 0014 LDBOOL R8 1 0 - 0x80041000, // 0015 RET 1 R8 - 0x70020046, // 0016 JMP #005E - 0x1C1C0D09, // 0017 EQ R7 R6 K9 - 0x781E0002, // 0018 JMPF R7 #001C - 0x501C0200, // 0019 LDBOOL R7 1 0 - 0x80040E00, // 001A RET 1 R7 - 0x70020041, // 001B JMP #005E - 0x1C1C0D0A, // 001C EQ R7 R6 K10 - 0x781E0002, // 001D JMPF R7 #0021 - 0x501C0200, // 001E LDBOOL R7 1 0 - 0x80040E00, // 001F RET 1 R7 - 0x7002003C, // 0020 JMP #005E - 0x1C1C0D0B, // 0021 EQ R7 R6 K11 - 0x781E000D, // 0022 JMPF R7 #0031 - 0x8C1C0505, // 0023 GETMET R7 R2 K5 - 0x58240004, // 0024 LDCONST R9 K4 - 0x7C1C0400, // 0025 CALL R7 2 - 0x8C20010C, // 0026 GETMET R8 R0 K12 - 0x5C280E00, // 0027 MOVE R10 R7 - 0x7C200400, // 0028 CALL R8 2 - 0x60200008, // 0029 GETGBL R8 G8 - 0x5C240E00, // 002A MOVE R9 R7 - 0x7C200200, // 002B CALL R8 1 - 0x00221A08, // 002C ADD R8 K13 R8 - 0x900E0E08, // 002D SETMBR R3 K7 R8 - 0x50200200, // 002E LDBOOL R8 1 0 - 0x80041000, // 002F RET 1 R8 - 0x7002002C, // 0030 JMP #005E - 0x541E0003, // 0031 LDINT R7 4 - 0x1C1C0C07, // 0032 EQ R7 R6 R7 - 0x781E0002, // 0033 JMPF R7 #0037 - 0x501C0200, // 0034 LDBOOL R7 1 0 - 0x80040E00, // 0035 RET 1 R7 - 0x70020026, // 0036 JMP #005E - 0x541E0004, // 0037 LDINT R7 5 - 0x1C1C0C07, // 0038 EQ R7 R6 R7 - 0x781E0002, // 0039 JMPF R7 #003D - 0x501C0200, // 003A LDBOOL R7 1 0 - 0x80040E00, // 003B RET 1 R7 - 0x70020020, // 003C JMP #005E - 0x541E0005, // 003D LDINT R7 6 - 0x1C1C0C07, // 003E EQ R7 R6 R7 - 0x781E0018, // 003F JMPF R7 #0059 - 0x8C1C0505, // 0040 GETMET R7 R2 K5 - 0x58240004, // 0041 LDCONST R9 K4 - 0x7C1C0400, // 0042 CALL R7 2 - 0x8C200505, // 0043 GETMET R8 R2 K5 - 0x58280009, // 0044 LDCONST R10 K9 - 0x7C200400, // 0045 CALL R8 2 - 0x8C240106, // 0046 GETMET R9 R0 K6 - 0x5C2C0E00, // 0047 MOVE R11 R7 - 0x7C240400, // 0048 CALL R9 2 - 0x8C24010C, // 0049 GETMET R9 R0 K12 - 0x5C2C1000, // 004A MOVE R11 R8 - 0x7C240400, // 004B CALL R9 2 - 0x60240008, // 004C GETGBL R9 G8 - 0x5C280E00, // 004D MOVE R10 R7 - 0x7C240200, // 004E CALL R9 1 - 0x00261009, // 004F ADD R9 K8 R9 - 0x0024130E, // 0050 ADD R9 R9 K14 - 0x60280008, // 0051 GETGBL R10 G8 - 0x5C2C1000, // 0052 MOVE R11 R8 - 0x7C280200, // 0053 CALL R10 1 - 0x0024120A, // 0054 ADD R9 R9 R10 - 0x900E0E09, // 0055 SETMBR R3 K7 R9 - 0x50240200, // 0056 LDBOOL R9 1 0 - 0x80041200, // 0057 RET 1 R9 - 0x70020004, // 0058 JMP #005E - 0x541E0046, // 0059 LDINT R7 71 - 0x1C1C0C07, // 005A EQ R7 R6 R7 - 0x781E0001, // 005B JMPF R7 #005E - 0x501C0200, // 005C LDBOOL R7 1 0 - 0x80040E00, // 005D RET 1 R7 - 0x70020008, // 005E JMP #0068 - 0x601C0003, // 005F GETGBL R7 G3 - 0x5C200000, // 0060 MOVE R8 R0 - 0x7C1C0200, // 0061 CALL R7 1 - 0x8C1C0F0F, // 0062 GETMET R7 R7 K15 - 0x5C240200, // 0063 MOVE R9 R1 - 0x5C280400, // 0064 MOVE R10 R2 - 0x5C2C0600, // 0065 MOVE R11 R3 - 0x7C1C0800, // 0066 CALL R7 4 - 0x80040E00, // 0067 RET 1 R7 - 0x80000000, // 0068 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: read_attribute ********************************************************************/ @@ -605,6 +460,168 @@ be_local_closure(Matter_Plugin_Bridge_Light3_read_attribute, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: invoke_request +********************************************************************/ +be_local_closure(Matter_Plugin_Bridge_Light3_invoke_request, /* name */ + be_nested_proto( + 15, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[19]) { /* constants */ + /* K0 */ be_nested_str_weak(matter), + /* K1 */ be_nested_str_weak(TLV), + /* K2 */ be_nested_str_weak(cluster), + /* K3 */ be_nested_str_weak(command), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str_weak(findsubval), + /* K6 */ be_nested_str_weak(set_hue), + /* K7 */ be_nested_str_weak(log), + /* K8 */ be_nested_str_weak(hue_X3A), + /* K9 */ be_nested_str_weak(publish_command), + /* K10 */ be_nested_str_weak(Hue), + /* K11 */ be_const_int(1), + /* K12 */ be_const_int(2), + /* K13 */ be_const_int(3), + /* K14 */ be_nested_str_weak(set_sat), + /* K15 */ be_nested_str_weak(sat_X3A), + /* K16 */ be_nested_str_weak(Sat), + /* K17 */ be_nested_str_weak(_X20sat_X3A), + /* K18 */ be_nested_str_weak(invoke_request), + }), + be_str_weak(invoke_request), + &be_const_str_solidified, + ( &(const binstruction[119]) { /* code */ + 0xB8120000, // 0000 GETNGBL R4 K0 + 0x88100901, // 0001 GETMBR R4 R4 K1 + 0x88140702, // 0002 GETMBR R5 R3 K2 + 0x88180703, // 0003 GETMBR R6 R3 K3 + 0x541E02FF, // 0004 LDINT R7 768 + 0x1C1C0A07, // 0005 EQ R7 R5 R7 + 0x781E0065, // 0006 JMPF R7 #006D + 0x1C1C0D04, // 0007 EQ R7 R6 K4 + 0x781E0011, // 0008 JMPF R7 #001B + 0x8C1C0505, // 0009 GETMET R7 R2 K5 + 0x58240004, // 000A LDCONST R9 K4 + 0x7C1C0400, // 000B CALL R7 2 + 0x8C200106, // 000C GETMET R8 R0 K6 + 0x5C280E00, // 000D MOVE R10 R7 + 0x7C200400, // 000E CALL R8 2 + 0x60200008, // 000F GETGBL R8 G8 + 0x5C240E00, // 0010 MOVE R9 R7 + 0x7C200200, // 0011 CALL R8 1 + 0x00221008, // 0012 ADD R8 K8 R8 + 0x900E0E08, // 0013 SETMBR R3 K7 R8 + 0x8C200109, // 0014 GETMET R8 R0 K9 + 0x5828000A, // 0015 LDCONST R10 K10 + 0x5C2C0E00, // 0016 MOVE R11 R7 + 0x7C200600, // 0017 CALL R8 3 + 0x50200200, // 0018 LDBOOL R8 1 0 + 0x80041000, // 0019 RET 1 R8 + 0x70020050, // 001A JMP #006C + 0x1C1C0D0B, // 001B EQ R7 R6 K11 + 0x781E0002, // 001C JMPF R7 #0020 + 0x501C0200, // 001D LDBOOL R7 1 0 + 0x80040E00, // 001E RET 1 R7 + 0x7002004B, // 001F JMP #006C + 0x1C1C0D0C, // 0020 EQ R7 R6 K12 + 0x781E0002, // 0021 JMPF R7 #0025 + 0x501C0200, // 0022 LDBOOL R7 1 0 + 0x80040E00, // 0023 RET 1 R7 + 0x70020046, // 0024 JMP #006C + 0x1C1C0D0D, // 0025 EQ R7 R6 K13 + 0x781E0011, // 0026 JMPF R7 #0039 + 0x8C1C0505, // 0027 GETMET R7 R2 K5 + 0x58240004, // 0028 LDCONST R9 K4 + 0x7C1C0400, // 0029 CALL R7 2 + 0x8C20010E, // 002A GETMET R8 R0 K14 + 0x5C280E00, // 002B MOVE R10 R7 + 0x7C200400, // 002C CALL R8 2 + 0x60200008, // 002D GETGBL R8 G8 + 0x5C240E00, // 002E MOVE R9 R7 + 0x7C200200, // 002F CALL R8 1 + 0x00221E08, // 0030 ADD R8 K15 R8 + 0x900E0E08, // 0031 SETMBR R3 K7 R8 + 0x8C200109, // 0032 GETMET R8 R0 K9 + 0x58280010, // 0033 LDCONST R10 K16 + 0x5C2C0E00, // 0034 MOVE R11 R7 + 0x7C200600, // 0035 CALL R8 3 + 0x50200200, // 0036 LDBOOL R8 1 0 + 0x80041000, // 0037 RET 1 R8 + 0x70020032, // 0038 JMP #006C + 0x541E0003, // 0039 LDINT R7 4 + 0x1C1C0C07, // 003A EQ R7 R6 R7 + 0x781E0002, // 003B JMPF R7 #003F + 0x501C0200, // 003C LDBOOL R7 1 0 + 0x80040E00, // 003D RET 1 R7 + 0x7002002C, // 003E JMP #006C + 0x541E0004, // 003F LDINT R7 5 + 0x1C1C0C07, // 0040 EQ R7 R6 R7 + 0x781E0002, // 0041 JMPF R7 #0045 + 0x501C0200, // 0042 LDBOOL R7 1 0 + 0x80040E00, // 0043 RET 1 R7 + 0x70020026, // 0044 JMP #006C + 0x541E0005, // 0045 LDINT R7 6 + 0x1C1C0C07, // 0046 EQ R7 R6 R7 + 0x781E001E, // 0047 JMPF R7 #0067 + 0x8C1C0505, // 0048 GETMET R7 R2 K5 + 0x58240004, // 0049 LDCONST R9 K4 + 0x7C1C0400, // 004A CALL R7 2 + 0x8C200505, // 004B GETMET R8 R2 K5 + 0x5828000B, // 004C LDCONST R10 K11 + 0x7C200400, // 004D CALL R8 2 + 0x8C240106, // 004E GETMET R9 R0 K6 + 0x5C2C0E00, // 004F MOVE R11 R7 + 0x7C240400, // 0050 CALL R9 2 + 0x8C24010E, // 0051 GETMET R9 R0 K14 + 0x5C2C1000, // 0052 MOVE R11 R8 + 0x7C240400, // 0053 CALL R9 2 + 0x60240008, // 0054 GETGBL R9 G8 + 0x5C280E00, // 0055 MOVE R10 R7 + 0x7C240200, // 0056 CALL R9 1 + 0x00261009, // 0057 ADD R9 K8 R9 + 0x00241311, // 0058 ADD R9 R9 K17 + 0x60280008, // 0059 GETGBL R10 G8 + 0x5C2C1000, // 005A MOVE R11 R8 + 0x7C280200, // 005B CALL R10 1 + 0x0024120A, // 005C ADD R9 R9 R10 + 0x900E0E09, // 005D SETMBR R3 K7 R9 + 0x8C240109, // 005E GETMET R9 R0 K9 + 0x582C000A, // 005F LDCONST R11 K10 + 0x5C300E00, // 0060 MOVE R12 R7 + 0x58340010, // 0061 LDCONST R13 K16 + 0x5C381000, // 0062 MOVE R14 R8 + 0x7C240A00, // 0063 CALL R9 5 + 0x50240200, // 0064 LDBOOL R9 1 0 + 0x80041200, // 0065 RET 1 R9 + 0x70020004, // 0066 JMP #006C + 0x541E0046, // 0067 LDINT R7 71 + 0x1C1C0C07, // 0068 EQ R7 R6 R7 + 0x781E0001, // 0069 JMPF R7 #006C + 0x501C0200, // 006A LDBOOL R7 1 0 + 0x80040E00, // 006B RET 1 R7 + 0x70020008, // 006C JMP #0076 + 0x601C0003, // 006D GETGBL R7 G3 + 0x5C200000, // 006E MOVE R8 R0 + 0x7C1C0200, // 006F CALL R7 1 + 0x8C1C0F12, // 0070 GETMET R7 R7 K18 + 0x5C240200, // 0071 MOVE R9 R1 + 0x5C280400, // 0072 MOVE R10 R2 + 0x5C2C0600, // 0073 MOVE R11 R3 + 0x7C1C0800, // 0074 CALL R7 4 + 0x80040E00, // 0075 RET 1 R7 + 0x80000000, // 0076 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: set_hue ********************************************************************/ @@ -698,26 +715,81 @@ be_local_class(Matter_Plugin_Bridge_Light3, &be_class_Matter_Plugin_Bridge_Light1, be_nested_map(14, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(set_sat, 12), be_const_closure(Matter_Plugin_Bridge_Light3_set_sat_closure) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Bridge_Light3_init_closure) }, + { be_const_key_weak(set_sat, 6), be_const_closure(Matter_Plugin_Bridge_Light3_set_sat_closure) }, + { be_const_key_weak(init, 8), be_const_closure(Matter_Plugin_Bridge_Light3_init_closure) }, { be_const_key_weak(parse_update, -1), be_const_closure(Matter_Plugin_Bridge_Light3_parse_update_closure) }, { be_const_key_weak(TYPE, -1), be_nested_str_weak(http_light3) }, { be_const_key_weak(web_values, -1), be_const_closure(Matter_Plugin_Bridge_Light3_web_values_closure) }, { be_const_key_weak(web_value_RGB, 1), be_const_closure(Matter_Plugin_Bridge_Light3_web_value_RGB_closure) }, - { be_const_key_weak(shadow_sat, 9), be_const_var(1) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Bridge_Light3_invoke_request_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Light_X203_X20RGB) }, - { be_const_key_weak(TYPES, 11), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, + { be_const_key_weak(CLUSTERS, 13), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(8, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(269, -1), be_const_int(2) }, + { be_const_key_int(8, 7), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(2), + be_const_int(3), + be_const_int(15), + be_const_int(17), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(57, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(7, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(17), + be_const_int(3), + be_const_int(5), + be_const_int(10), + be_const_int(15), + be_const_int(17), + be_const_int(18), + })) ) } )) }, + { be_const_key_int(29, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(6, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(3, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(4, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(4, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(5, 2), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(8, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(1), + be_const_int(2), + be_const_int(3), + be_const_int(4), + be_const_int(5), + be_const_int(65532), + be_const_int(65533), + })) ) } )) }, + { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { + be_const_list( * be_nested_list(3, + ( (struct bvalue*) &(const bvalue[]) { + be_const_int(0), + be_const_int(65532), + be_const_int(65533), })) ) } )) }, - { be_const_key_weak(shadow_hue, 6), be_const_var(0) }, - { be_const_key_weak(set_hue, -1), be_const_closure(Matter_Plugin_Bridge_Light3_set_hue_closure) }, - { be_const_key_weak(read_attribute, 13), be_const_closure(Matter_Plugin_Bridge_Light3_read_attribute_closure) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { { be_const_key_int(768, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { be_const_list( * be_nested_list(9, ( (struct bvalue*) &(const bvalue[]) { @@ -732,6 +804,17 @@ be_local_class(Matter_Plugin_Bridge_Light3, be_const_int(65533), })) ) } )) }, })) ) } )) }, + { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Bridge_Light3_invoke_request_closure) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(Light_X203_X20RGB) }, + { be_const_key_weak(set_hue, 11), be_const_closure(Matter_Plugin_Bridge_Light3_set_hue_closure) }, + { be_const_key_weak(shadow_hue, 9), be_const_var(0) }, + { be_const_key_weak(TYPES, 12), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { + be_const_map( * be_nested_map(1, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_int(269, -1), be_const_int(2) }, + })) ) } )) }, + { be_const_key_weak(shadow_sat, -1), be_const_var(1) }, + { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Bridge_Light3_read_attribute_closure) }, })), be_str_weak(Matter_Plugin_Bridge_Light3) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light0.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light0.h new file mode 100644 index 000000000..2d946c844 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light0.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Light0.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Light0; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Light0 +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Light0; +be_local_class(Matter_Plugin_Virt_Light0, + 0, + &be_class_Matter_Plugin_Light0, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2ELight_X200_X20On) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_light0) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Light0) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Light0_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Light0); + be_setglobal(vm, "Matter_Plugin_Virt_Light0"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light1.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light1.h new file mode 100644 index 000000000..123fc3e51 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light1.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Light1.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Light1; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Light1 +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Light1; +be_local_class(Matter_Plugin_Virt_Light1, + 0, + &be_class_Matter_Plugin_Light1, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2ELight_X201_X20Dimmer) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_light1) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Light1) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Light1_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Light1); + be_setglobal(vm, "Matter_Plugin_Virt_Light1"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light2.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light2.h new file mode 100644 index 000000000..c81c9044d --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light2.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Light2.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Light2; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Light2 +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Light2; +be_local_class(Matter_Plugin_Virt_Light2, + 0, + &be_class_Matter_Plugin_Light2, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2ELight_X202_X20CT) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_light2) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Light2) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Light2_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Light2); + be_setglobal(vm, "Matter_Plugin_Virt_Light2"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light3.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light3.h new file mode 100644 index 000000000..d90363be7 --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Light3.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Light3.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Light3; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Light3 +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Light3; +be_local_class(Matter_Plugin_Virt_Light3, + 0, + &be_class_Matter_Plugin_Light3, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2ELight_X203_X20RGB) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_light3) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Light3) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Light3_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Light3); + be_setglobal(vm, "Matter_Plugin_Virt_Light3"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_OnOff.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_OnOff.h new file mode 100644 index 000000000..ef9f3ac5b --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_OnOff.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_OnOff.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_OnOff; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_OnOff +********************************************************************/ +extern const bclass be_class_Matter_Plugin_OnOff; +be_local_class(Matter_Plugin_Virt_OnOff, + 0, + &be_class_Matter_Plugin_OnOff, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2ERelay) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_relay) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_OnOff) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_OnOff_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_OnOff); + be_setglobal(vm, "Matter_Plugin_Virt_OnOff"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Contact.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Contact.h new file mode 100644 index 000000000..a9a6b8aaf --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Contact.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Sensor_Contact.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Sensor_Contact; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Sensor_Contact +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Sensor_Contact; +be_local_class(Matter_Plugin_Virt_Sensor_Contact, + 0, + &be_class_Matter_Plugin_Sensor_Contact, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2EContact) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_contact) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Sensor_Contact) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Sensor_Contact_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Sensor_Contact); + be_setglobal(vm, "Matter_Plugin_Virt_Sensor_Contact"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Humidity.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Humidity.h new file mode 100644 index 000000000..21b40f75f --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Humidity.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Sensor_Humidity.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Sensor_Humidity; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Sensor_Humidity +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Sensor_Humidity; +be_local_class(Matter_Plugin_Virt_Sensor_Humidity, + 0, + &be_class_Matter_Plugin_Sensor_Humidity, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2EHumidity) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_humidity) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Sensor_Humidity) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Sensor_Humidity_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Sensor_Humidity); + be_setglobal(vm, "Matter_Plugin_Virt_Sensor_Humidity"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Illuminance.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Illuminance.h new file mode 100644 index 000000000..792d4324f --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Illuminance.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Sensor_Illuminance.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Sensor_Illuminance; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Sensor_Illuminance +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Sensor_Illuminance; +be_local_class(Matter_Plugin_Virt_Sensor_Illuminance, + 0, + &be_class_Matter_Plugin_Sensor_Illuminance, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2EIlluminance) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_illuminance) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Sensor_Illuminance) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Sensor_Illuminance_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Sensor_Illuminance); + be_setglobal(vm, "Matter_Plugin_Virt_Sensor_Illuminance"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Pressure.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Pressure.h new file mode 100644 index 000000000..db256979e --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Pressure.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Sensor_Pressure.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Sensor_Pressure; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Sensor_Pressure +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Sensor_Pressure; +be_local_class(Matter_Plugin_Virt_Sensor_Pressure, + 0, + &be_class_Matter_Plugin_Sensor_Pressure, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2EPressure) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_pressure) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Sensor_Pressure) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Sensor_Pressure_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Sensor_Pressure); + be_setglobal(vm, "Matter_Plugin_Virt_Sensor_Pressure"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Temp.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Temp.h new file mode 100644 index 000000000..3e678420d --- /dev/null +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_9_Virt_Sensor_Temp.h @@ -0,0 +1,34 @@ +/* Solidification of Matter_Plugin_9_Virt_Sensor_Temp.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" + +extern const bclass be_class_Matter_Plugin_Virt_Sensor_Temp; + +/******************************************************************** +** Solidified class: Matter_Plugin_Virt_Sensor_Temp +********************************************************************/ +extern const bclass be_class_Matter_Plugin_Sensor_Temp; +be_local_class(Matter_Plugin_Virt_Sensor_Temp, + 0, + &be_class_Matter_Plugin_Sensor_Temp, + be_nested_map(5, + ( (struct bmapnode*) &(const bmapnode[]) { + { be_const_key_weak(VIRTUAL, 3), be_const_bool(1) }, + { be_const_key_weak(DISPLAY_NAME, -1), be_nested_str_weak(v_X2ETemperature) }, + { be_const_key_weak(TYPE, -1), be_nested_str_weak(v_temp) }, + { be_const_key_weak(ARG_HINT, -1), be_nested_str_weak(_Not_X20used_) }, + { be_const_key_weak(ARG, 2), be_nested_str_weak() }, + })), + be_str_weak(Matter_Plugin_Virt_Sensor_Temp) +); +/*******************************************************************/ + +void be_load_Matter_Plugin_Virt_Sensor_Temp_class(bvm *vm) { + be_pushntvclass(vm, &be_class_Matter_Plugin_Virt_Sensor_Temp); + be_setglobal(vm, "Matter_Plugin_Virt_Sensor_Temp"); + be_pop(vm, 1); +} +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light0.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light0.h deleted file mode 100644 index 28aa6cea3..000000000 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light0.h +++ /dev/null @@ -1,315 +0,0 @@ -/* Solidification of Matter_Plugin_Light0.h */ -/********************************************************************\ -* Generated code, don't edit * -\********************************************************************/ -#include "be_constobj.h" - -extern const bclass be_class_Matter_Plugin_Light0; - -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_Light0_update_shadow, /* name */ - be_nested_proto( - 8, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(get), - /* K2 */ be_nested_str_weak(find), - /* K3 */ be_nested_str_weak(power), - /* K4 */ be_nested_str_weak(shadow_onoff), - /* K5 */ be_nested_str_weak(attribute_updated), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(update_shadow), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[24]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x4C0C0000, // 0003 LDNIL R3 - 0x200C0403, // 0004 NE R3 R2 R3 - 0x780E000B, // 0005 JMPF R3 #0012 - 0x8C0C0502, // 0006 GETMET R3 R2 K2 - 0x58140003, // 0007 LDCONST R5 K3 - 0x4C180000, // 0008 LDNIL R6 - 0x7C0C0600, // 0009 CALL R3 3 - 0x88100104, // 000A GETMBR R4 R0 K4 - 0x20100604, // 000B NE R4 R3 R4 - 0x78120004, // 000C JMPF R4 #0012 - 0x8C100105, // 000D GETMET R4 R0 K5 - 0x541A0005, // 000E LDINT R6 6 - 0x581C0006, // 000F LDCONST R7 K6 - 0x7C100600, // 0010 CALL R4 3 - 0x90020803, // 0011 SETMBR R0 K4 R3 - 0x600C0003, // 0012 GETGBL R3 G3 - 0x5C100000, // 0013 MOVE R4 R0 - 0x7C0C0200, // 0014 CALL R3 1 - 0x8C0C0707, // 0015 GETMET R3 R3 K7 - 0x7C0C0200, // 0016 CALL R3 1 - 0x80000000, // 0017 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: read_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_Light0_read_attribute, /* name */ - be_nested_proto( - 12, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(TLV), - /* K2 */ be_nested_str_weak(cluster), - /* K3 */ be_nested_str_weak(attribute), - /* K4 */ be_nested_str_weak(update_shadow_lazy), - /* K5 */ be_const_int(0), - /* K6 */ be_nested_str_weak(set), - /* K7 */ be_nested_str_weak(BOOL), - /* K8 */ be_nested_str_weak(shadow_onoff), - /* K9 */ be_nested_str_weak(U4), - /* K10 */ be_nested_str_weak(read_attribute), - }), - be_str_weak(read_attribute), - &be_const_str_solidified, - ( &(const binstruction[45]) { /* code */ - 0xB8120000, // 0000 GETNGBL R4 K0 - 0x88100901, // 0001 GETMBR R4 R4 K1 - 0x88140502, // 0002 GETMBR R5 R2 K2 - 0x88180503, // 0003 GETMBR R6 R2 K3 - 0x541E0005, // 0004 LDINT R7 6 - 0x1C1C0A07, // 0005 EQ R7 R5 R7 - 0x781E001B, // 0006 JMPF R7 #0023 - 0x8C1C0104, // 0007 GETMET R7 R0 K4 - 0x7C1C0200, // 0008 CALL R7 1 - 0x1C1C0D05, // 0009 EQ R7 R6 K5 - 0x781E0005, // 000A JMPF R7 #0011 - 0x8C1C0706, // 000B GETMET R7 R3 K6 - 0x88240907, // 000C GETMBR R9 R4 K7 - 0x88280108, // 000D GETMBR R10 R0 K8 - 0x7C1C0600, // 000E CALL R7 3 - 0x80040E00, // 000F RET 1 R7 - 0x70020010, // 0010 JMP #0022 - 0x541EFFFB, // 0011 LDINT R7 65532 - 0x1C1C0C07, // 0012 EQ R7 R6 R7 - 0x781E0005, // 0013 JMPF R7 #001A - 0x8C1C0706, // 0014 GETMET R7 R3 K6 - 0x88240909, // 0015 GETMBR R9 R4 K9 - 0x58280005, // 0016 LDCONST R10 K5 - 0x7C1C0600, // 0017 CALL R7 3 - 0x80040E00, // 0018 RET 1 R7 - 0x70020007, // 0019 JMP #0022 - 0x541EFFFC, // 001A LDINT R7 65533 - 0x1C1C0C07, // 001B EQ R7 R6 R7 - 0x781E0004, // 001C JMPF R7 #0022 - 0x8C1C0706, // 001D GETMET R7 R3 K6 - 0x88240909, // 001E GETMBR R9 R4 K9 - 0x542A0003, // 001F LDINT R10 4 - 0x7C1C0600, // 0020 CALL R7 3 - 0x80040E00, // 0021 RET 1 R7 - 0x70020008, // 0022 JMP #002C - 0x601C0003, // 0023 GETGBL R7 G3 - 0x5C200000, // 0024 MOVE R8 R0 - 0x7C1C0200, // 0025 CALL R7 1 - 0x8C1C0F0A, // 0026 GETMET R7 R7 K10 - 0x5C240200, // 0027 MOVE R9 R1 - 0x5C280400, // 0028 MOVE R10 R2 - 0x5C2C0600, // 0029 MOVE R11 R3 - 0x7C1C0800, // 002A CALL R7 4 - 0x80040E00, // 002B RET 1 R7 - 0x80000000, // 002C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_Light0_init, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str_weak(init), - /* K1 */ be_nested_str_weak(shadow_onoff), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x60100003, // 0000 GETGBL R4 G3 - 0x5C140000, // 0001 MOVE R5 R0 - 0x7C100200, // 0002 CALL R4 1 - 0x8C100900, // 0003 GETMET R4 R4 K0 - 0x5C180200, // 0004 MOVE R6 R1 - 0x5C1C0400, // 0005 MOVE R7 R2 - 0x5C200600, // 0006 MOVE R8 R3 - 0x7C100800, // 0007 CALL R4 4 - 0x50100000, // 0008 LDBOOL R4 0 0 - 0x90020204, // 0009 SETMBR R0 K1 R4 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Light0_invoke_request, /* name */ - be_nested_proto( - 12, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(command), - /* K5 */ be_nested_str_weak(update_shadow_lazy), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(set), - /* K8 */ be_nested_str_weak(power), - /* K9 */ be_nested_str_weak(update_shadow), - /* K10 */ be_const_int(1), - /* K11 */ be_const_int(2), - /* K12 */ be_nested_str_weak(shadow_onoff), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[52]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xB8160200, // 0001 GETNGBL R5 K1 - 0x88140B02, // 0002 GETMBR R5 R5 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x881C0704, // 0004 GETMBR R7 R3 K4 - 0x54220005, // 0005 LDINT R8 6 - 0x1C200C08, // 0006 EQ R8 R6 R8 - 0x7822002A, // 0007 JMPF R8 #0033 - 0x8C200105, // 0008 GETMET R8 R0 K5 - 0x7C200200, // 0009 CALL R8 1 - 0x1C200F06, // 000A EQ R8 R7 K6 - 0x7822000A, // 000B JMPF R8 #0017 - 0x8C200907, // 000C GETMET R8 R4 K7 - 0x60280013, // 000D GETGBL R10 G19 - 0x7C280000, // 000E CALL R10 0 - 0x502C0000, // 000F LDBOOL R11 0 0 - 0x982A100B, // 0010 SETIDX R10 K8 R11 - 0x7C200400, // 0011 CALL R8 2 - 0x8C200109, // 0012 GETMET R8 R0 K9 - 0x7C200200, // 0013 CALL R8 1 - 0x50200200, // 0014 LDBOOL R8 1 0 - 0x80041000, // 0015 RET 1 R8 - 0x7002001B, // 0016 JMP #0033 - 0x1C200F0A, // 0017 EQ R8 R7 K10 - 0x7822000A, // 0018 JMPF R8 #0024 - 0x8C200907, // 0019 GETMET R8 R4 K7 - 0x60280013, // 001A GETGBL R10 G19 - 0x7C280000, // 001B CALL R10 0 - 0x502C0200, // 001C LDBOOL R11 1 0 - 0x982A100B, // 001D SETIDX R10 K8 R11 - 0x7C200400, // 001E CALL R8 2 - 0x8C200109, // 001F GETMET R8 R0 K9 - 0x7C200200, // 0020 CALL R8 1 - 0x50200200, // 0021 LDBOOL R8 1 0 - 0x80041000, // 0022 RET 1 R8 - 0x7002000E, // 0023 JMP #0033 - 0x1C200F0B, // 0024 EQ R8 R7 K11 - 0x7822000C, // 0025 JMPF R8 #0033 - 0x8C200907, // 0026 GETMET R8 R4 K7 - 0x60280013, // 0027 GETGBL R10 G19 - 0x7C280000, // 0028 CALL R10 0 - 0x882C010C, // 0029 GETMBR R11 R0 K12 - 0x782E0000, // 002A JMPF R11 #002C - 0x502C0001, // 002B LDBOOL R11 0 1 - 0x502C0200, // 002C LDBOOL R11 1 0 - 0x982A100B, // 002D SETIDX R10 K8 R11 - 0x7C200400, // 002E CALL R8 2 - 0x8C200109, // 002F GETMET R8 R0 K9 - 0x7C200200, // 0030 CALL R8 1 - 0x50200200, // 0031 LDBOOL R8 1 0 - 0x80041000, // 0032 RET 1 R8 - 0x80000000, // 0033 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified class: Matter_Plugin_Light0 -********************************************************************/ -extern const bclass be_class_Matter_Plugin_Device; -be_local_class(Matter_Plugin_Light0, - 1, - &be_class_Matter_Plugin_Device, - be_nested_map(10, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(256, -1), be_const_int(2) }, - })) ) } )) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(light0) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Light0_read_attribute_closure) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Light_X200_X20On) }, - { be_const_key_weak(CLUSTERS, 3), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(6, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(3, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(65532), - be_const_int(65533), - })) ) } )) }, - })) ) } )) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light0_init_closure) }, - { be_const_key_weak(UPDATE_TIME, -1), be_const_int(250) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light0_invoke_request_closure) }, - { be_const_key_weak(shadow_onoff, -1), be_const_var(0) }, - { be_const_key_weak(update_shadow, 1), be_const_closure(Matter_Plugin_Light0_update_shadow_closure) }, - })), - be_str_weak(Matter_Plugin_Light0) -); -/*******************************************************************/ - -void be_load_Matter_Plugin_Light0_class(bvm *vm) { - be_pushntvclass(vm, &be_class_Matter_Plugin_Light0); - be_setglobal(vm, "Matter_Plugin_Light0"); - be_pop(vm, 1); -} -/********************************************************************/ -/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light1.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light1.h deleted file mode 100644 index 119611183..000000000 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light1.h +++ /dev/null @@ -1,436 +0,0 @@ -/* Solidification of Matter_Plugin_Light1.h */ -/********************************************************************\ -* Generated code, don't edit * -\********************************************************************/ -#include "be_constobj.h" - -extern const bclass be_class_Matter_Plugin_Light1; - -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_Light1_update_shadow, /* name */ - be_nested_proto( - 11, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[10]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(get), - /* K2 */ be_nested_str_weak(find), - /* K3 */ be_nested_str_weak(bri), - /* K4 */ be_nested_str_weak(tasmota), - /* K5 */ be_nested_str_weak(scale_uint), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(shadow_bri), - /* K8 */ be_nested_str_weak(attribute_updated), - /* K9 */ be_nested_str_weak(update_shadow), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[36]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x4C0C0000, // 0003 LDNIL R3 - 0x200C0403, // 0004 NE R3 R2 R3 - 0x780E0017, // 0005 JMPF R3 #001E - 0x8C0C0502, // 0006 GETMET R3 R2 K2 - 0x58140003, // 0007 LDCONST R5 K3 - 0x4C180000, // 0008 LDNIL R6 - 0x7C0C0600, // 0009 CALL R3 3 - 0x4C100000, // 000A LDNIL R4 - 0x20100604, // 000B NE R4 R3 R4 - 0x78120010, // 000C JMPF R4 #001E - 0xB8120800, // 000D GETNGBL R4 K4 - 0x8C100905, // 000E GETMET R4 R4 K5 - 0x5C180600, // 000F MOVE R6 R3 - 0x581C0006, // 0010 LDCONST R7 K6 - 0x542200FE, // 0011 LDINT R8 255 - 0x58240006, // 0012 LDCONST R9 K6 - 0x542A00FD, // 0013 LDINT R10 254 - 0x7C100C00, // 0014 CALL R4 6 - 0x5C0C0800, // 0015 MOVE R3 R4 - 0x88100107, // 0016 GETMBR R4 R0 K7 - 0x20100604, // 0017 NE R4 R3 R4 - 0x78120004, // 0018 JMPF R4 #001E - 0x8C100108, // 0019 GETMET R4 R0 K8 - 0x541A0007, // 001A LDINT R6 8 - 0x581C0006, // 001B LDCONST R7 K6 - 0x7C100600, // 001C CALL R4 3 - 0x90020E03, // 001D SETMBR R0 K7 R3 - 0x600C0003, // 001E GETGBL R3 G3 - 0x5C100000, // 001F MOVE R4 R0 - 0x7C0C0200, // 0020 CALL R3 1 - 0x8C0C0709, // 0021 GETMET R3 R3 K9 - 0x7C0C0200, // 0022 CALL R3 1 - 0x80000000, // 0023 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Light1_invoke_request, /* name */ - be_nested_proto( - 16, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[20]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(command), - /* K5 */ be_nested_str_weak(update_shadow_lazy), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(findsubval), - /* K8 */ be_nested_str_weak(tasmota), - /* K9 */ be_nested_str_weak(scale_uint), - /* K10 */ be_nested_str_weak(set), - /* K11 */ be_nested_str_weak(bri), - /* K12 */ be_nested_str_weak(update_shadow), - /* K13 */ be_nested_str_weak(log), - /* K14 */ be_nested_str_weak(bri_X3A), - /* K15 */ be_const_int(1), - /* K16 */ be_const_int(2), - /* K17 */ be_const_int(3), - /* K18 */ be_nested_str_weak(power), - /* K19 */ be_nested_str_weak(invoke_request), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[112]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xB8160200, // 0001 GETNGBL R5 K1 - 0x88140B02, // 0002 GETMBR R5 R5 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x881C0704, // 0004 GETMBR R7 R3 K4 - 0x54220007, // 0005 LDINT R8 8 - 0x1C200C08, // 0006 EQ R8 R6 R8 - 0x7822005D, // 0007 JMPF R8 #0066 - 0x8C200105, // 0008 GETMET R8 R0 K5 - 0x7C200200, // 0009 CALL R8 1 - 0x1C200F06, // 000A EQ R8 R7 K6 - 0x78220019, // 000B JMPF R8 #0026 - 0x8C200507, // 000C GETMET R8 R2 K7 - 0x58280006, // 000D LDCONST R10 K6 - 0x7C200400, // 000E CALL R8 2 - 0xB8261000, // 000F GETNGBL R9 K8 - 0x8C241309, // 0010 GETMET R9 R9 K9 - 0x5C2C1000, // 0011 MOVE R11 R8 - 0x58300006, // 0012 LDCONST R12 K6 - 0x543600FD, // 0013 LDINT R13 254 - 0x58380006, // 0014 LDCONST R14 K6 - 0x543E00FE, // 0015 LDINT R15 255 - 0x7C240C00, // 0016 CALL R9 6 - 0x8C28090A, // 0017 GETMET R10 R4 K10 - 0x60300013, // 0018 GETGBL R12 G19 - 0x7C300000, // 0019 CALL R12 0 - 0x98321609, // 001A SETIDX R12 K11 R9 - 0x7C280400, // 001B CALL R10 2 - 0x8C28010C, // 001C GETMET R10 R0 K12 - 0x7C280200, // 001D CALL R10 1 - 0x60280008, // 001E GETGBL R10 G8 - 0x5C2C1000, // 001F MOVE R11 R8 - 0x7C280200, // 0020 CALL R10 1 - 0x002A1C0A, // 0021 ADD R10 K14 R10 - 0x900E1A0A, // 0022 SETMBR R3 K13 R10 - 0x50280200, // 0023 LDBOOL R10 1 0 - 0x80041400, // 0024 RET 1 R10 - 0x7002003E, // 0025 JMP #0065 - 0x1C200F0F, // 0026 EQ R8 R7 K15 - 0x78220002, // 0027 JMPF R8 #002B - 0x50200200, // 0028 LDBOOL R8 1 0 - 0x80041000, // 0029 RET 1 R8 - 0x70020039, // 002A JMP #0065 - 0x1C200F10, // 002B EQ R8 R7 K16 - 0x78220002, // 002C JMPF R8 #0030 - 0x50200200, // 002D LDBOOL R8 1 0 - 0x80041000, // 002E RET 1 R8 - 0x70020034, // 002F JMP #0065 - 0x1C200F11, // 0030 EQ R8 R7 K17 - 0x78220002, // 0031 JMPF R8 #0035 - 0x50200200, // 0032 LDBOOL R8 1 0 - 0x80041000, // 0033 RET 1 R8 - 0x7002002F, // 0034 JMP #0065 - 0x54220003, // 0035 LDINT R8 4 - 0x1C200E08, // 0036 EQ R8 R7 R8 - 0x7822001B, // 0037 JMPF R8 #0054 - 0x8C200507, // 0038 GETMET R8 R2 K7 - 0x58280006, // 0039 LDCONST R10 K6 - 0x7C200400, // 003A CALL R8 2 - 0xB8261000, // 003B GETNGBL R9 K8 - 0x8C241309, // 003C GETMET R9 R9 K9 - 0x5C2C1000, // 003D MOVE R11 R8 - 0x58300006, // 003E LDCONST R12 K6 - 0x543600FD, // 003F LDINT R13 254 - 0x58380006, // 0040 LDCONST R14 K6 - 0x543E00FE, // 0041 LDINT R15 255 - 0x7C240C00, // 0042 CALL R9 6 - 0x24281306, // 0043 GT R10 R9 K6 - 0x8C2C090A, // 0044 GETMET R11 R4 K10 - 0x60340013, // 0045 GETGBL R13 G19 - 0x7C340000, // 0046 CALL R13 0 - 0x98361609, // 0047 SETIDX R13 K11 R9 - 0x9836240A, // 0048 SETIDX R13 K18 R10 - 0x7C2C0400, // 0049 CALL R11 2 - 0x8C2C010C, // 004A GETMET R11 R0 K12 - 0x7C2C0200, // 004B CALL R11 1 - 0x602C0008, // 004C GETGBL R11 G8 - 0x5C301000, // 004D MOVE R12 R8 - 0x7C2C0200, // 004E CALL R11 1 - 0x002E1C0B, // 004F ADD R11 K14 R11 - 0x900E1A0B, // 0050 SETMBR R3 K13 R11 - 0x502C0200, // 0051 LDBOOL R11 1 0 - 0x80041600, // 0052 RET 1 R11 - 0x70020010, // 0053 JMP #0065 - 0x54220004, // 0054 LDINT R8 5 - 0x1C200E08, // 0055 EQ R8 R7 R8 - 0x78220002, // 0056 JMPF R8 #005A - 0x50200200, // 0057 LDBOOL R8 1 0 - 0x80041000, // 0058 RET 1 R8 - 0x7002000A, // 0059 JMP #0065 - 0x54220005, // 005A LDINT R8 6 - 0x1C200E08, // 005B EQ R8 R7 R8 - 0x78220002, // 005C JMPF R8 #0060 - 0x50200200, // 005D LDBOOL R8 1 0 - 0x80041000, // 005E RET 1 R8 - 0x70020004, // 005F JMP #0065 - 0x54220006, // 0060 LDINT R8 7 - 0x1C200E08, // 0061 EQ R8 R7 R8 - 0x78220001, // 0062 JMPF R8 #0065 - 0x50200200, // 0063 LDBOOL R8 1 0 - 0x80041000, // 0064 RET 1 R8 - 0x70020008, // 0065 JMP #006F - 0x60200003, // 0066 GETGBL R8 G3 - 0x5C240000, // 0067 MOVE R9 R0 - 0x7C200200, // 0068 CALL R8 1 - 0x8C201113, // 0069 GETMET R8 R8 K19 - 0x5C280200, // 006A MOVE R10 R1 - 0x5C2C0400, // 006B MOVE R11 R2 - 0x5C300600, // 006C MOVE R12 R3 - 0x7C200800, // 006D CALL R8 4 - 0x80041000, // 006E RET 1 R8 - 0x80000000, // 006F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: read_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_Light1_read_attribute, /* name */ - be_nested_proto( - 12, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[14]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(TLV), - /* K2 */ be_nested_str_weak(cluster), - /* K3 */ be_nested_str_weak(attribute), - /* K4 */ be_nested_str_weak(update_shadow_lazy), - /* K5 */ be_const_int(0), - /* K6 */ be_nested_str_weak(set), - /* K7 */ be_nested_str_weak(U1), - /* K8 */ be_nested_str_weak(shadow_bri), - /* K9 */ be_const_int(2), - /* K10 */ be_const_int(3), - /* K11 */ be_nested_str_weak(U4), - /* K12 */ be_const_int(1), - /* K13 */ be_nested_str_weak(read_attribute), - }), - be_str_weak(read_attribute), - &be_const_str_solidified, - ( &(const binstruction[79]) { /* code */ - 0xB8120000, // 0000 GETNGBL R4 K0 - 0x88100901, // 0001 GETMBR R4 R4 K1 - 0x88140502, // 0002 GETMBR R5 R2 K2 - 0x88180503, // 0003 GETMBR R6 R2 K3 - 0x541E0007, // 0004 LDINT R7 8 - 0x1C1C0A07, // 0005 EQ R7 R5 R7 - 0x781E003D, // 0006 JMPF R7 #0045 - 0x8C1C0104, // 0007 GETMET R7 R0 K4 - 0x7C1C0200, // 0008 CALL R7 1 - 0x1C1C0D05, // 0009 EQ R7 R6 K5 - 0x781E0005, // 000A JMPF R7 #0011 - 0x8C1C0706, // 000B GETMET R7 R3 K6 - 0x88240907, // 000C GETMBR R9 R4 K7 - 0x88280108, // 000D GETMBR R10 R0 K8 - 0x7C1C0600, // 000E CALL R7 3 - 0x80040E00, // 000F RET 1 R7 - 0x70020032, // 0010 JMP #0044 - 0x1C1C0D09, // 0011 EQ R7 R6 K9 - 0x781E0005, // 0012 JMPF R7 #0019 - 0x8C1C0706, // 0013 GETMET R7 R3 K6 - 0x88240907, // 0014 GETMBR R9 R4 K7 - 0x58280005, // 0015 LDCONST R10 K5 - 0x7C1C0600, // 0016 CALL R7 3 - 0x80040E00, // 0017 RET 1 R7 - 0x7002002A, // 0018 JMP #0044 - 0x1C1C0D0A, // 0019 EQ R7 R6 K10 - 0x781E0005, // 001A JMPF R7 #0021 - 0x8C1C0706, // 001B GETMET R7 R3 K6 - 0x88240907, // 001C GETMBR R9 R4 K7 - 0x542A00FD, // 001D LDINT R10 254 - 0x7C1C0600, // 001E CALL R7 3 - 0x80040E00, // 001F RET 1 R7 - 0x70020022, // 0020 JMP #0044 - 0x541E000E, // 0021 LDINT R7 15 - 0x1C1C0C07, // 0022 EQ R7 R6 R7 - 0x781E0005, // 0023 JMPF R7 #002A - 0x8C1C0706, // 0024 GETMET R7 R3 K6 - 0x88240907, // 0025 GETMBR R9 R4 K7 - 0x58280005, // 0026 LDCONST R10 K5 - 0x7C1C0600, // 0027 CALL R7 3 - 0x80040E00, // 0028 RET 1 R7 - 0x70020019, // 0029 JMP #0044 - 0x541E0010, // 002A LDINT R7 17 - 0x1C1C0C07, // 002B EQ R7 R6 R7 - 0x781E0005, // 002C JMPF R7 #0033 - 0x8C1C0706, // 002D GETMET R7 R3 K6 - 0x88240907, // 002E GETMBR R9 R4 K7 - 0x88280108, // 002F GETMBR R10 R0 K8 - 0x7C1C0600, // 0030 CALL R7 3 - 0x80040E00, // 0031 RET 1 R7 - 0x70020010, // 0032 JMP #0044 - 0x541EFFFB, // 0033 LDINT R7 65532 - 0x1C1C0C07, // 0034 EQ R7 R6 R7 - 0x781E0005, // 0035 JMPF R7 #003C - 0x8C1C0706, // 0036 GETMET R7 R3 K6 - 0x8824090B, // 0037 GETMBR R9 R4 K11 - 0x5828000C, // 0038 LDCONST R10 K12 - 0x7C1C0600, // 0039 CALL R7 3 - 0x80040E00, // 003A RET 1 R7 - 0x70020007, // 003B JMP #0044 - 0x541EFFFC, // 003C LDINT R7 65533 - 0x1C1C0C07, // 003D EQ R7 R6 R7 - 0x781E0004, // 003E JMPF R7 #0044 - 0x8C1C0706, // 003F GETMET R7 R3 K6 - 0x8824090B, // 0040 GETMBR R9 R4 K11 - 0x542A0004, // 0041 LDINT R10 5 - 0x7C1C0600, // 0042 CALL R7 3 - 0x80040E00, // 0043 RET 1 R7 - 0x70020008, // 0044 JMP #004E - 0x601C0003, // 0045 GETGBL R7 G3 - 0x5C200000, // 0046 MOVE R8 R0 - 0x7C1C0200, // 0047 CALL R7 1 - 0x8C1C0F0D, // 0048 GETMET R7 R7 K13 - 0x5C240200, // 0049 MOVE R9 R1 - 0x5C280400, // 004A MOVE R10 R2 - 0x5C2C0600, // 004B MOVE R11 R3 - 0x7C1C0800, // 004C CALL R7 4 - 0x80040E00, // 004D RET 1 R7 - 0x80000000, // 004E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_Light1_init, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str_weak(init), - /* K1 */ be_nested_str_weak(shadow_bri), - /* K2 */ be_const_int(0), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x60100003, // 0000 GETGBL R4 G3 - 0x5C140000, // 0001 MOVE R5 R0 - 0x7C100200, // 0002 CALL R4 1 - 0x8C100900, // 0003 GETMET R4 R4 K0 - 0x5C180200, // 0004 MOVE R6 R1 - 0x5C1C0400, // 0005 MOVE R7 R2 - 0x5C200600, // 0006 MOVE R8 R3 - 0x7C100800, // 0007 CALL R4 4 - 0x90020302, // 0008 SETMBR R0 K1 K2 - 0x80000000, // 0009 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified class: Matter_Plugin_Light1 -********************************************************************/ -extern const bclass be_class_Matter_Plugin_Light0; -be_local_class(Matter_Plugin_Light1, - 1, - &be_class_Matter_Plugin_Light0, - be_nested_map(9, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light1_init_closure) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(light1) }, - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(257, -1), be_const_int(2) }, - })) ) } )) }, - { be_const_key_weak(NAME, -1), be_nested_str_weak(Light_X201_X20Dimmer) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(8, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(7, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(2), - be_const_int(3), - be_const_int(15), - be_const_int(17), - be_const_int(65532), - be_const_int(65533), - })) ) } )) }, - })) ) } )) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light1_invoke_request_closure) }, - { be_const_key_weak(read_attribute, 0), be_const_closure(Matter_Plugin_Light1_read_attribute_closure) }, - { be_const_key_weak(update_shadow, 8), be_const_closure(Matter_Plugin_Light1_update_shadow_closure) }, - { be_const_key_weak(shadow_bri, -1), be_const_var(0) }, - })), - be_str_weak(Matter_Plugin_Light1) -); -/*******************************************************************/ - -void be_load_Matter_Plugin_Light1_class(bvm *vm) { - be_pushntvclass(vm, &be_class_Matter_Plugin_Light1); - be_setglobal(vm, "Matter_Plugin_Light1"); - be_pop(vm, 1); -} -/********************************************************************/ -/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light3.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light3.h deleted file mode 100644 index 284eaf8e6..000000000 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Plugin_Light3.h +++ /dev/null @@ -1,539 +0,0 @@ -/* Solidification of Matter_Plugin_Light3.h */ -/********************************************************************\ -* Generated code, don't edit * -\********************************************************************/ -#include "be_constobj.h" - -extern const bclass be_class_Matter_Plugin_Light3; - -/******************************************************************** -** Solidified function: update_shadow -********************************************************************/ -be_local_closure(Matter_Plugin_Light3_update_shadow, /* name */ - be_nested_proto( - 12, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(update_shadow), - /* K2 */ be_nested_str_weak(get), - /* K3 */ be_nested_str_weak(find), - /* K4 */ be_nested_str_weak(hue), - /* K5 */ be_nested_str_weak(sat), - /* K6 */ be_nested_str_weak(tasmota), - /* K7 */ be_nested_str_weak(scale_uint), - /* K8 */ be_const_int(0), - /* K9 */ be_nested_str_weak(shadow_hue), - /* K10 */ be_nested_str_weak(shadow_sat), - /* K11 */ be_nested_str_weak(attribute_updated), - /* K12 */ be_const_int(1), - }), - be_str_weak(update_shadow), - &be_const_str_solidified, - ( &(const binstruction[64]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x60080003, // 0001 GETGBL R2 G3 - 0x5C0C0000, // 0002 MOVE R3 R0 - 0x7C080200, // 0003 CALL R2 1 - 0x8C080501, // 0004 GETMET R2 R2 K1 - 0x7C080200, // 0005 CALL R2 1 - 0x8C080302, // 0006 GETMET R2 R1 K2 - 0x7C080200, // 0007 CALL R2 1 - 0x4C0C0000, // 0008 LDNIL R3 - 0x200C0403, // 0009 NE R3 R2 R3 - 0x780E0033, // 000A JMPF R3 #003F - 0x8C0C0503, // 000B GETMET R3 R2 K3 - 0x58140004, // 000C LDCONST R5 K4 - 0x4C180000, // 000D LDNIL R6 - 0x7C0C0600, // 000E CALL R3 3 - 0x8C100503, // 000F GETMET R4 R2 K3 - 0x58180005, // 0010 LDCONST R6 K5 - 0x4C1C0000, // 0011 LDNIL R7 - 0x7C100600, // 0012 CALL R4 3 - 0x4C140000, // 0013 LDNIL R5 - 0x20140605, // 0014 NE R5 R3 R5 - 0x78160009, // 0015 JMPF R5 #0020 - 0xB8160C00, // 0016 GETNGBL R5 K6 - 0x8C140B07, // 0017 GETMET R5 R5 K7 - 0x5C1C0600, // 0018 MOVE R7 R3 - 0x58200008, // 0019 LDCONST R8 K8 - 0x54260167, // 001A LDINT R9 360 - 0x58280008, // 001B LDCONST R10 K8 - 0x542E00FD, // 001C LDINT R11 254 - 0x7C140C00, // 001D CALL R5 6 - 0x5C0C0A00, // 001E MOVE R3 R5 - 0x70020000, // 001F JMP #0021 - 0x880C0109, // 0020 GETMBR R3 R0 K9 - 0x4C140000, // 0021 LDNIL R5 - 0x20140805, // 0022 NE R5 R4 R5 - 0x78160009, // 0023 JMPF R5 #002E - 0xB8160C00, // 0024 GETNGBL R5 K6 - 0x8C140B07, // 0025 GETMET R5 R5 K7 - 0x5C1C0800, // 0026 MOVE R7 R4 - 0x58200008, // 0027 LDCONST R8 K8 - 0x542600FE, // 0028 LDINT R9 255 - 0x58280008, // 0029 LDCONST R10 K8 - 0x542E00FD, // 002A LDINT R11 254 - 0x7C140C00, // 002B CALL R5 6 - 0x5C100A00, // 002C MOVE R4 R5 - 0x70020000, // 002D JMP #002F - 0x8810010A, // 002E GETMBR R4 R0 K10 - 0x88140109, // 002F GETMBR R5 R0 K9 - 0x20140605, // 0030 NE R5 R3 R5 - 0x78160004, // 0031 JMPF R5 #0037 - 0x8C14010B, // 0032 GETMET R5 R0 K11 - 0x541E02FF, // 0033 LDINT R7 768 - 0x58200008, // 0034 LDCONST R8 K8 - 0x7C140600, // 0035 CALL R5 3 - 0x90021203, // 0036 SETMBR R0 K9 R3 - 0x8814010A, // 0037 GETMBR R5 R0 K10 - 0x20140805, // 0038 NE R5 R4 R5 - 0x78160004, // 0039 JMPF R5 #003F - 0x8C14010B, // 003A GETMET R5 R0 K11 - 0x541E02FF, // 003B LDINT R7 768 - 0x5820000C, // 003C LDCONST R8 K12 - 0x7C140600, // 003D CALL R5 3 - 0x90021404, // 003E SETMBR R0 K10 R4 - 0x80000000, // 003F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: read_attribute -********************************************************************/ -be_local_closure(Matter_Plugin_Light3_read_attribute, /* name */ - be_nested_proto( - 12, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[13]) { /* constants */ - /* K0 */ be_nested_str_weak(matter), - /* K1 */ be_nested_str_weak(TLV), - /* K2 */ be_nested_str_weak(cluster), - /* K3 */ be_nested_str_weak(attribute), - /* K4 */ be_nested_str_weak(update_shadow_lazy), - /* K5 */ be_const_int(0), - /* K6 */ be_nested_str_weak(set), - /* K7 */ be_nested_str_weak(U1), - /* K8 */ be_nested_str_weak(shadow_hue), - /* K9 */ be_const_int(1), - /* K10 */ be_nested_str_weak(shadow_sat), - /* K11 */ be_nested_str_weak(U4), - /* K12 */ be_nested_str_weak(read_attribute), - }), - be_str_weak(read_attribute), - &be_const_str_solidified, - ( &(const binstruction[107]) { /* code */ - 0xB8120000, // 0000 GETNGBL R4 K0 - 0x88100901, // 0001 GETMBR R4 R4 K1 - 0x88140502, // 0002 GETMBR R5 R2 K2 - 0x88180503, // 0003 GETMBR R6 R2 K3 - 0x541E02FF, // 0004 LDINT R7 768 - 0x1C1C0A07, // 0005 EQ R7 R5 R7 - 0x781E0059, // 0006 JMPF R7 #0061 - 0x8C1C0104, // 0007 GETMET R7 R0 K4 - 0x7C1C0200, // 0008 CALL R7 1 - 0x1C1C0D05, // 0009 EQ R7 R6 K5 - 0x781E0005, // 000A JMPF R7 #0011 - 0x8C1C0706, // 000B GETMET R7 R3 K6 - 0x88240907, // 000C GETMBR R9 R4 K7 - 0x88280108, // 000D GETMBR R10 R0 K8 - 0x7C1C0600, // 000E CALL R7 3 - 0x80040E00, // 000F RET 1 R7 - 0x7002004E, // 0010 JMP #0060 - 0x1C1C0D09, // 0011 EQ R7 R6 K9 - 0x781E0005, // 0012 JMPF R7 #0019 - 0x8C1C0706, // 0013 GETMET R7 R3 K6 - 0x88240907, // 0014 GETMBR R9 R4 K7 - 0x8828010A, // 0015 GETMBR R10 R0 K10 - 0x7C1C0600, // 0016 CALL R7 3 - 0x80040E00, // 0017 RET 1 R7 - 0x70020046, // 0018 JMP #0060 - 0x541E0006, // 0019 LDINT R7 7 - 0x1C1C0C07, // 001A EQ R7 R6 R7 - 0x781E0005, // 001B JMPF R7 #0022 - 0x8C1C0706, // 001C GETMET R7 R3 K6 - 0x88240907, // 001D GETMBR R9 R4 K7 - 0x58280005, // 001E LDCONST R10 K5 - 0x7C1C0600, // 001F CALL R7 3 - 0x80040E00, // 0020 RET 1 R7 - 0x7002003D, // 0021 JMP #0060 - 0x541E0007, // 0022 LDINT R7 8 - 0x1C1C0C07, // 0023 EQ R7 R6 R7 - 0x781E0005, // 0024 JMPF R7 #002B - 0x8C1C0706, // 0025 GETMET R7 R3 K6 - 0x88240907, // 0026 GETMBR R9 R4 K7 - 0x58280005, // 0027 LDCONST R10 K5 - 0x7C1C0600, // 0028 CALL R7 3 - 0x80040E00, // 0029 RET 1 R7 - 0x70020034, // 002A JMP #0060 - 0x541E000E, // 002B LDINT R7 15 - 0x1C1C0C07, // 002C EQ R7 R6 R7 - 0x781E0005, // 002D JMPF R7 #0034 - 0x8C1C0706, // 002E GETMET R7 R3 K6 - 0x88240907, // 002F GETMBR R9 R4 K7 - 0x58280005, // 0030 LDCONST R10 K5 - 0x7C1C0600, // 0031 CALL R7 3 - 0x80040E00, // 0032 RET 1 R7 - 0x7002002B, // 0033 JMP #0060 - 0x541E4000, // 0034 LDINT R7 16385 - 0x1C1C0C07, // 0035 EQ R7 R6 R7 - 0x781E0005, // 0036 JMPF R7 #003D - 0x8C1C0706, // 0037 GETMET R7 R3 K6 - 0x88240907, // 0038 GETMBR R9 R4 K7 - 0x58280005, // 0039 LDCONST R10 K5 - 0x7C1C0600, // 003A CALL R7 3 - 0x80040E00, // 003B RET 1 R7 - 0x70020022, // 003C JMP #0060 - 0x541E4009, // 003D LDINT R7 16394 - 0x1C1C0C07, // 003E EQ R7 R6 R7 - 0x781E0005, // 003F JMPF R7 #0046 - 0x8C1C0706, // 0040 GETMET R7 R3 K6 - 0x88240907, // 0041 GETMBR R9 R4 K7 - 0x58280009, // 0042 LDCONST R10 K9 - 0x7C1C0600, // 0043 CALL R7 3 - 0x80040E00, // 0044 RET 1 R7 - 0x70020019, // 0045 JMP #0060 - 0x541E000F, // 0046 LDINT R7 16 - 0x1C1C0C07, // 0047 EQ R7 R6 R7 - 0x781E0005, // 0048 JMPF R7 #004F - 0x8C1C0706, // 0049 GETMET R7 R3 K6 - 0x88240907, // 004A GETMBR R9 R4 K7 - 0x58280005, // 004B LDCONST R10 K5 - 0x7C1C0600, // 004C CALL R7 3 - 0x80040E00, // 004D RET 1 R7 - 0x70020010, // 004E JMP #0060 - 0x541EFFFB, // 004F LDINT R7 65532 - 0x1C1C0C07, // 0050 EQ R7 R6 R7 - 0x781E0005, // 0051 JMPF R7 #0058 - 0x8C1C0706, // 0052 GETMET R7 R3 K6 - 0x8824090B, // 0053 GETMBR R9 R4 K11 - 0x58280009, // 0054 LDCONST R10 K9 - 0x7C1C0600, // 0055 CALL R7 3 - 0x80040E00, // 0056 RET 1 R7 - 0x70020007, // 0057 JMP #0060 - 0x541EFFFC, // 0058 LDINT R7 65533 - 0x1C1C0C07, // 0059 EQ R7 R6 R7 - 0x781E0004, // 005A JMPF R7 #0060 - 0x8C1C0706, // 005B GETMET R7 R3 K6 - 0x8824090B, // 005C GETMBR R9 R4 K11 - 0x542A0004, // 005D LDINT R10 5 - 0x7C1C0600, // 005E CALL R7 3 - 0x80040E00, // 005F RET 1 R7 - 0x70020008, // 0060 JMP #006A - 0x601C0003, // 0061 GETGBL R7 G3 - 0x5C200000, // 0062 MOVE R8 R0 - 0x7C1C0200, // 0063 CALL R7 1 - 0x8C1C0F0C, // 0064 GETMET R7 R7 K12 - 0x5C240200, // 0065 MOVE R9 R1 - 0x5C280400, // 0066 MOVE R10 R2 - 0x5C2C0600, // 0067 MOVE R11 R3 - 0x7C1C0800, // 0068 CALL R7 4 - 0x80040E00, // 0069 RET 1 R7 - 0x80000000, // 006A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Matter_Plugin_Light3_init, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str_weak(init), - /* K1 */ be_nested_str_weak(shadow_hue), - /* K2 */ be_const_int(0), - /* K3 */ be_nested_str_weak(shadow_sat), - }), - be_str_weak(init), - &be_const_str_solidified, - ( &(const binstruction[11]) { /* code */ - 0x60100003, // 0000 GETGBL R4 G3 - 0x5C140000, // 0001 MOVE R5 R0 - 0x7C100200, // 0002 CALL R4 1 - 0x8C100900, // 0003 GETMET R4 R4 K0 - 0x5C180200, // 0004 MOVE R6 R1 - 0x5C1C0400, // 0005 MOVE R7 R2 - 0x5C200600, // 0006 MOVE R8 R3 - 0x7C100800, // 0007 CALL R4 4 - 0x90020302, // 0008 SETMBR R0 K1 K2 - 0x90020702, // 0009 SETMBR R0 K3 K2 - 0x80000000, // 000A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: invoke_request -********************************************************************/ -be_local_closure(Matter_Plugin_Light3_invoke_request, /* name */ - be_nested_proto( - 18, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[22]) { /* constants */ - /* K0 */ be_nested_str_weak(light), - /* K1 */ be_nested_str_weak(matter), - /* K2 */ be_nested_str_weak(TLV), - /* K3 */ be_nested_str_weak(cluster), - /* K4 */ be_nested_str_weak(command), - /* K5 */ be_nested_str_weak(update_shadow_lazy), - /* K6 */ be_const_int(0), - /* K7 */ be_nested_str_weak(findsubval), - /* K8 */ be_nested_str_weak(tasmota), - /* K9 */ be_nested_str_weak(scale_uint), - /* K10 */ be_nested_str_weak(set), - /* K11 */ be_nested_str_weak(hue), - /* K12 */ be_nested_str_weak(update_shadow), - /* K13 */ be_nested_str_weak(log), - /* K14 */ be_nested_str_weak(hue_X3A), - /* K15 */ be_const_int(1), - /* K16 */ be_const_int(2), - /* K17 */ be_const_int(3), - /* K18 */ be_nested_str_weak(sat), - /* K19 */ be_nested_str_weak(sat_X3A), - /* K20 */ be_nested_str_weak(_X20sat_X3A), - /* K21 */ be_nested_str_weak(invoke_request), - }), - be_str_weak(invoke_request), - &be_const_str_solidified, - ( &(const binstruction[150]) { /* code */ - 0xA4120000, // 0000 IMPORT R4 K0 - 0xB8160200, // 0001 GETNGBL R5 K1 - 0x88140B02, // 0002 GETMBR R5 R5 K2 - 0x88180703, // 0003 GETMBR R6 R3 K3 - 0x881C0704, // 0004 GETMBR R7 R3 K4 - 0x542202FF, // 0005 LDINT R8 768 - 0x1C200C08, // 0006 EQ R8 R6 R8 - 0x78220083, // 0007 JMPF R8 #008C - 0x8C200105, // 0008 GETMET R8 R0 K5 - 0x7C200200, // 0009 CALL R8 1 - 0x1C200F06, // 000A EQ R8 R7 K6 - 0x78220019, // 000B JMPF R8 #0026 - 0x8C200507, // 000C GETMET R8 R2 K7 - 0x58280006, // 000D LDCONST R10 K6 - 0x7C200400, // 000E CALL R8 2 - 0xB8261000, // 000F GETNGBL R9 K8 - 0x8C241309, // 0010 GETMET R9 R9 K9 - 0x5C2C1000, // 0011 MOVE R11 R8 - 0x58300006, // 0012 LDCONST R12 K6 - 0x543600FD, // 0013 LDINT R13 254 - 0x58380006, // 0014 LDCONST R14 K6 - 0x543E0167, // 0015 LDINT R15 360 - 0x7C240C00, // 0016 CALL R9 6 - 0x8C28090A, // 0017 GETMET R10 R4 K10 - 0x60300013, // 0018 GETGBL R12 G19 - 0x7C300000, // 0019 CALL R12 0 - 0x98321609, // 001A SETIDX R12 K11 R9 - 0x7C280400, // 001B CALL R10 2 - 0x8C28010C, // 001C GETMET R10 R0 K12 - 0x7C280200, // 001D CALL R10 1 - 0x60280008, // 001E GETGBL R10 G8 - 0x5C2C1000, // 001F MOVE R11 R8 - 0x7C280200, // 0020 CALL R10 1 - 0x002A1C0A, // 0021 ADD R10 K14 R10 - 0x900E1A0A, // 0022 SETMBR R3 K13 R10 - 0x50280200, // 0023 LDBOOL R10 1 0 - 0x80041400, // 0024 RET 1 R10 - 0x70020064, // 0025 JMP #008B - 0x1C200F0F, // 0026 EQ R8 R7 K15 - 0x78220002, // 0027 JMPF R8 #002B - 0x50200200, // 0028 LDBOOL R8 1 0 - 0x80041000, // 0029 RET 1 R8 - 0x7002005F, // 002A JMP #008B - 0x1C200F10, // 002B EQ R8 R7 K16 - 0x78220002, // 002C JMPF R8 #0030 - 0x50200200, // 002D LDBOOL R8 1 0 - 0x80041000, // 002E RET 1 R8 - 0x7002005A, // 002F JMP #008B - 0x1C200F11, // 0030 EQ R8 R7 K17 - 0x78220019, // 0031 JMPF R8 #004C - 0x8C200507, // 0032 GETMET R8 R2 K7 - 0x58280006, // 0033 LDCONST R10 K6 - 0x7C200400, // 0034 CALL R8 2 - 0xB8261000, // 0035 GETNGBL R9 K8 - 0x8C241309, // 0036 GETMET R9 R9 K9 - 0x5C2C1000, // 0037 MOVE R11 R8 - 0x58300006, // 0038 LDCONST R12 K6 - 0x543600FD, // 0039 LDINT R13 254 - 0x58380006, // 003A LDCONST R14 K6 - 0x543E00FE, // 003B LDINT R15 255 - 0x7C240C00, // 003C CALL R9 6 - 0x8C28090A, // 003D GETMET R10 R4 K10 - 0x60300013, // 003E GETGBL R12 G19 - 0x7C300000, // 003F CALL R12 0 - 0x98322409, // 0040 SETIDX R12 K18 R9 - 0x7C280400, // 0041 CALL R10 2 - 0x8C28010C, // 0042 GETMET R10 R0 K12 - 0x7C280200, // 0043 CALL R10 1 - 0x60280008, // 0044 GETGBL R10 G8 - 0x5C2C1000, // 0045 MOVE R11 R8 - 0x7C280200, // 0046 CALL R10 1 - 0x002A260A, // 0047 ADD R10 K19 R10 - 0x900E1A0A, // 0048 SETMBR R3 K13 R10 - 0x50280200, // 0049 LDBOOL R10 1 0 - 0x80041400, // 004A RET 1 R10 - 0x7002003E, // 004B JMP #008B - 0x54220003, // 004C LDINT R8 4 - 0x1C200E08, // 004D EQ R8 R7 R8 - 0x78220002, // 004E JMPF R8 #0052 - 0x50200200, // 004F LDBOOL R8 1 0 - 0x80041000, // 0050 RET 1 R8 - 0x70020038, // 0051 JMP #008B - 0x54220004, // 0052 LDINT R8 5 - 0x1C200E08, // 0053 EQ R8 R7 R8 - 0x78220002, // 0054 JMPF R8 #0058 - 0x50200200, // 0055 LDBOOL R8 1 0 - 0x80041000, // 0056 RET 1 R8 - 0x70020032, // 0057 JMP #008B - 0x54220005, // 0058 LDINT R8 6 - 0x1C200E08, // 0059 EQ R8 R7 R8 - 0x7822002A, // 005A JMPF R8 #0086 - 0x8C200507, // 005B GETMET R8 R2 K7 - 0x58280006, // 005C LDCONST R10 K6 - 0x7C200400, // 005D CALL R8 2 - 0xB8261000, // 005E GETNGBL R9 K8 - 0x8C241309, // 005F GETMET R9 R9 K9 - 0x5C2C1000, // 0060 MOVE R11 R8 - 0x58300006, // 0061 LDCONST R12 K6 - 0x543600FD, // 0062 LDINT R13 254 - 0x58380006, // 0063 LDCONST R14 K6 - 0x543E0167, // 0064 LDINT R15 360 - 0x7C240C00, // 0065 CALL R9 6 - 0x8C280507, // 0066 GETMET R10 R2 K7 - 0x5830000F, // 0067 LDCONST R12 K15 - 0x7C280400, // 0068 CALL R10 2 - 0xB82E1000, // 0069 GETNGBL R11 K8 - 0x8C2C1709, // 006A GETMET R11 R11 K9 - 0x5C341400, // 006B MOVE R13 R10 - 0x58380006, // 006C LDCONST R14 K6 - 0x543E00FD, // 006D LDINT R15 254 - 0x58400006, // 006E LDCONST R16 K6 - 0x544600FE, // 006F LDINT R17 255 - 0x7C2C0C00, // 0070 CALL R11 6 - 0x8C30090A, // 0071 GETMET R12 R4 K10 - 0x60380013, // 0072 GETGBL R14 G19 - 0x7C380000, // 0073 CALL R14 0 - 0x983A1609, // 0074 SETIDX R14 K11 R9 - 0x983A240B, // 0075 SETIDX R14 K18 R11 - 0x7C300400, // 0076 CALL R12 2 - 0x8C30010C, // 0077 GETMET R12 R0 K12 - 0x7C300200, // 0078 CALL R12 1 - 0x60300008, // 0079 GETGBL R12 G8 - 0x5C341000, // 007A MOVE R13 R8 - 0x7C300200, // 007B CALL R12 1 - 0x00321C0C, // 007C ADD R12 K14 R12 - 0x00301914, // 007D ADD R12 R12 K20 - 0x60340008, // 007E GETGBL R13 G8 - 0x5C381400, // 007F MOVE R14 R10 - 0x7C340200, // 0080 CALL R13 1 - 0x0030180D, // 0081 ADD R12 R12 R13 - 0x900E1A0C, // 0082 SETMBR R3 K13 R12 - 0x50300200, // 0083 LDBOOL R12 1 0 - 0x80041800, // 0084 RET 1 R12 - 0x70020004, // 0085 JMP #008B - 0x54220046, // 0086 LDINT R8 71 - 0x1C200E08, // 0087 EQ R8 R7 R8 - 0x78220001, // 0088 JMPF R8 #008B - 0x50200200, // 0089 LDBOOL R8 1 0 - 0x80041000, // 008A RET 1 R8 - 0x70020008, // 008B JMP #0095 - 0x60200003, // 008C GETGBL R8 G3 - 0x5C240000, // 008D MOVE R9 R0 - 0x7C200200, // 008E CALL R8 1 - 0x8C201115, // 008F GETMET R8 R8 K21 - 0x5C280200, // 0090 MOVE R10 R1 - 0x5C2C0400, // 0091 MOVE R11 R2 - 0x5C300600, // 0092 MOVE R12 R3 - 0x7C200800, // 0093 CALL R8 4 - 0x80041000, // 0094 RET 1 R8 - 0x80000000, // 0095 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified class: Matter_Plugin_Light3 -********************************************************************/ -extern const bclass be_class_Matter_Plugin_Light1; -be_local_class(Matter_Plugin_Light3, - 2, - &be_class_Matter_Plugin_Light1, - be_nested_map(10, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_weak(TYPES, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(269, -1), be_const_int(2) }, - })) ) } )) }, - { be_const_key_weak(TYPE, -1), be_nested_str_weak(light3) }, - { be_const_key_weak(shadow_hue, 8), be_const_var(0) }, - { be_const_key_weak(CLUSTERS, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_map, { - be_const_map( * be_nested_map(1, - ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key_int(768, -1), be_const_simple_instance(be_nested_simple_instance(&be_class_list, { - be_const_list( * be_nested_list(9, - ( (struct bvalue*) &(const bvalue[]) { - be_const_int(0), - be_const_int(1), - be_const_int(7), - be_const_int(8), - be_const_int(15), - be_const_int(16385), - be_const_int(16394), - be_const_int(65532), - be_const_int(65533), - })) ) } )) }, - })) ) } )) }, - { be_const_key_weak(NAME, 3), be_nested_str_weak(Light_X203_X20RGB) }, - { be_const_key_weak(init, -1), be_const_closure(Matter_Plugin_Light3_init_closure) }, - { be_const_key_weak(shadow_sat, -1), be_const_var(1) }, - { be_const_key_weak(invoke_request, -1), be_const_closure(Matter_Plugin_Light3_invoke_request_closure) }, - { be_const_key_weak(read_attribute, -1), be_const_closure(Matter_Plugin_Light3_read_attribute_closure) }, - { be_const_key_weak(update_shadow, 1), be_const_closure(Matter_Plugin_Light3_update_shadow_closure) }, - })), - be_str_weak(Matter_Plugin_Light3) -); -/*******************************************************************/ - -void be_load_Matter_Plugin_Light3_class(bvm *vm) { - be_pushntvclass(vm, &be_class_Matter_Plugin_Light3); - be_setglobal(vm, "Matter_Plugin_Light3"); - be_pop(vm, 1); -} -/********************************************************************/ -/* End of solidification */ diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h index b0e498421..cd1f28427 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_Session.h @@ -811,10 +811,14 @@ be_local_closure(Matter_Session_get_admin_subject, /* name */ }), be_str_weak(get_admin_subject), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ + ( &(const binstruction[ 7]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88040301, // 0001 GETMBR R1 R1 K1 - 0x80040200, // 0002 RET 1 R1 + 0x78060002, // 0001 JMPF R1 #0005 + 0x88040100, // 0002 GETMBR R1 R0 K0 + 0x88040301, // 0003 GETMBR R1 R1 K1 + 0x70020000, // 0004 JMP #0006 + 0x4C040000, // 0005 LDNIL R1 + 0x80040200, // 0006 RET 1 R1 }) ) ); @@ -840,10 +844,14 @@ be_local_closure(Matter_Session_get_fabric_compressed, /* name */ }), be_str_weak(get_fabric_compressed), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ + ( &(const binstruction[ 7]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88040301, // 0001 GETMBR R1 R1 K1 - 0x80040200, // 0002 RET 1 R1 + 0x78060002, // 0001 JMPF R1 #0005 + 0x88040100, // 0002 GETMBR R1 R0 K0 + 0x88040301, // 0003 GETMBR R1 R1 K1 + 0x70020000, // 0004 JMP #0006 + 0x4C040000, // 0005 LDNIL R1 + 0x80040200, // 0006 RET 1 R1 }) ) ); @@ -1261,10 +1269,14 @@ be_local_closure(Matter_Session_get_fabric_label, /* name */ }), be_str_weak(get_fabric_label), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ + ( &(const binstruction[ 7]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88040301, // 0001 GETMBR R1 R1 K1 - 0x80040200, // 0002 RET 1 R1 + 0x78060002, // 0001 JMPF R1 #0005 + 0x88040100, // 0002 GETMBR R1 R0 K0 + 0x88040301, // 0003 GETMBR R1 R1 K1 + 0x70020000, // 0004 JMP #0006 + 0x4C040000, // 0005 LDNIL R1 + 0x80040200, // 0006 RET 1 R1 }) ) ); @@ -1481,10 +1493,14 @@ be_local_closure(Matter_Session_get_admin_vendor, /* name */ }), be_str_weak(get_admin_vendor), &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ + ( &(const binstruction[ 7]) { /* code */ 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88040301, // 0001 GETMBR R1 R1 K1 - 0x80040200, // 0002 RET 1 R1 + 0x78060002, // 0001 JMPF R1 #0005 + 0x88040100, // 0002 GETMBR R1 R0 K0 + 0x88040301, // 0003 GETMBR R1 R1 K1 + 0x70020000, // 0004 JMP #0006 + 0x4C040000, // 0005 LDNIL R1 + 0x80040200, // 0006 RET 1 R1 }) ) ); diff --git a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h index 5e5fa2cd1..ea7755189 100644 --- a/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h +++ b/lib/libesp32/berry_matter/src/solidify/solidified_Matter_UI.h @@ -1627,8 +1627,8 @@ be_local_closure(Matter_UI_plugin_option, /* name */ /* K6 */ be_nested_str_weak(), /* K7 */ be_nested_str_weak(content_send), /* K8 */ be_nested_str_weak(_X3Coption_X20value_X3D_X27_X27_X3E_X3C_X2Foption_X3E), - /* K9 */ be_nested_str_weak(_X2Dhttp), - /* K10 */ be_nested_str_weak(_X3Coption_X20value_X3D_X27_X27_X20disabled_X3E_X2D_X2D_X2D_X20Tasmota_X20Remote_X20_X2D_X2D_X2D_X3C_X2Foption_X3E), + /* K9 */ be_nested_str_weak(_X2Dvirtual), + /* K10 */ be_nested_str_weak(_X3Coption_X20value_X3D_X27_X27_X20disabled_X3E_X2D_X2D_X2D_X20Virtual_X20Devices_X20_X2D_X2D_X2D_X3C_X2Foption_X3E), /* K11 */ be_nested_str_weak(device), /* K12 */ be_nested_str_weak(get_plugin_class_displayname), /* K13 */ be_nested_str_weak(_X3Coption_X20value_X3D_X27_X25s_X27_X25s_X3E_X25s_X3C_X2Foption_X3E), @@ -3372,7 +3372,7 @@ be_local_class(Matter_UI, { be_const_key_weak(show_commissioning_info, -1), be_const_closure(Matter_UI_show_commissioning_info_closure) }, { be_const_key_weak(page_part_ctl, 18), be_const_closure(Matter_UI_page_part_ctl_closure) }, { be_const_key_weak(show_fabric_info, -1), be_const_closure(Matter_UI_show_fabric_info_closure) }, - { be_const_key_weak(_CLASSES_TYPES, 4), be_nested_str_weak(_X7Crelay_X7Clight0_X7Clight1_X7Clight2_X7Clight3_X7Cshutter_X7Cshutter_X2Btilt_X7Ctemperature_X7Cpressure_X7Cilluminance_X7Chumidity_X7Coccupancy_X7Conoff_X7Ccontact) }, + { be_const_key_weak(_CLASSES_TYPES, 4), be_nested_str_weak(_X7Crelay_X7Clight0_X7Clight1_X7Clight2_X7Clight3_X7Cshutter_X7Cshutter_X2Btilt_X7Ctemperature_X7Cpressure_X7Cilluminance_X7Chumidity_X7Coccupancy_X7Conoff_X7Ccontact_X7C_X2Dvirtual_X7Cv_relay_X7Cv_light0_X7Cv_light1_X7Cv_light2_X7Cv_light3_X7Cv_temp_X7Cv_pressure_X7Cv_illuminance_X7Cv_humidity_X7Cv_contact) }, { be_const_key_weak(web_get_arg, -1), be_const_closure(Matter_UI_web_get_arg_closure) }, { be_const_key_weak(plugin_option, 5), be_const_closure(Matter_UI_plugin_option_closure) }, { be_const_key_weak(web_add_config_button, -1), be_const_closure(Matter_UI_web_add_config_button_closure) }, diff --git a/lib/libesp32/berry_tasmota/src/be_audio_opus_lib.c b/lib/libesp32/berry_tasmota/src/be_audio_opus_lib.c index c88143bb8..128736b09 100644 --- a/lib/libesp32/berry_tasmota/src/be_audio_opus_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_audio_opus_lib.c @@ -29,7 +29,7 @@ void *be_audio_opus_decoder_init_ntv(int freq, int channels) { return buf; } -int32_t be_audio_opus_decoder_init(struct bvm *vm) { +int be_audio_opus_decoder_init(struct bvm *vm) { return be_call_c_func(vm, (void*) &be_audio_opus_decoder_init_ntv, "+.p", "i[i]"); } @@ -38,13 +38,13 @@ void *be_audio_opus_decoder_deinit_ntv(OpusDecoder* buf) { if (buf) BE_EXPLICIT_FREE(buf); return NULL; } -int32_t be_audio_opus_decoder_deinit(struct bvm *vm) { +int be_audio_opus_decoder_deinit(struct bvm *vm) { return be_call_c_func(vm, (void*) &be_audio_opus_decoder_deinit_ntv, "", "."); } // decode(payload:bytes) -> pcm:bytes() -int32_t be_audio_opus_decoder_decode(struct bvm *vm) { +int be_audio_opus_decoder_decode(struct bvm *vm) { int32_t argc = be_top(vm); be_call_c_func(vm, NULL, NULL, ".(bytes)[ii]"); diff --git a/lib/libesp32/berry_tasmota/src/be_cron_class.cpp b/lib/libesp32/berry_tasmota/src/be_cron_class.cpp index 033dc81e7..d5daf03f1 100644 --- a/lib/libesp32/berry_tasmota/src/be_cron_class.cpp +++ b/lib/libesp32/berry_tasmota/src/be_cron_class.cpp @@ -21,7 +21,7 @@ static cron_expr* ccronexpr_init(struct bvm* vm, char* expr) { cron_parse_expr(expr, cron, &error); if (error) { - be_raise(vm, "value_error", error); // TODO any way to pass VM? + be_raise(vm, "value_error", error); } return cron; } diff --git a/lib/libesp32/berry_tasmota/src/be_display_lib.cpp b/lib/libesp32/berry_tasmota/src/be_display_lib.c similarity index 96% rename from lib/libesp32/berry_tasmota/src/be_display_lib.cpp rename to lib/libesp32/berry_tasmota/src/be_display_lib.c index acd0754fb..f1dbdad8c 100644 --- a/lib/libesp32/berry_tasmota/src/be_display_lib.cpp +++ b/lib/libesp32/berry_tasmota/src/be_display_lib.c @@ -12,7 +12,7 @@ extern int be_ntv_display_start(bvm *vm); extern int be_ntv_display_dimmer(bvm *vm); -extern bool be_ntv_display_started(void); +extern bbool be_ntv_display_started(void); BE_FUNC_CTYPE_DECLARE(be_ntv_display_started, "b", "") extern void be_ntv_display_touch_update(int32_t touches, int32_t raw_x, int32_t raw_y, int32_t gesture); BE_FUNC_CTYPE_DECLARE(be_ntv_display_touch_update, "", "iiii") diff --git a/lib/libesp32/berry_tasmota/src/be_gpio_lib.c b/lib/libesp32/berry_tasmota/src/be_gpio_lib.c index 592861b9c..e83347539 100644 --- a/lib/libesp32/berry_tasmota/src/be_gpio_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_gpio_lib.c @@ -15,6 +15,9 @@ extern int gp_pin_mode(bvm *vm); extern int gp_digital_write(bvm *vm); extern int gp_digital_read(bvm *vm); extern int gp_dac_voltage(bvm *vm); +extern int gp_counter_read(bvm *vm); +extern int gp_counter_set(bvm *vm); +extern int gp_counter_add(bvm *vm); extern int gp_pin_used(bvm *vm); extern int gp_pin(bvm *vm); @@ -31,6 +34,9 @@ module gpio (scope: global) { digital_write, func(gp_digital_write) digital_read, func(gp_digital_read) dac_voltage, func(gp_dac_voltage) + counter_read, func(gp_counter_read) + counter_set, func(gp_counter_set) + counter_add, func(gp_counter_add) pin_used, func(gp_pin_used) pin, func(gp_pin) diff --git a/lib/libesp32/berry_tasmota/src/be_i2s_audio_lib.c b/lib/libesp32/berry_tasmota/src/be_i2s_audio_lib.c new file mode 100644 index 000000000..b14794832 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/be_i2s_audio_lib.c @@ -0,0 +1,238 @@ +/******************************************************************** + * Tasmota I2S audio classes + * + * + *******************************************************************/ +#include "be_constobj.h" + +#ifdef USE_I2S +#ifdef USE_I2S_AUDIO_BERRY + +#include "be_mapping.h" + +extern int i2s_output_i2s_stop(bvm *vm); + +extern int i2s_generator_wav_init(bvm *vm); +extern int i2s_generator_wav_deinit(bvm *vm); +extern int i2s_generator_wav_begin(bvm *vm); +extern int i2s_generator_wav_loop(bvm *vm); +extern int i2s_generator_wav_stop(bvm *vm); +extern int i2s_generator_wav_isrunning(bvm *vm); + +extern int i2s_generator_mp3_init(bvm *vm); +extern int i2s_generator_mp3_deinit(bvm *vm); +extern int i2s_generator_mp3_begin(bvm *vm); +extern int i2s_generator_mp3_loop(bvm *vm); +extern int i2s_generator_mp3_stop(bvm *vm); +extern int i2s_generator_mp3_isrunning(bvm *vm); + +#ifdef USE_UFILESYS +extern int i2s_file_source_fs_init(bvm *vm); +extern int i2s_file_source_fs_deinit(bvm *vm); +#endif // USE_UFILESYS + + +// AudioOutputI2S.init() -> instance +extern void* be_audio_output_i2s_init(void); +BE_FUNC_CTYPE_DECLARE(be_audio_output_i2s_init, "+.p", ""); + +// AudioOutputI2S.deinit()-> void +extern void* be_audio_output_i2s_deinit(void* instance); +BE_FUNC_CTYPE_DECLARE(be_audio_output_i2s_deinit, "", "."); + +// AudioOutput.begin() -> bool +extern int be_audio_output_i2s_begin(void* out); +BE_FUNC_CTYPE_DECLARE(be_audio_output_i2s_begin, "b", "."); + +// AudioOutput.stop() -> bool +extern int be_audio_output_i2s_stop(void* out); +BE_FUNC_CTYPE_DECLARE(be_audio_output_i2s_stop, "b", "."); + +// AudioOutput.flush() -> bool +extern void be_audio_output_i2s_flush(void* out); +BE_FUNC_CTYPE_DECLARE(be_audio_output_i2s_flush, "", "."); + +// AudioOutput.set_rate(rate_hz:int) -> bool +extern int be_audio_output_set_rate(void* out, int hz); +BE_FUNC_CTYPE_DECLARE(be_audio_output_set_rate, "b", ".i"); + +// AudioOutput.set_bits_per_sample(bits_per_sample:int) -> bool +extern int be_audio_output_set_bits_per_sample(void* out, int bps); +BE_FUNC_CTYPE_DECLARE(be_audio_output_set_bits_per_sample, "b", ".i"); + +// AudioOutput.set_channels(channels:int) -> bool +extern int be_audio_output_set_channels(void* out, int channels); +BE_FUNC_CTYPE_DECLARE(be_audio_output_set_channels, "b", ".i"); + +// AudioOutput.set_gain(gain:real) -> bool +extern int be_audio_output_set_gain(void* out, float gain); +BE_FUNC_CTYPE_DECLARE(be_audio_output_set_gain, "b", ".f"); + + + +// AudioOutput.consume_mono(bytes) -> int +extern int be_audio_output_consume_mono(void* out, uint16_t *pcm, int bytes_len, int index); +BE_FUNC_CTYPE_DECLARE(be_audio_output_consume_mono, "i", ".(bytes)~i"); + +// AudioOutput.consume_stereo(bytes) -> int +extern int be_audio_output_consume_stereo(void* out, uint16_t *pcm, int bytes_len, int index); +BE_FUNC_CTYPE_DECLARE(be_audio_output_consume_stereo, "i", ".(bytes)~i"); + +// AudioOutput.consume_silence() -> int, push silence frames +extern int be_audio_output_consume_silence(void* out); +BE_FUNC_CTYPE_DECLARE(be_audio_output_consume_silence, "i", "."); + +// AudioOutputI2S.set_lsb_justified(gain:real) -> nil +extern int i2s_output_i2s_set_lsb_justified(void* out, bbool lsbJustified); +BE_FUNC_CTYPE_DECLARE(i2s_output_i2s_set_lsb_justified, "b", ".b"); + +// ---------------------------------------------------------------------- +// Audio Input I2S + +// AudioInputI2S.init() -> instance +extern void* be_audio_input_i2s_init(void); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_init, "+.p", ""); + +// AudioInputI2S.deinit()-> void +extern void* be_audio_input_i2s_deinit(void* instance); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_deinit, "", "."); + +// AudioInputI2S.begin() -> bool +extern int be_audio_input_i2s_begin(bvm *vm, void* in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_begin, "b", "@."); + +// AudioInputI2S.stop() -> bool +extern int be_audio_input_i2s_stop(void* in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_stop, "b", "."); + +extern int be_audio_input_i2s_read_bytes(bvm *vm); + +// AudioInputI2S.set_gain(gain:real) -> bool +extern int be_audio_input_set_gain(void* in, float gain); +BE_FUNC_CTYPE_DECLARE(be_audio_input_set_gain, "b", ".f"); + +// AudioInputI2S.get_rate() -> int +extern int be_audio_input_i2s_get_rate(void* in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_get_rate, "i", "."); + +// AudioInputI2S.get_bits_per_sample() -> int +extern int be_audio_input_i2s_get_bits_per_sample(void* in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_get_bits_per_sample, "i", "."); + +// AudioInputI2S.get_channels() -> int +extern int be_audio_input_i2s_get_channels(void* in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_get_channels, "i", "."); + +// AudioInputI2S.get_gain() -> real +extern float be_audio_input_i2s_get_gain(void* in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_get_gain, "f", "."); + +// AudioInputI2S.get_dc_offset() -> float +extern int be_audio_input_i2s_get_dc_offset(void* in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_get_dc_offset, "i", "."); + +// AudioInputI2S.get_lowpass_alpha() -> float +extern float be_audio_input_i2s_get_lowpass_alpha(void* in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_get_lowpass_alpha, "f", "."); + +// AudioInputI2S.set_lowpass_alpha(alpha:float) -> bool +extern int be_audio_input_i2s_set_lowpass_alpha(void* in, float alpha); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_set_lowpass_alpha, "b", ".f"); + +// AudioInputI2S.rms_bytes(int16*:bytes) -> int +extern int be_audio_input_i2s_rms_bytes(void *buf, size_t len); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_rms_bytes, "i", "(bytes)~"); + +// AudioInputI2S.sqrt_fast(int) -> int +extern int be_audio_input_i2s_sqrt_fast(int in); +BE_FUNC_CTYPE_DECLARE(be_audio_input_i2s_sqrt_fast, "i", "i"); + +#include "be_fixed_be_class_AudioOutputI2S.h" +#include "be_fixed_be_class_AudioGenerator.h" +#include "be_fixed_be_class_AudioGeneratorWAV.h" +#include "be_fixed_be_class_AudioGeneratorMP3.h" +#include "be_fixed_be_class_AudioFileSource.h" +#include "be_fixed_be_class_AudioFileSourceFS.h" +#include "be_fixed_be_class_AudioInputI2S.h" + +/* @const_object_info_begin + +class be_class_AudioGenerator (scope: global, name: AudioGenerator, strings: weak) { + .p, var +} + +class be_class_AudioFileSource (scope: global, name: AudioFileSource, strings: weak) { + .p, var +} + +class be_class_AudioOutputI2S (scope: global, name: AudioOutputI2S, strings: weak) { + .p, var + init, ctype_func(be_audio_output_i2s_init) + deinit, ctype_func(be_audio_output_i2s_deinit) + + begin, ctype_func(be_audio_output_i2s_begin) + stop, ctype_func(be_audio_output_i2s_stop) + flush, ctype_func(be_audio_output_i2s_flush) + + consume_mono, ctype_func(be_audio_output_consume_mono) + consume_stereo, ctype_func(be_audio_output_consume_stereo) + consume_silence, ctype_func(be_audio_output_consume_silence) + + set_rate, ctype_func(be_audio_output_set_rate) + set_bits_per_sample, ctype_func(be_audio_output_set_bits_per_sample) + set_channels, ctype_func(be_audio_output_set_channels) + set_gain, ctype_func(be_audio_output_set_gain) +} + +class be_class_AudioGeneratorWAV (scope: global, name: AudioGeneratorWAV, super: be_class_AudioGenerator, strings: weak) { + init, func(i2s_generator_wav_init) + deinit, func(i2s_generator_wav_deinit) + begin, func(i2s_generator_wav_begin) + loop, func(i2s_generator_wav_loop) + stop, func(i2s_generator_wav_stop) + isrunning, func(i2s_generator_wav_isrunning) +} + +class be_class_AudioGeneratorMP3 (scope: global, name: AudioGeneratorMP3, super: be_class_AudioGenerator, strings: weak) { + init, func(i2s_generator_mp3_init) + deinit, func(i2s_generator_mp3_deinit) + begin, func(i2s_generator_mp3_begin) + loop, func(i2s_generator_mp3_loop) + stop, func(i2s_generator_mp3_stop) + isrunning, func(i2s_generator_mp3_isrunning) +} + +class be_class_AudioFileSourceFS (scope: global, name: AudioFileSourceFS, super: be_class_AudioFileSource, strings: weak) { + init, func(i2s_file_source_fs_init) + deinit, func(i2s_file_source_fs_deinit) +} + +class be_class_AudioInputI2S (scope: global, name: AudioInputI2S, strings: weak) { + .p, var + peak, var + init, ctype_func(be_audio_input_i2s_init) + deinit, ctype_func(be_audio_input_i2s_deinit) + + begin, ctype_func(be_audio_input_i2s_begin) + stop, ctype_func(be_audio_input_i2s_stop) + read_bytes, func(be_audio_input_i2s_read_bytes) + + get_rate, ctype_func(be_audio_input_i2s_get_rate) + get_bits_per_sample, ctype_func(be_audio_input_i2s_get_bits_per_sample) + get_channels, ctype_func(be_audio_input_i2s_get_channels) + get_gain, ctype_func(be_audio_input_i2s_get_gain) + + set_gain, ctype_func(be_audio_input_set_gain) + get_dc_offset, ctype_func(be_audio_input_i2s_get_dc_offset) + + get_lowpass_alpha, ctype_func(be_audio_input_i2s_get_lowpass_alpha) + set_lowpass_alpha, ctype_func(be_audio_input_i2s_set_lowpass_alpha) + + rms_bytes, static_ctype_func(be_audio_input_i2s_rms_bytes) + sqrt_fast, static_ctype_func(be_audio_input_i2s_sqrt_fast) +} + +@const_object_info_end */ + +#endif // USE_I2S_AUDIO_BERRY +#endif // USE_I2S \ No newline at end of file diff --git a/lib/libesp32/berry_tasmota/src/be_i2s_audio_lib.cpp b/lib/libesp32/berry_tasmota/src/be_i2s_audio_lib.cpp deleted file mode 100644 index 40322c08f..000000000 --- a/lib/libesp32/berry_tasmota/src/be_i2s_audio_lib.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/******************************************************************** - * Tasmota I2S audio classes - * - * - *******************************************************************/ -#include "be_constobj.h" - -#ifdef USE_I2S -#ifdef USE_I2S_AUDIO_BERRY - -#include "be_mapping.h" -#include "AudioOutput.h" - -extern "C" void berry_log_C(const char * berry_buf, ...); - -extern "C" { - extern int i2s_output_i2s_init(bvm *vm); - extern int i2s_output_i2s_deinit(bvm *vm); - extern int i2s_output_i2s_stop(bvm *vm); - - extern int i2s_generator_wav_init(bvm *vm); - extern int i2s_generator_wav_deinit(bvm *vm); - extern int i2s_generator_wav_begin(bvm *vm); - extern int i2s_generator_wav_loop(bvm *vm); - extern int i2s_generator_wav_stop(bvm *vm); - extern int i2s_generator_wav_isrunning(bvm *vm); - - extern int i2s_generator_mp3_init(bvm *vm); - extern int i2s_generator_mp3_deinit(bvm *vm); - extern int i2s_generator_mp3_begin(bvm *vm); - extern int i2s_generator_mp3_loop(bvm *vm); - extern int i2s_generator_mp3_stop(bvm *vm); - extern int i2s_generator_mp3_isrunning(bvm *vm); - -#ifdef USE_UFILESYS - extern int i2s_file_source_fs_init(bvm *vm); - extern int i2s_file_source_fs_deinit(bvm *vm); -#endif // USE_UFILESYS -} - -// AudioOutput.set_rate(rate_hz:int) -> bool -AudioOutput* be_audio_output_init(void) { - return new AudioOutput(); -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_init, "+.p", ""); - -// AudioOutput.set_rate(rate_hz:int) -> bool -int be_audio_output_set_rate(AudioOutput* out, int hz) { - return out->SetRate(hz); -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_set_rate, "b", ".i"); - -// AudioOutput.set_bits_per_sample(bits_per_sample:int) -> bool -int be_audio_output_set_bits_per_sample(AudioOutput* out, int bps) { - return out->SetBitsPerSample(bps); -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_set_bits_per_sample, "b", ".i"); - -// AudioOutput.set_channels(channels:int) -> bool -int be_audio_output_set_channels(AudioOutput* out, int channels) { - return out->SetChannels(channels); -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_set_channels, "b", ".i"); - -// AudioOutput.set_gain(gain:real) -> bool -int be_audio_output_set_gain(AudioOutput* out, float gain) { - return out->SetGain(gain); -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_set_gain, "b", ".f"); - -// AudioOutput.begin() -> bool -int be_audio_output_begin(AudioOutput* out) { - return out->begin(); -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_begin, "b", "."); - -// AudioOutput.stop() -> bool -int be_audio_output_stop(AudioOutput* out) { - return out->stop(); -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_stop, "b", "."); - -// AudioOutput.flush() -> bool -void be_audio_output_flush(AudioOutput* out) { - out->flush(); -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_flush, "", "."); - -// AudioOutput.consume_mono(bytes) -> int -int be_audio_output_consume_mono(AudioOutput* out, uint16_t *pcm, int bytes_len, int index) { - int pcm_len = bytes_len / 2; - int n; - // berry_log_C("be_audio_output_consume_mono_ntv out=%p pcm=%p bytes_len=%i index=%i", out, pcm, bytes_len, index); - for (n = 0; index + n < pcm_len; n++) { - int16_t ms[2]; - ms[AudioOutput::LEFTCHANNEL] = ms[AudioOutput::RIGHTCHANNEL] = pcm[index + n]; - if (!out->ConsumeSample(ms)) { break; } - } - return n; -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_consume_mono, "i", ".(bytes)~i"); - -// AudioOutput.consume_stereo(bytes) -> int -int be_audio_output_consume_stereo(AudioOutput* out, uint16_t *pcm, int bytes_len, int index) { - int pcm_len = bytes_len / 4; // 2 samples LEFT+RIGHT of 2 bytes each - int n; - // berry_log_C("be_audio_output_consume_stereo_ntv out=%p pcm=%p bytes_len=%i index=%i", out, pcm, bytes_len, index); - for (n = 0; index + n < pcm_len; n++) { - int16_t ms[2]; - ms[AudioOutput::LEFTCHANNEL] = pcm[index + n + n]; - ms[AudioOutput::RIGHTCHANNEL] = pcm[index + n + n + 1]; - if (!out->ConsumeSample(ms)) { break; } - } - return n; -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_consume_stereo, "i", ".(bytes)~i"); - -// AudioOutput.consume_silence() -> int, push silence frames -int be_audio_output_consume_silence(AudioOutput* out) { - int n = 0; - int16_t ms[2] = {0, 0}; - while (true) { - if (!out->ConsumeSample(ms)) { break; } - n++; - } - return n; -} -BE_FUNC_CTYPE_DECLARE(be_audio_output_consume_silence, "i", "."); - -#include "AudioOutputI2S.h" - -// AudioOutputI2S.set_lsb_justified(gain:real) -> nil -int i2s_output_i2s_set_lsb_justified(AudioOutputI2S* out, bbool lsbJustified) { - return out->SetLsbJustified(lsbJustified); -} -BE_FUNC_CTYPE_DECLARE(i2s_output_i2s_set_lsb_justified, "b", ".b"); - -extern "C" { - -#include "be_fixed_be_class_AudioOutput.h" -#include "be_fixed_be_class_AudioOutputI2S.h" -#include "be_fixed_be_class_AudioGenerator.h" -#include "be_fixed_be_class_AudioGeneratorWAV.h" -#include "be_fixed_be_class_AudioGeneratorMP3.h" -#include "be_fixed_be_class_AudioFileSource.h" -#include "be_fixed_be_class_AudioFileSourceFS.h" - -} -/* @const_object_info_begin - -class be_class_AudioOutput (scope: global, name: AudioOutput, strings: weak) { - .p, var - init, ctype_func(be_audio_output_init) - - begin, ctype_func(be_audio_output_begin) - stop, ctype_func(be_audio_output_stop) - flush, ctype_func(be_audio_output_flush) - - consume_mono, ctype_func(be_audio_output_consume_mono) - consume_stereo, ctype_func(be_audio_output_consume_stereo) - consume_silence, ctype_func(be_audio_output_consume_silence) - - set_rate, ctype_func(be_audio_output_set_rate) - set_bits_per_sample, ctype_func(be_audio_output_set_bits_per_sample) - set_channels, ctype_func(be_audio_output_set_channels) - set_gain, ctype_func(be_audio_output_set_gain) -} - -class be_class_AudioGenerator (scope: global, name: AudioGenerator, strings: weak) { - .p, var -} - -class be_class_AudioFileSource (scope: global, name: AudioFileSource, strings: weak) { - .p, var -} - -class be_class_AudioOutputI2S (scope: global, name: AudioOutputI2S, super: be_class_AudioOutput, strings: weak) { - EXTERNAL_I2S, int(AudioOutputI2S::EXTERNAL_I2S) - INTERNAL_DAC, int(AudioOutputI2S::INTERNAL_DAC) - INTERNAL_PDM, int(AudioOutputI2S::INTERNAL_PDM) - - init, func(i2s_output_i2s_init) - deinit, func(i2s_output_i2s_deinit) - stop, func(i2s_output_i2s_stop) - - set_lsb_justified, ctype_func(i2s_output_i2s_set_lsb_justified) -} - -class be_class_AudioGeneratorWAV (scope: global, name: AudioGeneratorWAV, super: be_class_AudioGenerator, strings: weak) { - init, func(i2s_generator_wav_init) - deinit, func(i2s_generator_wav_deinit) - begin, func(i2s_generator_wav_begin) - loop, func(i2s_generator_wav_loop) - stop, func(i2s_generator_wav_stop) - isrunning, func(i2s_generator_wav_isrunning) -} - -class be_class_AudioGeneratorMP3 (scope: global, name: AudioGeneratorMP3, super: be_class_AudioGenerator, strings: weak) { - init, func(i2s_generator_mp3_init) - deinit, func(i2s_generator_mp3_deinit) - begin, func(i2s_generator_mp3_begin) - loop, func(i2s_generator_mp3_loop) - stop, func(i2s_generator_mp3_stop) - isrunning, func(i2s_generator_mp3_isrunning) -} - -class be_class_AudioFileSourceFS (scope: global, name: AudioFileSourceFS, super: be_class_AudioFileSource, strings: weak) { - init, func(i2s_file_source_fs_init) - deinit, func(i2s_file_source_fs_deinit) -} - -@const_object_info_end */ - -#endif // USE_I2S_AUDIO_BERRY -#endif // USE_I2S \ No newline at end of file diff --git a/lib/libesp32/berry_tasmota/src/be_light_lib.c b/lib/libesp32/berry_tasmota/src/be_light_lib.c index cb0393411..a0153e10c 100644 --- a/lib/libesp32/berry_tasmota/src/be_light_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_light_lib.c @@ -4,6 +4,7 @@ * To use: `import tasmota` *******************************************************************/ #include "be_constobj.h" +#include "be_mapping.h" #ifdef USE_LIGHT extern int l_getlight(bvm *vm); @@ -13,6 +14,10 @@ extern int l_gamma8(bvm *vm); extern int l_gamma10(bvm *vm); extern int l_rev_gamma10(bvm *vm); +// light.set_bri(bri:int) -> nil +extern void l_set_bri(int bri); +BE_FUNC_CTYPE_DECLARE(l_set_bri, "", "i"); + /* @const_object_info_begin module light (scope: global) { get, func(l_getlight) @@ -21,6 +26,8 @@ module light (scope: global) { gamma8, func(l_gamma8) gamma10, func(l_gamma10) reverse_gamma10, func(l_rev_gamma10) + + set_bri, ctype_func(l_set_bri) } @const_object_info_end */ #include "be_fixed_light.h" diff --git a/lib/libesp32/berry_tasmota/src/be_light_state_class.c b/lib/libesp32/berry_tasmota/src/be_light_state_class.c new file mode 100644 index 000000000..fa68e5150 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/be_light_state_class.c @@ -0,0 +1,115 @@ +/******************************************************************** + * Light_state class - abstract light state + * + * Handles all states and events for a virtual light. + * Can be eventually subclassed to handle a physical light. + * + *******************************************************************/ +#ifdef USE_LIGHT + +#include "be_constobj.h" +#include "be_mapping.h" + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +extern void * ls_init(int32_t type); BE_FUNC_CTYPE_DECLARE(ls_init, "+_p", "i") +extern void ls_set_rgb(void* l, int32_t r, int32_t g, int32_t b); BE_FUNC_CTYPE_DECLARE(ls_set_rgb, "", ".iii") +extern void ls_set_huesat(void* l, int32_t hue, int32_t sat); BE_FUNC_CTYPE_DECLARE(ls_set_huesat, "", ".ii") +extern void ls_set_hue16sat(void* l, int32_t hue16, int32_t sat); BE_FUNC_CTYPE_DECLARE(ls_set_hue16sat, "", ".ii") +extern void ls_set_ct(void* l, int32_t ct); BE_FUNC_CTYPE_DECLARE(ls_set_ct, "", ".i") +extern void ls_set_bri(void* l, int32_t bri); BE_FUNC_CTYPE_DECLARE(ls_set_bri, "", ".i") +extern void ls_set_xy(void* l, float x, float y); BE_FUNC_CTYPE_DECLARE(ls_set_xy, "", ".ff") +extern int32_t ls_r(void* l); BE_VAR_CTYPE_DECLARE(ls_r, "i"); +extern int32_t ls_g(void* l); BE_VAR_CTYPE_DECLARE(ls_g, "i"); +extern int32_t ls_b(void* l); BE_VAR_CTYPE_DECLARE(ls_b, "i"); +extern float ls_x(void* l); BE_VAR_CTYPE_DECLARE(ls_x, "f"); +extern float ls_y(void* l); BE_VAR_CTYPE_DECLARE(ls_y, "f"); +extern int32_t ls_hue(void* l); BE_VAR_CTYPE_DECLARE(ls_hue, "i"); +extern int32_t ls_hue16(void* l); BE_VAR_CTYPE_DECLARE(ls_hue16, "i"); +extern int32_t ls_sat(void* l); BE_VAR_CTYPE_DECLARE(ls_sat, "i"); +extern int32_t ls_bri(void* l); BE_VAR_CTYPE_DECLARE(ls_bri, "i"); +extern int32_t ls_ct(void* l); BE_VAR_CTYPE_DECLARE(ls_ct, "i"); +extern int32_t ls_type(void* l); BE_VAR_CTYPE_DECLARE(ls_type, "i"); + +extern int32_t ls_mode_rgb(void* l); BE_VAR_CTYPE_DECLARE(ls_mode_rgb, "b"); +extern int32_t ls_mode_ct(void* l); BE_VAR_CTYPE_DECLARE(ls_mode_ct, "b"); +extern void ls_set_mode_rgb(void* l); BE_FUNC_CTYPE_DECLARE(ls_set_mode_rgb, "", "."); +extern void ls_set_mode_ct(void* l); BE_FUNC_CTYPE_DECLARE(ls_set_mode_ct, "", "."); +extern int32_t ls_get_power(void* l); BE_VAR_CTYPE_DECLARE(ls_get_power, "b"); +extern void ls_set_power(void* l, int32_t pow); BE_FUNC_CTYPE_DECLARE(ls_set_power, "", ".b"); +extern int32_t ls_reachable(void* p); BE_VAR_CTYPE_DECLARE(ls_reachable, "b"); +extern void ls_set_reachable(void* l, int32_t pow); BE_FUNC_CTYPE_DECLARE(ls_set_reachable, "", ".b"); + +extern void ls_signal_change(void) {} BE_FUNC_CTYPE_DECLARE(ls_signal_change, "", "."); + +extern int32_t ls_gamma8(int32_t val); BE_FUNC_CTYPE_DECLARE(ls_gamma8, "i", "i") +extern int32_t ls_gamma10(int32_t val); BE_FUNC_CTYPE_DECLARE(ls_gamma10, "i", "i") +extern int32_t ls_rev_gamma10(int32_t val); BE_FUNC_CTYPE_DECLARE(ls_rev_gamma10, "i", "i") + +// moved to constants array +const be_const_member_t light_state_members[] = { + { ">b", be_ctype(ls_b) }, + { ">bri", be_ctype(ls_bri) }, + { ">ct", be_ctype(ls_ct) }, + { ">g", be_ctype(ls_g) }, + { ">hue", be_ctype(ls_hue) }, + { ">hue16", be_ctype(ls_hue16) }, + { ">mode_ct", be_ctype(ls_mode_ct) }, + { ">mode_rgb", be_ctype(ls_mode_rgb) }, + { ">power", be_ctype(ls_get_power) }, + { ">r", be_ctype(ls_r) }, + { ">reachable", be_ctype(ls_reachable) }, + { ">sat", be_ctype(ls_sat) }, + { ">type", be_ctype(ls_type) }, + { ">x", be_ctype(ls_x) }, + { ">y", be_ctype(ls_y) }, +}; + +extern int light_state_get(bvm *vm); + +static int light_state_member(bvm *vm) { + be_const_class_member_raise(vm, light_state_members, ARRAY_SIZE(light_state_members)); + be_return(vm); +} + +#include "be_fixed_be_class_light_state.h" + +/* @const_object_info_begin +class be_class_light_state (scope: global, name: light_state) { + RELAY, int(0) + DIMMER, int(1) + CT, int(2) + RGB, int(3) + RGBW, int(4) + RGBCT, int(5) + + _p, var + init, ctype_func(ls_init) + + member, func(light_state_member) + + set_rgb, ctype_func(ls_set_rgb) + set_huesat, ctype_func(ls_set_huesat) + set_hue16sat, ctype_func(ls_set_hue16sat) + set_xy, ctype_func(ls_set_xy) + set_ct, ctype_func(ls_set_ct) + set_bri, ctype_func(ls_set_bri) + + set_mode_rgb, ctype_func(ls_set_mode_rgb) + set_mode_ct, ctype_func(ls_set_mode_ct) + set_power, ctype_func(ls_set_power) + set_reachable, ctype_func(ls_set_reachable) + + get, func(light_state_get) + + signal_change, ctype_func(ls_signal_change) + + gamma8, static_ctype_func(ls_gamma8) + gamma10, static_ctype_func(ls_gamma10) + reverse_gamma10, static_ctype_func(ls_rev_gamma10) +} +@const_object_info_end */ + +#endif // USE_LIGHT diff --git a/lib/libesp32/berry_tasmota/src/be_light_state_class.cpp b/lib/libesp32/berry_tasmota/src/be_light_state_class.cpp deleted file mode 100644 index 7d81ce686..000000000 --- a/lib/libesp32/berry_tasmota/src/be_light_state_class.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************************** - * Light_state class - abstract light state - * - * Handles all states and events for a virtual light. - * Can be eventually subclassed to handle a physical light. - * - *******************************************************************/ -#ifdef USE_LIGHT - -#include "be_constobj.h" -#include "be_mapping.h" - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -extern void * ls_init(int32_t type); BE_FUNC_CTYPE_DECLARE(ls_init, "+_p", "i") -extern void ls_set_rgb(class LightStateClass* l, int32_t r, int32_t g, int32_t b); BE_FUNC_CTYPE_DECLARE(ls_set_rgb, "", ".iii") -extern void ls_set_huesat(class LightStateClass* l, int32_t hue, int32_t sat); BE_FUNC_CTYPE_DECLARE(ls_set_huesat, "", ".ii") -extern void ls_set_hue16sat(class LightStateClass* l, int32_t hue16, int32_t sat); BE_FUNC_CTYPE_DECLARE(ls_set_hue16sat, "", ".ii") -extern void ls_set_ct(class LightStateClass* l, int32_t ct); BE_FUNC_CTYPE_DECLARE(ls_set_ct, "", ".i") -extern void ls_set_bri(class LightStateClass* l, int32_t bri); BE_FUNC_CTYPE_DECLARE(ls_set_bri, "", ".i") -extern void ls_set_xy(class LightStateClass* l, float x, float y); BE_FUNC_CTYPE_DECLARE(ls_set_xy, "", ".ff") -extern int32_t ls_r(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_r, "i"); -extern int32_t ls_g(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_g, "i"); -extern int32_t ls_b(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_b, "i"); -extern float ls_x(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_x, "f"); -extern float ls_y(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_y, "f"); -extern int32_t ls_hue(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_hue, "i"); -extern int32_t ls_hue16(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_hue16, "i"); -extern int32_t ls_sat(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_sat, "i"); -extern int32_t ls_bri(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_bri, "i"); -extern int32_t ls_ct(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_ct, "i"); -extern int32_t ls_type(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_type, "i"); - -extern int32_t ls_mode_rgb(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_mode_rgb, "b"); -extern int32_t ls_mode_ct(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_mode_ct, "b"); -extern void ls_set_mode_rgb(class LightStateClass* l); BE_FUNC_CTYPE_DECLARE(ls_set_mode_rgb, "", "."); -extern void ls_set_mode_ct(class LightStateClass* l); BE_FUNC_CTYPE_DECLARE(ls_set_mode_ct, "", "."); -extern int32_t ls_get_power(class LightStateClass* l); BE_VAR_CTYPE_DECLARE(ls_get_power, "b"); -extern void ls_set_power(class LightStateClass* l, int32_t pow); BE_FUNC_CTYPE_DECLARE(ls_set_power, "", ".b"); -extern int32_t ls_reachable(class LightStateClass* p); BE_VAR_CTYPE_DECLARE(ls_reachable, "b"); -extern void ls_set_reachable(class LightStateClass* l, int32_t pow); BE_FUNC_CTYPE_DECLARE(ls_set_reachable, "", ".b"); - -extern void ls_signal_change(void) {} BE_FUNC_CTYPE_DECLARE(ls_signal_change, "", "."); - -extern int32_t ls_gamma8(int32_t val); BE_FUNC_CTYPE_DECLARE(ls_gamma8, "i", "i") -extern int32_t ls_gamma10(int32_t val); BE_FUNC_CTYPE_DECLARE(ls_gamma10, "i", "i") -extern int32_t ls_rev_gamma10(int32_t val); BE_FUNC_CTYPE_DECLARE(ls_rev_gamma10, "i", "i") - -// moved to constants array -const be_const_member_t light_state_members[] = { - { ">b", be_ctype(ls_b) }, - { ">bri", be_ctype(ls_bri) }, - { ">ct", be_ctype(ls_ct) }, - { ">g", be_ctype(ls_g) }, - { ">hue", be_ctype(ls_hue) }, - { ">hue16", be_ctype(ls_hue16) }, - { ">mode_ct", be_ctype(ls_mode_ct) }, - { ">mode_rgb", be_ctype(ls_mode_rgb) }, - { ">power", be_ctype(ls_get_power) }, - { ">r", be_ctype(ls_r) }, - { ">reachable", be_ctype(ls_reachable) }, - { ">sat", be_ctype(ls_sat) }, - { ">type", be_ctype(ls_type) }, - { ">x", be_ctype(ls_x) }, - { ">y", be_ctype(ls_y) }, -}; - -extern "C" int light_state_get(bvm *vm); - -static int light_state_member(bvm *vm) { - be_const_class_member_raise(vm, light_state_members, ARRAY_SIZE(light_state_members)); - be_return(vm); -} - -#include "be_fixed_be_class_light_state.h" - -extern "C" void be_load_light_state_class(bvm *vm) { - be_pushntvclass(vm, &be_class_light_state); - be_setglobal(vm, "light_state"); - be_pop(vm, 1); -} - -/* @const_object_info_begin -class be_class_light_state (scope: global, name: light_state) { - RELAY, int(0) - DIMMER, int(1) - CT, int(2) - RGB, int(3) - RGBW, int(4) - RGBCT, int(5) - - _p, var - init, ctype_func(ls_init) - - member, func(light_state_member) - - set_rgb, ctype_func(ls_set_rgb) - set_huesat, ctype_func(ls_set_huesat) - set_hue16sat, ctype_func(ls_set_hue16sat) - set_xy, ctype_func(ls_set_xy) - set_ct, ctype_func(ls_set_ct) - set_bri, ctype_func(ls_set_bri) - - set_mode_rgb, ctype_func(ls_set_mode_rgb) - set_mode_ct, ctype_func(ls_set_mode_ct) - set_power, ctype_func(ls_set_power) - set_reachable, ctype_func(ls_set_reachable) - - get, func(light_state_get) - - signal_change, ctype_func(ls_signal_change) - - gamma8, static_ctype_func(ls_gamma8) - gamma10, static_ctype_func(ls_gamma10) - reverse_gamma10, static_ctype_func(ls_rev_gamma10) -} -@const_object_info_end */ - -#endif // USE_LIGHT diff --git a/lib/libesp32/berry_tasmota/src/be_mdns_module.c b/lib/libesp32/berry_tasmota/src/be_mdns_module.c new file mode 100644 index 000000000..19bc1ac84 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/be_mdns_module.c @@ -0,0 +1,45 @@ +/******************************************************************** + * Berry module `mdns` + * + * To use: `import mdns` + * + * MDNS support + *******************************************************************/ +#include "be_constobj.h" +#include "be_mapping.h" +#include "be_mem.h" + +#ifdef USE_DISCOVERY + +extern void m_mdns_start(struct bvm *vm, const char* hostname); +BE_FUNC_CTYPE_DECLARE(m_mdns_start, "", "@[s]") + +extern void m_mdns_stop(void); +BE_FUNC_CTYPE_DECLARE(m_mdns_stop, "", "") + +extern void m_mdns_set_hostname(struct bvm *vm, const char * hostname); +BE_FUNC_CTYPE_DECLARE(m_mdns_set_hostname, "", "@s") + +extern int m_mdns_add_service(struct bvm *vm); +extern int m_mdns_remove_service(struct bvm *vm); +extern int m_dns_add_subtype(struct bvm *vm); +extern int m_dns_add_hostname(struct bvm *vm); +extern int m_dns_find_service(struct bvm *vm); + +/* @const_object_info_begin +module mdns (scope: global) { + start, ctype_func(m_mdns_start) + stop, ctype_func(m_mdns_stop) + set_hostname, ctype_func(m_mdns_set_hostname) + add_service, func(m_mdns_add_service) + add_hostname, func(m_dns_add_hostname) + add_subtype, func(m_dns_add_subtype) + remove_service, func(m_mdns_remove_service) + + // querying + find_service, func(m_dns_find_service) +} +@const_object_info_end */ +#include "be_fixed_mdns.h" + +#endif // USE_DISCOVERY \ No newline at end of file diff --git a/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp b/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp deleted file mode 100644 index aa7629519..000000000 --- a/lib/libesp32/berry_tasmota/src/be_mdns_module.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/******************************************************************** - * Berry module `mdns` - * - * To use: `import mdns` - * - * MDNS support - *******************************************************************/ -#include "be_constobj.h" -#include "be_mapping.h" -#include "be_mem.h" - -#ifdef USE_DISCOVERY -#include "mdns.h" -#include -#include "IPAddress.h" - -// -// `mdsn.start([hostname:string]) -> nil` -// start or restart mdns, specify hostname or use tasmota.hostname() if none provided (default) -extern char* NetworkHostname(void); -static void m_mdns_start(struct bvm *vm, const char* hostname) { - esp_err_t err = mdns_init(); - if (err != ESP_OK) { - be_raisef(vm, "internal_error", "could not initialize mdns err=%i", err); - } - if (hostname == NULL) { - hostname = NetworkHostname(); // revert to default hostname if none is specified - } - err = mdns_hostname_set(hostname); - if (err != ESP_OK) { - be_raisef(vm, "internal_error", "could not set hostname err=%i", err); - } -} -BE_FUNC_CTYPE_DECLARE(m_mdns_start, "", "@[s]") - -// -// `msdn.stop() -> nil` -// free all mdns resources -static void m_mdns_stop(void) { - mdns_free(); -} -BE_FUNC_CTYPE_DECLARE(m_mdns_stop, "", "") - -// -// `mdns.set_hostname(hostname:string) -> nil` -// change the hostname -static void m_mdns_set_hostname(struct bvm *vm, const char * hostname) { - esp_err_t err = mdns_hostname_set(hostname); - if (err != ESP_OK) { - be_raisef(vm, "internal_error", "mdns set_hostname err=%i", err); - } -} -BE_FUNC_CTYPE_DECLARE(m_mdns_set_hostname, "", "@s") - -// -// `mdns.add_service(service:string, proto:string, port:int, txt:map [, instance:string, hostname:string]) -> nil` -// -// add a service declaration using the current hostname as instance name, and specify TXT fields as a `map` -// -// Test: -// import mdns mdns.add_service("_arduino","_tcp",1111, {"board":"tasmota", "tcp_check":"no", "ssh_upload":"no", "auth_upload":"no"}) -// -// import mdns mdns.add_service("_matterc","_udp", 5540, {"VP":"65521+32768", "SII":5000, "SAI":300, "T":1, "D":3840, "CM":1, "PH":33, "PI":""}) -static int32_t m_mdns_add_service(struct bvm *vm) { - int32_t top = be_top(vm); - if (top >= 3 && be_isstring(vm, 1) && be_isstring(vm, 2) && be_isint(vm, 3)) { - const char* service_type = be_tostring(vm, 1); - const char* proto = be_tostring(vm, 2); - uint16_t port = be_toint(vm, 3); - const char * instance = nullptr; - const char * hostname = nullptr; - if (top >= 5 && be_isstring(vm, 5)) { - instance = be_tostring(vm, 5); - } - if (top >= 6 && be_isstring(vm, 6)) { - hostname = be_tostring(vm, 6); - } - - mdns_txt_item_t * txt_items = NULL; - int32_t txt_num = 0; - if (top >= 4 && be_ismapinstance(vm, 4)) { - // parse txt map - be_getmember(vm, 4, ".p"); - int32_t map_len = be_data_size(vm, -1); - if (map_len > 0) { - uint32_t i= 0; - txt_items = (mdns_txt_item_t*) be_os_malloc(sizeof(mdns_txt_item_t) * map_len); - if (txt_items != NULL) { - be_pushiter(vm, -1); /* map iterator use 1 register */ - while (be_iter_hasnext(vm, -2) && i < map_len) { - be_iter_next(vm, -2); - const char* key = be_tostring(vm, -2); - const char* val = be_tostring(vm, -1); - size_t key_len = strlen(key)+1; - txt_items[i].key = (const char*)be_os_malloc(key_len); - if (txt_items[i].key) { strcpy((char*)txt_items[i].key, key); } - size_t val_len = strlen(val)+1; - txt_items[i].value = (const char*)be_os_malloc(val_len); - if (txt_items[i].value) { strcpy((char*)txt_items[i].value, val); } - be_pop(vm, 2); - i++; - } - txt_num = i; - } else { - txt_num = 0; // failed to allocate, pretend it's empty - } - be_pop(vm, 1); /* pop iterator */ - } - } - esp_err_t err; - if (hostname == nullptr) { - err = mdns_service_add(instance, service_type, proto, port, txt_items, txt_num); - } else { - err = mdns_service_add_for_host(instance, service_type, proto, hostname, port, txt_items, txt_num); - } - // free all allocated memory - if (txt_items != NULL) { - for (uint32_t i = 0; i < txt_num; i++) { - if (txt_items[i].key != NULL) { be_os_free((void*)txt_items[i].key); } - if (txt_items[i].value != NULL) { be_os_free((void*)txt_items[i].value); } - } - be_os_free(txt_items); - } - if (err != ESP_OK) { - be_raisef(vm, "internal_error", "mdns service_add err=%i", err); - } - be_return_nil(vm); - } - be_raise(vm, "value_error", "wrong or missing arguments"); -} - - -// -// `mdns.remove_service(service:string, proto:string [, instance:string, hostname:string]) -> nil` -// -// remove service from mDNS server with hostname. -// -// Test: -// import mdns mdns.remove_service("_arduino","_tcp") -// -// import mdns mdns.remove_service("_matterc","_udp") -static int32_t m_mdns_remove_service(struct bvm *vm) { - int32_t top = be_top(vm); - if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { - const char* service_type = be_tostring(vm, 1); - const char* proto = be_tostring(vm, 2); - const char * instance = nullptr; - const char * hostname = nullptr; - if (top >= 3 && be_isstring(vm, 3)) { - instance = be_tostring(vm, 3); - } - if (top >= 4 && be_isstring(vm, 4)) { - hostname = be_tostring(vm, 4); - } - - esp_err_t err; - if (hostname == nullptr) { - err = mdns_service_remove(service_type, proto); - } else { - err = mdns_service_remove_for_host(instance, service_type, proto, hostname); - } - if (err != ESP_OK) { - be_raisef(vm, "internal_error", "mdns service_remove err=%i", err); - } - be_return_nil(vm); - } - be_raise(vm, "value_error", "wrong or missing arguments"); -} - -// `mdns_service_subtype_add_for_host()` is only available in most recent esp-protocols version -// -// This alias makes sure that the compilation succeeds even if the function is not available -// -extern "C" esp_err_t __tasmota_mdns_service_subtype_add_for_host (const char *instance_name, const char *service_type, const char *proto, const char *hostname, const char *subtype) -{ return ESP_OK; } -extern "C" esp_err_t mdns_service_subtype_add_for_host(const char *instance_name, const char *service_type, const char *proto, const char *hostname, const char *subtype) __attribute__ ((weak, alias ("__tasmota_mdns_service_subtype_add_for_host"))); - -// -// `mdns.add_subtype(service:string, proto:string, instance:string, hostname:string, subtype:string) -> nil` -// -// add a subtype -// -static int32_t m_dns_add_subtype(struct bvm *vm) { - int32_t top = be_top(vm); - if (top >= 5 && be_isstring(vm, 1) && be_isstring(vm, 2) && be_isstring(vm, 3) && be_isstring(vm, 4) && be_isstring(vm, 5)) { - const char* service_type = be_tostring(vm, 1); - const char* proto = be_tostring(vm, 2); - const char* instance = be_tostring(vm, 3); - const char* hostname = be_tostring(vm, 4); - const char* subtype = be_tostring(vm, 5); - - esp_err_t err; - // Waiting for support of `mdns_service_subtype_add_for_host()` - err = mdns_service_subtype_add_for_host(instance, service_type, proto, hostname, subtype); - if (err != ESP_OK) { - be_raisef(vm, "internal_error", "mdns add_subtype err=%i", err); - } - be_return_nil(vm); - } - be_raise(vm, "value_error", "wrong or missing arguments"); -} - -// -// `mdns.add_hostname(hostname:string, ip:string [, ip:string]*) -> nil` -// -// add a delegate hostname -// -static int32_t m_dns_add_hostname(struct bvm *vm) { - int32_t top = be_top(vm); - if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { - mdns_ip_addr_t * head = nullptr; // head of the linked list of addresses - esp_err_t err = ESP_OK; // return status - - const char* hostname = be_tostring(vm, 1); - const char* ip_text = nullptr; - ip_addr_t a; - for (uint16_t i = 2; i <= top; i++) { - const char* ip_text = be_tostring(vm, i); - if (ip_text == nullptr || ip_text[0] == 0) { continue; } // ignore empty string - IPAddress ip; - if (!ip.fromString(ip_text)) { err = -1; break; } - - // allocate new slot - mdns_ip_addr_t *new_head = (mdns_ip_addr_t*) be_os_malloc(sizeof(mdns_ip_addr_t)); - if (new_head == nullptr) { err = -2; break; } - new_head->next = head; - head = new_head; - - // - ip_addr_t *ip_addr = (ip_addr_t*) ip; - head->addr.type = ip_addr->type; - if (ip_addr->type == ESP_IPADDR_TYPE_V6) { - memcpy(head->addr.u_addr.ip6.addr, ip_addr->u_addr.ip6.addr, 16); - } else { - head->addr.u_addr.ip4.addr = ip_addr->u_addr.ip4.addr; - } - } while (0); - - if (err == ESP_OK && head != nullptr) { - err = mdns_delegate_hostname_add(hostname, head); - } - - // deallocate all memory - while (head != nullptr) { - mdns_ip_addr_t * next = head->next; - be_os_free(head); - head = next; - } - - if (err == -1) { - be_raisef(vm, "value_error", "Invalid IP Address '%s'", ip_text); - } else if (err == -2) { - be_raise(vm, "memory_error", nullptr); - } else if (err != ESP_OK) { - be_raisef(vm, "value_error", "mdns_delegate_hostname_add err=%i", err); - } - be_return_nil(vm); - - } - be_raise(vm, "value_error", "wrong or missing arguments"); -} - -// -// `mdns.find_service(service:string, proto:string [timeout_ms:int(3000), max_responses:int(20)]) -> map` -// -static int32_t m_dns_find_service(struct bvm *vm) { - static const char * ip_protocol_str[] = {"v4", "v6", "max"}; - int32_t top = be_top(vm); - if (top >= 2 && be_isstring(vm, 1) && be_isstring(vm, 2)) { - const char* service_name = be_tostring(vm, 1); - const char* proto = be_tostring(vm, 2); - int32_t timeout_ms = 3000; - if (top >= 3 && be_isint(vm, 3)) { - timeout_ms = be_toint(vm, 3); - } - int32_t max_responses = 20; - if (top >= 4 && be_isint(vm, 4)) { - max_responses = be_toint(vm, 4); - } - - mdns_result_t * results = NULL; - esp_err_t err = mdns_query_ptr(service_name, proto, timeout_ms, max_responses, &results); - if (err != ESP_OK) { be_raisef(vm, "value_error", "mdns_query_ptr err=%i", err); } - if (results == NULL) { be_return_nil(vm); } - - mdns_result_t * r = results; - mdns_ip_addr_t * a = NULL; - be_newobject(vm, "list"); - while (r) { - be_newobject(vm, "map"); - be_map_insert_str(vm, "type", ip_protocol_str[r->ip_protocol]); - if (r->instance_name) { be_map_insert_str(vm, "instance", r->instance_name); } - if (r->hostname) { be_map_insert_str(vm, "hostname", r->hostname); } - // TXT - be_pushstring(vm, "txt"); - be_newobject(vm, "map"); - for (int32_t t=0; t < r->txt_count; t++){ - be_map_insert_str(vm, r->txt[t].key, r->txt[t].value); - } - // - be_pop(vm, 1); - be_data_insert(vm, -3); - be_pop(vm, 2); - // - - // IP addresses - be_pushstring(vm, "ip"); - be_newobject(vm, "list"); - // - for (a = r->addr; a != NULL; a = a->next) { - ip_addr_t ip_addr; - if (a->addr.type == IPADDR_TYPE_V6) { - ip_addr_copy_from_ip6(ip_addr, a->addr.u_addr.ip6); - } else if (a->addr.type == IPADDR_TYPE_V4) { - ip_addr_copy_from_ip4(ip_addr, a->addr.u_addr.ip4); - } else { - continue; - } - be_pushstring(vm, IPAddress(ip_addr).toString().c_str()); - be_data_push(vm, -2); - be_pop(vm, 1); - } - // - be_pop(vm, 1); - be_data_insert(vm, -3); - be_pop(vm, 2); - - be_pop(vm, 1); - be_data_push(vm, -2); - be_pop(vm, 1); - - r = r->next; - } - be_pop(vm, 1); // now list is on top - - mdns_query_results_free(results); - be_return(vm); - } - be_raise(vm, "value_error", "wrong or missing arguments"); -} - -/* @const_object_info_begin -module mdns (scope: global) { - start, ctype_func(m_mdns_start) - stop, ctype_func(m_mdns_stop) - set_hostname, ctype_func(m_mdns_set_hostname) - add_service, func(m_mdns_add_service) - add_hostname, func(m_dns_add_hostname) - add_subtype, func(m_dns_add_subtype) - remove_service, func(m_mdns_remove_service) - - // querying - find_service, func(m_dns_find_service) -} -@const_object_info_end */ -#include "be_fixed_mdns.h" - -#endif // USE_DISCOVERY \ No newline at end of file diff --git a/lib/libesp32/berry_tasmota/src/be_mqtt_lib.c b/lib/libesp32/berry_tasmota/src/be_mqtt_lib.c index c0237fc07..b356dc619 100644 --- a/lib/libesp32/berry_tasmota/src/be_mqtt_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_mqtt_lib.c @@ -25,7 +25,7 @@ class be_class_MQTT_ntv (scope: global, name: MQTT_ntv) { // mqtt module extern const bclass be_class_MQTT; -static int zigbee_init(bvm *vm) { +static int mqtt_init(bvm *vm) { be_pushntvclass(vm, &be_class_MQTT); be_call(vm, 0); be_return(vm); @@ -34,7 +34,7 @@ static int zigbee_init(bvm *vm) { #include "be_fixed_mqtt.h" /* @const_object_info_begin module mqtt (scope: global) { - init, func(zigbee_init) + init, func(mqtt_init) } @const_object_info_end */ diff --git a/lib/libesp32/berry_tasmota/src/be_serial_lib.c b/lib/libesp32/berry_tasmota/src/be_serial_lib.c index 504afe0d2..3b2c4cfd7 100644 --- a/lib/libesp32/berry_tasmota/src/be_serial_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_serial_lib.c @@ -6,8 +6,7 @@ * 2 wire communication - I2C *******************************************************************/ #include "be_constobj.h" - -#include "esp32-hal.h" +#include "esp_idf_version.h" extern int b_serial_init(bvm *vm); extern int b_serial_deinit(bvm *vm); @@ -17,6 +16,40 @@ extern int b_serial_read(bvm *vm); extern int b_serial_available(bvm *vm); extern int b_serial_flush(bvm *vm); +#if ESP_IDF_VERSION_MAJOR < 5 + #include "esp32-hal.h" +#else + // it should be #include "HardwareSerial.h" + // but the C++ header cannot be included in a C file + // so there's a copy below + enum SerialConfig { + SERIAL_5N1 = 0x8000010, + SERIAL_6N1 = 0x8000014, + SERIAL_7N1 = 0x8000018, + SERIAL_8N1 = 0x800001c, + SERIAL_5N2 = 0x8000030, + SERIAL_6N2 = 0x8000034, + SERIAL_7N2 = 0x8000038, + SERIAL_8N2 = 0x800003c, + SERIAL_5E1 = 0x8000012, + SERIAL_6E1 = 0x8000016, + SERIAL_7E1 = 0x800001a, + SERIAL_8E1 = 0x800001e, + SERIAL_5E2 = 0x8000032, + SERIAL_6E2 = 0x8000036, + SERIAL_7E2 = 0x800003a, + SERIAL_8E2 = 0x800003e, + SERIAL_5O1 = 0x8000013, + SERIAL_6O1 = 0x8000017, + SERIAL_7O1 = 0x800001b, + SERIAL_8O1 = 0x800001f, + SERIAL_5O2 = 0x8000033, + SERIAL_6O2 = 0x8000037, + SERIAL_7O2 = 0x800003b, + SERIAL_8O2 = 0x800003f + }; +#endif + #include "be_fixed_be_class_serial.h" /* @const_object_info_begin diff --git a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c index e0fd4cdf8..e4962d731 100644 --- a/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c +++ b/lib/libesp32/berry_tasmota/src/be_tasmota_lib.c @@ -5,6 +5,7 @@ *******************************************************************/ #include "be_constobj.h" #include "be_ctypes.h" +#include "be_mapping.h" extern struct TasmotaGlobal_t TasmotaGlobal; extern struct TSettings * Settings; @@ -62,6 +63,10 @@ extern int l_i2cenabled(bvm *vm); extern int tasm_find_op(bvm *vm); extern int tasm_apply_str_op(bvm *vm); +// tasmota.version() -> int +extern int32_t be_Tasmota_version(void); +BE_FUNC_CTYPE_DECLARE(be_Tasmota_version, "i", "-"); + #include "solidify/solidified_tasmota_class.h" #include "solidify/solidified_rule_matcher.h" #include "solidify/solidified_trigger_class.h" @@ -137,6 +142,7 @@ class be_class_tasmota (scope: global, name: Tasmota) { get_switches, func(l_getswitch) i2c_enabled, func(l_i2cenabled) + version, ctype_func(be_Tasmota_version) fast_loop, closure(Tasmota_fast_loop_closure) add_fast_loop, closure(Tasmota_add_fast_loop_closure) @@ -145,6 +151,7 @@ class be_class_tasmota (scope: global, name: Tasmota) { _find_op, func(tasm_find_op) // new C version for finding a rule operator _apply_str_op, func(tasm_apply_str_op) find_key_i, closure(Tasmota_find_key_i_closure) + find_list_i, closure(Tasmota_find_list_i_closure) find_op, closure(Tasmota_find_op_closure) add_rule, closure(Tasmota_add_rule_closure) remove_rule, closure(Tasmota_remove_rule_closure) diff --git a/lib/libesp32/berry_tasmota/src/be_tasmota_log_reader_class.cpp b/lib/libesp32/berry_tasmota/src/be_tasmota_log_reader_class.c similarity index 79% rename from lib/libesp32/berry_tasmota/src/be_tasmota_log_reader_class.cpp rename to lib/libesp32/berry_tasmota/src/be_tasmota_log_reader_class.c index 7f9ac60d8..13277fbe2 100644 --- a/lib/libesp32/berry_tasmota/src/be_tasmota_log_reader_class.cpp +++ b/lib/libesp32/berry_tasmota/src/be_tasmota_log_reader_class.c @@ -10,11 +10,6 @@ extern char* tlr_get_log(uint32_t* idx, int32_t log_level); BE_FUNC_CTYPE_DECLAR #include "be_fixed_be_class_tasmota_log_reader.h" -extern "C" void be_load_tasmota_log_reader_class(bvm *vm) { - be_pushntvclass(vm, &be_class_tasmota_log_reader); - be_setglobal(vm, "tasmota_log_reader"); - be_pop(vm, 1); -} /* @const_object_info_begin class be_class_tasmota_log_reader (scope: global, name: tasmota_log_reader) { diff --git a/lib/libesp32/berry_tasmota/src/be_udp_lib.c b/lib/libesp32/berry_tasmota/src/be_udp_lib.c new file mode 100644 index 000000000..e49dc5e48 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/be_udp_lib.c @@ -0,0 +1,57 @@ +/******************************************************************** + * UDP lib + * + * To use: `d = udp()` + * + *******************************************************************/ +#include "be_constobj.h" +#include "be_mapping.h" + +#ifdef USE_WEBCLIENT + +extern int be_udp_read(struct bvm *vm); + +extern void *be_udp_init_ntv(void); +BE_FUNC_CTYPE_DECLARE(be_udp_init_ntv, "+.p", "") + +extern void *be_udp_deinit_ntv(void *udp); +BE_FUNC_CTYPE_DECLARE(be_udp_deinit_ntv, "=.p", "") + +extern int32_t be_udp_begin_ntv(void *udp, const char *host, int32_t port); +BE_FUNC_CTYPE_DECLARE(be_udp_begin_ntv, "b", ".si") + +extern void be_udp_stop_ntv(void *udp); +BE_FUNC_CTYPE_DECLARE(be_udp_stop_ntv, "", ".") + +extern int32_t be_udp_begin_mcast_ntv(void *udp, const char *host, int32_t port); +BE_FUNC_CTYPE_DECLARE(be_udp_begin_mcast_ntv, "b", ".si") + +extern int32_t be_udp_send_ntv(void *udp, const char *host, int32_t port, const uint8_t* buf, int32_t len); +BE_FUNC_CTYPE_DECLARE(be_udp_send_ntv, "b", ".si(bytes)~") + +extern int32_t be_udp_send_mcast_ntv(void *udp, const uint8_t* buf, int32_t len); +BE_FUNC_CTYPE_DECLARE(be_udp_send_mcast_ntv, "b", ".(bytes)~") + +#include "be_mapping.h" +#include "be_fixed_be_class_udp.h" + +/* @const_object_info_begin + +class be_class_udp (scope: global, name: udp) { + .p, var + remote_ip, var + remote_port, var + init, ctype_func(be_udp_init_ntv) + deinit, ctype_func(be_udp_deinit_ntv) + + send, ctype_func(be_udp_send_ntv) + send_multicast, ctype_func(be_udp_send_mcast_ntv) + + begin, ctype_func(be_udp_begin_ntv) + begin_multicast, ctype_func(be_udp_begin_mcast_ntv) + read, func(be_udp_read) + close, ctype_func(be_udp_stop_ntv) +} +@const_object_info_end */ + +#endif // USE_WEBCLIENT diff --git a/lib/libesp32/berry_tasmota/src/be_unishox_lib.c b/lib/libesp32/berry_tasmota/src/be_unishox_lib.c new file mode 100644 index 000000000..60161dd81 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/be_unishox_lib.c @@ -0,0 +1,24 @@ +/******************************************************************** + * Berry module `unishox` + * + * To use: `import unishox` + * + * Allows to respond to HTTP request + *******************************************************************/ + +#ifdef USE_UNISHOX_COMPRESSION + +#include "be_constobj.h" + +extern int be_ntv_unishox_compress(bvm *vm); +extern int be_ntv_unishox_decompress(bvm *vm); + +/* @const_object_info_begin +module unishox (scope: global) { + decompress, func(be_ntv_unishox_decompress) + compress, func(be_ntv_unishox_compress) +} +@const_object_info_end */ +#include "be_fixed_unishox.h" + +#endif // USE_UNISHOX_COMPRESSION diff --git a/lib/libesp32/berry_tasmota/src/be_unishox_lib.cpp b/lib/libesp32/berry_tasmota/src/be_unishox_lib.cpp deleted file mode 100644 index af4317987..000000000 --- a/lib/libesp32/berry_tasmota/src/be_unishox_lib.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************** - * Berry module `unishox` - * - * To use: `import unishox` - * - * Allows to respond to HTTP request - *******************************************************************/ - -#ifdef USE_UNISHOX_COMPRESSION - -#include "be_constobj.h" -#include "be_mapping.h" -#include -#include "unishox.h" - -extern Unishox compressor; - -/*********************************************************************************************\ - * Native functions mapped to Berry functions - * - * import unishox - * - * -\*********************************************************************************************/ -static int be_ntv_unishox_compress(bvm *vm) { - int32_t argc = be_top(vm); // Get the number of arguments - if (argc == 1 && be_isstring(vm, 1)) { - const char * s = be_tostring(vm, 1); - // do a dry-run to know the compressed size - int32_t compressed_size = compressor.unishox_compress(s, strlen(s), (char*) nullptr, 0); - if (compressed_size < 0) { - be_raise(vm, "internal_error", nullptr); - } - void * buf = be_pushbytes(vm, NULL, compressed_size); - if (compressed_size > 0) { - int32_t ret = compressor.unishox_compress(s, strlen(s), (char*) buf, compressed_size+5); // We expand by 4 the buffer size to avoid an error, but we are sure it will not overflow (see unishox implementation) - if (ret < 0 || ret != compressed_size) { - be_raisef(vm, "internal_error", "unishox size=%i ret=%i", compressed_size, ret); - } - } - be_return(vm); - } - be_raise(vm, "type_error", nullptr); -} - -static int be_ntv_unishox_decompress(bvm *vm) { - int32_t argc = be_top(vm); // Get the number of arguments - if (argc == 1 && be_isbytes(vm, 1)) { - size_t len; - const void * buf = be_tobytes(vm, 1, &len); - if (len == 0) { - be_pushstring(vm, ""); - } else { - int32_t decomp_size = compressor.unishox_decompress((const char*)buf, len, (char*) nullptr, 0); - if (decomp_size < 0) { - be_raise(vm, "internal_error", nullptr); - } - if (decomp_size == 0) { - be_pushstring(vm, ""); - } else { - void * buf_out = be_pushbuffer(vm, decomp_size); - int32_t ret = compressor.unishox_decompress((const char*)buf, len, (char*) buf_out, decomp_size); - if (ret < 0 || ret != decomp_size) { - be_raisef(vm, "internal_error", "unishox size=%i ret=%i", decomp_size, ret); - } - be_pushnstring(vm, (const char*) buf_out, decomp_size); - } - } - be_return(vm); - } - be_raise(vm, "type_error", nullptr); -} - - -/* @const_object_info_begin -module unishox (scope: global) { - decompress, func(be_ntv_unishox_decompress) - compress, func(be_ntv_unishox_compress) -} -@const_object_info_end */ -#include "be_fixed_unishox.h" - -#endif // USE_UNISHOX_COMPRESSION diff --git a/lib/libesp32/berry_tasmota/src/be_zigbee_zcl_attributes.c b/lib/libesp32/berry_tasmota/src/be_zigbee_zcl_attribute.c similarity index 100% rename from lib/libesp32/berry_tasmota/src/be_zigbee_zcl_attributes.c rename to lib/libesp32/berry_tasmota/src/be_zigbee_zcl_attribute.c diff --git a/lib/libesp32/berry_tasmota/src/embedded/partition_core.be b/lib/libesp32/berry_tasmota/src/embedded/partition_core.be index 08736292c..5fee46839 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/partition_core.be +++ b/lib/libesp32/berry_tasmota/src/embedded/partition_core.be @@ -591,7 +591,6 @@ class Partition var fs_slot = self.slots[-1] fs_slot.sz += unallocated * 1024 self.save() - self.invalidate_spiffs() # erase SPIFFS or data is corrupt # restart tasmota.global.restart_flag = 2 @@ -601,19 +600,6 @@ class Partition end end - #- invalidate SPIFFS partition to force format at next boot -# - #- we simply erase the first byte of the first 2 blocks in the SPIFFS partition -# - def invalidate_spiffs() - import flash - #- we expect the SPIFFS partition to be the last one -# - var spiffs = self.slots[-1] - if !spiffs.is_spiffs() raise 'value_error', 'No SPIFFS partition found' end - - var b = bytes("00") #- flash memory: we can turn bits from '1' to '0' -# - flash.write(spiffs.start , b) #- block #0 -# - flash.write(spiffs.start + 0x1000, b) #- block #1 -# - end - # switch to safeboot `factory` partition def switch_factory(force_ota) import flash diff --git a/lib/libesp32/berry_tasmota/src/embedded/partition_core_shelly.be b/lib/libesp32/berry_tasmota/src/embedded/partition_core_shelly.be new file mode 100644 index 000000000..620cc352d --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/embedded/partition_core_shelly.be @@ -0,0 +1,631 @@ +####################################################################### +# Partition manager for ESP32 - ESP32C3 - ESP32S2 +# +# use : `import partition_core_shelly` +# +# Provides low-level objects and a Web UI +####################################################################### + +var partition_core_shelly = module('partition_core_shelly') + +####################################################################### +# Class for a partition table entry +# +# typedef struct { +# uint16_t magic; +# uint8_t type; +# uint8_t subtype; +# uint32_t offset; +# uint32_t size; +# uint8_t label[16]; +# uint32_t flags; +# } esp_partition_info_t_simplified; +# +####################################################################### +class Partition_info + var type + var subtype + var start + var sz + var label + var flags + + #- remove trailing NULL chars from a bytes buffer before converting to string -# + #- Berry strings can contain NULL, but this messes up C-Berry interface -# + static def remove_trailing_zeroes(b) + var sz = size(b) + var i = 0 + while i < sz + if b[-1-i] != 0 break end + i += 1 + end + if i > 0 + b.resize(size(b)-i) + end + return b + end + + # Init the Parition information structure, either from a bytes() buffer or an empty if no buffer is provided + def init(raw) + self.type = 0 + self.subtype = 0 + self.start = 0 + self.sz = 0 + self.label = '' + self.flags = 0 + + if !issubclass(bytes, raw) # no payload, empty partition information + return + end + + #- we have a payload, parse it -# + var magic = raw.get(0,2) + if magic == 0x50AA #- partition entry -# + + self.type = raw.get(2,1) + self.subtype = raw.get(3,1) + self.start = raw.get(4,4) + self.sz = raw.get(8,4) + self.label = self.remove_trailing_zeroes(raw[12..27]).asstring() + self.flags = raw.get(28,4) + + # elif magic == 0xEBEB #- MD5 -# + else + import string + raise "internal_error", string.format("invalid magic number %02X", magic) + end + + end + + # check if the parition is an OTA partition + # if yes, return OTA number (starting at 0) + # if no, return nil + def is_ota() + var sub_type = self.subtype + if self.type == 0 && (sub_type >= 0x10 && sub_type < 0x20) + return sub_type - 0x10 + end + end + + # check if factory 'safeboot' partition + def is_factory() + return self.type == 0 && self.subtype == 0 + end + + # check if the parition is a SPIFFS partition + # returns bool + def is_spiffs() + return self.type == 1 && self.subtype == 130 + end + + # get the actual image size give of the partition + # returns -1 if the partition is not an app ota partition + def get_image_size() + import flash + if self.is_ota() == nil && !self.is_factory() return -1 end + try + var addr = self.start + var sz = self.sz + var magic_byte = flash.read(addr, 1).get(0, 1) + if magic_byte != 0xE9 return -1 end + + var seg_count = flash.read(addr+1, 1).get(0, 1) + # print("Segment count", seg_count) + + var seg_offset = addr + 0x20 # sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) = 24 + 8 + + var seg_num = 0 + while seg_num < seg_count + # print(string.format("Reading 0x%08X", seg_offset)) + var segment_header = flash.read(seg_offset - 8, 8) + var seg_start_addr = segment_header.get(0, 4) + var seg_size = segment_header.get(4,4) + # print(string.format("Segment %i: flash_offset=0x%08X start_addr=0x%08X sz=0x%08X", seg_num, seg_offset, seg_start_addr, seg_size)) + + seg_offset += seg_size + 8 # add segment_length + sizeof(esp_image_segment_header_t) + if seg_offset >= (addr + sz) return -1 end + + seg_num += 1 + end + var total_size = seg_offset - addr + 1 # add 1KB for safety + + # print(string.format("Total size = %i KB", total_size/1024)) + + return total_size + except .. as e, m + tasmota.log("BRY: Exception> '" + e + "' - " + m, 2) + return -1 + end + end + + def type_to_string() + if self.type == 0 return "app" + elif self.type == 1 return "data" + end + import string + return string.format("0x%02X", self.type) + end + + def subtype_to_string() + if self.type == 0 + if self.subtype == 0 return "factory" + elif self.subtype >= 0x10 && self.subtype < 0x20 return "ota_" + str(self.subtype - 0x10) + elif self.subtype == 0x20 return "test" + end + elif self.type == 1 + if self.subtype == 0x00 return "otadata" + elif self.subtype == 0x01 return "phy" + elif self.subtype == 0x02 return "nvs" + elif self.subtype == 0x03 return "coredump" + elif self.subtype == 0x04 return "nvskeys" + elif self.subtype == 0x05 return "efuse_em" + elif self.subtype == 0x80 return "esphttpd" + elif self.subtype == 0x81 return "fat" + elif self.subtype == 0x82 return "spiffs" + end + end + import string + return string.format("0x%02X", self.subtype) + end + + # Human readable version of Partition information + # this method is not included in the solidified version to save space, + # it is included only in the optional application `tapp` version + def tostring() + import string + var type_s = self.type_to_string() + var subtype_s = self.subtype_to_string() + + # reformat strings + if type_s != "" type_s = " (" + type_s + ")" end + if subtype_s != "" subtype_s = " (" + subtype_s + ")" end + return string.format("", + self.type, type_s, + self.subtype, subtype_s, + self.start, self.sz, + self.label, self.flags) + end + + def tobytes() + #- convert to raw bytes -# + var b = bytes('AA50') #- set magic number -# + b.resize(32).resize(2) #- pre-reserve 32 bytes -# + b.add(self.type, 1) + b.add(self.subtype, 1) + b.add(self.start, 4) + b.add(self.sz, 4) + var label = bytes().fromstring(self.label) + label.resize(16) + b = b + label + b.add(self.flags, 4) + return b + end + +end +partition_core_shelly.Partition_info = Partition_info + +#------------------------------------------------------------- + - OTA Data + - + - Selection of the active OTA partition + - + typedef struct { + uint32_t ota_seq; + uint8_t seq_label[20]; + uint32_t ota_state; + uint32_t crc; /* CRC32 of ota_seq field only */ + } esp_ota_select_entry_t; + + - Excerp from esp_ota_ops.c + esp32_idf use two sector for store information about which partition is running + it defined the two sector as ota data partition,two structure esp_ota_select_entry_t is saved in the two sector + named data in first sector as otadata[0], second sector data as otadata[1] + e.g. + if otadata[0].ota_seq == otadata[1].ota_seq == 0xFFFFFFFF,means ota info partition is in init status + so it will boot factory application(if there is),if there's no factory application,it will boot ota[0] application + if otadata[0].ota_seq != 0 and otadata[1].ota_seq != 0,it will choose a max seq ,and get value of max_seq%max_ota_app_number + and boot a subtype (mask 0x0F) value is (max_seq - 1)%max_ota_app_number,so if want switch to run ota[x],can use next formulas. + for example, if otadata[0].ota_seq = 4, otadata[1].ota_seq = 5, and there are 8 ota application, + current running is (5-1)%8 = 4,running ota[4],so if we want to switch to run ota[7], + we should add otadata[0].ota_seq (is 4) to 4 ,(8-1)%8=7,then it will boot ota[7] + if A=(B - C)%D + then B=(A + C)%D + D*n ,n= (0,1,2...) + so current ota app sub type id is x , dest bin subtype is y,total ota app count is n + seq will add (x + n*1 + 1 - seq)%n + -------------------------------------------------------------# +class Partition_otadata + var maxota # number of highest OTA partition, default 1 (double ota0/ota1) + var has_factory # is there a factory partition + var offset # offset of the otadata partition (0x2000 in length), default 0xE000 + var active_otadata # which otadata block is active, 0 or 1, i.e. 0xE000 or 0xF000 -- or -1 if no OTA active, i.e. boot on factory + var seq0 # ota_seq of first block + var seq1 # ota_seq of second block + + #- crc32 for ota_seq as 32 bits unsigned, with init vector -1 -# + static def crc32_ota_seq(seq) + import crc + return crc.crc32(0xFFFFFFFF, bytes().add(seq, 4)) + end + + #---------------------------------------------------------------------# + # Rest of the class + #---------------------------------------------------------------------# + def init(maxota, has_factory, offset) + self.maxota = maxota + self.has_factory = has_factory + if self.maxota == nil self.maxota = 1 end + self.offset = offset + if self.offset == nil self.offset = 0xE000 end + self.active_otadata = -1 + self.load() + end + + #- update ota_max, needs to recompute everything -# + def set_ota_max(n) + self.maxota = n + end + + # change the active OTA partition + def set_active(n) + var seq_max = 0 #- current highest seq number -# + var block_act = 0 #- block number containing the highest seq number -# + + if self.seq0 != nil + seq_max = self.seq0 + block_act = 0 + end + if self.seq1 != nil && self.seq1 > seq_max + seq_max = self.seq1 + block_act = 1 + end + + #- compute the next sequence number -# + var actual_ota = (seq_max - 1) % (self.maxota + 1) + if actual_ota != n #- change only if different -# + if n > actual_ota seq_max += n - actual_ota + else seq_max += (self.maxota + 1) - actual_ota + n + end + + #- update internal structure -# + if block_act == 1 #- current block is 1, so update block 0 -# + self.seq0 = seq_max + else #- or write to block 1 -# + self.seq1 = seq_max + end + self._validate() + end + end + + #- load otadata from SPI Flash -# + def load() + import flash + var otadata0 = flash.read(self.offset, 32) + var otadata1 = flash.read(self.offset + 0x1000, 32) + self.seq0 = otadata0.get(0, 4) #- ota_seq for block 1 -# + self.seq1 = otadata1.get(0, 4) #- ota_seq for block 2 -# + # var valid0 = otadata0.get(28, 4) == self.crc32_ota_seq(self.seq0) #- is CRC32 valid? -# + # var valid1 = otadata1.get(28, 4) == self.crc32_ota_seq(self.seq1) #- is CRC32 valid? -# + # if !valid0 self.seq0 = nil end + # if !valid1 self.seq1 = nil end + + self._validate() + end + + #- internally used, validate data -# + def _validate() + self.active_otadata = self.has_factory ? -1 : 0 # if no valid otadata, then use factory (-1) if any, or ota_0 + if self.seq0 != nil + self.active_otadata = (self.seq0 - 1) % (self.maxota + 1) + end + if self.seq1 != nil && (self.seq0 == nil || self.seq1 > self.seq0) + self.active_otadata = (self.seq1 - 1) % (self.maxota + 1) + end + end + + # Save partition information to SPI Flash + def save() + import flash + #- check the block number to save, 0 or 1. Choose the highest ota_seq -# + var block_to_save = -1 #- invalid -# + var seq_to_save = -1 #- invalid value -# + + # check seq0 + if self.seq0 != nil + seq_to_save = self.seq0 + block_to_save = 0 + end + if (self.seq1 != nil) && (self.seq1 > seq_to_save) + seq_to_save = self.seq1 + block_to_save = 1 + end + # if none was good + if block_to_save < 0 block_to_save = 0 end + if seq_to_save < 0 seq_to_save = 1 end + + var offset_to_save = self.offset + 0x1000 * block_to_save #- default 0xE000 or 0xF000 -# + + var bytes_to_save = bytes() + bytes_to_save.add(seq_to_save, 4) + bytes_to_save += bytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF") + bytes_to_save.add(self.crc32_ota_seq(seq_to_save), 4) + + #- erase flash area and write -# + flash.erase(offset_to_save, 0x1000) + flash.write(offset_to_save, bytes_to_save) + end + + # Produce a human-readable representation of the object with relevant information + def tostring() + import string + return string.format("", + self.active_otadata >= 0 ? "ota_" + str(self.active_otadata) : "factory", + self.seq0, self.seq1, self.maxota) + end +end +partition_core_shelly.Partition_otadata = Partition_otadata + +#------------------------------------------------------------- + - Class for a partition table entry + -------------------------------------------------------------# +class Partition + var raw #- raw bytes of the partition table in flash -# + var md5 #- md5 hash of partition list -# + var slots + var otadata #- instance of Partition_otadata() -# + + def init() + self.slots = [] + self.load() + self.parse() + self.load_otadata() + end + + # Load partition information from SPI Flash + def load() + import flash + self.raw = flash.read(0x8000,0x1000) + end + + #- parse the raw bytes to a structured list of partition items -# + def parse() + for i:0..94 # there are maximum 95 slots + md5 (0xC00) + var item_raw = self.raw[i*32..(i+1)*32-1] + var magic = item_raw.get(0,2) + if magic == 0x50AA #- partition entry -# + var slot = partition_core_shelly.Partition_info(item_raw) + self.slots.push(slot) + elif magic == 0xEBEB #- MD5 -# + self.md5 = self.raw[i*32+16..i*33-1] + break + else + break + end + end + end + + def get_ota_slot(n) + for slot: self.slots + if slot.is_ota() == n return slot end + end + return nil + end + + def get_factory_slot() + for slot: self.slots + if slot.is_factory() return slot end + end + end + + def has_factory() + return self.get_factory_slot() != nil + end + + #- compute the highest ota partition -# + def ota_max() + var ota_max = nil + for slot:self.slots + if slot.type == 0 && (slot.subtype >= 0x10 && slot.subtype < 0x20) + var ota_num = slot.subtype - 0x10 + if (ota_max == nil) || (ota_num > ota_max) ota_max = ota_num end + end + end + return ota_max + end + + # get the active OTA app partition number + def get_active() + return self.otadata.active_otadata + end + + def load_otadata() + #- look for otadata partition offset, and max_ota -# + var otadata_offset = 0xE000 #- default value -# + var ota_max = self.ota_max() + for slot:self.slots + if slot.type == 1 && slot.subtype == 0 #- otadata -# + otadata_offset = slot.start + end + end + + self.otadata = partition_core_shelly.Partition_otadata(ota_max, self.has_factory(), otadata_offset) + end + + #- change the active partition -# + def set_active(n) + if n < 0 || n > self.ota_max() raise "value_error", "Invalid ota partition number" end + self.otadata.set_ota_max(self.ota_max()) #- update ota_max if it changed -# + self.otadata.set_active(n) + end + + # Human readable version of Partition information + # this method is not included in the solidified version to save space, + # it is included only in the optional application `tapp` version + #- convert to human readble -# + def tostring() + var ret = " 95 raise "value_error", "Too many partiition slots" end + var b = bytes() + for slot: self.slots + b += slot.tobytes() + end + #- compute MD5 -# + var md5 = MD5() + md5.update(b) + #- add the last segment -# + b += bytes("EBEBFFFFFFFFFFFFFFFFFFFFFFFFFFFF") + b += md5.finish() + #- complete -# + return b + end + + #- write back to flash -# + def save() + import flash + var b = self.tobytes() + #- erase flash area and write -# + flash.erase(0x8000, 0x1000) + flash.write(0x8000, b) + self.otadata.save() + end + + # Internal: returns which flash sector contains the partition definition + # Returns 0 or 1, or `nil` if something went wrong + # Note: partition flash sector vary from ESP32 to ESP32C3/S3 + static def get_flash_definition_sector() + import flash + for i:0..1 + var offset = i * 0x1000 + if flash.read(offset, 1) == bytes('E9') return offset end + end + end + + # Internal: returns the maximum flash size possible + # Returns max flash size ok kB + def get_max_flash_size_k() + var flash_size_k = tasmota.memory()['flash'] + var flash_size_real_k = tasmota.memory().find("flash_real", flash_size_k) + if (flash_size_k != flash_size_real_k) && self.get_flash_definition_sector() != nil + flash_size_k = flash_size_real_k # try to expand the flash size definition + end + return flash_size_k + end + + # Internal: returns the unallocated flash size (in kB) beyond the file-system + # this indicates that the file-system can be extended (although erased at the same time) + def get_unallocated_k() + var last_slot = self.slots[-1] + if last_slot.is_spiffs() + # verify that last slot is filesystem + var flash_size_k = self.get_max_flash_size_k() + var partition_end_k = (last_slot.start + last_slot.sz) / 1024 # last kb used for fs + if partition_end_k < flash_size_k + return flash_size_k - partition_end_k + end + end + return 0 + end + + #- ---------------------------------------------------------------------- -# + #- Resize flash definition if needed + #- ---------------------------------------------------------------------- -# + def resize_max_flash_size_k() + var flash_size_k = tasmota.memory()['flash'] + var flash_size_real_k = tasmota.memory().find("flash_real", flash_size_k) + var flash_definition_sector = self.get_flash_definition_sector() + if (flash_size_k != flash_size_real_k) && flash_definition_sector != nil + import flash + import string + + flash_size_k = flash_size_real_k # try to expand the flash size definition + + var flash_def = flash.read(flash_definition_sector, 4) + var size_before = flash_def[3] + + var flash_size_code + var flash_size_real_m = flash_size_real_k / 1024 # size in MB + if flash_size_real_m == 1 flash_size_code = 0x00 + elif flash_size_real_m == 2 flash_size_code = 0x10 + elif flash_size_real_m == 4 flash_size_code = 0x20 + elif flash_size_real_m == 8 flash_size_code = 0x30 + elif flash_size_real_m == 16 flash_size_code = 0x40 + elif flash_size_real_m == 32 flash_size_code = 0x50 + elif flash_size_real_m == 64 flash_size_code = 0x60 + elif flash_size_real_m == 128 flash_size_code = 0x70 + end + + if flash_size_code != nil + # apply the update + var old_def = flash_def[3] + flash_def[3] = (flash_def[3] & 0x0F) | flash_size_code + flash.write(flash_definition_sector, flash_def) + tasmota.log(string.format("UPL: changing flash definition from 0x02X to 0x%02X", old_def, flash_def[3]), 3) + else + raise "internal_error", "wrong flash size "+str(flash_size_real_m) + end + end + end + + # Called at first boot + # Try to expand FS to max of flash size + def resize_fs_to_max() + import string + try + var unallocated = self.get_unallocated_k() + if unallocated <= 0 return nil end + + tasmota.log(string.format("BRY: Trying to expand FS by %i kB", unallocated), 2) + + self.resize_max_flash_size_k() # resize if needed + # since unallocated succeeded, we know the last slot is FS + var fs_slot = self.slots[-1] + fs_slot.sz += unallocated * 1024 + self.save() + + # restart + tasmota.global.restart_flag = 2 + tasmota.log("BRY: Successfully resized FS, restarting", 2) + except .. as e, m + tasmota.log(string.format("BRY: Exception> '%s' - %s", e, m), 2) + end + end + + # switch to safeboot `factory` partition + def switch_factory(force_ota) + import flash + flash.factory(force_ota) + end +end +partition_core_shelly.Partition = Partition + +# init method to force the global `partition_core_shelly` is defined even if the import is done within a function +def init(m) + import global + global.partition_core_shelly = m + return m +end +partition_core_shelly.init = init + +return partition_core_shelly + +#- Example + +import partition_core_shelly + +# read +p = partition_core_shelly.Partition() +print(p) + +-# diff --git a/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be b/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be index bd06672c2..2259e0a68 100644 --- a/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be +++ b/lib/libesp32/berry_tasmota/src/embedded/tasmota_class.be @@ -64,6 +64,19 @@ class Tasmota end end + # find a string in a list, case insensitive + def find_list_i(l, vali) + import string + var idx = 0 + var valu = string.toupper(vali) + while idx < size(l) + if string.toupper(l[idx]) == valu + return idx + end + idx += 1 + end + return nil + end # split the item when there is an operator, returns a list of (left,op,right) #- diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_animate_module.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_animate_module.h index 4eea694a5..a153a3817 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_animate_module.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_animate_module.h @@ -600,9 +600,9 @@ be_local_closure(Animate_engine_animate, /* name */ 0x140C0706, // 0018 LT R3 R3 K6 0x780E0000, // 0019 JMPF R3 #001B 0xB0060F08, // 001A RAISE 1 K7 K8 - 0x880C0104, // 001B GETMBR R3 R0 K4 - 0x88100105, // 001C GETMBR R4 R0 K5 - 0x940C0803, // 001D GETIDX R3 R4 R3 + 0x880C0105, // 001B GETMBR R3 R0 K5 + 0x88100104, // 001C GETMBR R4 R0 K4 + 0x940C0604, // 001D GETIDX R3 R3 R4 0x6014000F, // 001E GETGBL R5 G15 0x5C180600, // 001F MOVE R6 R3 0xB81E1200, // 0020 GETNGBL R7 K9 diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core.h index caadd3a25..919b870ca 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core.h @@ -504,294 +504,6 @@ be_local_class(Partition_otadata, extern const bclass be_class_Partition; -/******************************************************************** -** Solidified function: save -********************************************************************/ -be_local_closure(Partition_save, /* name */ - be_nested_proto( - 7, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(flash), - /* K1 */ be_nested_str(tobytes), - /* K2 */ be_nested_str(erase), - /* K3 */ be_nested_str(write), - /* K4 */ be_nested_str(otadata), - /* K5 */ be_nested_str(save), - }), - &be_const_str_save, - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080101, // 0001 GETMET R2 R0 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x8C0C0302, // 0003 GETMET R3 R1 K2 - 0x54167FFF, // 0004 LDINT R5 32768 - 0x541A0FFF, // 0005 LDINT R6 4096 - 0x7C0C0600, // 0006 CALL R3 3 - 0x8C0C0303, // 0007 GETMET R3 R1 K3 - 0x54167FFF, // 0008 LDINT R5 32768 - 0x5C180400, // 0009 MOVE R6 R2 - 0x7C0C0600, // 000A CALL R3 3 - 0x880C0104, // 000B GETMBR R3 R0 K4 - 0x8C0C0705, // 000C GETMET R3 R3 K5 - 0x7C0C0200, // 000D CALL R3 1 - 0x80000000, // 000E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: load -********************************************************************/ -be_local_closure(Partition_load, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(flash), - /* K1 */ be_nested_str(raw), - /* K2 */ be_nested_str(read), - }), - &be_const_str_load, - &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080302, // 0001 GETMET R2 R1 K2 - 0x54127FFF, // 0002 LDINT R4 32768 - 0x54160FFF, // 0003 LDINT R5 4096 - 0x7C080600, // 0004 CALL R2 3 - 0x90020202, // 0005 SETMBR R0 K1 R2 - 0x80000000, // 0006 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_active -********************************************************************/ -be_local_closure(Partition_get_active, /* name */ - be_nested_proto( - 2, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str(otadata), - /* K1 */ be_nested_str(active_otadata), - }), - &be_const_str_get_active, - &be_const_str_solidified, - ( &(const binstruction[ 3]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x88040301, // 0001 GETMBR R1 R1 K1 - 0x80040200, // 0002 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: init -********************************************************************/ -be_local_closure(Partition_init, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str(slots), - /* K1 */ be_nested_str(load), - /* K2 */ be_nested_str(parse), - /* K3 */ be_nested_str(load_otadata), - }), - &be_const_str_init, - &be_const_str_solidified, - ( &(const binstruction[10]) { /* code */ - 0x60040012, // 0000 GETGBL R1 G18 - 0x7C040000, // 0001 CALL R1 0 - 0x90020001, // 0002 SETMBR R0 K0 R1 - 0x8C040101, // 0003 GETMET R1 R0 K1 - 0x7C040200, // 0004 CALL R1 1 - 0x8C040102, // 0005 GETMET R1 R0 K2 - 0x7C040200, // 0006 CALL R1 1 - 0x8C040103, // 0007 GETMET R1 R0 K3 - 0x7C040200, // 0008 CALL R1 1 - 0x80000000, // 0009 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: parse -********************************************************************/ -be_local_closure(Partition_parse, /* name */ - be_nested_proto( - 9, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[11]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str(raw), - /* K2 */ be_const_int(1), - /* K3 */ be_nested_str(get), - /* K4 */ be_const_int(2), - /* K5 */ be_nested_str(partition_core), - /* K6 */ be_nested_str(Partition_info), - /* K7 */ be_nested_str(slots), - /* K8 */ be_nested_str(push), - /* K9 */ be_nested_str(md5), - /* K10 */ be_nested_str(stop_iteration), - }), - &be_const_str_parse, - &be_const_str_solidified, - ( &(const binstruction[57]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x540A005D, // 0001 LDINT R2 94 - 0x400A0002, // 0002 CONNECT R2 K0 R2 - 0x7C040200, // 0003 CALL R1 1 - 0xA802002F, // 0004 EXBLK 0 #0035 - 0x5C080200, // 0005 MOVE R2 R1 - 0x7C080000, // 0006 CALL R2 0 - 0x540E001F, // 0007 LDINT R3 32 - 0x080C0403, // 0008 MUL R3 R2 R3 - 0x00100502, // 0009 ADD R4 R2 K2 - 0x5416001F, // 000A LDINT R5 32 - 0x08100805, // 000B MUL R4 R4 R5 - 0x04100902, // 000C SUB R4 R4 K2 - 0x400C0604, // 000D CONNECT R3 R3 R4 - 0x88100101, // 000E GETMBR R4 R0 K1 - 0x940C0803, // 000F GETIDX R3 R4 R3 - 0x8C140703, // 0010 GETMET R5 R3 K3 - 0x581C0000, // 0011 LDCONST R7 K0 - 0x58200004, // 0012 LDCONST R8 K4 - 0x7C140600, // 0013 CALL R5 3 - 0x5C100A00, // 0014 MOVE R4 R5 - 0x541650A9, // 0015 LDINT R5 20650 - 0x1C140805, // 0016 EQ R5 R4 R5 - 0x78160008, // 0017 JMPF R5 #0021 - 0xB8160A00, // 0018 GETNGBL R5 K5 - 0x8C140B06, // 0019 GETMET R5 R5 K6 - 0x5C1C0600, // 001A MOVE R7 R3 - 0x7C140400, // 001B CALL R5 2 - 0x88180107, // 001C GETMBR R6 R0 K7 - 0x8C180D08, // 001D GETMET R6 R6 K8 - 0x5C200A00, // 001E MOVE R8 R5 - 0x7C180400, // 001F CALL R6 2 - 0x70020010, // 0020 JMP #0032 - 0x5416EBEA, // 0021 LDINT R5 60395 - 0x1C140805, // 0022 EQ R5 R4 R5 - 0x7816000C, // 0023 JMPF R5 #0031 - 0x5416001F, // 0024 LDINT R5 32 - 0x08140405, // 0025 MUL R5 R2 R5 - 0x541A000F, // 0026 LDINT R6 16 - 0x00140A06, // 0027 ADD R5 R5 R6 - 0x541A0020, // 0028 LDINT R6 33 - 0x08180406, // 0029 MUL R6 R2 R6 - 0x04180D02, // 002A SUB R6 R6 K2 - 0x40140A06, // 002B CONNECT R5 R5 R6 - 0x88180101, // 002C GETMBR R6 R0 K1 - 0x94140C05, // 002D GETIDX R5 R6 R5 - 0x90021205, // 002E SETMBR R0 K9 R5 - 0x70020002, // 002F JMP #0033 - 0x70020000, // 0030 JMP #0032 - 0x70020000, // 0031 JMP #0033 - 0x7001FFD1, // 0032 JMP #0005 - 0xA8040001, // 0033 EXBLK 1 1 - 0x70020002, // 0034 JMP #0038 - 0x5804000A, // 0035 LDCONST R1 K10 - 0xAC040200, // 0036 CATCH R1 1 0 - 0xB0080000, // 0037 RAISE 2 R0 R0 - 0x80000000, // 0038 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_max_flash_size_k -********************************************************************/ -be_local_closure(Partition_get_max_flash_size_k, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(tasmota), - /* K1 */ be_nested_str(memory), - /* K2 */ be_nested_str(flash), - /* K3 */ be_nested_str(find), - /* K4 */ be_nested_str(flash_real), - /* K5 */ be_nested_str(get_flash_definition_sector), - }), - &be_const_str_get_max_flash_size_k, - &be_const_str_solidified, - ( &(const binstruction[20]) { /* code */ - 0xB8060000, // 0000 GETNGBL R1 K0 - 0x8C040301, // 0001 GETMET R1 R1 K1 - 0x7C040200, // 0002 CALL R1 1 - 0x94040302, // 0003 GETIDX R1 R1 K2 - 0xB80A0000, // 0004 GETNGBL R2 K0 - 0x8C080501, // 0005 GETMET R2 R2 K1 - 0x7C080200, // 0006 CALL R2 1 - 0x8C080503, // 0007 GETMET R2 R2 K3 - 0x58100004, // 0008 LDCONST R4 K4 - 0x5C140200, // 0009 MOVE R5 R1 - 0x7C080600, // 000A CALL R2 3 - 0x200C0202, // 000B NE R3 R1 R2 - 0x780E0005, // 000C JMPF R3 #0013 - 0x8C0C0105, // 000D GETMET R3 R0 K5 - 0x7C0C0200, // 000E CALL R3 1 - 0x4C100000, // 000F LDNIL R4 - 0x200C0604, // 0010 NE R3 R3 R4 - 0x780E0000, // 0011 JMPF R3 #0013 - 0x5C040400, // 0012 MOVE R1 R2 - 0x80040200, // 0013 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified function: resize_max_flash_size_k ********************************************************************/ @@ -927,68 +639,11 @@ be_local_closure(Partition_resize_max_flash_size_k, /* name */ /******************************************************************** -** Solidified function: get_flash_definition_sector +** Solidified function: get_max_flash_size_k ********************************************************************/ -be_local_closure(Partition_get_flash_definition_sector, /* name */ +be_local_closure(Partition_get_max_flash_size_k, /* name */ be_nested_proto( - 9, /* nstack */ - 0, /* argc */ - 4, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_const_class(be_class_Partition), - /* K1 */ be_nested_str(flash), - /* K2 */ be_const_int(0), - /* K3 */ be_const_int(1), - /* K4 */ be_nested_str(read), - /* K5 */ be_nested_str(E9), - /* K6 */ be_nested_str(stop_iteration), - }), - &be_const_str_get_flash_definition_sector, - &be_const_str_solidified, - ( &(const binstruction[26]) { /* code */ - 0x58000000, // 0000 LDCONST R0 K0 - 0xA4060200, // 0001 IMPORT R1 K1 - 0x60080010, // 0002 GETGBL R2 G16 - 0x400E0503, // 0003 CONNECT R3 K2 K3 - 0x7C080200, // 0004 CALL R2 1 - 0xA802000F, // 0005 EXBLK 0 #0016 - 0x5C0C0400, // 0006 MOVE R3 R2 - 0x7C0C0000, // 0007 CALL R3 0 - 0x54120FFF, // 0008 LDINT R4 4096 - 0x08100604, // 0009 MUL R4 R3 R4 - 0x8C140304, // 000A GETMET R5 R1 K4 - 0x5C1C0800, // 000B MOVE R7 R4 - 0x58200003, // 000C LDCONST R8 K3 - 0x7C140600, // 000D CALL R5 3 - 0x60180015, // 000E GETGBL R6 G21 - 0x581C0005, // 000F LDCONST R7 K5 - 0x7C180200, // 0010 CALL R6 1 - 0x1C140A06, // 0011 EQ R5 R5 R6 - 0x78160001, // 0012 JMPF R5 #0015 - 0xA8040001, // 0013 EXBLK 1 1 - 0x80040800, // 0014 RET 1 R4 - 0x7001FFEF, // 0015 JMP #0006 - 0x58080006, // 0016 LDCONST R2 K6 - 0xAC080200, // 0017 CATCH R2 1 0 - 0xB0080000, // 0018 RAISE 2 R0 R0 - 0x80000000, // 0019 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: resize_fs_to_max -********************************************************************/ -be_local_closure(Partition_resize_fs_to_max, /* name */ - be_nested_proto( - 9, /* nstack */ + 6, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -996,80 +651,37 @@ be_local_closure(Partition_resize_fs_to_max, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[15]) { /* constants */ - /* K0 */ be_nested_str(get_unallocated_k), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(tasmota), - /* K3 */ be_nested_str(log), - /* K4 */ be_nested_str(BRY_X3A_X20Trying_X20to_X20expand_X20FS_X20by_X20_X25i_X20kB), - /* K5 */ be_const_int(2), - /* K6 */ be_nested_str(resize_max_flash_size_k), - /* K7 */ be_nested_str(slots), - /* K8 */ be_nested_str(sz), - /* K9 */ be_nested_str(save), - /* K10 */ be_nested_str(invalidate_spiffs), - /* K11 */ be_nested_str(global), - /* K12 */ be_nested_str(restart_flag), - /* K13 */ be_nested_str(BRY_X3A_X20Successfully_X20resized_X20FS_X2C_X20restarting), - /* K14 */ be_nested_str(BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s), + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(tasmota), + /* K1 */ be_nested_str(memory), + /* K2 */ be_nested_str(flash), + /* K3 */ be_nested_str(find), + /* K4 */ be_nested_str(flash_real), + /* K5 */ be_nested_str(get_flash_definition_sector), }), - &be_const_str_resize_fs_to_max, + &be_const_str_get_max_flash_size_k, &be_const_str_solidified, - ( &(const binstruction[54]) { /* code */ - 0xA8020026, // 0000 EXBLK 0 #0028 - 0x8C040100, // 0001 GETMET R1 R0 K0 + ( &(const binstruction[20]) { /* code */ + 0xB8060000, // 0000 GETNGBL R1 K0 + 0x8C040301, // 0001 GETMET R1 R1 K1 0x7C040200, // 0002 CALL R1 1 - 0x18080301, // 0003 LE R2 R1 K1 - 0x780A0002, // 0004 JMPF R2 #0008 - 0x4C080000, // 0005 LDNIL R2 - 0xA8040001, // 0006 EXBLK 1 1 - 0x80040400, // 0007 RET 1 R2 - 0xB80A0400, // 0008 GETNGBL R2 K2 - 0x8C080503, // 0009 GETMET R2 R2 K3 - 0x60100018, // 000A GETGBL R4 G24 - 0x58140004, // 000B LDCONST R5 K4 - 0x5C180200, // 000C MOVE R6 R1 - 0x7C100400, // 000D CALL R4 2 - 0x58140005, // 000E LDCONST R5 K5 - 0x7C080600, // 000F CALL R2 3 - 0x8C080106, // 0010 GETMET R2 R0 K6 - 0x7C080200, // 0011 CALL R2 1 - 0x5409FFFE, // 0012 LDINT R2 -1 - 0x880C0107, // 0013 GETMBR R3 R0 K7 - 0x94080602, // 0014 GETIDX R2 R3 R2 - 0x541603FF, // 0015 LDINT R5 1024 - 0x08140205, // 0016 MUL R5 R1 R5 - 0x88100508, // 0017 GETMBR R4 R2 K8 - 0x00100805, // 0018 ADD R4 R4 R5 - 0x900A1004, // 0019 SETMBR R2 K8 R4 - 0x8C100109, // 001A GETMET R4 R0 K9 - 0x7C100200, // 001B CALL R4 1 - 0x8C0C010A, // 001C GETMET R3 R0 K10 - 0x7C0C0200, // 001D CALL R3 1 - 0xB80E0400, // 001E GETNGBL R3 K2 - 0x880C070B, // 001F GETMBR R3 R3 K11 - 0x900E1905, // 0020 SETMBR R3 K12 K5 - 0xB80E0400, // 0021 GETNGBL R3 K2 - 0x8C0C0703, // 0022 GETMET R3 R3 K3 - 0x5814000D, // 0023 LDCONST R5 K13 - 0x58180005, // 0024 LDCONST R6 K5 - 0x7C0C0600, // 0025 CALL R3 3 - 0xA8040001, // 0026 EXBLK 1 1 - 0x7002000C, // 0027 JMP #0035 - 0xAC040002, // 0028 CATCH R1 0 2 - 0x70020009, // 0029 JMP #0034 - 0xB80E0400, // 002A GETNGBL R3 K2 - 0x8C0C0703, // 002B GETMET R3 R3 K3 - 0x60140018, // 002C GETGBL R5 G24 - 0x5818000E, // 002D LDCONST R6 K14 - 0x5C1C0200, // 002E MOVE R7 R1 - 0x5C200400, // 002F MOVE R8 R2 - 0x7C140600, // 0030 CALL R5 3 - 0x58180005, // 0031 LDCONST R6 K5 - 0x7C0C0600, // 0032 CALL R3 3 - 0x70020000, // 0033 JMP #0035 - 0xB0080000, // 0034 RAISE 2 R0 R0 - 0x80000000, // 0035 RET 0 + 0x94040302, // 0003 GETIDX R1 R1 K2 + 0xB80A0000, // 0004 GETNGBL R2 K0 + 0x8C080501, // 0005 GETMET R2 R2 K1 + 0x7C080200, // 0006 CALL R2 1 + 0x8C080503, // 0007 GETMET R2 R2 K3 + 0x58100004, // 0008 LDCONST R4 K4 + 0x5C140200, // 0009 MOVE R5 R1 + 0x7C080600, // 000A CALL R2 3 + 0x200C0202, // 000B NE R3 R1 R2 + 0x780E0005, // 000C JMPF R3 #0013 + 0x8C0C0105, // 000D GETMET R3 R0 K5 + 0x7C0C0200, // 000E CALL R3 1 + 0x4C100000, // 000F LDNIL R4 + 0x200C0604, // 0010 NE R3 R3 R4 + 0x780E0000, // 0011 JMPF R3 #0013 + 0x5C040400, // 0012 MOVE R1 R2 + 0x80040200, // 0013 RET 1 R1 }) ) ); @@ -1077,42 +689,11 @@ be_local_closure(Partition_resize_fs_to_max, /* name */ /******************************************************************** -** Solidified function: switch_factory +** Solidified function: get_unallocated_k ********************************************************************/ -be_local_closure(Partition_switch_factory, /* name */ +be_local_closure(Partition_get_unallocated_k, /* name */ be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str(flash), - /* K1 */ be_nested_str(factory), - }), - &be_const_str_switch_factory, - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x8C0C0501, // 0001 GETMET R3 R2 K1 - 0x5C140200, // 0002 MOVE R5 R1 - 0x7C0C0400, // 0003 CALL R3 2 - 0x80000000, // 0004 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: load_otadata -********************************************************************/ -be_local_closure(Partition_load_otadata, /* name */ - be_nested_proto( - 8, /* nstack */ + 5, /* nstack */ 1, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1120,138 +701,36 @@ be_local_closure(Partition_load_otadata, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ - /* K0 */ be_nested_str(ota_max), - /* K1 */ be_nested_str(slots), - /* K2 */ be_nested_str(type), - /* K3 */ be_const_int(1), - /* K4 */ be_nested_str(subtype), + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(slots), + /* K1 */ be_nested_str(is_spiffs), + /* K2 */ be_nested_str(get_max_flash_size_k), + /* K3 */ be_nested_str(start), + /* K4 */ be_nested_str(sz), /* K5 */ be_const_int(0), - /* K6 */ be_nested_str(start), - /* K7 */ be_nested_str(stop_iteration), - /* K8 */ be_nested_str(otadata), - /* K9 */ be_nested_str(partition_core), - /* K10 */ be_nested_str(Partition_otadata), - /* K11 */ be_nested_str(has_factory), }), - &be_const_str_load_otadata, + &be_const_str_get_unallocated_k, &be_const_str_solidified, - ( &(const binstruction[29]) { /* code */ - 0x5406DFFF, // 0000 LDINT R1 57344 - 0x8C080100, // 0001 GETMET R2 R0 K0 - 0x7C080200, // 0002 CALL R2 1 - 0x600C0010, // 0003 GETGBL R3 G16 - 0x88100101, // 0004 GETMBR R4 R0 K1 - 0x7C0C0200, // 0005 CALL R3 1 - 0xA8020009, // 0006 EXBLK 0 #0011 - 0x5C100600, // 0007 MOVE R4 R3 - 0x7C100000, // 0008 CALL R4 0 - 0x88140902, // 0009 GETMBR R5 R4 K2 - 0x1C140B03, // 000A EQ R5 R5 K3 - 0x78160003, // 000B JMPF R5 #0010 - 0x88140904, // 000C GETMBR R5 R4 K4 - 0x1C140B05, // 000D EQ R5 R5 K5 - 0x78160000, // 000E JMPF R5 #0010 - 0x88040906, // 000F GETMBR R1 R4 K6 - 0x7001FFF5, // 0010 JMP #0007 - 0x580C0007, // 0011 LDCONST R3 K7 - 0xAC0C0200, // 0012 CATCH R3 1 0 - 0xB0080000, // 0013 RAISE 2 R0 R0 - 0xB80E1200, // 0014 GETNGBL R3 K9 - 0x8C0C070A, // 0015 GETMET R3 R3 K10 - 0x5C140400, // 0016 MOVE R5 R2 - 0x8C18010B, // 0017 GETMET R6 R0 K11 - 0x7C180200, // 0018 CALL R6 1 - 0x5C1C0200, // 0019 MOVE R7 R1 - 0x7C0C0800, // 001A CALL R3 4 - 0x90021003, // 001B SETMBR R0 K8 R3 - 0x80000000, // 001C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: tostring -********************************************************************/ -be_local_closure(Partition_tostring, /* name */ - be_nested_proto( - 6, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str(_X3Cinstance_X3A_X20Partition_X28_X5B_X0A), - /* K1 */ be_nested_str(slots), - /* K2 */ be_nested_str(_X20_X20), - /* K3 */ be_nested_str(tostring), - /* K4 */ be_nested_str(_X0A), - /* K5 */ be_nested_str(stop_iteration), - /* K6 */ be_nested_str(_X5D_X2C_X0A_X20_X20), - /* K7 */ be_nested_str(otadata), - /* K8 */ be_nested_str(_X0A_X29_X3E), - }), - &be_const_str_tostring, - &be_const_str_solidified, - ( &(const binstruction[23]) { /* code */ - 0x58040000, // 0000 LDCONST R1 K0 - 0x60080010, // 0001 GETGBL R2 G16 - 0x880C0101, // 0002 GETMBR R3 R0 K1 - 0x7C080200, // 0003 CALL R2 1 - 0xA8020007, // 0004 EXBLK 0 #000D - 0x5C0C0400, // 0005 MOVE R3 R2 - 0x7C0C0000, // 0006 CALL R3 0 - 0x00040302, // 0007 ADD R1 R1 K2 - 0x8C100703, // 0008 GETMET R4 R3 K3 - 0x7C100200, // 0009 CALL R4 1 - 0x00040204, // 000A ADD R1 R1 R4 - 0x00040304, // 000B ADD R1 R1 K4 - 0x7001FFF7, // 000C JMP #0005 - 0x58080005, // 000D LDCONST R2 K5 - 0xAC080200, // 000E CATCH R2 1 0 - 0xB0080000, // 000F RAISE 2 R0 R0 - 0x00040306, // 0010 ADD R1 R1 K6 - 0x88080107, // 0011 GETMBR R2 R0 K7 - 0x8C080503, // 0012 GETMET R2 R2 K3 - 0x7C080200, // 0013 CALL R2 1 - 0x00040202, // 0014 ADD R1 R1 R2 - 0x00040308, // 0015 ADD R1 R1 K8 - 0x80040200, // 0016 RET 1 R1 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: has_factory -********************************************************************/ -be_local_closure(Partition_has_factory, /* name */ - be_nested_proto( - 3, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 1]) { /* constants */ - /* K0 */ be_nested_str(get_factory_slot), - }), - &be_const_str_has_factory, - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0x8C040100, // 0000 GETMET R1 R0 K0 - 0x7C040200, // 0001 CALL R1 1 - 0x4C080000, // 0002 LDNIL R2 - 0x20040202, // 0003 NE R1 R1 R2 - 0x80040200, // 0004 RET 1 R1 + ( &(const binstruction[19]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x5409FFFE, // 0001 LDINT R2 -1 + 0x94040202, // 0002 GETIDX R1 R1 R2 + 0x8C0C0301, // 0003 GETMET R3 R1 K1 + 0x7C0C0200, // 0004 CALL R3 1 + 0x780E000B, // 0005 JMPF R3 #0012 + 0x8C0C0102, // 0006 GETMET R3 R0 K2 + 0x7C0C0200, // 0007 CALL R3 1 + 0x5C080600, // 0008 MOVE R2 R3 + 0x880C0303, // 0009 GETMBR R3 R1 K3 + 0x88100304, // 000A GETMBR R4 R1 K4 + 0x000C0604, // 000B ADD R3 R3 R4 + 0x541203FF, // 000C LDINT R4 1024 + 0x0C0C0604, // 000D DIV R3 R3 R4 + 0x14100602, // 000E LT R4 R3 R2 + 0x78120001, // 000F JMPF R4 #0012 + 0x04100403, // 0010 SUB R4 R2 R3 + 0x80040800, // 0011 RET 1 R4 + 0x80060A00, // 0012 RET 1 K5 }) ) ); @@ -1326,6 +805,511 @@ be_local_closure(Partition_tobytes, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: has_factory +********************************************************************/ +be_local_closure(Partition_has_factory, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 1]) { /* constants */ + /* K0 */ be_nested_str(get_factory_slot), + }), + &be_const_str_has_factory, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0x8C040100, // 0000 GETMET R1 R0 K0 + 0x7C040200, // 0001 CALL R1 1 + 0x4C080000, // 0002 LDNIL R2 + 0x20040202, // 0003 NE R1 R1 R2 + 0x80040200, // 0004 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: resize_fs_to_max +********************************************************************/ +be_local_closure(Partition_resize_fs_to_max, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[14]) { /* constants */ + /* K0 */ be_nested_str(get_unallocated_k), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(tasmota), + /* K3 */ be_nested_str(log), + /* K4 */ be_nested_str(BRY_X3A_X20Trying_X20to_X20expand_X20FS_X20by_X20_X25i_X20kB), + /* K5 */ be_const_int(2), + /* K6 */ be_nested_str(resize_max_flash_size_k), + /* K7 */ be_nested_str(slots), + /* K8 */ be_nested_str(sz), + /* K9 */ be_nested_str(save), + /* K10 */ be_nested_str(global), + /* K11 */ be_nested_str(restart_flag), + /* K12 */ be_nested_str(BRY_X3A_X20Successfully_X20resized_X20FS_X2C_X20restarting), + /* K13 */ be_nested_str(BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s), + }), + &be_const_str_resize_fs_to_max, + &be_const_str_solidified, + ( &(const binstruction[52]) { /* code */ + 0xA8020024, // 0000 EXBLK 0 #0026 + 0x8C040100, // 0001 GETMET R1 R0 K0 + 0x7C040200, // 0002 CALL R1 1 + 0x18080301, // 0003 LE R2 R1 K1 + 0x780A0002, // 0004 JMPF R2 #0008 + 0x4C080000, // 0005 LDNIL R2 + 0xA8040001, // 0006 EXBLK 1 1 + 0x80040400, // 0007 RET 1 R2 + 0xB80A0400, // 0008 GETNGBL R2 K2 + 0x8C080503, // 0009 GETMET R2 R2 K3 + 0x60100018, // 000A GETGBL R4 G24 + 0x58140004, // 000B LDCONST R5 K4 + 0x5C180200, // 000C MOVE R6 R1 + 0x7C100400, // 000D CALL R4 2 + 0x58140005, // 000E LDCONST R5 K5 + 0x7C080600, // 000F CALL R2 3 + 0x8C080106, // 0010 GETMET R2 R0 K6 + 0x7C080200, // 0011 CALL R2 1 + 0x88080107, // 0012 GETMBR R2 R0 K7 + 0x540DFFFE, // 0013 LDINT R3 -1 + 0x94080403, // 0014 GETIDX R2 R2 R3 + 0x541603FF, // 0015 LDINT R5 1024 + 0x08140205, // 0016 MUL R5 R1 R5 + 0x88100508, // 0017 GETMBR R4 R2 K8 + 0x00100805, // 0018 ADD R4 R4 R5 + 0x900A1004, // 0019 SETMBR R2 K8 R4 + 0x8C100109, // 001A GETMET R4 R0 K9 + 0x7C100200, // 001B CALL R4 1 + 0xB80E0400, // 001C GETNGBL R3 K2 + 0x880C070A, // 001D GETMBR R3 R3 K10 + 0x900E1705, // 001E SETMBR R3 K11 K5 + 0xB80E0400, // 001F GETNGBL R3 K2 + 0x8C0C0703, // 0020 GETMET R3 R3 K3 + 0x5814000C, // 0021 LDCONST R5 K12 + 0x58180005, // 0022 LDCONST R6 K5 + 0x7C0C0600, // 0023 CALL R3 3 + 0xA8040001, // 0024 EXBLK 1 1 + 0x7002000C, // 0025 JMP #0033 + 0xAC040002, // 0026 CATCH R1 0 2 + 0x70020009, // 0027 JMP #0032 + 0xB80E0400, // 0028 GETNGBL R3 K2 + 0x8C0C0703, // 0029 GETMET R3 R3 K3 + 0x60140018, // 002A GETGBL R5 G24 + 0x5818000D, // 002B LDCONST R6 K13 + 0x5C1C0200, // 002C MOVE R7 R1 + 0x5C200400, // 002D MOVE R8 R2 + 0x7C140600, // 002E CALL R5 3 + 0x58180005, // 002F LDCONST R6 K5 + 0x7C0C0600, // 0030 CALL R3 3 + 0x70020000, // 0031 JMP #0033 + 0xB0080000, // 0032 RAISE 2 R0 R0 + 0x80000000, // 0033 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_ota_slot +********************************************************************/ +be_local_closure(Partition_get_ota_slot, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(slots), + /* K1 */ be_nested_str(is_ota), + /* K2 */ be_nested_str(stop_iteration), + }), + &be_const_str_get_ota_slot, + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x60080010, // 0000 GETGBL R2 G16 + 0x880C0100, // 0001 GETMBR R3 R0 K0 + 0x7C080200, // 0002 CALL R2 1 + 0xA8020008, // 0003 EXBLK 0 #000D + 0x5C0C0400, // 0004 MOVE R3 R2 + 0x7C0C0000, // 0005 CALL R3 0 + 0x8C100701, // 0006 GETMET R4 R3 K1 + 0x7C100200, // 0007 CALL R4 1 + 0x1C100801, // 0008 EQ R4 R4 R1 + 0x78120001, // 0009 JMPF R4 #000C + 0xA8040001, // 000A EXBLK 1 1 + 0x80040600, // 000B RET 1 R3 + 0x7001FFF6, // 000C JMP #0004 + 0x58080002, // 000D LDCONST R2 K2 + 0xAC080200, // 000E CATCH R2 1 0 + 0xB0080000, // 000F RAISE 2 R0 R0 + 0x4C080000, // 0010 LDNIL R2 + 0x80040400, // 0011 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: tostring +********************************************************************/ +be_local_closure(Partition_tostring, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str(_X3Cinstance_X3A_X20Partition_X28_X5B_X0A), + /* K1 */ be_nested_str(slots), + /* K2 */ be_nested_str(_X20_X20), + /* K3 */ be_nested_str(tostring), + /* K4 */ be_nested_str(_X0A), + /* K5 */ be_nested_str(stop_iteration), + /* K6 */ be_nested_str(_X5D_X2C_X0A_X20_X20), + /* K7 */ be_nested_str(otadata), + /* K8 */ be_nested_str(_X0A_X29_X3E), + }), + &be_const_str_tostring, + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x58040000, // 0000 LDCONST R1 K0 + 0x60080010, // 0001 GETGBL R2 G16 + 0x880C0101, // 0002 GETMBR R3 R0 K1 + 0x7C080200, // 0003 CALL R2 1 + 0xA8020007, // 0004 EXBLK 0 #000D + 0x5C0C0400, // 0005 MOVE R3 R2 + 0x7C0C0000, // 0006 CALL R3 0 + 0x00040302, // 0007 ADD R1 R1 K2 + 0x8C100703, // 0008 GETMET R4 R3 K3 + 0x7C100200, // 0009 CALL R4 1 + 0x00040204, // 000A ADD R1 R1 R4 + 0x00040304, // 000B ADD R1 R1 K4 + 0x7001FFF7, // 000C JMP #0005 + 0x58080005, // 000D LDCONST R2 K5 + 0xAC080200, // 000E CATCH R2 1 0 + 0xB0080000, // 000F RAISE 2 R0 R0 + 0x00040306, // 0010 ADD R1 R1 K6 + 0x88080107, // 0011 GETMBR R2 R0 K7 + 0x8C080503, // 0012 GETMET R2 R2 K3 + 0x7C080200, // 0013 CALL R2 1 + 0x00040202, // 0014 ADD R1 R1 R2 + 0x00040308, // 0015 ADD R1 R1 K8 + 0x80040200, // 0016 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: parse +********************************************************************/ +be_local_closure(Partition_parse, /* name */ + be_nested_proto( + 9, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[11]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str(raw), + /* K2 */ be_const_int(1), + /* K3 */ be_nested_str(get), + /* K4 */ be_const_int(2), + /* K5 */ be_nested_str(partition_core), + /* K6 */ be_nested_str(Partition_info), + /* K7 */ be_nested_str(slots), + /* K8 */ be_nested_str(push), + /* K9 */ be_nested_str(md5), + /* K10 */ be_nested_str(stop_iteration), + }), + &be_const_str_parse, + &be_const_str_solidified, + ( &(const binstruction[57]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x540A005D, // 0001 LDINT R2 94 + 0x400A0002, // 0002 CONNECT R2 K0 R2 + 0x7C040200, // 0003 CALL R1 1 + 0xA802002F, // 0004 EXBLK 0 #0035 + 0x5C080200, // 0005 MOVE R2 R1 + 0x7C080000, // 0006 CALL R2 0 + 0x540E001F, // 0007 LDINT R3 32 + 0x080C0403, // 0008 MUL R3 R2 R3 + 0x00100502, // 0009 ADD R4 R2 K2 + 0x5416001F, // 000A LDINT R5 32 + 0x08100805, // 000B MUL R4 R4 R5 + 0x04100902, // 000C SUB R4 R4 K2 + 0x400C0604, // 000D CONNECT R3 R3 R4 + 0x88100101, // 000E GETMBR R4 R0 K1 + 0x940C0803, // 000F GETIDX R3 R4 R3 + 0x8C140703, // 0010 GETMET R5 R3 K3 + 0x581C0000, // 0011 LDCONST R7 K0 + 0x58200004, // 0012 LDCONST R8 K4 + 0x7C140600, // 0013 CALL R5 3 + 0x5C100A00, // 0014 MOVE R4 R5 + 0x541650A9, // 0015 LDINT R5 20650 + 0x1C140805, // 0016 EQ R5 R4 R5 + 0x78160008, // 0017 JMPF R5 #0021 + 0xB8160A00, // 0018 GETNGBL R5 K5 + 0x8C140B06, // 0019 GETMET R5 R5 K6 + 0x5C1C0600, // 001A MOVE R7 R3 + 0x7C140400, // 001B CALL R5 2 + 0x88180107, // 001C GETMBR R6 R0 K7 + 0x8C180D08, // 001D GETMET R6 R6 K8 + 0x5C200A00, // 001E MOVE R8 R5 + 0x7C180400, // 001F CALL R6 2 + 0x70020010, // 0020 JMP #0032 + 0x5416EBEA, // 0021 LDINT R5 60395 + 0x1C140805, // 0022 EQ R5 R4 R5 + 0x7816000C, // 0023 JMPF R5 #0031 + 0x5416001F, // 0024 LDINT R5 32 + 0x08140405, // 0025 MUL R5 R2 R5 + 0x541A000F, // 0026 LDINT R6 16 + 0x00140A06, // 0027 ADD R5 R5 R6 + 0x541A0020, // 0028 LDINT R6 33 + 0x08180406, // 0029 MUL R6 R2 R6 + 0x04180D02, // 002A SUB R6 R6 K2 + 0x40140A06, // 002B CONNECT R5 R5 R6 + 0x88180101, // 002C GETMBR R6 R0 K1 + 0x94140C05, // 002D GETIDX R5 R6 R5 + 0x90021205, // 002E SETMBR R0 K9 R5 + 0x70020002, // 002F JMP #0033 + 0x70020000, // 0030 JMP #0032 + 0x70020000, // 0031 JMP #0033 + 0x7001FFD1, // 0032 JMP #0005 + 0xA8040001, // 0033 EXBLK 1 1 + 0x70020002, // 0034 JMP #0038 + 0x5804000A, // 0035 LDCONST R1 K10 + 0xAC040200, // 0036 CATCH R1 1 0 + 0xB0080000, // 0037 RAISE 2 R0 R0 + 0x80000000, // 0038 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: load +********************************************************************/ +be_local_closure(Partition_load, /* name */ + be_nested_proto( + 6, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(flash), + /* K1 */ be_nested_str(raw), + /* K2 */ be_nested_str(read), + }), + &be_const_str_load, + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080302, // 0001 GETMET R2 R1 K2 + 0x54127FFF, // 0002 LDINT R4 32768 + 0x54160FFF, // 0003 LDINT R5 4096 + 0x7C080600, // 0004 CALL R2 3 + 0x90020202, // 0005 SETMBR R0 K1 R2 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_factory_slot +********************************************************************/ +be_local_closure(Partition_get_factory_slot, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(slots), + /* K1 */ be_nested_str(is_factory), + /* K2 */ be_nested_str(stop_iteration), + }), + &be_const_str_get_factory_slot, + &be_const_str_solidified, + ( &(const binstruction[16]) { /* code */ + 0x60040010, // 0000 GETGBL R1 G16 + 0x88080100, // 0001 GETMBR R2 R0 K0 + 0x7C040200, // 0002 CALL R1 1 + 0xA8020007, // 0003 EXBLK 0 #000C + 0x5C080200, // 0004 MOVE R2 R1 + 0x7C080000, // 0005 CALL R2 0 + 0x8C0C0501, // 0006 GETMET R3 R2 K1 + 0x7C0C0200, // 0007 CALL R3 1 + 0x780E0001, // 0008 JMPF R3 #000B + 0xA8040001, // 0009 EXBLK 1 1 + 0x80040400, // 000A RET 1 R2 + 0x7001FFF7, // 000B JMP #0004 + 0x58040002, // 000C LDCONST R1 K2 + 0xAC040200, // 000D CATCH R1 1 0 + 0xB0080000, // 000E RAISE 2 R0 R0 + 0x80000000, // 000F RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: init +********************************************************************/ +be_local_closure(Partition_init, /* name */ + be_nested_proto( + 3, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str(slots), + /* K1 */ be_nested_str(load), + /* K2 */ be_nested_str(parse), + /* K3 */ be_nested_str(load_otadata), + }), + &be_const_str_init, + &be_const_str_solidified, + ( &(const binstruction[10]) { /* code */ + 0x60040012, // 0000 GETGBL R1 G18 + 0x7C040000, // 0001 CALL R1 0 + 0x90020001, // 0002 SETMBR R0 K0 R1 + 0x8C040101, // 0003 GETMET R1 R0 K1 + 0x7C040200, // 0004 CALL R1 1 + 0x8C040102, // 0005 GETMET R1 R0 K2 + 0x7C040200, // 0006 CALL R1 1 + 0x8C040103, // 0007 GETMET R1 R0 K3 + 0x7C040200, // 0008 CALL R1 1 + 0x80000000, // 0009 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: set_active +********************************************************************/ +be_local_closure(Partition_set_active, /* name */ + be_nested_proto( + 6, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_const_int(0), + /* K1 */ be_nested_str(ota_max), + /* K2 */ be_nested_str(value_error), + /* K3 */ be_nested_str(Invalid_X20ota_X20partition_X20number), + /* K4 */ be_nested_str(otadata), + /* K5 */ be_nested_str(set_ota_max), + /* K6 */ be_nested_str(set_active), + }), + &be_const_str_set_active, + &be_const_str_solidified, + ( &(const binstruction[17]) { /* code */ + 0x14080300, // 0000 LT R2 R1 K0 + 0x740A0003, // 0001 JMPT R2 #0006 + 0x8C080101, // 0002 GETMET R2 R0 K1 + 0x7C080200, // 0003 CALL R2 1 + 0x24080202, // 0004 GT R2 R1 R2 + 0x780A0000, // 0005 JMPF R2 #0007 + 0xB0060503, // 0006 RAISE 1 K2 K3 + 0x88080104, // 0007 GETMBR R2 R0 K4 + 0x8C080505, // 0008 GETMET R2 R2 K5 + 0x8C100101, // 0009 GETMET R4 R0 K1 + 0x7C100200, // 000A CALL R4 1 + 0x7C080400, // 000B CALL R2 2 + 0x88080104, // 000C GETMBR R2 R0 K4 + 0x8C080506, // 000D GETMET R2 R2 K6 + 0x5C100200, // 000E MOVE R4 R1 + 0x7C080400, // 000F CALL R2 2 + 0x80000000, // 0010 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: get_active +********************************************************************/ +be_local_closure(Partition_get_active, /* name */ + be_nested_proto( + 2, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(otadata), + /* K1 */ be_nested_str(active_otadata), + }), + &be_const_str_get_active, + &be_const_str_solidified, + ( &(const binstruction[ 3]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x88040301, // 0001 GETMBR R1 R1 K1 + 0x80040200, // 0002 RET 1 R1 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: ota_max ********************************************************************/ @@ -1388,9 +1372,54 @@ be_local_closure(Partition_ota_max, /* name */ /******************************************************************** -** Solidified function: invalidate_spiffs +** Solidified function: save ********************************************************************/ -be_local_closure(Partition_invalidate_spiffs, /* name */ +be_local_closure(Partition_save, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(flash), + /* K1 */ be_nested_str(tobytes), + /* K2 */ be_nested_str(erase), + /* K3 */ be_nested_str(write), + /* K4 */ be_nested_str(otadata), + /* K5 */ be_nested_str(save), + }), + &be_const_str_save, + &be_const_str_solidified, + ( &(const binstruction[15]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080101, // 0001 GETMET R2 R0 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x8C0C0302, // 0003 GETMET R3 R1 K2 + 0x54167FFF, // 0004 LDINT R5 32768 + 0x541A0FFF, // 0005 LDINT R6 4096 + 0x7C0C0600, // 0006 CALL R3 3 + 0x8C0C0303, // 0007 GETMET R3 R1 K3 + 0x54167FFF, // 0008 LDINT R5 32768 + 0x5C180400, // 0009 MOVE R6 R2 + 0x7C0C0600, // 000A CALL R3 3 + 0x880C0104, // 000B GETMBR R3 R0 K4 + 0x8C0C0705, // 000C GETMET R3 R3 K5 + 0x7C0C0200, // 000D CALL R3 1 + 0x80000000, // 000E RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: load_otadata +********************************************************************/ +be_local_closure(Partition_load_otadata, /* name */ be_nested_proto( 8, /* nstack */ 1, /* argc */ @@ -1400,41 +1429,52 @@ be_local_closure(Partition_invalidate_spiffs, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str(flash), + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str(ota_max), /* K1 */ be_nested_str(slots), - /* K2 */ be_nested_str(is_spiffs), - /* K3 */ be_nested_str(value_error), - /* K4 */ be_nested_str(No_X20SPIFFS_X20partition_X20found), - /* K5 */ be_nested_str(00), - /* K6 */ be_nested_str(write), - /* K7 */ be_nested_str(start), + /* K2 */ be_nested_str(type), + /* K3 */ be_const_int(1), + /* K4 */ be_nested_str(subtype), + /* K5 */ be_const_int(0), + /* K6 */ be_nested_str(start), + /* K7 */ be_nested_str(stop_iteration), + /* K8 */ be_nested_str(otadata), + /* K9 */ be_nested_str(partition_core), + /* K10 */ be_nested_str(Partition_otadata), + /* K11 */ be_nested_str(has_factory), }), - &be_const_str_invalidate_spiffs, + &be_const_str_load_otadata, &be_const_str_solidified, - ( &(const binstruction[22]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x5409FFFE, // 0001 LDINT R2 -1 - 0x880C0101, // 0002 GETMBR R3 R0 K1 - 0x94080602, // 0003 GETIDX R2 R3 R2 - 0x8C100502, // 0004 GETMET R4 R2 K2 - 0x7C100200, // 0005 CALL R4 1 - 0x74120000, // 0006 JMPT R4 #0008 - 0xB0060704, // 0007 RAISE 1 K3 K4 - 0x600C0015, // 0008 GETGBL R3 G21 - 0x58100005, // 0009 LDCONST R4 K5 - 0x7C0C0200, // 000A CALL R3 1 - 0x8C100306, // 000B GETMET R4 R1 K6 - 0x88180507, // 000C GETMBR R6 R2 K7 - 0x5C1C0600, // 000D MOVE R7 R3 - 0x7C100600, // 000E CALL R4 3 - 0x8C100306, // 000F GETMET R4 R1 K6 - 0x88180507, // 0010 GETMBR R6 R2 K7 - 0x541E0FFF, // 0011 LDINT R7 4096 - 0x00180C07, // 0012 ADD R6 R6 R7 - 0x5C1C0600, // 0013 MOVE R7 R3 - 0x7C100600, // 0014 CALL R4 3 - 0x80000000, // 0015 RET 0 + ( &(const binstruction[29]) { /* code */ + 0x5406DFFF, // 0000 LDINT R1 57344 + 0x8C080100, // 0001 GETMET R2 R0 K0 + 0x7C080200, // 0002 CALL R2 1 + 0x600C0010, // 0003 GETGBL R3 G16 + 0x88100101, // 0004 GETMBR R4 R0 K1 + 0x7C0C0200, // 0005 CALL R3 1 + 0xA8020009, // 0006 EXBLK 0 #0011 + 0x5C100600, // 0007 MOVE R4 R3 + 0x7C100000, // 0008 CALL R4 0 + 0x88140902, // 0009 GETMBR R5 R4 K2 + 0x1C140B03, // 000A EQ R5 R5 K3 + 0x78160003, // 000B JMPF R5 #0010 + 0x88140904, // 000C GETMBR R5 R4 K4 + 0x1C140B05, // 000D EQ R5 R5 K5 + 0x78160000, // 000E JMPF R5 #0010 + 0x88040906, // 000F GETMBR R1 R4 K6 + 0x7001FFF5, // 0010 JMP #0007 + 0x580C0007, // 0011 LDCONST R3 K7 + 0xAC0C0200, // 0012 CATCH R3 1 0 + 0xB0080000, // 0013 RAISE 2 R0 R0 + 0xB80E1200, // 0014 GETNGBL R3 K9 + 0x8C0C070A, // 0015 GETMET R3 R3 K10 + 0x5C140400, // 0016 MOVE R5 R2 + 0x8C18010B, // 0017 GETMET R6 R0 K11 + 0x7C180200, // 0018 CALL R6 1 + 0x5C1C0200, // 0019 MOVE R7 R1 + 0x7C0C0800, // 001A CALL R3 4 + 0x90021003, // 001B SETMBR R0 K8 R3 + 0x80000000, // 001C RET 0 }) ) ); @@ -1442,90 +1482,56 @@ be_local_closure(Partition_invalidate_spiffs, /* name */ /******************************************************************** -** Solidified function: get_factory_slot +** Solidified function: get_flash_definition_sector ********************************************************************/ -be_local_closure(Partition_get_factory_slot, /* name */ +be_local_closure(Partition_get_flash_definition_sector, /* name */ be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(slots), - /* K1 */ be_nested_str(is_factory), - /* K2 */ be_nested_str(stop_iteration), - }), - &be_const_str_get_factory_slot, - &be_const_str_solidified, - ( &(const binstruction[16]) { /* code */ - 0x60040010, // 0000 GETGBL R1 G16 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x7C040200, // 0002 CALL R1 1 - 0xA8020007, // 0003 EXBLK 0 #000C - 0x5C080200, // 0004 MOVE R2 R1 - 0x7C080000, // 0005 CALL R2 0 - 0x8C0C0501, // 0006 GETMET R3 R2 K1 - 0x7C0C0200, // 0007 CALL R3 1 - 0x780E0001, // 0008 JMPF R3 #000B - 0xA8040001, // 0009 EXBLK 1 1 - 0x80040400, // 000A RET 1 R2 - 0x7001FFF7, // 000B JMP #0004 - 0x58040002, // 000C LDCONST R1 K2 - 0xAC040200, // 000D CATCH R1 1 0 - 0xB0080000, // 000E RAISE 2 R0 R0 - 0x80000000, // 000F RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: set_active -********************************************************************/ -be_local_closure(Partition_set_active, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ + 9, /* nstack */ + 0, /* argc */ + 4, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_const_int(0), - /* K1 */ be_nested_str(ota_max), - /* K2 */ be_nested_str(value_error), - /* K3 */ be_nested_str(Invalid_X20ota_X20partition_X20number), - /* K4 */ be_nested_str(otadata), - /* K5 */ be_nested_str(set_ota_max), - /* K6 */ be_nested_str(set_active), + /* K0 */ be_const_class(be_class_Partition), + /* K1 */ be_nested_str(flash), + /* K2 */ be_const_int(0), + /* K3 */ be_const_int(1), + /* K4 */ be_nested_str(read), + /* K5 */ be_nested_str(E9), + /* K6 */ be_nested_str(stop_iteration), }), - &be_const_str_set_active, + &be_const_str_get_flash_definition_sector, &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ - 0x14080300, // 0000 LT R2 R1 K0 - 0x740A0003, // 0001 JMPT R2 #0006 - 0x8C080101, // 0002 GETMET R2 R0 K1 - 0x7C080200, // 0003 CALL R2 1 - 0x24080202, // 0004 GT R2 R1 R2 - 0x780A0000, // 0005 JMPF R2 #0007 - 0xB0060503, // 0006 RAISE 1 K2 K3 - 0x88080104, // 0007 GETMBR R2 R0 K4 - 0x8C080505, // 0008 GETMET R2 R2 K5 - 0x8C100101, // 0009 GETMET R4 R0 K1 - 0x7C100200, // 000A CALL R4 1 - 0x7C080400, // 000B CALL R2 2 - 0x88080104, // 000C GETMBR R2 R0 K4 - 0x8C080506, // 000D GETMET R2 R2 K6 - 0x5C100200, // 000E MOVE R4 R1 - 0x7C080400, // 000F CALL R2 2 - 0x80000000, // 0010 RET 0 + ( &(const binstruction[26]) { /* code */ + 0x58000000, // 0000 LDCONST R0 K0 + 0xA4060200, // 0001 IMPORT R1 K1 + 0x60080010, // 0002 GETGBL R2 G16 + 0x400E0503, // 0003 CONNECT R3 K2 K3 + 0x7C080200, // 0004 CALL R2 1 + 0xA802000F, // 0005 EXBLK 0 #0016 + 0x5C0C0400, // 0006 MOVE R3 R2 + 0x7C0C0000, // 0007 CALL R3 0 + 0x54120FFF, // 0008 LDINT R4 4096 + 0x08100604, // 0009 MUL R4 R3 R4 + 0x8C140304, // 000A GETMET R5 R1 K4 + 0x5C1C0800, // 000B MOVE R7 R4 + 0x58200003, // 000C LDCONST R8 K3 + 0x7C140600, // 000D CALL R5 3 + 0x60180015, // 000E GETGBL R6 G21 + 0x581C0005, // 000F LDCONST R7 K5 + 0x7C180200, // 0010 CALL R6 1 + 0x1C140A06, // 0011 EQ R5 R5 R6 + 0x78160001, // 0012 JMPF R5 #0015 + 0xA8040001, // 0013 EXBLK 1 1 + 0x80040800, // 0014 RET 1 R4 + 0x7001FFEF, // 0015 JMP #0006 + 0x58080006, // 0016 LDCONST R2 K6 + 0xAC080200, // 0017 CATCH R2 1 0 + 0xB0080000, // 0018 RAISE 2 R0 R0 + 0x80000000, // 0019 RET 0 }) ) ); @@ -1533,58 +1539,9 @@ be_local_closure(Partition_set_active, /* name */ /******************************************************************** -** Solidified function: get_unallocated_k +** Solidified function: switch_factory ********************************************************************/ -be_local_closure(Partition_get_unallocated_k, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(slots), - /* K1 */ be_nested_str(is_spiffs), - /* K2 */ be_nested_str(get_max_flash_size_k), - /* K3 */ be_nested_str(start), - /* K4 */ be_nested_str(sz), - /* K5 */ be_const_int(0), - }), - &be_const_str_get_unallocated_k, - &be_const_str_solidified, - ( &(const binstruction[19]) { /* code */ - 0x5405FFFE, // 0000 LDINT R1 -1 - 0x88080100, // 0001 GETMBR R2 R0 K0 - 0x94040401, // 0002 GETIDX R1 R2 R1 - 0x8C0C0301, // 0003 GETMET R3 R1 K1 - 0x7C0C0200, // 0004 CALL R3 1 - 0x780E000B, // 0005 JMPF R3 #0012 - 0x8C0C0102, // 0006 GETMET R3 R0 K2 - 0x7C0C0200, // 0007 CALL R3 1 - 0x5C080600, // 0008 MOVE R2 R3 - 0x880C0303, // 0009 GETMBR R3 R1 K3 - 0x88100304, // 000A GETMBR R4 R1 K4 - 0x000C0604, // 000B ADD R3 R3 R4 - 0x541203FF, // 000C LDINT R4 1024 - 0x0C0C0604, // 000D DIV R3 R3 R4 - 0x14100602, // 000E LT R4 R3 R2 - 0x78120001, // 000F JMPF R4 #0012 - 0x04100403, // 0010 SUB R4 R2 R3 - 0x80040800, // 0011 RET 1 R4 - 0x80060A00, // 0012 RET 1 K5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: get_ota_slot -********************************************************************/ -be_local_closure(Partition_get_ota_slot, /* name */ +be_local_closure(Partition_switch_factory, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ @@ -1594,32 +1551,18 @@ be_local_closure(Partition_get_ota_slot, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(slots), - /* K1 */ be_nested_str(is_ota), - /* K2 */ be_nested_str(stop_iteration), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(flash), + /* K1 */ be_nested_str(factory), }), - &be_const_str_get_ota_slot, + &be_const_str_switch_factory, &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x60080010, // 0000 GETGBL R2 G16 - 0x880C0100, // 0001 GETMBR R3 R0 K0 - 0x7C080200, // 0002 CALL R2 1 - 0xA8020008, // 0003 EXBLK 0 #000D - 0x5C0C0400, // 0004 MOVE R3 R2 - 0x7C0C0000, // 0005 CALL R3 0 - 0x8C100701, // 0006 GETMET R4 R3 K1 - 0x7C100200, // 0007 CALL R4 1 - 0x1C100801, // 0008 EQ R4 R4 R1 - 0x78120001, // 0009 JMPF R4 #000C - 0xA8040001, // 000A EXBLK 1 1 - 0x80040600, // 000B RET 1 R3 - 0x7001FFF6, // 000C JMP #0004 - 0x58080002, // 000D LDCONST R2 K2 - 0xAC080200, // 000E CATCH R2 1 0 - 0xB0080000, // 000F RAISE 2 R0 R0 - 0x4C080000, // 0010 LDNIL R2 - 0x80040400, // 0011 RET 1 R2 + ( &(const binstruction[ 5]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x80000000, // 0004 RET 0 }) ) ); @@ -1632,32 +1575,31 @@ be_local_closure(Partition_get_ota_slot, /* name */ be_local_class(Partition, 4, NULL, - be_nested_map(24, + be_nested_map(23, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key(save, -1), be_const_closure(Partition_save_closure) }, - { be_const_key(load, 8), be_const_closure(Partition_load_closure) }, - { be_const_key(get_active, -1), be_const_closure(Partition_get_active_closure) }, - { be_const_key(init, -1), be_const_closure(Partition_init_closure) }, - { be_const_key(parse, 21), be_const_closure(Partition_parse_closure) }, - { be_const_key(otadata, -1), be_const_var(3) }, - { be_const_key(slots, 11), be_const_var(2) }, - { be_const_key(get_ota_slot, -1), be_const_closure(Partition_get_ota_slot_closure) }, { be_const_key(resize_max_flash_size_k, -1), be_const_closure(Partition_resize_max_flash_size_k_closure) }, - { be_const_key(get_flash_definition_sector, -1), be_const_static_closure(Partition_get_flash_definition_sector_closure) }, - { be_const_key(resize_fs_to_max, -1), be_const_closure(Partition_resize_fs_to_max_closure) }, - { be_const_key(set_active, -1), be_const_closure(Partition_set_active_closure) }, - { be_const_key(get_factory_slot, -1), be_const_closure(Partition_get_factory_slot_closure) }, - { be_const_key(tostring, -1), be_const_closure(Partition_tostring_closure) }, - { be_const_key(invalidate_spiffs, -1), be_const_closure(Partition_invalidate_spiffs_closure) }, - { be_const_key(tobytes, 12), be_const_closure(Partition_tobytes_closure) }, - { be_const_key(load_otadata, 20), be_const_closure(Partition_load_otadata_closure) }, + { be_const_key(switch_factory, 21), be_const_closure(Partition_switch_factory_closure) }, + { be_const_key(get_flash_definition_sector, 5), be_const_static_closure(Partition_get_flash_definition_sector_closure) }, + { be_const_key(load, 22), be_const_closure(Partition_load_closure) }, + { be_const_key(has_factory, -1), be_const_closure(Partition_has_factory_closure) }, + { be_const_key(slots, -1), be_const_var(2) }, { be_const_key(raw, -1), be_const_var(0) }, - { be_const_key(has_factory, 14), be_const_closure(Partition_has_factory_closure) }, - { be_const_key(md5, -1), be_const_var(1) }, + { be_const_key(set_active, -1), be_const_closure(Partition_set_active_closure) }, + { be_const_key(get_ota_slot, -1), be_const_closure(Partition_get_ota_slot_closure) }, + { be_const_key(tostring, -1), be_const_closure(Partition_tostring_closure) }, + { be_const_key(tobytes, 1), be_const_closure(Partition_tobytes_closure) }, + { be_const_key(get_unallocated_k, 3), be_const_closure(Partition_get_unallocated_k_closure) }, + { be_const_key(otadata, -1), be_const_var(3) }, + { be_const_key(md5, 2), be_const_var(1) }, + { be_const_key(init, 7), be_const_closure(Partition_init_closure) }, + { be_const_key(get_active, -1), be_const_closure(Partition_get_active_closure) }, + { be_const_key(get_factory_slot, 15), be_const_closure(Partition_get_factory_slot_closure) }, + { be_const_key(get_max_flash_size_k, 12), be_const_closure(Partition_get_max_flash_size_k_closure) }, { be_const_key(ota_max, -1), be_const_closure(Partition_ota_max_closure) }, - { be_const_key(switch_factory, -1), be_const_closure(Partition_switch_factory_closure) }, - { be_const_key(get_unallocated_k, -1), be_const_closure(Partition_get_unallocated_k_closure) }, - { be_const_key(get_max_flash_size_k, 7), be_const_closure(Partition_get_max_flash_size_k_closure) }, + { be_const_key(save, -1), be_const_closure(Partition_save_closure) }, + { be_const_key(load_otadata, -1), be_const_closure(Partition_load_otadata_closure) }, + { be_const_key(parse, -1), be_const_closure(Partition_parse_closure) }, + { be_const_key(resize_fs_to_max, -1), be_const_closure(Partition_resize_fs_to_max_closure) }, })), (bstring*) &be_const_str_Partition ); diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core_shelly.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core_shelly.h new file mode 100644 index 000000000..ba79c01a3 --- /dev/null +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_partition_core_shelly.h @@ -0,0 +1,7 @@ +/* Solidification of partition_core_shelly.h */ +/********************************************************************\ +* Generated code, don't edit * +\********************************************************************/ +#include "be_constobj.h" +/********************************************************************/ +/* End of solidification */ diff --git a/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h b/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h index 0c7730c97..1488c004f 100644 --- a/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h +++ b/lib/libesp32/berry_tasmota/src/solidify/solidified_tasmota_class.h @@ -7,85 +7,43 @@ extern const bclass be_class_Tasmota; /******************************************************************** -** Solidified function: exec_rules +** Solidified function: try_rule ********************************************************************/ -be_local_closure(Tasmota_exec_rules, /* name */ +be_local_closure(Tasmota_try_rule, /* name */ be_nested_proto( - 14, /* nstack */ - 3, /* argc */ + 9, /* nstack */ + 4, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ - /* K0 */ be_nested_str(cmd_res), - /* K1 */ be_nested_str(_rules), - /* K2 */ be_nested_str(json), - /* K3 */ be_nested_str(load), - /* K4 */ be_nested_str(log), - /* K5 */ be_nested_str(BRY_X3A_X20ERROR_X2C_X20bad_X20json_X3A_X20), - /* K6 */ be_const_int(3), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str(try_rule), - /* K9 */ be_nested_str(trig), - /* K10 */ be_nested_str(f), - /* K11 */ be_const_int(1), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(match), + /* K1 */ be_nested_str(trigger), }), - &be_const_str_exec_rules, + &be_const_str_try_rule, &be_const_str_solidified, - ( &(const binstruction[50]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x88100101, // 0001 GETMBR R4 R0 K1 - 0x74120002, // 0002 JMPT R4 #0006 - 0x4C100000, // 0003 LDNIL R4 - 0x20100604, // 0004 NE R4 R3 R4 - 0x78120029, // 0005 JMPF R4 #0030 - 0xA4120400, // 0006 IMPORT R4 K2 - 0x4C140000, // 0007 LDNIL R5 - 0x90020005, // 0008 SETMBR R0 K0 R5 - 0x50140000, // 0009 LDBOOL R5 0 0 - 0x8C180903, // 000A GETMET R6 R4 K3 - 0x5C200200, // 000B MOVE R8 R1 - 0x7C180400, // 000C CALL R6 2 - 0x4C1C0000, // 000D LDNIL R7 - 0x1C1C0C07, // 000E EQ R7 R6 R7 - 0x781E0004, // 000F JMPF R7 #0015 - 0x8C1C0104, // 0010 GETMET R7 R0 K4 - 0x00260A01, // 0011 ADD R9 K5 R1 - 0x58280006, // 0012 LDCONST R10 K6 - 0x7C1C0600, // 0013 CALL R7 3 - 0x5C180200, // 0014 MOVE R6 R1 - 0x780A0014, // 0015 JMPF R2 #002B - 0x881C0101, // 0016 GETMBR R7 R0 K1 - 0x781E0012, // 0017 JMPF R7 #002B - 0x581C0007, // 0018 LDCONST R7 K7 - 0x6020000C, // 0019 GETGBL R8 G12 - 0x88240101, // 001A GETMBR R9 R0 K1 - 0x7C200200, // 001B CALL R8 1 - 0x14200E08, // 001C LT R8 R7 R8 - 0x7822000C, // 001D JMPF R8 #002B - 0x88200101, // 001E GETMBR R8 R0 K1 - 0x94201007, // 001F GETIDX R8 R8 R7 - 0x8C240108, // 0020 GETMET R9 R0 K8 - 0x5C2C0C00, // 0021 MOVE R11 R6 - 0x88301109, // 0022 GETMBR R12 R8 K9 - 0x8834110A, // 0023 GETMBR R13 R8 K10 - 0x7C240800, // 0024 CALL R9 4 - 0x74260001, // 0025 JMPT R9 #0028 - 0x74160000, // 0026 JMPT R5 #0028 - 0x50140001, // 0027 LDBOOL R5 0 1 - 0x50140200, // 0028 LDBOOL R5 1 0 - 0x001C0F0B, // 0029 ADD R7 R7 K11 - 0x7001FFED, // 002A JMP #0019 - 0x4C1C0000, // 002B LDNIL R7 - 0x201C0607, // 002C NE R7 R3 R7 - 0x781E0000, // 002D JMPF R7 #002F - 0x90020006, // 002E SETMBR R0 K0 R6 - 0x80040A00, // 002F RET 1 R5 - 0x50100000, // 0030 LDBOOL R4 0 0 - 0x80040800, // 0031 RET 1 R4 + ( &(const binstruction[18]) { /* code */ + 0x8C100500, // 0000 GETMET R4 R2 K0 + 0x5C180200, // 0001 MOVE R6 R1 + 0x7C100400, // 0002 CALL R4 2 + 0x4C140000, // 0003 LDNIL R5 + 0x20140805, // 0004 NE R5 R4 R5 + 0x78160009, // 0005 JMPF R5 #0010 + 0x4C140000, // 0006 LDNIL R5 + 0x20140605, // 0007 NE R5 R3 R5 + 0x78160004, // 0008 JMPF R5 #000E + 0x5C140600, // 0009 MOVE R5 R3 + 0x5C180800, // 000A MOVE R6 R4 + 0x881C0501, // 000B GETMBR R7 R2 K1 + 0x5C200200, // 000C MOVE R8 R1 + 0x7C140600, // 000D CALL R5 3 + 0x50140200, // 000E LDBOOL R5 1 0 + 0x80040A00, // 000F RET 1 R5 + 0x50140000, // 0010 LDBOOL R5 0 0 + 0x80040A00, // 0011 RET 1 R5 }) ) ); @@ -93,67 +51,9 @@ be_local_closure(Tasmota_exec_rules, /* name */ /******************************************************************** -** Solidified function: cmd +** Solidified function: gen_cb ********************************************************************/ -be_local_closure(Tasmota_cmd, /* name */ - be_nested_proto( - 8, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str(cmd_res), - /* K1 */ be_nested_str(tasmota), - /* K2 */ be_nested_str(global), - /* K3 */ be_nested_str(maxlog_level), - /* K4 */ be_const_int(2), - /* K5 */ be_const_int(1), - /* K6 */ be_nested_str(_cmd), - }), - &be_const_str_cmd, - &be_const_str_solidified, - ( &(const binstruction[27]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x50100200, // 0001 LDBOOL R4 1 0 - 0x90020004, // 0002 SETMBR R0 K0 R4 - 0xB8120200, // 0003 GETNGBL R4 K1 - 0x88100902, // 0004 GETMBR R4 R4 K2 - 0x88100903, // 0005 GETMBR R4 R4 K3 - 0x780A0004, // 0006 JMPF R2 #000C - 0x28140904, // 0007 GE R5 R4 K4 - 0x78160002, // 0008 JMPF R5 #000C - 0xB8160200, // 0009 GETNGBL R5 K1 - 0x88140B02, // 000A GETMBR R5 R5 K2 - 0x90160705, // 000B SETMBR R5 K3 K5 - 0x8C140106, // 000C GETMET R5 R0 K6 - 0x5C1C0200, // 000D MOVE R7 R1 - 0x7C140400, // 000E CALL R5 2 - 0x4C140000, // 000F LDNIL R5 - 0x88180100, // 0010 GETMBR R6 R0 K0 - 0x501C0200, // 0011 LDBOOL R7 1 0 - 0x20180C07, // 0012 NE R6 R6 R7 - 0x781A0000, // 0013 JMPF R6 #0015 - 0x88140100, // 0014 GETMBR R5 R0 K0 - 0x90020003, // 0015 SETMBR R0 K0 R3 - 0x780A0002, // 0016 JMPF R2 #001A - 0xB81A0200, // 0017 GETNGBL R6 K1 - 0x88180D02, // 0018 GETMBR R6 R6 K2 - 0x901A0604, // 0019 SETMBR R6 K3 R4 - 0x80040A00, // 001A RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: check_not_method -********************************************************************/ -be_local_closure(Tasmota_check_not_method, /* name */ +be_local_closure(Tasmota_gen_cb, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ @@ -163,31 +63,59 @@ be_local_closure(Tasmota_check_not_method, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(introspect), - /* K1 */ be_nested_str(function), - /* K2 */ be_nested_str(type_error), - /* K3 */ be_nested_str(BRY_X3A_X20argument_X20must_X20be_X20a_X20function), - /* K4 */ be_nested_str(ismethod), - /* K5 */ be_nested_str(BRY_X3A_X20method_X20not_X20allowed_X2C_X20use_X20a_X20closure_X20like_X20_X27_X2F_X20args_X20_X2D_X3E_X20obj_X2Efunc_X28args_X29_X27), + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(cb), + /* K1 */ be_nested_str(gen_cb), }), - &be_const_str_check_not_method, + &be_const_str_gen_cb, + &be_const_str_solidified, + ( &(const binstruction[ 5]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x8C0C0501, // 0001 GETMET R3 R2 K1 + 0x5C140200, // 0002 MOVE R5 R1 + 0x7C0C0400, // 0003 CALL R3 2 + 0x80040600, // 0004 RET 1 R3 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: fast_loop +********************************************************************/ +be_local_closure(Tasmota_fast_loop, /* name */ + be_nested_proto( + 5, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(_fl), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + }), + &be_const_str_fast_loop, &be_const_str_solidified, ( &(const binstruction[15]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x600C0004, // 0001 GETGBL R3 G4 - 0x5C100200, // 0002 MOVE R4 R1 - 0x7C0C0200, // 0003 CALL R3 1 - 0x200C0701, // 0004 NE R3 R3 K1 - 0x780E0000, // 0005 JMPF R3 #0007 - 0xB0060503, // 0006 RAISE 1 K2 K3 - 0x8C0C0504, // 0007 GETMET R3 R2 K4 - 0x5C140200, // 0008 MOVE R5 R1 - 0x7C0C0400, // 0009 CALL R3 2 - 0x50100200, // 000A LDBOOL R4 1 0 - 0x1C0C0604, // 000B EQ R3 R3 R4 - 0x780E0000, // 000C JMPF R3 #000E - 0xB0060505, // 000D RAISE 1 K2 K5 + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x5C080200, // 0001 MOVE R2 R1 + 0x740A0000, // 0002 JMPT R2 #0004 + 0x80000400, // 0003 RET 0 + 0x58080001, // 0004 LDCONST R2 K1 + 0x600C000C, // 0005 GETGBL R3 G12 + 0x5C100200, // 0006 MOVE R4 R1 + 0x7C0C0200, // 0007 CALL R3 1 + 0x14100403, // 0008 LT R4 R2 R3 + 0x78120003, // 0009 JMPF R4 #000E + 0x94100202, // 000A GETIDX R4 R1 R2 + 0x7C100000, // 000B CALL R4 0 + 0x00080502, // 000C ADD R2 R2 K2 + 0x7001FFF9, // 000D JMP #0008 0x80000000, // 000E RET 0 }) ) @@ -196,67 +124,9 @@ be_local_closure(Tasmota_check_not_method, /* name */ /******************************************************************** -** Solidified function: remove_rule +** Solidified function: remove_fast_loop ********************************************************************/ -be_local_closure(Tasmota_remove_rule, /* name */ - be_nested_proto( - 7, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 7]) { /* constants */ - /* K0 */ be_nested_str(_rules), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(trig), - /* K3 */ be_nested_str(rule), - /* K4 */ be_nested_str(id), - /* K5 */ be_nested_str(remove), - /* K6 */ be_const_int(1), - }), - &be_const_str_remove_rule, - &be_const_str_solidified, - ( &(const binstruction[27]) { /* code */ - 0x880C0100, // 0000 GETMBR R3 R0 K0 - 0x780E0017, // 0001 JMPF R3 #001A - 0x580C0001, // 0002 LDCONST R3 K1 - 0x6010000C, // 0003 GETGBL R4 G12 - 0x88140100, // 0004 GETMBR R5 R0 K0 - 0x7C100200, // 0005 CALL R4 1 - 0x14100604, // 0006 LT R4 R3 R4 - 0x78120011, // 0007 JMPF R4 #001A - 0x88100100, // 0008 GETMBR R4 R0 K0 - 0x94100803, // 0009 GETIDX R4 R4 R3 - 0x88100902, // 000A GETMBR R4 R4 K2 - 0x88100903, // 000B GETMBR R4 R4 K3 - 0x1C100801, // 000C EQ R4 R4 R1 - 0x78120009, // 000D JMPF R4 #0018 - 0x88100100, // 000E GETMBR R4 R0 K0 - 0x94100803, // 000F GETIDX R4 R4 R3 - 0x88100904, // 0010 GETMBR R4 R4 K4 - 0x1C100802, // 0011 EQ R4 R4 R2 - 0x78120004, // 0012 JMPF R4 #0018 - 0x88100100, // 0013 GETMBR R4 R0 K0 - 0x8C100905, // 0014 GETMET R4 R4 K5 - 0x5C180600, // 0015 MOVE R6 R3 - 0x7C100400, // 0016 CALL R4 2 - 0x70020000, // 0017 JMP #0019 - 0x000C0706, // 0018 ADD R3 R3 K6 - 0x7001FFE8, // 0019 JMP #0003 - 0x80000000, // 001A RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_driver -********************************************************************/ -be_local_closure(Tasmota_remove_driver, /* name */ +be_local_closure(Tasmota_remove_fast_loop, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ @@ -267,27 +137,28 @@ be_local_closure(Tasmota_remove_driver, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(_drivers), + /* K0 */ be_nested_str(_fl), /* K1 */ be_nested_str(find), - /* K2 */ be_nested_str(pop), + /* K2 */ be_nested_str(remove), }), - &be_const_str_remove_driver, + &be_const_str_remove_fast_loop, &be_const_str_solidified, - ( &(const binstruction[14]) { /* code */ + ( &(const binstruction[15]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A000A, // 0001 JMPF R2 #000D - 0x88080100, // 0002 GETMBR R2 R0 K0 - 0x8C080501, // 0003 GETMET R2 R2 K1 - 0x5C100200, // 0004 MOVE R4 R1 - 0x7C080400, // 0005 CALL R2 2 - 0x4C0C0000, // 0006 LDNIL R3 - 0x200C0403, // 0007 NE R3 R2 R3 - 0x780E0003, // 0008 JMPF R3 #000D - 0x880C0100, // 0009 GETMBR R3 R0 K0 - 0x8C0C0702, // 000A GETMET R3 R3 K2 - 0x5C140400, // 000B MOVE R5 R2 - 0x7C0C0400, // 000C CALL R3 2 - 0x80000000, // 000D RET 0 + 0x740A0000, // 0001 JMPT R2 #0003 + 0x80000400, // 0002 RET 0 + 0x88080100, // 0003 GETMBR R2 R0 K0 + 0x8C080501, // 0004 GETMET R2 R2 K1 + 0x5C100200, // 0005 MOVE R4 R1 + 0x7C080400, // 0006 CALL R2 2 + 0x4C0C0000, // 0007 LDNIL R3 + 0x200C0403, // 0008 NE R3 R2 R3 + 0x780E0003, // 0009 JMPF R3 #000E + 0x880C0100, // 000A GETMBR R3 R0 K0 + 0x8C0C0702, // 000B GETMET R3 R3 K2 + 0x5C140400, // 000C MOVE R5 R2 + 0x7C0C0400, // 000D CALL R3 2 + 0x80000000, // 000E RET 0 }) ) ); @@ -354,11 +225,11 @@ be_local_closure(Tasmota_find_key_i, /* name */ /******************************************************************** -** Solidified function: remove_timer +** Solidified function: check_not_method ********************************************************************/ -be_local_closure(Tasmota_remove_timer, /* name */ +be_local_closure(Tasmota_check_not_method, /* name */ be_nested_proto( - 7, /* nstack */ + 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -367,34 +238,31 @@ be_local_closure(Tasmota_remove_timer, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(_timers), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(size), - /* K3 */ be_nested_str(id), - /* K4 */ be_nested_str(remove), - /* K5 */ be_const_int(1), + /* K0 */ be_nested_str(introspect), + /* K1 */ be_nested_str(function), + /* K2 */ be_nested_str(type_error), + /* K3 */ be_nested_str(BRY_X3A_X20argument_X20must_X20be_X20a_X20function), + /* K4 */ be_nested_str(ismethod), + /* K5 */ be_nested_str(BRY_X3A_X20method_X20not_X20allowed_X2C_X20use_X20a_X20closure_X20like_X20_X27_X2F_X20args_X20_X2D_X3E_X20obj_X2Efunc_X28args_X29_X27), }), - &be_const_str_remove_timer, + &be_const_str_check_not_method, &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A000E, // 0001 JMPF R2 #0011 - 0x580C0001, // 0002 LDCONST R3 K1 - 0x8C100502, // 0003 GETMET R4 R2 K2 - 0x7C100200, // 0004 CALL R4 1 - 0x14100604, // 0005 LT R4 R3 R4 - 0x78120009, // 0006 JMPF R4 #0011 - 0x94100403, // 0007 GETIDX R4 R2 R3 - 0x88100903, // 0008 GETMBR R4 R4 K3 - 0x1C100801, // 0009 EQ R4 R4 R1 - 0x78120003, // 000A JMPF R4 #000F - 0x8C100504, // 000B GETMET R4 R2 K4 - 0x5C180600, // 000C MOVE R6 R3 - 0x7C100400, // 000D CALL R4 2 - 0x70020000, // 000E JMP #0010 - 0x000C0705, // 000F ADD R3 R3 K5 - 0x7001FFF1, // 0010 JMP #0003 - 0x80000000, // 0011 RET 0 + ( &(const binstruction[15]) { /* code */ + 0xA40A0000, // 0000 IMPORT R2 K0 + 0x600C0004, // 0001 GETGBL R3 G4 + 0x5C100200, // 0002 MOVE R4 R1 + 0x7C0C0200, // 0003 CALL R3 1 + 0x200C0701, // 0004 NE R3 R3 K1 + 0x780E0000, // 0005 JMPF R3 #0007 + 0xB0060503, // 0006 RAISE 1 K2 K3 + 0x8C0C0504, // 0007 GETMET R3 R2 K4 + 0x5C140200, // 0008 MOVE R5 R1 + 0x7C0C0400, // 0009 CALL R3 2 + 0x50100200, // 000A LDBOOL R4 1 0 + 0x1C0C0604, // 000B EQ R3 R3 R4 + 0x780E0000, // 000C JMPF R3 #000E + 0xB0060505, // 000D RAISE 1 K2 K5 + 0x80000000, // 000E RET 0 }) ) ); @@ -470,56 +338,156 @@ be_local_closure(Tasmota_run_cron, /* name */ /******************************************************************** -** Solidified function: run_deferred +** Solidified function: event ********************************************************************/ -be_local_closure(Tasmota_run_deferred, /* name */ +be_local_closure(Tasmota_event, /* name */ be_nested_proto( - 7, /* nstack */ - 1, /* argc */ + 19, /* nstack */ + 6, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 8]) { /* constants */ - /* K0 */ be_nested_str(_timers), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(size), - /* K3 */ be_nested_str(time_reached), - /* K4 */ be_nested_str(trig), - /* K5 */ be_nested_str(f), - /* K6 */ be_nested_str(remove), - /* K7 */ be_const_int(1), + ( &(const bvalue[25]) { /* constants */ + /* K0 */ be_nested_str(introspect), + /* K1 */ be_nested_str(every_50ms), + /* K2 */ be_nested_str(run_deferred), + /* K3 */ be_nested_str(every_250ms), + /* K4 */ be_nested_str(run_cron), + /* K5 */ be_nested_str(mqtt_data), + /* K6 */ be_nested_str(cmd), + /* K7 */ be_nested_str(exec_cmd), + /* K8 */ be_nested_str(tele), + /* K9 */ be_nested_str(exec_tele), + /* K10 */ be_nested_str(rule), + /* K11 */ be_nested_str(exec_rules), + /* K12 */ be_nested_str(gc), + /* K13 */ be_nested_str(_drivers), + /* K14 */ be_const_int(0), + /* K15 */ be_nested_str(get), + /* K16 */ be_nested_str(function), + /* K17 */ be_nested_str(BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s), + /* K18 */ be_nested_str(_debug_present), + /* K19 */ be_nested_str(debug), + /* K20 */ be_nested_str(traceback), + /* K21 */ be_const_int(1), + /* K22 */ be_nested_str(save_before_restart), + /* K23 */ be_nested_str(persist), + /* K24 */ be_nested_str(save), }), - &be_const_str_run_deferred, + &be_const_str_event, &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x78060015, // 0001 JMPF R1 #0018 - 0x58040001, // 0002 LDCONST R1 K1 - 0x88080100, // 0003 GETMBR R2 R0 K0 - 0x8C080502, // 0004 GETMET R2 R2 K2 - 0x7C080200, // 0005 CALL R2 1 - 0x14080202, // 0006 LT R2 R1 R2 - 0x780A000F, // 0007 JMPF R2 #0018 - 0x88080100, // 0008 GETMBR R2 R0 K0 - 0x94080401, // 0009 GETIDX R2 R2 R1 - 0x8C0C0103, // 000A GETMET R3 R0 K3 - 0x88140504, // 000B GETMBR R5 R2 K4 - 0x7C0C0400, // 000C CALL R3 2 - 0x780E0007, // 000D JMPF R3 #0016 - 0x880C0505, // 000E GETMBR R3 R2 K5 - 0x88100100, // 000F GETMBR R4 R0 K0 - 0x8C100906, // 0010 GETMET R4 R4 K6 - 0x5C180200, // 0011 MOVE R6 R1 - 0x7C100400, // 0012 CALL R4 2 - 0x5C100600, // 0013 MOVE R4 R3 - 0x7C100000, // 0014 CALL R4 0 - 0x70020000, // 0015 JMP #0017 - 0x00040307, // 0016 ADD R1 R1 K7 - 0x7001FFEA, // 0017 JMP #0003 - 0x80000000, // 0018 RET 0 + ( &(const binstruction[108]) { /* code */ + 0xA41A0000, // 0000 IMPORT R6 K0 + 0x1C1C0301, // 0001 EQ R7 R1 K1 + 0x781E0001, // 0002 JMPF R7 #0005 + 0x8C1C0102, // 0003 GETMET R7 R0 K2 + 0x7C1C0200, // 0004 CALL R7 1 + 0x1C1C0303, // 0005 EQ R7 R1 K3 + 0x781E0001, // 0006 JMPF R7 #0009 + 0x8C1C0104, // 0007 GETMET R7 R0 K4 + 0x7C1C0200, // 0008 CALL R7 1 + 0x501C0000, // 0009 LDBOOL R7 0 0 + 0x50200000, // 000A LDBOOL R8 0 0 + 0x1C240305, // 000B EQ R9 R1 K5 + 0x78260000, // 000C JMPF R9 #000E + 0x50200200, // 000D LDBOOL R8 1 0 + 0x1C240306, // 000E EQ R9 R1 K6 + 0x78260006, // 000F JMPF R9 #0017 + 0x8C240107, // 0010 GETMET R9 R0 K7 + 0x5C2C0400, // 0011 MOVE R11 R2 + 0x5C300600, // 0012 MOVE R12 R3 + 0x5C340800, // 0013 MOVE R13 R4 + 0x7C240800, // 0014 CALL R9 4 + 0x80041200, // 0015 RET 1 R9 + 0x7002004E, // 0016 JMP #0066 + 0x1C240308, // 0017 EQ R9 R1 K8 + 0x78260004, // 0018 JMPF R9 #001E + 0x8C240109, // 0019 GETMET R9 R0 K9 + 0x5C2C0800, // 001A MOVE R11 R4 + 0x7C240400, // 001B CALL R9 2 + 0x80041200, // 001C RET 1 R9 + 0x70020047, // 001D JMP #0066 + 0x1C24030A, // 001E EQ R9 R1 K10 + 0x78260007, // 001F JMPF R9 #0028 + 0x8C24010B, // 0020 GETMET R9 R0 K11 + 0x5C2C0800, // 0021 MOVE R11 R4 + 0x60300017, // 0022 GETGBL R12 G23 + 0x5C340600, // 0023 MOVE R13 R3 + 0x7C300200, // 0024 CALL R12 1 + 0x7C240600, // 0025 CALL R9 3 + 0x80041200, // 0026 RET 1 R9 + 0x7002003D, // 0027 JMP #0066 + 0x1C24030C, // 0028 EQ R9 R1 K12 + 0x78260003, // 0029 JMPF R9 #002E + 0x8C24010C, // 002A GETMET R9 R0 K12 + 0x7C240200, // 002B CALL R9 1 + 0x80041200, // 002C RET 1 R9 + 0x70020037, // 002D JMP #0066 + 0x8824010D, // 002E GETMBR R9 R0 K13 + 0x78260035, // 002F JMPF R9 #0066 + 0x5824000E, // 0030 LDCONST R9 K14 + 0x6028000C, // 0031 GETGBL R10 G12 + 0x882C010D, // 0032 GETMBR R11 R0 K13 + 0x7C280200, // 0033 CALL R10 1 + 0x1428120A, // 0034 LT R10 R9 R10 + 0x782A002F, // 0035 JMPF R10 #0066 + 0x8828010D, // 0036 GETMBR R10 R0 K13 + 0x94281409, // 0037 GETIDX R10 R10 R9 + 0x8C2C0D0F, // 0038 GETMET R11 R6 K15 + 0x5C341400, // 0039 MOVE R13 R10 + 0x5C380200, // 003A MOVE R14 R1 + 0x7C2C0600, // 003B CALL R11 3 + 0x60300004, // 003C GETGBL R12 G4 + 0x5C341600, // 003D MOVE R13 R11 + 0x7C300200, // 003E CALL R12 1 + 0x1C301910, // 003F EQ R12 R12 K16 + 0x78320022, // 0040 JMPF R12 #0064 + 0xA8020011, // 0041 EXBLK 0 #0054 + 0x5C301600, // 0042 MOVE R12 R11 + 0x5C341400, // 0043 MOVE R13 R10 + 0x5C380400, // 0044 MOVE R14 R2 + 0x5C3C0600, // 0045 MOVE R15 R3 + 0x5C400800, // 0046 MOVE R16 R4 + 0x5C440A00, // 0047 MOVE R17 R5 + 0x7C300A00, // 0048 CALL R12 5 + 0x74320001, // 0049 JMPT R12 #004C + 0x741E0000, // 004A JMPT R7 #004C + 0x501C0001, // 004B LDBOOL R7 0 1 + 0x501C0200, // 004C LDBOOL R7 1 0 + 0x781E0003, // 004D JMPF R7 #0052 + 0x5C301000, // 004E MOVE R12 R8 + 0x74320001, // 004F JMPT R12 #0052 + 0xA8040001, // 0050 EXBLK 1 1 + 0x70020013, // 0051 JMP #0066 + 0xA8040001, // 0052 EXBLK 1 1 + 0x7002000F, // 0053 JMP #0064 + 0xAC300002, // 0054 CATCH R12 0 2 + 0x7002000C, // 0055 JMP #0063 + 0x60380001, // 0056 GETGBL R14 G1 + 0x603C0018, // 0057 GETGBL R15 G24 + 0x58400011, // 0058 LDCONST R16 K17 + 0x5C441800, // 0059 MOVE R17 R12 + 0x5C481A00, // 005A MOVE R18 R13 + 0x7C3C0600, // 005B CALL R15 3 + 0x7C380200, // 005C CALL R14 1 + 0x88380112, // 005D GETMBR R14 R0 K18 + 0x783A0002, // 005E JMPF R14 #0062 + 0xA43A2600, // 005F IMPORT R14 K19 + 0x8C3C1D14, // 0060 GETMET R15 R14 K20 + 0x7C3C0200, // 0061 CALL R15 1 + 0x70020000, // 0062 JMP #0064 + 0xB0080000, // 0063 RAISE 2 R0 R0 + 0x00241315, // 0064 ADD R9 R9 K21 + 0x7001FFCA, // 0065 JMP #0031 + 0x1C240316, // 0066 EQ R9 R1 K22 + 0x78260002, // 0067 JMPF R9 #006B + 0xA4262E00, // 0068 IMPORT R9 K23 + 0x8C281318, // 0069 GETMET R10 R9 K24 + 0x7C280200, // 006A CALL R10 1 + 0x80040E00, // 006B RET 1 R7 }) ) ); @@ -527,11 +495,11 @@ be_local_closure(Tasmota_run_deferred, /* name */ /******************************************************************** -** Solidified function: wire_scan +** Solidified function: urlfetch ********************************************************************/ -be_local_closure(Tasmota_wire_scan, /* name */ +be_local_closure(Tasmota_urlfetch, /* name */ be_nested_proto( - 6, /* nstack */ + 10, /* nstack */ 3, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -539,49 +507,76 @@ be_local_closure(Tasmota_wire_scan, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str(i2c_enabled), - /* K1 */ be_nested_str(wire1), - /* K2 */ be_nested_str(enabled), - /* K3 */ be_nested_str(detect), - /* K4 */ be_nested_str(wire2), + ( &(const bvalue[17]) { /* constants */ + /* K0 */ be_nested_str(string), + /* K1 */ be_nested_str(split), + /* K2 */ be_nested_str(_X2F), + /* K3 */ be_nested_str(pop), + /* K4 */ be_const_int(0), + /* K5 */ be_nested_str(index_X2Ehtml), + /* K6 */ be_nested_str(webclient), + /* K7 */ be_nested_str(set_follow_redirects), + /* K8 */ be_nested_str(begin), + /* K9 */ be_nested_str(GET), + /* K10 */ be_nested_str(status_X3A_X20), + /* K11 */ be_nested_str(connection_error), + /* K12 */ be_nested_str(write_file), + /* K13 */ be_nested_str(close), + /* K14 */ be_nested_str(log), + /* K15 */ be_nested_str(BRY_X3A_X20Fetched_X20), + /* K16 */ be_const_int(3), }), - &be_const_str_wire_scan, + &be_const_str_urlfetch, &be_const_str_solidified, - ( &(const binstruction[33]) { /* code */ + ( &(const binstruction[48]) { /* code */ 0x4C0C0000, // 0000 LDNIL R3 - 0x200C0403, // 0001 NE R3 R2 R3 - 0x780E0005, // 0002 JMPF R3 #0009 - 0x8C0C0100, // 0003 GETMET R3 R0 K0 - 0x5C140400, // 0004 MOVE R5 R2 - 0x7C0C0400, // 0005 CALL R3 2 - 0x740E0001, // 0006 JMPT R3 #0009 - 0x4C0C0000, // 0007 LDNIL R3 - 0x80040600, // 0008 RET 1 R3 - 0x880C0101, // 0009 GETMBR R3 R0 K1 - 0x8C0C0702, // 000A GETMET R3 R3 K2 - 0x7C0C0200, // 000B CALL R3 1 - 0x780E0006, // 000C JMPF R3 #0014 - 0x880C0101, // 000D GETMBR R3 R0 K1 - 0x8C0C0703, // 000E GETMET R3 R3 K3 - 0x5C140200, // 000F MOVE R5 R1 - 0x7C0C0400, // 0010 CALL R3 2 - 0x780E0001, // 0011 JMPF R3 #0014 - 0x880C0101, // 0012 GETMBR R3 R0 K1 - 0x80040600, // 0013 RET 1 R3 - 0x880C0104, // 0014 GETMBR R3 R0 K4 - 0x8C0C0702, // 0015 GETMET R3 R3 K2 - 0x7C0C0200, // 0016 CALL R3 1 - 0x780E0006, // 0017 JMPF R3 #001F - 0x880C0104, // 0018 GETMBR R3 R0 K4 - 0x8C0C0703, // 0019 GETMET R3 R3 K3 - 0x5C140200, // 001A MOVE R5 R1 - 0x7C0C0400, // 001B CALL R3 2 - 0x780E0001, // 001C JMPF R3 #001F - 0x880C0104, // 001D GETMBR R3 R0 K4 - 0x80040600, // 001E RET 1 R3 - 0x4C0C0000, // 001F LDNIL R3 - 0x80040600, // 0020 RET 1 R3 + 0x1C0C0403, // 0001 EQ R3 R2 R3 + 0x780E000D, // 0002 JMPF R3 #0011 + 0xA40E0000, // 0003 IMPORT R3 K0 + 0x8C100701, // 0004 GETMET R4 R3 K1 + 0x5C180200, // 0005 MOVE R6 R1 + 0x581C0002, // 0006 LDCONST R7 K2 + 0x7C100600, // 0007 CALL R4 3 + 0x8C100903, // 0008 GETMET R4 R4 K3 + 0x7C100200, // 0009 CALL R4 1 + 0x5C080800, // 000A MOVE R2 R4 + 0x6010000C, // 000B GETGBL R4 G12 + 0x5C140400, // 000C MOVE R5 R2 + 0x7C100200, // 000D CALL R4 1 + 0x1C100904, // 000E EQ R4 R4 K4 + 0x78120000, // 000F JMPF R4 #0011 + 0x58080005, // 0010 LDCONST R2 K5 + 0xB80E0C00, // 0011 GETNGBL R3 K6 + 0x7C0C0000, // 0012 CALL R3 0 + 0x8C100707, // 0013 GETMET R4 R3 K7 + 0x50180200, // 0014 LDBOOL R6 1 0 + 0x7C100400, // 0015 CALL R4 2 + 0x8C100708, // 0016 GETMET R4 R3 K8 + 0x5C180200, // 0017 MOVE R6 R1 + 0x7C100400, // 0018 CALL R4 2 + 0x8C100709, // 0019 GETMET R4 R3 K9 + 0x7C100200, // 001A CALL R4 1 + 0x541600C7, // 001B LDINT R5 200 + 0x20140805, // 001C NE R5 R4 R5 + 0x78160004, // 001D JMPF R5 #0023 + 0x60140008, // 001E GETGBL R5 G8 + 0x5C180800, // 001F MOVE R6 R4 + 0x7C140200, // 0020 CALL R5 1 + 0x00161405, // 0021 ADD R5 K10 R5 + 0xB0061605, // 0022 RAISE 1 K11 R5 + 0x8C14070C, // 0023 GETMET R5 R3 K12 + 0x5C1C0400, // 0024 MOVE R7 R2 + 0x7C140400, // 0025 CALL R5 2 + 0x8C18070D, // 0026 GETMET R6 R3 K13 + 0x7C180200, // 0027 CALL R6 1 + 0x8C18010E, // 0028 GETMET R6 R0 K14 + 0x60200008, // 0029 GETGBL R8 G8 + 0x5C240A00, // 002A MOVE R9 R5 + 0x7C200200, // 002B CALL R8 1 + 0x00221E08, // 002C ADD R8 K15 R8 + 0x58240010, // 002D LDCONST R9 K16 + 0x7C180600, // 002E CALL R6 3 + 0x80040800, // 002F RET 1 R4 }) ) ); @@ -589,11 +584,67 @@ be_local_closure(Tasmota_wire_scan, /* name */ /******************************************************************** -** Solidified function: next_cron +** Solidified function: exec_cmd ********************************************************************/ -be_local_closure(Tasmota_next_cron, /* name */ +be_local_closure(Tasmota_exec_cmd, /* name */ be_nested_proto( - 6, /* nstack */ + 12, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str(_ccmd), + /* K1 */ be_nested_str(json), + /* K2 */ be_nested_str(load), + /* K3 */ be_nested_str(find_key_i), + /* K4 */ be_nested_str(resolvecmnd), + }), + &be_const_str_exec_cmd, + &be_const_str_solidified, + ( &(const binstruction[27]) { /* code */ + 0x88100100, // 0000 GETMBR R4 R0 K0 + 0x78120016, // 0001 JMPF R4 #0019 + 0xA4120200, // 0002 IMPORT R4 K1 + 0x8C140902, // 0003 GETMET R5 R4 K2 + 0x5C1C0600, // 0004 MOVE R7 R3 + 0x7C140400, // 0005 CALL R5 2 + 0x8C180103, // 0006 GETMET R6 R0 K3 + 0x88200100, // 0007 GETMBR R8 R0 K0 + 0x5C240200, // 0008 MOVE R9 R1 + 0x7C180600, // 0009 CALL R6 3 + 0x4C1C0000, // 000A LDNIL R7 + 0x201C0C07, // 000B NE R7 R6 R7 + 0x781E000B, // 000C JMPF R7 #0019 + 0x8C1C0104, // 000D GETMET R7 R0 K4 + 0x5C240C00, // 000E MOVE R9 R6 + 0x7C1C0400, // 000F CALL R7 2 + 0x881C0100, // 0010 GETMBR R7 R0 K0 + 0x941C0E06, // 0011 GETIDX R7 R7 R6 + 0x5C200C00, // 0012 MOVE R8 R6 + 0x5C240400, // 0013 MOVE R9 R2 + 0x5C280600, // 0014 MOVE R10 R3 + 0x5C2C0A00, // 0015 MOVE R11 R5 + 0x7C1C0800, // 0016 CALL R7 4 + 0x501C0200, // 0017 LDBOOL R7 1 0 + 0x80040E00, // 0018 RET 1 R7 + 0x50100000, // 0019 LDBOOL R4 0 0 + 0x80040800, // 001A RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_cron +********************************************************************/ +be_local_closure(Tasmota_remove_cron, /* name */ + be_nested_proto( + 7, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -606,29 +657,78 @@ be_local_closure(Tasmota_next_cron, /* name */ /* K1 */ be_const_int(0), /* K2 */ be_nested_str(size), /* K3 */ be_nested_str(id), - /* K4 */ be_nested_str(trig), + /* K4 */ be_nested_str(remove), /* K5 */ be_const_int(1), }), - &be_const_str_next_cron, + &be_const_str_remove_cron, &be_const_str_solidified, - ( &(const binstruction[17]) { /* code */ + ( &(const binstruction[18]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A000D, // 0001 JMPF R2 #0010 + 0x780A000E, // 0001 JMPF R2 #0011 0x580C0001, // 0002 LDCONST R3 K1 0x8C100502, // 0003 GETMET R4 R2 K2 0x7C100200, // 0004 CALL R4 1 0x14100604, // 0005 LT R4 R3 R4 - 0x78120008, // 0006 JMPF R4 #0010 + 0x78120009, // 0006 JMPF R4 #0011 0x94100403, // 0007 GETIDX R4 R2 R3 0x88100903, // 0008 GETMBR R4 R4 K3 0x1C100801, // 0009 EQ R4 R4 R1 - 0x78120002, // 000A JMPF R4 #000E - 0x94100403, // 000B GETIDX R4 R2 R3 - 0x88100904, // 000C GETMBR R4 R4 K4 - 0x80040800, // 000D RET 1 R4 - 0x000C0705, // 000E ADD R3 R3 K5 - 0x7001FFF2, // 000F JMP #0003 - 0x80000000, // 0010 RET 0 + 0x78120003, // 000A JMPF R4 #000F + 0x8C100504, // 000B GETMET R4 R2 K4 + 0x5C180600, // 000C MOVE R6 R3 + 0x7C100400, // 000D CALL R4 2 + 0x70020000, // 000E JMP #0010 + 0x000C0705, // 000F ADD R3 R3 K5 + 0x7001FFF1, // 0010 JMP #0003 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_list_i +********************************************************************/ +be_local_closure(Tasmota_find_list_i, /* name */ + be_nested_proto( + 9, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str(string), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(toupper), + /* K3 */ be_const_int(1), + }), + &be_const_str_find_list_i, + &be_const_str_solidified, + ( &(const binstruction[20]) { /* code */ + 0xA40E0000, // 0000 IMPORT R3 K0 + 0x58100001, // 0001 LDCONST R4 K1 + 0x8C140702, // 0002 GETMET R5 R3 K2 + 0x5C1C0400, // 0003 MOVE R7 R2 + 0x7C140400, // 0004 CALL R5 2 + 0x6018000C, // 0005 GETGBL R6 G12 + 0x5C1C0200, // 0006 MOVE R7 R1 + 0x7C180200, // 0007 CALL R6 1 + 0x14180806, // 0008 LT R6 R4 R6 + 0x781A0007, // 0009 JMPF R6 #0012 + 0x8C180702, // 000A GETMET R6 R3 K2 + 0x94200204, // 000B GETIDX R8 R1 R4 + 0x7C180400, // 000C CALL R6 2 + 0x1C180C05, // 000D EQ R6 R6 R5 + 0x781A0000, // 000E JMPF R6 #0010 + 0x80040800, // 000F RET 1 R4 + 0x00100903, // 0010 ADD R4 R4 K3 + 0x7001FFF2, // 0011 JMP #0005 + 0x4C180000, // 0012 LDNIL R6 + 0x80040C00, // 0013 RET 1 R6 }) ) ); @@ -681,9 +781,90 @@ be_local_closure(Tasmota_set_light, /* name */ /******************************************************************** -** Solidified function: remove_fast_loop +** Solidified function: remove_timer ********************************************************************/ -be_local_closure(Tasmota_remove_fast_loop, /* name */ +be_local_closure(Tasmota_remove_timer, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(_timers), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(size), + /* K3 */ be_nested_str(id), + /* K4 */ be_nested_str(remove), + /* K5 */ be_const_int(1), + }), + &be_const_str_remove_timer, + &be_const_str_solidified, + ( &(const binstruction[18]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A000E, // 0001 JMPF R2 #0011 + 0x580C0001, // 0002 LDCONST R3 K1 + 0x8C100502, // 0003 GETMET R4 R2 K2 + 0x7C100200, // 0004 CALL R4 1 + 0x14100604, // 0005 LT R4 R3 R4 + 0x78120009, // 0006 JMPF R4 #0011 + 0x94100403, // 0007 GETIDX R4 R2 R3 + 0x88100903, // 0008 GETMBR R4 R4 K3 + 0x1C100801, // 0009 EQ R4 R4 R1 + 0x78120003, // 000A JMPF R4 #000F + 0x8C100504, // 000B GETMET R4 R2 K4 + 0x5C180600, // 000C MOVE R6 R3 + 0x7C100400, // 000D CALL R4 2 + 0x70020000, // 000E JMP #0010 + 0x000C0705, // 000F ADD R3 R3 K5 + 0x7001FFF1, // 0010 JMP #0003 + 0x80000000, // 0011 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_cmd +********************************************************************/ +be_local_closure(Tasmota_remove_cmd, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 2]) { /* constants */ + /* K0 */ be_nested_str(_ccmd), + /* K1 */ be_nested_str(remove), + }), + &be_const_str_remove_cmd, + &be_const_str_solidified, + ( &(const binstruction[ 7]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A0003, // 0001 JMPF R2 #0006 + 0x88080100, // 0002 GETMBR R2 R0 K0 + 0x8C080501, // 0003 GETMET R2 R2 K1 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x80000000, // 0006 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: remove_driver +********************************************************************/ +be_local_closure(Tasmota_remove_driver, /* name */ be_nested_proto( 6, /* nstack */ 2, /* argc */ @@ -694,28 +875,27 @@ be_local_closure(Tasmota_remove_fast_loop, /* name */ NULL, /* no sub protos */ 1, /* has constants */ ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(_fl), + /* K0 */ be_nested_str(_drivers), /* K1 */ be_nested_str(find), - /* K2 */ be_nested_str(remove), + /* K2 */ be_nested_str(pop), }), - &be_const_str_remove_fast_loop, + &be_const_str_remove_driver, &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ + ( &(const binstruction[14]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x740A0000, // 0001 JMPT R2 #0003 - 0x80000400, // 0002 RET 0 - 0x88080100, // 0003 GETMBR R2 R0 K0 - 0x8C080501, // 0004 GETMET R2 R2 K1 - 0x5C100200, // 0005 MOVE R4 R1 - 0x7C080400, // 0006 CALL R2 2 - 0x4C0C0000, // 0007 LDNIL R3 - 0x200C0403, // 0008 NE R3 R2 R3 - 0x780E0003, // 0009 JMPF R3 #000E - 0x880C0100, // 000A GETMBR R3 R0 K0 - 0x8C0C0702, // 000B GETMET R3 R3 K2 - 0x5C140400, // 000C MOVE R5 R2 - 0x7C0C0400, // 000D CALL R3 2 - 0x80000000, // 000E RET 0 + 0x780A000A, // 0001 JMPF R2 #000D + 0x88080100, // 0002 GETMBR R2 R0 K0 + 0x8C080501, // 0003 GETMET R2 R2 K1 + 0x5C100200, // 0004 MOVE R4 R1 + 0x7C080400, // 0005 CALL R2 2 + 0x4C0C0000, // 0006 LDNIL R3 + 0x200C0403, // 0007 NE R3 R2 R3 + 0x780E0003, // 0008 JMPF R3 #000D + 0x880C0100, // 0009 GETMBR R3 R0 K0 + 0x8C0C0702, // 000A GETMET R3 R3 K2 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C0C0400, // 000C CALL R3 2 + 0x80000000, // 000D RET 0 }) ) ); @@ -833,12 +1013,144 @@ be_local_closure(Tasmota_init, /* name */ /******************************************************************** -** Solidified function: set_timer +** Solidified function: add_driver ********************************************************************/ -be_local_closure(Tasmota_set_timer, /* name */ +be_local_closure(Tasmota_add_driver, /* name */ be_nested_proto( - 10, /* nstack */ - 4, /* argc */ + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(instance), + /* K1 */ be_nested_str(value_error), + /* K2 */ be_nested_str(instance_X20required), + /* K3 */ be_nested_str(_drivers), + /* K4 */ be_nested_str(find), + /* K5 */ be_nested_str(push), + }), + &be_const_str_add_driver, + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x60080004, // 0000 GETGBL R2 G4 + 0x5C0C0200, // 0001 MOVE R3 R1 + 0x7C080200, // 0002 CALL R2 1 + 0x20080500, // 0003 NE R2 R2 K0 + 0x780A0000, // 0004 JMPF R2 #0006 + 0xB0060302, // 0005 RAISE 1 K1 K2 + 0x88080103, // 0006 GETMBR R2 R0 K3 + 0x780A000B, // 0007 JMPF R2 #0014 + 0x88080103, // 0008 GETMBR R2 R0 K3 + 0x8C080504, // 0009 GETMET R2 R2 K4 + 0x5C100200, // 000A MOVE R4 R1 + 0x7C080400, // 000B CALL R2 2 + 0x4C0C0000, // 000C LDNIL R3 + 0x1C080403, // 000D EQ R2 R2 R3 + 0x780A0003, // 000E JMPF R2 #0013 + 0x88080103, // 000F GETMBR R2 R0 K3 + 0x8C080505, // 0010 GETMET R2 R2 K5 + 0x5C100200, // 0011 MOVE R4 R1 + 0x7C080400, // 0012 CALL R2 2 + 0x70020003, // 0013 JMP #0018 + 0x60080012, // 0014 GETGBL R2 G18 + 0x7C080000, // 0015 CALL R2 0 + 0x400C0401, // 0016 CONNECT R3 R2 R1 + 0x90020602, // 0017 SETMBR R0 K3 R2 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: exec_tele +********************************************************************/ +be_local_closure(Tasmota_exec_tele, /* name */ + be_nested_proto( + 12, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str(_rules), + /* K1 */ be_nested_str(json), + /* K2 */ be_nested_str(load), + /* K3 */ be_nested_str(log), + /* K4 */ be_nested_str(BRY_X3A_X20ERROR_X2C_X20bad_X20json_X3A_X20), + /* K5 */ be_const_int(3), + /* K6 */ be_nested_str(Tele), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str(try_rule), + /* K9 */ be_nested_str(trig), + /* K10 */ be_nested_str(f), + /* K11 */ be_const_int(1), + }), + &be_const_str_exec_tele, + &be_const_str_solidified, + ( &(const binstruction[41]) { /* code */ + 0x88080100, // 0000 GETMBR R2 R0 K0 + 0x780A0024, // 0001 JMPF R2 #0027 + 0xA40A0200, // 0002 IMPORT R2 K1 + 0x8C0C0502, // 0003 GETMET R3 R2 K2 + 0x5C140200, // 0004 MOVE R5 R1 + 0x7C0C0400, // 0005 CALL R3 2 + 0x50100000, // 0006 LDBOOL R4 0 0 + 0x4C140000, // 0007 LDNIL R5 + 0x1C140605, // 0008 EQ R5 R3 R5 + 0x78160004, // 0009 JMPF R5 #000F + 0x8C140103, // 000A GETMET R5 R0 K3 + 0x001E0801, // 000B ADD R7 K4 R1 + 0x58200005, // 000C LDCONST R8 K5 + 0x7C140600, // 000D CALL R5 3 + 0x5C0C0200, // 000E MOVE R3 R1 + 0x60140013, // 000F GETGBL R5 G19 + 0x7C140000, // 0010 CALL R5 0 + 0x98160C03, // 0011 SETIDX R5 K6 R3 + 0x5C0C0A00, // 0012 MOVE R3 R5 + 0x58140007, // 0013 LDCONST R5 K7 + 0x6018000C, // 0014 GETGBL R6 G12 + 0x881C0100, // 0015 GETMBR R7 R0 K0 + 0x7C180200, // 0016 CALL R6 1 + 0x14180A06, // 0017 LT R6 R5 R6 + 0x781A000C, // 0018 JMPF R6 #0026 + 0x88180100, // 0019 GETMBR R6 R0 K0 + 0x94180C05, // 001A GETIDX R6 R6 R5 + 0x8C1C0108, // 001B GETMET R7 R0 K8 + 0x5C240600, // 001C MOVE R9 R3 + 0x88280D09, // 001D GETMBR R10 R6 K9 + 0x882C0D0A, // 001E GETMBR R11 R6 K10 + 0x7C1C0800, // 001F CALL R7 4 + 0x741E0001, // 0020 JMPT R7 #0023 + 0x74120000, // 0021 JMPT R4 #0023 + 0x50100001, // 0022 LDBOOL R4 0 1 + 0x50100200, // 0023 LDBOOL R4 1 0 + 0x00140B0B, // 0024 ADD R5 R5 K11 + 0x7001FFED, // 0025 JMP #0014 + 0x80040800, // 0026 RET 1 R4 + 0x50080000, // 0027 LDBOOL R2 0 0 + 0x80040400, // 0028 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_cmd +********************************************************************/ +be_local_closure(Tasmota_add_cmd, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ @@ -847,35 +1159,93 @@ be_local_closure(Tasmota_set_timer, /* name */ 1, /* has constants */ ( &(const bvalue[ 5]) { /* constants */ /* K0 */ be_nested_str(check_not_method), - /* K1 */ be_nested_str(_timers), - /* K2 */ be_nested_str(push), - /* K3 */ be_nested_str(Trigger), - /* K4 */ be_nested_str(millis), + /* K1 */ be_nested_str(_ccmd), + /* K2 */ be_nested_str(function), + /* K3 */ be_nested_str(value_error), + /* K4 */ be_nested_str(the_X20second_X20argument_X20is_X20not_X20a_X20function), }), - &be_const_str_set_timer, + &be_const_str_add_cmd, &be_const_str_solidified, - ( &(const binstruction[21]) { /* code */ - 0x8C100100, // 0000 GETMET R4 R0 K0 - 0x5C180400, // 0001 MOVE R6 R2 - 0x7C100400, // 0002 CALL R4 2 - 0x88100101, // 0003 GETMBR R4 R0 K1 - 0x4C140000, // 0004 LDNIL R5 - 0x1C100805, // 0005 EQ R4 R4 R5 - 0x78120002, // 0006 JMPF R4 #000A - 0x60100012, // 0007 GETGBL R4 G18 - 0x7C100000, // 0008 CALL R4 0 - 0x90020204, // 0009 SETMBR R0 K1 R4 - 0x88100101, // 000A GETMBR R4 R0 K1 - 0x8C100902, // 000B GETMET R4 R4 K2 - 0xB81A0600, // 000C GETNGBL R6 K3 - 0x8C1C0104, // 000D GETMET R7 R0 K4 - 0x5C240200, // 000E MOVE R9 R1 - 0x7C1C0400, // 000F CALL R7 2 - 0x5C200400, // 0010 MOVE R8 R2 - 0x5C240600, // 0011 MOVE R9 R3 - 0x7C180600, // 0012 CALL R6 3 - 0x7C100400, // 0013 CALL R4 2 - 0x80000000, // 0014 RET 0 + ( &(const binstruction[20]) { /* code */ + 0x8C0C0100, // 0000 GETMET R3 R0 K0 + 0x5C140400, // 0001 MOVE R5 R2 + 0x7C0C0400, // 0002 CALL R3 2 + 0x880C0101, // 0003 GETMBR R3 R0 K1 + 0x4C100000, // 0004 LDNIL R4 + 0x1C0C0604, // 0005 EQ R3 R3 R4 + 0x780E0002, // 0006 JMPF R3 #000A + 0x600C0013, // 0007 GETGBL R3 G19 + 0x7C0C0000, // 0008 CALL R3 0 + 0x90020203, // 0009 SETMBR R0 K1 R3 + 0x600C0004, // 000A GETGBL R3 G4 + 0x5C100400, // 000B MOVE R4 R2 + 0x7C0C0200, // 000C CALL R3 1 + 0x1C0C0702, // 000D EQ R3 R3 K2 + 0x780E0002, // 000E JMPF R3 #0012 + 0x880C0101, // 000F GETMBR R3 R0 K1 + 0x980C0202, // 0010 SETIDX R3 R1 R2 + 0x70020000, // 0011 JMP #0013 + 0xB0060704, // 0012 RAISE 1 K3 K4 + 0x80000000, // 0013 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: find_op +********************************************************************/ +be_local_closure(Tasmota_find_op, /* name */ + be_nested_proto( + 7, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 4]) { /* constants */ + /* K0 */ be_nested_str(_find_op), + /* K1 */ be_const_int(0), + /* K2 */ be_const_int(1), + /* K3 */ be_const_int(2147483647), + }), + &be_const_str_find_op, + &be_const_str_solidified, + ( &(const binstruction[31]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x280C0501, // 0003 GE R3 R2 K1 + 0x780E0011, // 0004 JMPF R3 #0017 + 0x540E7FFE, // 0005 LDINT R3 32767 + 0x2C0C0403, // 0006 AND R3 R2 R3 + 0x5412000F, // 0007 LDINT R4 16 + 0x3C100404, // 0008 SHR R4 R2 R4 + 0x60140012, // 0009 GETGBL R5 G18 + 0x7C140000, // 000A CALL R5 0 + 0x04180702, // 000B SUB R6 R3 K2 + 0x401A0206, // 000C CONNECT R6 K1 R6 + 0x94180206, // 000D GETIDX R6 R1 R6 + 0x40180A06, // 000E CONNECT R6 R5 R6 + 0x04180902, // 000F SUB R6 R4 K2 + 0x40180606, // 0010 CONNECT R6 R3 R6 + 0x94180206, // 0011 GETIDX R6 R1 R6 + 0x40180A06, // 0012 CONNECT R6 R5 R6 + 0x40180903, // 0013 CONNECT R6 R4 K3 + 0x94180206, // 0014 GETIDX R6 R1 R6 + 0x40180A06, // 0015 CONNECT R6 R5 R6 + 0x80040A00, // 0016 RET 1 R5 + 0x600C0012, // 0017 GETGBL R3 G18 + 0x7C0C0000, // 0018 CALL R3 0 + 0x40100601, // 0019 CONNECT R4 R3 R1 + 0x4C100000, // 001A LDNIL R4 + 0x40100604, // 001B CONNECT R4 R3 R4 + 0x4C100000, // 001C LDNIL R4 + 0x40100604, // 001D CONNECT R4 R3 R4 + 0x80040600, // 001E RET 1 R3 }) ) ); @@ -940,32 +1310,119 @@ be_local_closure(Tasmota_add_cron, /* name */ /******************************************************************** -** Solidified function: gc +** Solidified function: remove_rule ********************************************************************/ -be_local_closure(Tasmota_gc, /* name */ +be_local_closure(Tasmota_remove_rule, /* name */ be_nested_proto( - 4, /* nstack */ - 1, /* argc */ + 7, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(gc), - /* K1 */ be_nested_str(collect), - /* K2 */ be_nested_str(allocated), + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str(_rules), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(trig), + /* K3 */ be_nested_str(rule), + /* K4 */ be_nested_str(id), + /* K5 */ be_nested_str(remove), + /* K6 */ be_const_int(1), }), - &be_const_str_gc, + &be_const_str_remove_rule, &be_const_str_solidified, - ( &(const binstruction[ 6]) { /* code */ - 0xA4060000, // 0000 IMPORT R1 K0 - 0x8C080301, // 0001 GETMET R2 R1 K1 - 0x7C080200, // 0002 CALL R2 1 - 0x8C080302, // 0003 GETMET R2 R1 K2 - 0x7C080200, // 0004 CALL R2 1 - 0x80040400, // 0005 RET 1 R2 + ( &(const binstruction[27]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x780E0017, // 0001 JMPF R3 #001A + 0x580C0001, // 0002 LDCONST R3 K1 + 0x6010000C, // 0003 GETGBL R4 G12 + 0x88140100, // 0004 GETMBR R5 R0 K0 + 0x7C100200, // 0005 CALL R4 1 + 0x14100604, // 0006 LT R4 R3 R4 + 0x78120011, // 0007 JMPF R4 #001A + 0x88100100, // 0008 GETMBR R4 R0 K0 + 0x94100803, // 0009 GETIDX R4 R4 R3 + 0x88100902, // 000A GETMBR R4 R4 K2 + 0x88100903, // 000B GETMBR R4 R4 K3 + 0x1C100801, // 000C EQ R4 R4 R1 + 0x78120009, // 000D JMPF R4 #0018 + 0x88100100, // 000E GETMBR R4 R0 K0 + 0x94100803, // 000F GETIDX R4 R4 R3 + 0x88100904, // 0010 GETMBR R4 R4 K4 + 0x1C100802, // 0011 EQ R4 R4 R2 + 0x78120004, // 0012 JMPF R4 #0018 + 0x88100100, // 0013 GETMBR R4 R0 K0 + 0x8C100905, // 0014 GETMET R4 R4 K5 + 0x5C180600, // 0015 MOVE R6 R3 + 0x7C100400, // 0016 CALL R4 2 + 0x70020000, // 0017 JMP #0019 + 0x000C0706, // 0018 ADD R3 R3 K6 + 0x7001FFE8, // 0019 JMP #0003 + 0x80000000, // 001A RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: wire_scan +********************************************************************/ +be_local_closure(Tasmota_wire_scan, /* name */ + be_nested_proto( + 6, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str(i2c_enabled), + /* K1 */ be_nested_str(wire1), + /* K2 */ be_nested_str(enabled), + /* K3 */ be_nested_str(detect), + /* K4 */ be_nested_str(wire2), + }), + &be_const_str_wire_scan, + &be_const_str_solidified, + ( &(const binstruction[33]) { /* code */ + 0x4C0C0000, // 0000 LDNIL R3 + 0x200C0403, // 0001 NE R3 R2 R3 + 0x780E0005, // 0002 JMPF R3 #0009 + 0x8C0C0100, // 0003 GETMET R3 R0 K0 + 0x5C140400, // 0004 MOVE R5 R2 + 0x7C0C0400, // 0005 CALL R3 2 + 0x740E0001, // 0006 JMPT R3 #0009 + 0x4C0C0000, // 0007 LDNIL R3 + 0x80040600, // 0008 RET 1 R3 + 0x880C0101, // 0009 GETMBR R3 R0 K1 + 0x8C0C0702, // 000A GETMET R3 R3 K2 + 0x7C0C0200, // 000B CALL R3 1 + 0x780E0006, // 000C JMPF R3 #0014 + 0x880C0101, // 000D GETMBR R3 R0 K1 + 0x8C0C0703, // 000E GETMET R3 R3 K3 + 0x5C140200, // 000F MOVE R5 R1 + 0x7C0C0400, // 0010 CALL R3 2 + 0x780E0001, // 0011 JMPF R3 #0014 + 0x880C0101, // 0012 GETMBR R3 R0 K1 + 0x80040600, // 0013 RET 1 R3 + 0x880C0104, // 0014 GETMBR R3 R0 K4 + 0x8C0C0702, // 0015 GETMET R3 R3 K2 + 0x7C0C0200, // 0016 CALL R3 1 + 0x780E0006, // 0017 JMPF R3 #001F + 0x880C0104, // 0018 GETMBR R3 R0 K4 + 0x8C0C0703, // 0019 GETMET R3 R3 K3 + 0x5C140200, // 001A MOVE R5 R1 + 0x7C0C0400, // 001B CALL R3 2 + 0x780E0001, // 001C JMPF R3 #001F + 0x880C0104, // 001D GETMBR R3 R0 K4 + 0x80040600, // 001E RET 1 R3 + 0x4C0C0000, // 001F LDNIL R3 + 0x80040600, // 0020 RET 1 R3 }) ) ); @@ -1016,32 +1473,57 @@ be_local_closure(Tasmota_get_light, /* name */ /******************************************************************** -** Solidified function: remove_cmd +** Solidified function: cmd ********************************************************************/ -be_local_closure(Tasmota_remove_cmd, /* name */ +be_local_closure(Tasmota_cmd, /* name */ be_nested_proto( - 5, /* nstack */ - 2, /* argc */ + 8, /* nstack */ + 3, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str(_ccmd), - /* K1 */ be_nested_str(remove), + ( &(const bvalue[ 7]) { /* constants */ + /* K0 */ be_nested_str(cmd_res), + /* K1 */ be_nested_str(tasmota), + /* K2 */ be_nested_str(global), + /* K3 */ be_nested_str(maxlog_level), + /* K4 */ be_const_int(2), + /* K5 */ be_const_int(1), + /* K6 */ be_nested_str(_cmd), }), - &be_const_str_remove_cmd, + &be_const_str_cmd, &be_const_str_solidified, - ( &(const binstruction[ 7]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A0003, // 0001 JMPF R2 #0006 - 0x88080100, // 0002 GETMBR R2 R0 K0 - 0x8C080501, // 0003 GETMET R2 R2 K1 - 0x5C100200, // 0004 MOVE R4 R1 - 0x7C080400, // 0005 CALL R2 2 - 0x80000000, // 0006 RET 0 + ( &(const binstruction[27]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x50100200, // 0001 LDBOOL R4 1 0 + 0x90020004, // 0002 SETMBR R0 K0 R4 + 0xB8120200, // 0003 GETNGBL R4 K1 + 0x88100902, // 0004 GETMBR R4 R4 K2 + 0x88100903, // 0005 GETMBR R4 R4 K3 + 0x780A0004, // 0006 JMPF R2 #000C + 0x28140904, // 0007 GE R5 R4 K4 + 0x78160002, // 0008 JMPF R5 #000C + 0xB8160200, // 0009 GETNGBL R5 K1 + 0x88140B02, // 000A GETMBR R5 R5 K2 + 0x90160705, // 000B SETMBR R5 K3 K5 + 0x8C140106, // 000C GETMET R5 R0 K6 + 0x5C1C0200, // 000D MOVE R7 R1 + 0x7C140400, // 000E CALL R5 2 + 0x4C140000, // 000F LDNIL R5 + 0x88180100, // 0010 GETMBR R6 R0 K0 + 0x501C0200, // 0011 LDBOOL R7 1 0 + 0x20180C07, // 0012 NE R6 R6 R7 + 0x781A0000, // 0013 JMPF R6 #0015 + 0x88140100, // 0014 GETMBR R5 R0 K0 + 0x90020003, // 0015 SETMBR R0 K0 R3 + 0x780A0002, // 0016 JMPF R2 #001A + 0xB81A0200, // 0017 GETNGBL R6 K1 + 0x88180D02, // 0018 GETMBR R6 R6 K2 + 0x901A0604, // 0019 SETMBR R6 K3 R4 + 0x80040A00, // 001A RET 1 R5 }) ) ); @@ -1049,54 +1531,49 @@ be_local_closure(Tasmota_remove_cmd, /* name */ /******************************************************************** -** Solidified function: add_driver +** Solidified function: set_timer ********************************************************************/ -be_local_closure(Tasmota_add_driver, /* name */ +be_local_closure(Tasmota_set_timer, /* name */ be_nested_proto( - 5, /* nstack */ - 2, /* argc */ + 10, /* nstack */ + 4, /* argc */ 2, /* varg */ 0, /* has upvals */ NULL, /* no upvals */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(instance), - /* K1 */ be_nested_str(value_error), - /* K2 */ be_nested_str(instance_X20required), - /* K3 */ be_nested_str(_drivers), - /* K4 */ be_nested_str(find), - /* K5 */ be_nested_str(push), + ( &(const bvalue[ 5]) { /* constants */ + /* K0 */ be_nested_str(check_not_method), + /* K1 */ be_nested_str(_timers), + /* K2 */ be_nested_str(push), + /* K3 */ be_nested_str(Trigger), + /* K4 */ be_nested_str(millis), }), - &be_const_str_add_driver, + &be_const_str_set_timer, &be_const_str_solidified, - ( &(const binstruction[25]) { /* code */ - 0x60080004, // 0000 GETGBL R2 G4 - 0x5C0C0200, // 0001 MOVE R3 R1 - 0x7C080200, // 0002 CALL R2 1 - 0x20080500, // 0003 NE R2 R2 K0 - 0x780A0000, // 0004 JMPF R2 #0006 - 0xB0060302, // 0005 RAISE 1 K1 K2 - 0x88080103, // 0006 GETMBR R2 R0 K3 - 0x780A000B, // 0007 JMPF R2 #0014 - 0x88080103, // 0008 GETMBR R2 R0 K3 - 0x8C080504, // 0009 GETMET R2 R2 K4 - 0x5C100200, // 000A MOVE R4 R1 - 0x7C080400, // 000B CALL R2 2 - 0x4C0C0000, // 000C LDNIL R3 - 0x1C080403, // 000D EQ R2 R2 R3 - 0x780A0003, // 000E JMPF R2 #0013 - 0x88080103, // 000F GETMBR R2 R0 K3 - 0x8C080505, // 0010 GETMET R2 R2 K5 - 0x5C100200, // 0011 MOVE R4 R1 - 0x7C080400, // 0012 CALL R2 2 - 0x70020003, // 0013 JMP #0018 - 0x60080012, // 0014 GETGBL R2 G18 - 0x7C080000, // 0015 CALL R2 0 - 0x400C0401, // 0016 CONNECT R3 R2 R1 - 0x90020602, // 0017 SETMBR R0 K3 R2 - 0x80000000, // 0018 RET 0 + ( &(const binstruction[21]) { /* code */ + 0x8C100100, // 0000 GETMET R4 R0 K0 + 0x5C180400, // 0001 MOVE R6 R2 + 0x7C100400, // 0002 CALL R4 2 + 0x88100101, // 0003 GETMBR R4 R0 K1 + 0x4C140000, // 0004 LDNIL R5 + 0x1C100805, // 0005 EQ R4 R4 R5 + 0x78120002, // 0006 JMPF R4 #000A + 0x60100012, // 0007 GETGBL R4 G18 + 0x7C100000, // 0008 CALL R4 0 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x88100101, // 000A GETMBR R4 R0 K1 + 0x8C100902, // 000B GETMET R4 R4 K2 + 0xB81A0600, // 000C GETNGBL R6 K3 + 0x8C1C0104, // 000D GETMET R7 R0 K4 + 0x5C240200, // 000E MOVE R9 R1 + 0x7C1C0400, // 000F CALL R7 2 + 0x5C200400, // 0010 MOVE R8 R2 + 0x5C240600, // 0011 MOVE R9 R3 + 0x7C180600, // 0012 CALL R6 3 + 0x7C100400, // 0013 CALL R4 2 + 0x80000000, // 0014 RET 0 }) ) ); @@ -1574,100 +2051,11 @@ be_local_closure(Tasmota_load, /* name */ /******************************************************************** -** Solidified function: urlfetch +** Solidified function: next_cron ********************************************************************/ -be_local_closure(Tasmota_urlfetch, /* name */ +be_local_closure(Tasmota_next_cron, /* name */ be_nested_proto( - 10, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[17]) { /* constants */ - /* K0 */ be_nested_str(string), - /* K1 */ be_nested_str(split), - /* K2 */ be_nested_str(_X2F), - /* K3 */ be_nested_str(pop), - /* K4 */ be_const_int(0), - /* K5 */ be_nested_str(index_X2Ehtml), - /* K6 */ be_nested_str(webclient), - /* K7 */ be_nested_str(set_follow_redirects), - /* K8 */ be_nested_str(begin), - /* K9 */ be_nested_str(GET), - /* K10 */ be_nested_str(status_X3A_X20), - /* K11 */ be_nested_str(connection_error), - /* K12 */ be_nested_str(write_file), - /* K13 */ be_nested_str(close), - /* K14 */ be_nested_str(log), - /* K15 */ be_nested_str(BRY_X3A_X20Fetched_X20), - /* K16 */ be_const_int(3), - }), - &be_const_str_urlfetch, - &be_const_str_solidified, - ( &(const binstruction[48]) { /* code */ - 0x4C0C0000, // 0000 LDNIL R3 - 0x1C0C0403, // 0001 EQ R3 R2 R3 - 0x780E000D, // 0002 JMPF R3 #0011 - 0xA40E0000, // 0003 IMPORT R3 K0 - 0x8C100701, // 0004 GETMET R4 R3 K1 - 0x5C180200, // 0005 MOVE R6 R1 - 0x581C0002, // 0006 LDCONST R7 K2 - 0x7C100600, // 0007 CALL R4 3 - 0x8C100903, // 0008 GETMET R4 R4 K3 - 0x7C100200, // 0009 CALL R4 1 - 0x5C080800, // 000A MOVE R2 R4 - 0x6010000C, // 000B GETGBL R4 G12 - 0x5C140400, // 000C MOVE R5 R2 - 0x7C100200, // 000D CALL R4 1 - 0x1C100904, // 000E EQ R4 R4 K4 - 0x78120000, // 000F JMPF R4 #0011 - 0x58080005, // 0010 LDCONST R2 K5 - 0xB80E0C00, // 0011 GETNGBL R3 K6 - 0x7C0C0000, // 0012 CALL R3 0 - 0x8C100707, // 0013 GETMET R4 R3 K7 - 0x50180200, // 0014 LDBOOL R6 1 0 - 0x7C100400, // 0015 CALL R4 2 - 0x8C100708, // 0016 GETMET R4 R3 K8 - 0x5C180200, // 0017 MOVE R6 R1 - 0x7C100400, // 0018 CALL R4 2 - 0x8C100709, // 0019 GETMET R4 R3 K9 - 0x7C100200, // 001A CALL R4 1 - 0x541600C7, // 001B LDINT R5 200 - 0x20140805, // 001C NE R5 R4 R5 - 0x78160004, // 001D JMPF R5 #0023 - 0x60140008, // 001E GETGBL R5 G8 - 0x5C180800, // 001F MOVE R6 R4 - 0x7C140200, // 0020 CALL R5 1 - 0x00161405, // 0021 ADD R5 K10 R5 - 0xB0061605, // 0022 RAISE 1 K11 R5 - 0x8C14070C, // 0023 GETMET R5 R3 K12 - 0x5C1C0400, // 0024 MOVE R7 R2 - 0x7C140400, // 0025 CALL R5 2 - 0x8C18070D, // 0026 GETMET R6 R3 K13 - 0x7C180200, // 0027 CALL R6 1 - 0x8C18010E, // 0028 GETMET R6 R0 K14 - 0x60200008, // 0029 GETGBL R8 G8 - 0x5C240A00, // 002A MOVE R9 R5 - 0x7C200200, // 002B CALL R8 1 - 0x00221E08, // 002C ADD R8 K15 R8 - 0x58240010, // 002D LDCONST R9 K16 - 0x7C180600, // 002E CALL R6 3 - 0x80040800, // 002F RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: exec_tele -********************************************************************/ -be_local_closure(Tasmota_exec_tele, /* name */ - be_nested_proto( - 12, /* nstack */ + 6, /* nstack */ 2, /* argc */ 2, /* varg */ 0, /* has upvals */ @@ -1675,64 +2063,34 @@ be_local_closure(Tasmota_exec_tele, /* name */ 0, /* has sup protos */ NULL, /* no sub protos */ 1, /* has constants */ - ( &(const bvalue[12]) { /* constants */ - /* K0 */ be_nested_str(_rules), - /* K1 */ be_nested_str(json), - /* K2 */ be_nested_str(load), - /* K3 */ be_nested_str(log), - /* K4 */ be_nested_str(BRY_X3A_X20ERROR_X2C_X20bad_X20json_X3A_X20), - /* K5 */ be_const_int(3), - /* K6 */ be_nested_str(Tele), - /* K7 */ be_const_int(0), - /* K8 */ be_nested_str(try_rule), - /* K9 */ be_nested_str(trig), - /* K10 */ be_nested_str(f), - /* K11 */ be_const_int(1), + ( &(const bvalue[ 6]) { /* constants */ + /* K0 */ be_nested_str(_crons), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(size), + /* K3 */ be_nested_str(id), + /* K4 */ be_nested_str(trig), + /* K5 */ be_const_int(1), }), - &be_const_str_exec_tele, + &be_const_str_next_cron, &be_const_str_solidified, - ( &(const binstruction[41]) { /* code */ + ( &(const binstruction[17]) { /* code */ 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A0024, // 0001 JMPF R2 #0027 - 0xA40A0200, // 0002 IMPORT R2 K1 - 0x8C0C0502, // 0003 GETMET R3 R2 K2 - 0x5C140200, // 0004 MOVE R5 R1 - 0x7C0C0400, // 0005 CALL R3 2 - 0x50100000, // 0006 LDBOOL R4 0 0 - 0x4C140000, // 0007 LDNIL R5 - 0x1C140605, // 0008 EQ R5 R3 R5 - 0x78160004, // 0009 JMPF R5 #000F - 0x8C140103, // 000A GETMET R5 R0 K3 - 0x001E0801, // 000B ADD R7 K4 R1 - 0x58200005, // 000C LDCONST R8 K5 - 0x7C140600, // 000D CALL R5 3 - 0x5C0C0200, // 000E MOVE R3 R1 - 0x60140013, // 000F GETGBL R5 G19 - 0x7C140000, // 0010 CALL R5 0 - 0x98160C03, // 0011 SETIDX R5 K6 R3 - 0x5C0C0A00, // 0012 MOVE R3 R5 - 0x58140007, // 0013 LDCONST R5 K7 - 0x6018000C, // 0014 GETGBL R6 G12 - 0x881C0100, // 0015 GETMBR R7 R0 K0 - 0x7C180200, // 0016 CALL R6 1 - 0x14180A06, // 0017 LT R6 R5 R6 - 0x781A000C, // 0018 JMPF R6 #0026 - 0x88180100, // 0019 GETMBR R6 R0 K0 - 0x94180C05, // 001A GETIDX R6 R6 R5 - 0x8C1C0108, // 001B GETMET R7 R0 K8 - 0x5C240600, // 001C MOVE R9 R3 - 0x88280D09, // 001D GETMBR R10 R6 K9 - 0x882C0D0A, // 001E GETMBR R11 R6 K10 - 0x7C1C0800, // 001F CALL R7 4 - 0x741E0001, // 0020 JMPT R7 #0023 - 0x74120000, // 0021 JMPT R4 #0023 - 0x50100001, // 0022 LDBOOL R4 0 1 - 0x50100200, // 0023 LDBOOL R4 1 0 - 0x00140B0B, // 0024 ADD R5 R5 K11 - 0x7001FFED, // 0025 JMP #0014 - 0x80040800, // 0026 RET 1 R4 - 0x50080000, // 0027 LDBOOL R2 0 0 - 0x80040400, // 0028 RET 1 R2 + 0x780A000D, // 0001 JMPF R2 #0010 + 0x580C0001, // 0002 LDCONST R3 K1 + 0x8C100502, // 0003 GETMET R4 R2 K2 + 0x7C100200, // 0004 CALL R4 1 + 0x14100604, // 0005 LT R4 R3 R4 + 0x78120008, // 0006 JMPF R4 #0010 + 0x94100403, // 0007 GETIDX R4 R2 R3 + 0x88100903, // 0008 GETMBR R4 R4 K3 + 0x1C100801, // 0009 EQ R4 R4 R1 + 0x78120002, // 000A JMPF R4 #000E + 0x94100403, // 000B GETIDX R4 R2 R3 + 0x88100904, // 000C GETMBR R4 R4 K4 + 0x80040800, // 000D RET 1 R4 + 0x000C0705, // 000E ADD R3 R3 K5 + 0x7001FFF2, // 000F JMP #0003 + 0x80000000, // 0010 RET 0 }) ) ); @@ -1784,6 +2142,187 @@ be_local_closure(Tasmota_time_str, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: exec_rules +********************************************************************/ +be_local_closure(Tasmota_exec_rules, /* name */ + be_nested_proto( + 14, /* nstack */ + 3, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[12]) { /* constants */ + /* K0 */ be_nested_str(cmd_res), + /* K1 */ be_nested_str(_rules), + /* K2 */ be_nested_str(json), + /* K3 */ be_nested_str(load), + /* K4 */ be_nested_str(log), + /* K5 */ be_nested_str(BRY_X3A_X20ERROR_X2C_X20bad_X20json_X3A_X20), + /* K6 */ be_const_int(3), + /* K7 */ be_const_int(0), + /* K8 */ be_nested_str(try_rule), + /* K9 */ be_nested_str(trig), + /* K10 */ be_nested_str(f), + /* K11 */ be_const_int(1), + }), + &be_const_str_exec_rules, + &be_const_str_solidified, + ( &(const binstruction[50]) { /* code */ + 0x880C0100, // 0000 GETMBR R3 R0 K0 + 0x88100101, // 0001 GETMBR R4 R0 K1 + 0x74120002, // 0002 JMPT R4 #0006 + 0x4C100000, // 0003 LDNIL R4 + 0x20100604, // 0004 NE R4 R3 R4 + 0x78120029, // 0005 JMPF R4 #0030 + 0xA4120400, // 0006 IMPORT R4 K2 + 0x4C140000, // 0007 LDNIL R5 + 0x90020005, // 0008 SETMBR R0 K0 R5 + 0x50140000, // 0009 LDBOOL R5 0 0 + 0x8C180903, // 000A GETMET R6 R4 K3 + 0x5C200200, // 000B MOVE R8 R1 + 0x7C180400, // 000C CALL R6 2 + 0x4C1C0000, // 000D LDNIL R7 + 0x1C1C0C07, // 000E EQ R7 R6 R7 + 0x781E0004, // 000F JMPF R7 #0015 + 0x8C1C0104, // 0010 GETMET R7 R0 K4 + 0x00260A01, // 0011 ADD R9 K5 R1 + 0x58280006, // 0012 LDCONST R10 K6 + 0x7C1C0600, // 0013 CALL R7 3 + 0x5C180200, // 0014 MOVE R6 R1 + 0x780A0014, // 0015 JMPF R2 #002B + 0x881C0101, // 0016 GETMBR R7 R0 K1 + 0x781E0012, // 0017 JMPF R7 #002B + 0x581C0007, // 0018 LDCONST R7 K7 + 0x6020000C, // 0019 GETGBL R8 G12 + 0x88240101, // 001A GETMBR R9 R0 K1 + 0x7C200200, // 001B CALL R8 1 + 0x14200E08, // 001C LT R8 R7 R8 + 0x7822000C, // 001D JMPF R8 #002B + 0x88200101, // 001E GETMBR R8 R0 K1 + 0x94201007, // 001F GETIDX R8 R8 R7 + 0x8C240108, // 0020 GETMET R9 R0 K8 + 0x5C2C0C00, // 0021 MOVE R11 R6 + 0x88301109, // 0022 GETMBR R12 R8 K9 + 0x8834110A, // 0023 GETMBR R13 R8 K10 + 0x7C240800, // 0024 CALL R9 4 + 0x74260001, // 0025 JMPT R9 #0028 + 0x74160000, // 0026 JMPT R5 #0028 + 0x50140001, // 0027 LDBOOL R5 0 1 + 0x50140200, // 0028 LDBOOL R5 1 0 + 0x001C0F0B, // 0029 ADD R7 R7 K11 + 0x7001FFED, // 002A JMP #0019 + 0x4C1C0000, // 002B LDNIL R7 + 0x201C0607, // 002C NE R7 R3 R7 + 0x781E0000, // 002D JMPF R7 #002F + 0x90020006, // 002E SETMBR R0 K0 R6 + 0x80040A00, // 002F RET 1 R5 + 0x50100000, // 0030 LDBOOL R4 0 0 + 0x80040800, // 0031 RET 1 R4 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: add_rule +********************************************************************/ +be_local_closure(Tasmota_add_rule, /* name */ + be_nested_proto( + 10, /* nstack */ + 4, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str(check_not_method), + /* K1 */ be_nested_str(_rules), + /* K2 */ be_nested_str(function), + /* K3 */ be_nested_str(push), + /* K4 */ be_nested_str(Trigger), + /* K5 */ be_nested_str(Rule_Matcher), + /* K6 */ be_nested_str(parse), + /* K7 */ be_nested_str(value_error), + /* K8 */ be_nested_str(the_X20second_X20argument_X20is_X20not_X20a_X20function), + }), + &be_const_str_add_rule, + &be_const_str_solidified, + ( &(const binstruction[29]) { /* code */ + 0x8C100100, // 0000 GETMET R4 R0 K0 + 0x5C180400, // 0001 MOVE R6 R2 + 0x7C100400, // 0002 CALL R4 2 + 0x88100101, // 0003 GETMBR R4 R0 K1 + 0x4C140000, // 0004 LDNIL R5 + 0x1C100805, // 0005 EQ R4 R4 R5 + 0x78120002, // 0006 JMPF R4 #000A + 0x60100012, // 0007 GETGBL R4 G18 + 0x7C100000, // 0008 CALL R4 0 + 0x90020204, // 0009 SETMBR R0 K1 R4 + 0x60100004, // 000A GETGBL R4 G4 + 0x5C140400, // 000B MOVE R5 R2 + 0x7C100200, // 000C CALL R4 1 + 0x1C100902, // 000D EQ R4 R4 K2 + 0x7812000B, // 000E JMPF R4 #001B + 0x88100101, // 000F GETMBR R4 R0 K1 + 0x8C100903, // 0010 GETMET R4 R4 K3 + 0xB81A0800, // 0011 GETNGBL R6 K4 + 0x881C0105, // 0012 GETMBR R7 R0 K5 + 0x8C1C0F06, // 0013 GETMET R7 R7 K6 + 0x5C240200, // 0014 MOVE R9 R1 + 0x7C1C0400, // 0015 CALL R7 2 + 0x5C200400, // 0016 MOVE R8 R2 + 0x5C240600, // 0017 MOVE R9 R3 + 0x7C180600, // 0018 CALL R6 3 + 0x7C100400, // 0019 CALL R4 2 + 0x70020000, // 001A JMP #001C + 0xB0060F08, // 001B RAISE 1 K7 K8 + 0x80000000, // 001C RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: gc +********************************************************************/ +be_local_closure(Tasmota_gc, /* name */ + be_nested_proto( + 4, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 3]) { /* constants */ + /* K0 */ be_nested_str(gc), + /* K1 */ be_nested_str(collect), + /* K2 */ be_nested_str(allocated), + }), + &be_const_str_gc, + &be_const_str_solidified, + ( &(const binstruction[ 6]) { /* code */ + 0xA4060000, // 0000 IMPORT R1 K0 + 0x8C080301, // 0001 GETMET R2 R1 K1 + 0x7C080200, // 0002 CALL R2 1 + 0x8C080302, // 0003 GETMET R2 R1 K2 + 0x7C080200, // 0004 CALL R2 1 + 0x80040400, // 0005 RET 1 R2 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: urlfetch_cmd ********************************************************************/ @@ -1852,6 +2391,119 @@ be_local_closure(Tasmota_urlfetch_cmd, /* name */ /*******************************************************************/ +/******************************************************************** +** Solidified function: add_fast_loop +********************************************************************/ +be_local_closure(Tasmota_add_fast_loop, /* name */ + be_nested_proto( + 5, /* nstack */ + 2, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 9]) { /* constants */ + /* K0 */ be_nested_str(check_not_method), + /* K1 */ be_nested_str(_fl), + /* K2 */ be_nested_str(function), + /* K3 */ be_nested_str(value_error), + /* K4 */ be_nested_str(argument_X20must_X20be_X20a_X20function), + /* K5 */ be_nested_str(global), + /* K6 */ be_nested_str(fast_loop_enabled), + /* K7 */ be_const_int(1), + /* K8 */ be_nested_str(push), + }), + &be_const_str_add_fast_loop, + &be_const_str_solidified, + ( &(const binstruction[23]) { /* code */ + 0x8C080100, // 0000 GETMET R2 R0 K0 + 0x5C100200, // 0001 MOVE R4 R1 + 0x7C080400, // 0002 CALL R2 2 + 0x88080101, // 0003 GETMBR R2 R0 K1 + 0x4C0C0000, // 0004 LDNIL R3 + 0x1C080403, // 0005 EQ R2 R2 R3 + 0x780A0002, // 0006 JMPF R2 #000A + 0x60080012, // 0007 GETGBL R2 G18 + 0x7C080000, // 0008 CALL R2 0 + 0x90020202, // 0009 SETMBR R0 K1 R2 + 0x60080004, // 000A GETGBL R2 G4 + 0x5C0C0200, // 000B MOVE R3 R1 + 0x7C080200, // 000C CALL R2 1 + 0x20080502, // 000D NE R2 R2 K2 + 0x780A0000, // 000E JMPF R2 #0010 + 0xB0060704, // 000F RAISE 1 K3 K4 + 0x88080105, // 0010 GETMBR R2 R0 K5 + 0x900A0D07, // 0011 SETMBR R2 K6 K7 + 0x88080101, // 0012 GETMBR R2 R0 K1 + 0x8C080508, // 0013 GETMET R2 R2 K8 + 0x5C100200, // 0014 MOVE R4 R1 + 0x7C080400, // 0015 CALL R2 2 + 0x80000000, // 0016 RET 0 + }) + ) +); +/*******************************************************************/ + + +/******************************************************************** +** Solidified function: run_deferred +********************************************************************/ +be_local_closure(Tasmota_run_deferred, /* name */ + be_nested_proto( + 7, /* nstack */ + 1, /* argc */ + 2, /* varg */ + 0, /* has upvals */ + NULL, /* no upvals */ + 0, /* has sup protos */ + NULL, /* no sub protos */ + 1, /* has constants */ + ( &(const bvalue[ 8]) { /* constants */ + /* K0 */ be_nested_str(_timers), + /* K1 */ be_const_int(0), + /* K2 */ be_nested_str(size), + /* K3 */ be_nested_str(time_reached), + /* K4 */ be_nested_str(trig), + /* K5 */ be_nested_str(f), + /* K6 */ be_nested_str(remove), + /* K7 */ be_const_int(1), + }), + &be_const_str_run_deferred, + &be_const_str_solidified, + ( &(const binstruction[25]) { /* code */ + 0x88040100, // 0000 GETMBR R1 R0 K0 + 0x78060015, // 0001 JMPF R1 #0018 + 0x58040001, // 0002 LDCONST R1 K1 + 0x88080100, // 0003 GETMBR R2 R0 K0 + 0x8C080502, // 0004 GETMET R2 R2 K2 + 0x7C080200, // 0005 CALL R2 1 + 0x14080202, // 0006 LT R2 R1 R2 + 0x780A000F, // 0007 JMPF R2 #0018 + 0x88080100, // 0008 GETMBR R2 R0 K0 + 0x94080401, // 0009 GETIDX R2 R2 R1 + 0x8C0C0103, // 000A GETMET R3 R0 K3 + 0x88140504, // 000B GETMBR R5 R2 K4 + 0x7C0C0400, // 000C CALL R3 2 + 0x780E0007, // 000D JMPF R3 #0016 + 0x880C0505, // 000E GETMBR R3 R2 K5 + 0x88100100, // 000F GETMBR R4 R0 K0 + 0x8C100906, // 0010 GETMET R4 R4 K6 + 0x5C180200, // 0011 MOVE R6 R1 + 0x7C100400, // 0012 CALL R4 2 + 0x5C100600, // 0013 MOVE R4 R3 + 0x7C100000, // 0014 CALL R4 0 + 0x70020000, // 0015 JMP #0017 + 0x00040307, // 0016 ADD R1 R1 K7 + 0x7001FFEA, // 0017 JMP #0003 + 0x80000000, // 0018 RET 0 + }) + ) +); +/*******************************************************************/ + + /******************************************************************** ** Solidified function: hs2rgb ********************************************************************/ @@ -1950,667 +2602,64 @@ be_local_closure(Tasmota_hs2rgb, /* name */ /*******************************************************************/ -/******************************************************************** -** Solidified function: try_rule -********************************************************************/ -be_local_closure(Tasmota_try_rule, /* name */ - be_nested_proto( - 9, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str(match), - /* K1 */ be_nested_str(trigger), - }), - &be_const_str_try_rule, - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x8C100500, // 0000 GETMET R4 R2 K0 - 0x5C180200, // 0001 MOVE R6 R1 - 0x7C100400, // 0002 CALL R4 2 - 0x4C140000, // 0003 LDNIL R5 - 0x20140805, // 0004 NE R5 R4 R5 - 0x78160009, // 0005 JMPF R5 #0010 - 0x4C140000, // 0006 LDNIL R5 - 0x20140605, // 0007 NE R5 R3 R5 - 0x78160004, // 0008 JMPF R5 #000E - 0x5C140600, // 0009 MOVE R5 R3 - 0x5C180800, // 000A MOVE R6 R4 - 0x881C0501, // 000B GETMBR R7 R2 K1 - 0x5C200200, // 000C MOVE R8 R1 - 0x7C140600, // 000D CALL R5 3 - 0x50140200, // 000E LDBOOL R5 1 0 - 0x80040A00, // 000F RET 1 R5 - 0x50140000, // 0010 LDBOOL R5 0 0 - 0x80040A00, // 0011 RET 1 R5 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: exec_cmd -********************************************************************/ -be_local_closure(Tasmota_exec_cmd, /* name */ - be_nested_proto( - 12, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str(_ccmd), - /* K1 */ be_nested_str(json), - /* K2 */ be_nested_str(load), - /* K3 */ be_nested_str(find_key_i), - /* K4 */ be_nested_str(resolvecmnd), - }), - &be_const_str_exec_cmd, - &be_const_str_solidified, - ( &(const binstruction[27]) { /* code */ - 0x88100100, // 0000 GETMBR R4 R0 K0 - 0x78120016, // 0001 JMPF R4 #0019 - 0xA4120200, // 0002 IMPORT R4 K1 - 0x8C140902, // 0003 GETMET R5 R4 K2 - 0x5C1C0600, // 0004 MOVE R7 R3 - 0x7C140400, // 0005 CALL R5 2 - 0x8C180103, // 0006 GETMET R6 R0 K3 - 0x88200100, // 0007 GETMBR R8 R0 K0 - 0x5C240200, // 0008 MOVE R9 R1 - 0x7C180600, // 0009 CALL R6 3 - 0x4C1C0000, // 000A LDNIL R7 - 0x201C0C07, // 000B NE R7 R6 R7 - 0x781E000B, // 000C JMPF R7 #0019 - 0x8C1C0104, // 000D GETMET R7 R0 K4 - 0x5C240C00, // 000E MOVE R9 R6 - 0x7C1C0400, // 000F CALL R7 2 - 0x881C0100, // 0010 GETMBR R7 R0 K0 - 0x941C0E06, // 0011 GETIDX R7 R7 R6 - 0x5C200C00, // 0012 MOVE R8 R6 - 0x5C240400, // 0013 MOVE R9 R2 - 0x5C280600, // 0014 MOVE R10 R3 - 0x5C2C0A00, // 0015 MOVE R11 R5 - 0x7C1C0800, // 0016 CALL R7 4 - 0x501C0200, // 0017 LDBOOL R7 1 0 - 0x80040E00, // 0018 RET 1 R7 - 0x50100000, // 0019 LDBOOL R4 0 0 - 0x80040800, // 001A RET 1 R4 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_cmd -********************************************************************/ -be_local_closure(Tasmota_add_cmd, /* name */ - be_nested_proto( - 6, /* nstack */ - 3, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 5]) { /* constants */ - /* K0 */ be_nested_str(check_not_method), - /* K1 */ be_nested_str(_ccmd), - /* K2 */ be_nested_str(function), - /* K3 */ be_nested_str(value_error), - /* K4 */ be_nested_str(the_X20second_X20argument_X20is_X20not_X20a_X20function), - }), - &be_const_str_add_cmd, - &be_const_str_solidified, - ( &(const binstruction[20]) { /* code */ - 0x8C0C0100, // 0000 GETMET R3 R0 K0 - 0x5C140400, // 0001 MOVE R5 R2 - 0x7C0C0400, // 0002 CALL R3 2 - 0x880C0101, // 0003 GETMBR R3 R0 K1 - 0x4C100000, // 0004 LDNIL R4 - 0x1C0C0604, // 0005 EQ R3 R3 R4 - 0x780E0002, // 0006 JMPF R3 #000A - 0x600C0013, // 0007 GETGBL R3 G19 - 0x7C0C0000, // 0008 CALL R3 0 - 0x90020203, // 0009 SETMBR R0 K1 R3 - 0x600C0004, // 000A GETGBL R3 G4 - 0x5C100400, // 000B MOVE R4 R2 - 0x7C0C0200, // 000C CALL R3 1 - 0x1C0C0702, // 000D EQ R3 R3 K2 - 0x780E0002, // 000E JMPF R3 #0012 - 0x880C0101, // 000F GETMBR R3 R0 K1 - 0x980C0202, // 0010 SETIDX R3 R1 R2 - 0x70020000, // 0011 JMP #0013 - 0xB0060704, // 0012 RAISE 1 K3 K4 - 0x80000000, // 0013 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: find_op -********************************************************************/ -be_local_closure(Tasmota_find_op, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 4]) { /* constants */ - /* K0 */ be_nested_str(_find_op), - /* K1 */ be_const_int(0), - /* K2 */ be_const_int(1), - /* K3 */ be_const_int(2147483647), - }), - &be_const_str_find_op, - &be_const_str_solidified, - ( &(const binstruction[31]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x7C080400, // 0002 CALL R2 2 - 0x280C0501, // 0003 GE R3 R2 K1 - 0x780E0011, // 0004 JMPF R3 #0017 - 0x540E7FFE, // 0005 LDINT R3 32767 - 0x2C0C0403, // 0006 AND R3 R2 R3 - 0x5412000F, // 0007 LDINT R4 16 - 0x3C100404, // 0008 SHR R4 R2 R4 - 0x60140012, // 0009 GETGBL R5 G18 - 0x7C140000, // 000A CALL R5 0 - 0x04180702, // 000B SUB R6 R3 K2 - 0x401A0206, // 000C CONNECT R6 K1 R6 - 0x94180206, // 000D GETIDX R6 R1 R6 - 0x40180A06, // 000E CONNECT R6 R5 R6 - 0x04180902, // 000F SUB R6 R4 K2 - 0x40180606, // 0010 CONNECT R6 R3 R6 - 0x94180206, // 0011 GETIDX R6 R1 R6 - 0x40180A06, // 0012 CONNECT R6 R5 R6 - 0x40180903, // 0013 CONNECT R6 R4 K3 - 0x94180206, // 0014 GETIDX R6 R1 R6 - 0x40180A06, // 0015 CONNECT R6 R5 R6 - 0x80040A00, // 0016 RET 1 R5 - 0x600C0012, // 0017 GETGBL R3 G18 - 0x7C0C0000, // 0018 CALL R3 0 - 0x40100601, // 0019 CONNECT R4 R3 R1 - 0x4C100000, // 001A LDNIL R4 - 0x40100604, // 001B CONNECT R4 R3 R4 - 0x4C100000, // 001C LDNIL R4 - 0x40100604, // 001D CONNECT R4 R3 R4 - 0x80040600, // 001E RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_fast_loop -********************************************************************/ -be_local_closure(Tasmota_add_fast_loop, /* name */ - be_nested_proto( - 5, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str(check_not_method), - /* K1 */ be_nested_str(_fl), - /* K2 */ be_nested_str(function), - /* K3 */ be_nested_str(value_error), - /* K4 */ be_nested_str(argument_X20must_X20be_X20a_X20function), - /* K5 */ be_nested_str(global), - /* K6 */ be_nested_str(fast_loop_enabled), - /* K7 */ be_const_int(1), - /* K8 */ be_nested_str(push), - }), - &be_const_str_add_fast_loop, - &be_const_str_solidified, - ( &(const binstruction[23]) { /* code */ - 0x8C080100, // 0000 GETMET R2 R0 K0 - 0x5C100200, // 0001 MOVE R4 R1 - 0x7C080400, // 0002 CALL R2 2 - 0x88080101, // 0003 GETMBR R2 R0 K1 - 0x4C0C0000, // 0004 LDNIL R3 - 0x1C080403, // 0005 EQ R2 R2 R3 - 0x780A0002, // 0006 JMPF R2 #000A - 0x60080012, // 0007 GETGBL R2 G18 - 0x7C080000, // 0008 CALL R2 0 - 0x90020202, // 0009 SETMBR R0 K1 R2 - 0x60080004, // 000A GETGBL R2 G4 - 0x5C0C0200, // 000B MOVE R3 R1 - 0x7C080200, // 000C CALL R2 1 - 0x20080502, // 000D NE R2 R2 K2 - 0x780A0000, // 000E JMPF R2 #0010 - 0xB0060704, // 000F RAISE 1 K3 K4 - 0x88080105, // 0010 GETMBR R2 R0 K5 - 0x900A0D07, // 0011 SETMBR R2 K6 K7 - 0x88080101, // 0012 GETMBR R2 R0 K1 - 0x8C080508, // 0013 GETMET R2 R2 K8 - 0x5C100200, // 0014 MOVE R4 R1 - 0x7C080400, // 0015 CALL R2 2 - 0x80000000, // 0016 RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: add_rule -********************************************************************/ -be_local_closure(Tasmota_add_rule, /* name */ - be_nested_proto( - 10, /* nstack */ - 4, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 9]) { /* constants */ - /* K0 */ be_nested_str(check_not_method), - /* K1 */ be_nested_str(_rules), - /* K2 */ be_nested_str(function), - /* K3 */ be_nested_str(push), - /* K4 */ be_nested_str(Trigger), - /* K5 */ be_nested_str(Rule_Matcher), - /* K6 */ be_nested_str(parse), - /* K7 */ be_nested_str(value_error), - /* K8 */ be_nested_str(the_X20second_X20argument_X20is_X20not_X20a_X20function), - }), - &be_const_str_add_rule, - &be_const_str_solidified, - ( &(const binstruction[29]) { /* code */ - 0x8C100100, // 0000 GETMET R4 R0 K0 - 0x5C180400, // 0001 MOVE R6 R2 - 0x7C100400, // 0002 CALL R4 2 - 0x88100101, // 0003 GETMBR R4 R0 K1 - 0x4C140000, // 0004 LDNIL R5 - 0x1C100805, // 0005 EQ R4 R4 R5 - 0x78120002, // 0006 JMPF R4 #000A - 0x60100012, // 0007 GETGBL R4 G18 - 0x7C100000, // 0008 CALL R4 0 - 0x90020204, // 0009 SETMBR R0 K1 R4 - 0x60100004, // 000A GETGBL R4 G4 - 0x5C140400, // 000B MOVE R5 R2 - 0x7C100200, // 000C CALL R4 1 - 0x1C100902, // 000D EQ R4 R4 K2 - 0x7812000B, // 000E JMPF R4 #001B - 0x88100101, // 000F GETMBR R4 R0 K1 - 0x8C100903, // 0010 GETMET R4 R4 K3 - 0xB81A0800, // 0011 GETNGBL R6 K4 - 0x881C0105, // 0012 GETMBR R7 R0 K5 - 0x8C1C0F06, // 0013 GETMET R7 R7 K6 - 0x5C240200, // 0014 MOVE R9 R1 - 0x7C1C0400, // 0015 CALL R7 2 - 0x5C200400, // 0016 MOVE R8 R2 - 0x5C240600, // 0017 MOVE R9 R3 - 0x7C180600, // 0018 CALL R6 3 - 0x7C100400, // 0019 CALL R4 2 - 0x70020000, // 001A JMP #001C - 0xB0060F08, // 001B RAISE 1 K7 K8 - 0x80000000, // 001C RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: gen_cb -********************************************************************/ -be_local_closure(Tasmota_gen_cb, /* name */ - be_nested_proto( - 6, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 2]) { /* constants */ - /* K0 */ be_nested_str(cb), - /* K1 */ be_nested_str(gen_cb), - }), - &be_const_str_gen_cb, - &be_const_str_solidified, - ( &(const binstruction[ 5]) { /* code */ - 0xA40A0000, // 0000 IMPORT R2 K0 - 0x8C0C0501, // 0001 GETMET R3 R2 K1 - 0x5C140200, // 0002 MOVE R5 R1 - 0x7C0C0400, // 0003 CALL R3 2 - 0x80040600, // 0004 RET 1 R3 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: event -********************************************************************/ -be_local_closure(Tasmota_event, /* name */ - be_nested_proto( - 19, /* nstack */ - 6, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[25]) { /* constants */ - /* K0 */ be_nested_str(introspect), - /* K1 */ be_nested_str(every_50ms), - /* K2 */ be_nested_str(run_deferred), - /* K3 */ be_nested_str(every_250ms), - /* K4 */ be_nested_str(run_cron), - /* K5 */ be_nested_str(mqtt_data), - /* K6 */ be_nested_str(cmd), - /* K7 */ be_nested_str(exec_cmd), - /* K8 */ be_nested_str(tele), - /* K9 */ be_nested_str(exec_tele), - /* K10 */ be_nested_str(rule), - /* K11 */ be_nested_str(exec_rules), - /* K12 */ be_nested_str(gc), - /* K13 */ be_nested_str(_drivers), - /* K14 */ be_const_int(0), - /* K15 */ be_nested_str(get), - /* K16 */ be_nested_str(function), - /* K17 */ be_nested_str(BRY_X3A_X20Exception_X3E_X20_X27_X25s_X27_X20_X2D_X20_X25s), - /* K18 */ be_nested_str(_debug_present), - /* K19 */ be_nested_str(debug), - /* K20 */ be_nested_str(traceback), - /* K21 */ be_const_int(1), - /* K22 */ be_nested_str(save_before_restart), - /* K23 */ be_nested_str(persist), - /* K24 */ be_nested_str(save), - }), - &be_const_str_event, - &be_const_str_solidified, - ( &(const binstruction[108]) { /* code */ - 0xA41A0000, // 0000 IMPORT R6 K0 - 0x1C1C0301, // 0001 EQ R7 R1 K1 - 0x781E0001, // 0002 JMPF R7 #0005 - 0x8C1C0102, // 0003 GETMET R7 R0 K2 - 0x7C1C0200, // 0004 CALL R7 1 - 0x1C1C0303, // 0005 EQ R7 R1 K3 - 0x781E0001, // 0006 JMPF R7 #0009 - 0x8C1C0104, // 0007 GETMET R7 R0 K4 - 0x7C1C0200, // 0008 CALL R7 1 - 0x501C0000, // 0009 LDBOOL R7 0 0 - 0x50200000, // 000A LDBOOL R8 0 0 - 0x1C240305, // 000B EQ R9 R1 K5 - 0x78260000, // 000C JMPF R9 #000E - 0x50200200, // 000D LDBOOL R8 1 0 - 0x1C240306, // 000E EQ R9 R1 K6 - 0x78260006, // 000F JMPF R9 #0017 - 0x8C240107, // 0010 GETMET R9 R0 K7 - 0x5C2C0400, // 0011 MOVE R11 R2 - 0x5C300600, // 0012 MOVE R12 R3 - 0x5C340800, // 0013 MOVE R13 R4 - 0x7C240800, // 0014 CALL R9 4 - 0x80041200, // 0015 RET 1 R9 - 0x7002004E, // 0016 JMP #0066 - 0x1C240308, // 0017 EQ R9 R1 K8 - 0x78260004, // 0018 JMPF R9 #001E - 0x8C240109, // 0019 GETMET R9 R0 K9 - 0x5C2C0800, // 001A MOVE R11 R4 - 0x7C240400, // 001B CALL R9 2 - 0x80041200, // 001C RET 1 R9 - 0x70020047, // 001D JMP #0066 - 0x1C24030A, // 001E EQ R9 R1 K10 - 0x78260007, // 001F JMPF R9 #0028 - 0x8C24010B, // 0020 GETMET R9 R0 K11 - 0x5C2C0800, // 0021 MOVE R11 R4 - 0x60300017, // 0022 GETGBL R12 G23 - 0x5C340600, // 0023 MOVE R13 R3 - 0x7C300200, // 0024 CALL R12 1 - 0x7C240600, // 0025 CALL R9 3 - 0x80041200, // 0026 RET 1 R9 - 0x7002003D, // 0027 JMP #0066 - 0x1C24030C, // 0028 EQ R9 R1 K12 - 0x78260003, // 0029 JMPF R9 #002E - 0x8C24010C, // 002A GETMET R9 R0 K12 - 0x7C240200, // 002B CALL R9 1 - 0x80041200, // 002C RET 1 R9 - 0x70020037, // 002D JMP #0066 - 0x8824010D, // 002E GETMBR R9 R0 K13 - 0x78260035, // 002F JMPF R9 #0066 - 0x5824000E, // 0030 LDCONST R9 K14 - 0x6028000C, // 0031 GETGBL R10 G12 - 0x882C010D, // 0032 GETMBR R11 R0 K13 - 0x7C280200, // 0033 CALL R10 1 - 0x1428120A, // 0034 LT R10 R9 R10 - 0x782A002F, // 0035 JMPF R10 #0066 - 0x8828010D, // 0036 GETMBR R10 R0 K13 - 0x94281409, // 0037 GETIDX R10 R10 R9 - 0x8C2C0D0F, // 0038 GETMET R11 R6 K15 - 0x5C341400, // 0039 MOVE R13 R10 - 0x5C380200, // 003A MOVE R14 R1 - 0x7C2C0600, // 003B CALL R11 3 - 0x60300004, // 003C GETGBL R12 G4 - 0x5C341600, // 003D MOVE R13 R11 - 0x7C300200, // 003E CALL R12 1 - 0x1C301910, // 003F EQ R12 R12 K16 - 0x78320022, // 0040 JMPF R12 #0064 - 0xA8020011, // 0041 EXBLK 0 #0054 - 0x5C301600, // 0042 MOVE R12 R11 - 0x5C341400, // 0043 MOVE R13 R10 - 0x5C380400, // 0044 MOVE R14 R2 - 0x5C3C0600, // 0045 MOVE R15 R3 - 0x5C400800, // 0046 MOVE R16 R4 - 0x5C440A00, // 0047 MOVE R17 R5 - 0x7C300A00, // 0048 CALL R12 5 - 0x74320001, // 0049 JMPT R12 #004C - 0x741E0000, // 004A JMPT R7 #004C - 0x501C0001, // 004B LDBOOL R7 0 1 - 0x501C0200, // 004C LDBOOL R7 1 0 - 0x781E0003, // 004D JMPF R7 #0052 - 0x5C301000, // 004E MOVE R12 R8 - 0x74320001, // 004F JMPT R12 #0052 - 0xA8040001, // 0050 EXBLK 1 1 - 0x70020013, // 0051 JMP #0066 - 0xA8040001, // 0052 EXBLK 1 1 - 0x7002000F, // 0053 JMP #0064 - 0xAC300002, // 0054 CATCH R12 0 2 - 0x7002000C, // 0055 JMP #0063 - 0x60380001, // 0056 GETGBL R14 G1 - 0x603C0018, // 0057 GETGBL R15 G24 - 0x58400011, // 0058 LDCONST R16 K17 - 0x5C441800, // 0059 MOVE R17 R12 - 0x5C481A00, // 005A MOVE R18 R13 - 0x7C3C0600, // 005B CALL R15 3 - 0x7C380200, // 005C CALL R14 1 - 0x88380112, // 005D GETMBR R14 R0 K18 - 0x783A0002, // 005E JMPF R14 #0062 - 0xA43A2600, // 005F IMPORT R14 K19 - 0x8C3C1D14, // 0060 GETMET R15 R14 K20 - 0x7C3C0200, // 0061 CALL R15 1 - 0x70020000, // 0062 JMP #0064 - 0xB0080000, // 0063 RAISE 2 R0 R0 - 0x00241315, // 0064 ADD R9 R9 K21 - 0x7001FFCA, // 0065 JMP #0031 - 0x1C240316, // 0066 EQ R9 R1 K22 - 0x78260002, // 0067 JMPF R9 #006B - 0xA4262E00, // 0068 IMPORT R9 K23 - 0x8C281318, // 0069 GETMET R10 R9 K24 - 0x7C280200, // 006A CALL R10 1 - 0x80040E00, // 006B RET 1 R7 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: fast_loop -********************************************************************/ -be_local_closure(Tasmota_fast_loop, /* name */ - be_nested_proto( - 5, /* nstack */ - 1, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 3]) { /* constants */ - /* K0 */ be_nested_str(_fl), - /* K1 */ be_const_int(0), - /* K2 */ be_const_int(1), - }), - &be_const_str_fast_loop, - &be_const_str_solidified, - ( &(const binstruction[15]) { /* code */ - 0x88040100, // 0000 GETMBR R1 R0 K0 - 0x5C080200, // 0001 MOVE R2 R1 - 0x740A0000, // 0002 JMPT R2 #0004 - 0x80000400, // 0003 RET 0 - 0x58080001, // 0004 LDCONST R2 K1 - 0x600C000C, // 0005 GETGBL R3 G12 - 0x5C100200, // 0006 MOVE R4 R1 - 0x7C0C0200, // 0007 CALL R3 1 - 0x14100403, // 0008 LT R4 R2 R3 - 0x78120003, // 0009 JMPF R4 #000E - 0x94100202, // 000A GETIDX R4 R1 R2 - 0x7C100000, // 000B CALL R4 0 - 0x00080502, // 000C ADD R2 R2 K2 - 0x7001FFF9, // 000D JMP #0008 - 0x80000000, // 000E RET 0 - }) - ) -); -/*******************************************************************/ - - -/******************************************************************** -** Solidified function: remove_cron -********************************************************************/ -be_local_closure(Tasmota_remove_cron, /* name */ - be_nested_proto( - 7, /* nstack */ - 2, /* argc */ - 2, /* varg */ - 0, /* has upvals */ - NULL, /* no upvals */ - 0, /* has sup protos */ - NULL, /* no sub protos */ - 1, /* has constants */ - ( &(const bvalue[ 6]) { /* constants */ - /* K0 */ be_nested_str(_crons), - /* K1 */ be_const_int(0), - /* K2 */ be_nested_str(size), - /* K3 */ be_nested_str(id), - /* K4 */ be_nested_str(remove), - /* K5 */ be_const_int(1), - }), - &be_const_str_remove_cron, - &be_const_str_solidified, - ( &(const binstruction[18]) { /* code */ - 0x88080100, // 0000 GETMBR R2 R0 K0 - 0x780A000E, // 0001 JMPF R2 #0011 - 0x580C0001, // 0002 LDCONST R3 K1 - 0x8C100502, // 0003 GETMET R4 R2 K2 - 0x7C100200, // 0004 CALL R4 1 - 0x14100604, // 0005 LT R4 R3 R4 - 0x78120009, // 0006 JMPF R4 #0011 - 0x94100403, // 0007 GETIDX R4 R2 R3 - 0x88100903, // 0008 GETMBR R4 R4 K3 - 0x1C100801, // 0009 EQ R4 R4 R1 - 0x78120003, // 000A JMPF R4 #000F - 0x8C100504, // 000B GETMET R4 R2 K4 - 0x5C180600, // 000C MOVE R6 R3 - 0x7C100400, // 000D CALL R4 2 - 0x70020000, // 000E JMP #0010 - 0x000C0705, // 000F ADD R3 R3 K5 - 0x7001FFF1, // 0010 JMP #0003 - 0x80000000, // 0011 RET 0 - }) - ) -); -/*******************************************************************/ - - /******************************************************************** ** Solidified class: Tasmota ********************************************************************/ be_local_class(Tasmota, 13, NULL, - be_nested_map(49, + be_nested_map(50, ( (struct bmapnode*) &(const bmapnode[]) { - { be_const_key(exec_rules, 45), be_const_closure(Tasmota_exec_rules_closure) }, - { be_const_key(cmd, 30), be_const_closure(Tasmota_cmd_closure) }, - { be_const_key(remove_cron, -1), be_const_closure(Tasmota_remove_cron_closure) }, - { be_const_key(remove_rule, 23), be_const_closure(Tasmota_remove_rule_closure) }, + { be_const_key(hs2rgb, 34), be_const_closure(Tasmota_hs2rgb_closure) }, + { be_const_key(gen_cb, 22), be_const_closure(Tasmota_gen_cb_closure) }, + { be_const_key(fast_loop, 44), be_const_closure(Tasmota_fast_loop_closure) }, + { be_const_key(remove_fast_loop, -1), be_const_closure(Tasmota_remove_fast_loop_closure) }, + { be_const_key(global, -1), be_const_var(9) }, + { be_const_key(try_rule, 17), be_const_closure(Tasmota_try_rule_closure) }, + { be_const_key(wd, -1), be_const_var(11) }, + { be_const_key(check_not_method, -1), be_const_closure(Tasmota_check_not_method_closure) }, { be_const_key(run_deferred, -1), be_const_closure(Tasmota_run_deferred_closure) }, - { be_const_key(find_key_i, 22), be_const_closure(Tasmota_find_key_i_closure) }, - { be_const_key(remove_timer, -1), be_const_closure(Tasmota_remove_timer_closure) }, - { be_const_key(_crons, -1), be_const_var(3) }, - { be_const_key(gen_cb, -1), be_const_closure(Tasmota_gen_cb_closure) }, - { be_const_key(add_cron, -1), be_const_closure(Tasmota_add_cron_closure) }, - { be_const_key(_rules, -1), be_const_var(1) }, - { be_const_key(_drivers, 4), be_const_var(5) }, - { be_const_key(wire1, -1), be_const_var(6) }, - { be_const_key(run_cron, 7), be_const_closure(Tasmota_run_cron_closure) }, - { be_const_key(wire_scan, 9), be_const_closure(Tasmota_wire_scan_closure) }, - { be_const_key(add_rule, -1), be_const_closure(Tasmota_add_rule_closure) }, - { be_const_key(_fl, 36), be_const_var(0) }, - { be_const_key(get_light, -1), be_const_closure(Tasmota_get_light_closure) }, - { be_const_key(find_op, -1), be_const_closure(Tasmota_find_op_closure) }, - { be_const_key(init, -1), be_const_closure(Tasmota_init_closure) }, - { be_const_key(_ccmd, -1), be_const_var(4) }, - { be_const_key(set_timer, -1), be_const_closure(Tasmota_set_timer_closure) }, - { be_const_key(urlfetch, -1), be_const_closure(Tasmota_urlfetch_closure) }, { be_const_key(exec_cmd, -1), be_const_closure(Tasmota_exec_cmd_closure) }, - { be_const_key(gc, -1), be_const_closure(Tasmota_gc_closure) }, - { be_const_key(remove_fast_loop, 17), be_const_closure(Tasmota_remove_fast_loop_closure) }, - { be_const_key(remove_cmd, -1), be_const_closure(Tasmota_remove_cmd_closure) }, - { be_const_key(add_driver, 18), be_const_closure(Tasmota_add_driver_closure) }, - { be_const_key(settings, 41), be_const_var(10) }, - { be_const_key(wire2, -1), be_const_var(7) }, - { be_const_key(remove_driver, -1), be_const_closure(Tasmota_remove_driver_closure) }, - { be_const_key(check_not_method, 29), be_const_closure(Tasmota_check_not_method_closure) }, - { be_const_key(set_light, 37), be_const_closure(Tasmota_set_light_closure) }, - { be_const_key(cmd_res, -1), be_const_var(8) }, - { be_const_key(wd, 8), be_const_var(11) }, + { be_const_key(urlfetch, -1), be_const_closure(Tasmota_urlfetch_closure) }, { be_const_key(urlfetch_cmd, -1), be_const_closure(Tasmota_urlfetch_cmd_closure) }, - { be_const_key(global, 39), be_const_var(9) }, - { be_const_key(time_str, -1), be_const_closure(Tasmota_time_str_closure) }, - { be_const_key(try_rule, -1), be_const_closure(Tasmota_try_rule_closure) }, - { be_const_key(exec_tele, -1), be_const_closure(Tasmota_exec_tele_closure) }, - { be_const_key(add_cmd, -1), be_const_closure(Tasmota_add_cmd_closure) }, - { be_const_key(load, -1), be_const_closure(Tasmota_load_closure) }, - { be_const_key(add_fast_loop, -1), be_const_closure(Tasmota_add_fast_loop_closure) }, - { be_const_key(next_cron, 15), be_const_closure(Tasmota_next_cron_closure) }, - { be_const_key(_debug_present, -1), be_const_var(12) }, + { be_const_key(remove_cron, 24), be_const_closure(Tasmota_remove_cron_closure) }, + { be_const_key(find_list_i, 23), be_const_closure(Tasmota_find_list_i_closure) }, + { be_const_key(gc, -1), be_const_closure(Tasmota_gc_closure) }, + { be_const_key(remove_timer, -1), be_const_closure(Tasmota_remove_timer_closure) }, { be_const_key(_timers, -1), be_const_var(2) }, - { be_const_key(event, -1), be_const_closure(Tasmota_event_closure) }, - { be_const_key(fast_loop, -1), be_const_closure(Tasmota_fast_loop_closure) }, - { be_const_key(hs2rgb, 2), be_const_closure(Tasmota_hs2rgb_closure) }, + { be_const_key(init, 48), be_const_closure(Tasmota_init_closure) }, + { be_const_key(remove_driver, -1), be_const_closure(Tasmota_remove_driver_closure) }, + { be_const_key(wire1, -1), be_const_var(6) }, + { be_const_key(_fl, -1), be_const_var(0) }, + { be_const_key(add_driver, 14), be_const_closure(Tasmota_add_driver_closure) }, + { be_const_key(exec_tele, -1), be_const_closure(Tasmota_exec_tele_closure) }, + { be_const_key(_ccmd, -1), be_const_var(4) }, + { be_const_key(time_str, 36), be_const_closure(Tasmota_time_str_closure) }, + { be_const_key(_debug_present, -1), be_const_var(12) }, + { be_const_key(find_key_i, 31), be_const_closure(Tasmota_find_key_i_closure) }, + { be_const_key(add_cron, -1), be_const_closure(Tasmota_add_cron_closure) }, + { be_const_key(remove_rule, 6), be_const_closure(Tasmota_remove_rule_closure) }, + { be_const_key(add_cmd, 39), be_const_closure(Tasmota_add_cmd_closure) }, + { be_const_key(wire_scan, -1), be_const_closure(Tasmota_wire_scan_closure) }, + { be_const_key(get_light, 40), be_const_closure(Tasmota_get_light_closure) }, + { be_const_key(cmd, 9), be_const_closure(Tasmota_cmd_closure) }, + { be_const_key(set_timer, 11), be_const_closure(Tasmota_set_timer_closure) }, + { be_const_key(load, 32), be_const_closure(Tasmota_load_closure) }, + { be_const_key(_drivers, -1), be_const_var(5) }, + { be_const_key(cmd_res, -1), be_const_var(8) }, + { be_const_key(next_cron, -1), be_const_closure(Tasmota_next_cron_closure) }, + { be_const_key(wire2, -1), be_const_var(7) }, + { be_const_key(_crons, -1), be_const_var(3) }, + { be_const_key(find_op, 41), be_const_closure(Tasmota_find_op_closure) }, + { be_const_key(settings, -1), be_const_var(10) }, + { be_const_key(exec_rules, 20), be_const_closure(Tasmota_exec_rules_closure) }, + { be_const_key(add_rule, -1), be_const_closure(Tasmota_add_rule_closure) }, + { be_const_key(remove_cmd, 45), be_const_closure(Tasmota_remove_cmd_closure) }, + { be_const_key(set_light, -1), be_const_closure(Tasmota_set_light_closure) }, + { be_const_key(add_fast_loop, 8), be_const_closure(Tasmota_add_fast_loop_closure) }, + { be_const_key(_rules, -1), be_const_var(1) }, + { be_const_key(run_cron, 47), be_const_closure(Tasmota_run_cron_closure) }, + { be_const_key(event, 0), be_const_closure(Tasmota_event_closure) }, })), (bstring*) &be_const_str_Tasmota ); diff --git a/lib/libesp32/lib_mail/.github/FUNDING.yml b/lib/libesp32/lib_mail/.github/FUNDING.yml deleted file mode 100644 index c6f438926..000000000 --- a/lib/libesp32/lib_mail/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: ["https://www.paypal.me/mobizt"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/lib/libesp32/lib_mail/.github/stale.yml b/lib/libesp32/lib_mail/.github/stale.yml deleted file mode 100644 index 73494a333..000000000 --- a/lib/libesp32/lib_mail/.github/stale.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 20 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 5 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security -# Label to use when marking an issue as stale -staleLabel: wontfix -# Comment to post when marking an issue 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 if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/lib/libesp32/lib_mail/README.md b/lib/libesp32/lib_mail/README.md deleted file mode 100644 index 6025aec0e..000000000 --- a/lib/libesp32/lib_mail/README.md +++ /dev/null @@ -1,385 +0,0 @@ -# Mail Client Arduino Library for ESP32 and ESP8266 v 1.2.0 - -[![Join the chat at https://gitter.im/mobizt/ESP_Mail_Client](https://badges.gitter.im/mobizt/ESP_Mail_Client.svg)](https://gitter.im/mobizt/ESP_Mail_Client?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -The complete and secure Mail Client for ESP32 and ESP8266 devices for sending and reading the Email through the SMTP and IMAP servers. - -With this library, the devices can both send and read the Email with many types of attachments supported and provides more reliable and flexibilities of usages. - -The library was tested and work well with ESP32s and ESP8266s based modules. - -This library was developed to replace the deprecated ESP32 Mail Client library with more options and features, better reliability and also conforms to the RFC standards. - -![ESP Mail](/media/images/esp-mail-client.svg) - -Copyright (c) 2021 K. Suwatchai (Mobizt). - -# Features - -* Support Espressif ESP32 and ESP8266 MCUs based devices. -* Support TCP session reusage. -* Support PLAIN, LOGIN and XOAUTH2 authentication mechanisms. -* Support secured (with SSL and TLS) and non-secure ports. -* Support mailbox selection for Email reading and searching. -* Support the content encodings e.g. quoted-printable and base64. -* Support the content decodings e.g. base64, UTF-8, UTF-7, quoted-printable, ISO-8859-1 (latin1) and ISO-8859-11 (Thai). -* Support many types of embedded contents e.g. inline images, attachments, parallel media attachments and RFC822 message. -* Support full debuging. -* Support flash memory and SD card for file storages which can be changed in [**ESP_Mail_FS.h**](/src/ESP_Mail_FS.h). -* Support Ethernet (ESP32 using LAN8720, TLK110 and IP101 Ethernet boards). ESP8266 Ethernet is not yet supported. -* Customizable operating configurations (see the examples for the usages) - -## Tested Devices - -This following devices were tested. - - * Sparkfun ESP32 Thing - * NodeMCU-32 - * WEMOS LOLIN32 - * TTGO T8 V1.8 - * M5Stack ESP32 - * NodeMCU ESP8266 - * Wemos D1 Mini (ESP8266) - - - -## Prerequisites - - -The library requires Arduino's ESP32 or ESP8266 Core SDK to be installed based on the platform. - -The latest Core SDK is recommended. For ESP8266, the Core SDK version 2.6.3 or later is recommended. - -The ESP8266 Core SDK version 2.5.x and earlier are not supported. - - - -## Instalation - - -Click on **Clone or download** dropdown at the top of repository, select **Download ZIP** and save file on your computer. - -From Arduino IDE, goto menu **Sketch** -> **Include Library** -> **Add .ZIP Library...** and choose **ESP-Mail-Client-master.zip** that previously downloaded. - -Go to menu **Files** -> **Examples** -> **ESP-Mail-Client-master** and choose one from examples - - - - - - -## IDE Configuaration for ESP8266 MMU - Adjust the Ratio of ICACHE to IRAM - -### Arduino IDE - -When you update the ESP8266 Arduino Core SDK to v3.0.0, the memory can be configurable from Arduino IDE board settings. - -By default MMU **option 1** was selected, the free Heap can be low and may not suitable for the SSL client usage in this library. - -To increase the Heap, choose the MMU **option 3**, 16KB cache + 48KB IRAM and 2nd Heap (shared). - -![Arduino IDE config](/media/images/ArduinoIDE.png) - - -More about MMU settings. -https://arduino-esp8266.readthedocs.io/en/latest/mmu.html - -### PlatformIO IDE - -When Core SDK v3.0.0 becomes available in PlatformIO, - -By default the balanced ratio (32KB cache + 32KB IRAM) configuration is used. - -To increase the heap, **PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED** build flag should be assigned in platformio.ini. - -At the time of writing, to update SDK to v3.0.0 you can follow these steps. - -1. In platformio.ini, edit the config as the following - -```ini -[env:d1_mini] -platform = https://github.com/platformio/platform-espressif8266.git -build_flags = -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED -board = d1_mini -framework = arduino -monitor_speed = 115200 -``` - -2. Delete this folder **C:\Users\UserName\\.platformio\platforms\espressif8266@src-?????????????** -3. Delete .pio and .vscode folders in your project. -4. Clean and Compile the project. - - - -The supportedd MMU build flags in PlatformIO. - -- **PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48** - - 16KB cache + 48KB IRAM (IRAM) - -- **PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED** - - 16KB cache + 48KB IRAM and 2nd Heap (shared) - -- **PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM32_SECHEAP_NOTSHARED** - - 16KB cache + 32KB IRAM + 16KB 2nd Heap (not shared) - -- **PIO_FRAMEWORK_ARDUINO_MMU_EXTERNAL_128K** - - 128K External 23LC1024 - -- **PIO_FRAMEWORK_ARDUINO_MMU_EXTERNAL_1024K** - - 1M External 64 MBit PSRAM - -- **PIO_FRAMEWORK_ARDUINO_MMU_CUSTOM** - - Disables default configuration and expects user-specified flags - - -### Test code for MMU - -```cpp - -#include -#include - -void setup() -{ - Serial.begin(74880); - HeapSelectIram ephemeral; - Serial.printf("IRAM free: %6d bytes\r\n", ESP.getFreeHeap()); - { - HeapSelectDram ephemeral; - Serial.printf("DRAM free: %6d bytes\r\n", ESP.getFreeHeap()); - } -} - -void loop() { - // put your main code here, to run repeatedly: -} - -``` - - - - - - -## Usage - - -See [Full Examples](/examples) for complete usages. - -See [Function Description](/src/README.md) for all available functions. - - -The following examples showed the minimum usage which many options are not configured. - -The examples in the examples folder provide the full options usages. - -## Notes - -The string in the function's parameters or properties of structured data is the pointer to constant char or char array. - -You need to assign the string literal or char array or pointer to constant char to it. - -#### Ex. - -```cpp -message.sender.name = "My Mail"; -message.sender.email = "sender or your Email address"; -``` - -Or using String class - -```cpp -String name = "John"; -String email = "john@mail.com"; - -message.sender.name = name.c_str(); -message.sender.email = email.c_str(); -``` - - - - -### Send the Email - - -```C++ - -// Include ESP Mail Client library (this library) -#include - - -// Define the SMTP Session object which used for SMTP transsport -SMTPSession smtp; - -// Define the session config data which used to store the TCP session configuration -ESP_Mail_Session session; - -// Set the session config -session.server.host_name = "smtp.office365.com"; //for outlook.com -session.server.port = 587; -session.login.email = "your Email address"; //set to empty for no SMTP Authentication -session.login.password = "your Email password"; //set to empty for no SMTP Authentication -session.login.user_domain = "client domain or ip e.g. mydomain.com"; - -// Define the SMTP_Message class variable to handle to message being transport -SMTP_Message message; - -// Set the message headers -message.sender.name = "My Mail"; -message.sender.email = "sender or your Email address"; -message.subject = "Test sending Email"; -message.addRecipient("name1", "email1"); -message.addRecipient("name2", "email2"); - -message.addCc("email3"); -message.addBcc("email4"); - -// Set the message content -message.text.content = "This is simple plain text message"; - -//Base64 data of image -const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII="; - -// Define the attachment data -SMTP_Attachment att; - -// Set the attatchment info -att.descr.filename = "green.png"; -att.descr.mime = "image/png"; -att.blob.data = (uint8_t *)greenImg; -att.blob.size = strlen(greenImg); -// Set the transfer encoding to base64 -att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; -// We set the content encoding to match the above greenImage data -att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; - -// Add attachment to the message -message.addAttachment(att); - -// Connect to server with the session config -smtp.connect(&session); - -// Start sending Email and close the session -if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); - - -``` - - -### Read the Email - - -```C++ - -// Include ESP Mail Client library (this library) -#include - - -// Define the IMAP Session object which used for IMAP transsport -IMAP_Config config; - - -// Define the session config data which used to store the TCP session configuration -ESP_Mail_Session session; - -// Set the session config -session.server.host_name = "outlook.office365.com"; //for outlook.com -session.server.port = 993; -session.login.email = "your Email address"; -session.login.password = "your Email password"; - -// Define the config class variable for searching or fetching operation and store the messsagess data -IMAP_Config config; - -// Define the message UID which required to fetch or read the message -config.fetch.uid = "100"; - -// Define the empty search criteria to disable the messsage search -config.search.criteria = ""; - -// Set to enable the message content which will be stored in the IMAP_Config data -config.enable.html = true; -config.enable.text = true; - - -// Connect to the server with the defined session and options -imap.connect(&session, &config); - -// Open or select the mailbox folder to read the message -imap.selectFolder("INBOX"); - - -// Read the Email and close the session -MailClient.readMail(&imap); - - -// Get the message(s) list -IMAP_MSG_List msgList = imap.data(); - -for (size_t i = 0; i < msgList.msgItems.size(); i++) -{ - // Iterate to get each message data through the message item data - IMAP_MSG_Item msg = msgList.msgItems[i]; - - Serial.println("################################"); - Serial.printf("Messsage Number: %s\n", msg.msgNo); - Serial.printf("Messsage UID: %s\n", msg.UID); - Serial.printf("Messsage ID: %s\n", msg.ID); - Serial.printf("Accept Language: %s\n", msg.acceptLang); - Serial.printf("Content Language: %s\n", msg.contentLang); - Serial.printf("From: %s\n", msg.from); - Serial.printf("From Charset: %s\n", msg.fromCharset); - Serial.printf("To: %s\n", msg.to); - Serial.printf("To Charset: %s\n", msg.toCharset); - Serial.printf("CC: %s\n", msg.cc); - Serial.printf("CC Charset: %s\n", msg.ccCharset); - Serial.printf("Date: %s\n", msg.date); - Serial.printf("Subject: %s\n", msg.subject); - Serial.printf("Subject Charset: %s\n", msg.subjectCharset); - - // If the message body is available - if (!imap.headerOnly()) - { - Serial.printf("Text Message: %s\n", msg.text.content); - Serial.printf("Text Message Charset: %s\n", msg.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", msg.html.content); - Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); - } -} - -``` - - - -## License - -The MIT License (MIT) - -Copyright (c) 2021 K. Suwatchai (Mobizt) - - -Permission is hereby granted, free of charge, to any person returning a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/libesp32/lib_mail/examples/Copy_Messages/Copy_Messsages.ino b/lib/libesp32/lib_mail/examples/Copy_Messages/Copy_Messsages.ino deleted file mode 100644 index 539a0956a..000000000 --- a/lib/libesp32/lib_mail/examples/Copy_Messages/Copy_Messsages.ino +++ /dev/null @@ -1,147 +0,0 @@ -/** - * This example showed how to copy messages from the opened mailbox folder to other folder. - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha - * -*/ - -/** For ESP8266, with BearSSL WiFi Client - * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which - * may cause your device out of memory reset in case the memory - * allocation error. -*/ - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ -#define IMAP_HOST "################" - -/** The imap port e.g. - * 143 or esp_mail_imap_port_143 - * 993 or esp_mail_imap_port_993 -*/ -#define IMAP_PORT 993 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* Print the list of mailbox folders */ -void printAllMailboxesInfo(IMAPSession &imap); - -/* Print the selected folder info */ -void printSelectedMailboxInfo(IMAPSession &imap); - -/* The IMAP Session object used for Email reading */ -IMAPSession imap; - - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - imap.debug(1); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = IMAP_HOST; - session.server.port = IMAP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - - - /* Setup the configuration for searching or fetching operation and its result */ - IMAP_Config config; - - /* Connect to server with the session and config */ - if (!imap.connect(&session, &config)) - return; - - /* {Optional] */ - printAllMailboxesInfo(imap); - - /* Open or select the mailbox folder to read or search the message */ - if (!imap.selectFolder("INBOX")) - return; - - /* Define the MessageList class to add the message to copy */ - MessageList toCopy; - - /* Add message uid to copy to the list */ - toCopy.add(3); - toCopy.add(4); - - //imap.createFolder("test"); - - /* Copy all messages in the list to the folder "test" */ - if (imap.deleteMessages(&toCopy, "test")) - Serial.println("Messages copied"); - - /* Delete all messages in the list from the opened folder (move to trash) */ - //imap.deleteMessages(&toCopy); - - //imap.deleteolder("test"); -} - -void loop() -{ - -} - -void printAllMailboxesInfo(IMAPSession &imap) -{ - /* Declare the folder collection class to get the list of mailbox folders */ - FoldersCollection folders; - - /* Get the mailbox folders */ - if (imap.getFolders(folders)) - { - for (size_t i = 0; i < folders.size(); i++) - { - /* Iterate each folder info using the folder info item data */ - FolderInfo folderInfo = folders.info(i); - Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); - } - } -} diff --git a/lib/libesp32/lib_mail/examples/Delete_Messages/Delete_Messsages.ino b/lib/libesp32/lib_mail/examples/Delete_Messages/Delete_Messsages.ino deleted file mode 100644 index f52e3c708..000000000 --- a/lib/libesp32/lib_mail/examples/Delete_Messages/Delete_Messsages.ino +++ /dev/null @@ -1,142 +0,0 @@ -/** - * This example showed how to delete messages from the opened mailbox folder. - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha - * -*/ - -/** For ESP8266, with BearSSL WiFi Client - * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which - * may cause your device out of memory reset in case the memory - * allocation error. -*/ - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ -#define IMAP_HOST "################" - -/** The imap port e.g. - * 143 or esp_mail_imap_port_143 - * 993 or esp_mail_imap_port_993 -*/ -#define IMAP_PORT 993 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* Print the list of mailbox folders */ -void printAllMailboxesInfo(IMAPSession &imap); - -/* Print the selected folder info */ -void printSelectedMailboxInfo(IMAPSession &imap); - -/* The IMAP Session object used for Email reading */ -IMAPSession imap; - - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - imap.debug(1); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = IMAP_HOST; - session.server.port = IMAP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - - - /* Setup the configuration for searching or fetching operation and its result */ - IMAP_Config config; - - /* Connect to server with the session and config */ - if (!imap.connect(&session, &config)) - return; - - /* {Optional] */ - printAllMailboxesInfo(imap); - - /* Open or select the mailbox folder to read or search the message */ - if (!imap.selectFolder("INBOX")) - return; - - /* Define the MessageList class to add the message to delete */ - MessageList toDelete; - /* Add message uid to delete to the list */ - toDelete.add(10); - toDelete.add(12); - - /* Delete all messages in the list (move to trash) */ - if(imap.deleteMessages(&toDelete)) - Serial.println("Messages deeted"); - - /* Delete all messages permanently by assign the second param to true*/ - //imap.deleteMessages(&toDelete, true); -} - -void loop() -{ - -} - -void printAllMailboxesInfo(IMAPSession &imap) -{ - /* Declare the folder collection class to get the list of mailbox folders */ - FoldersCollection folders; - - /* Get the mailbox folders */ - if (imap.getFolders(folders)) - { - for (size_t i = 0; i < folders.size(); i++) - { - /* Iterate each folder info using the folder info item data */ - FolderInfo folderInfo = folders.info(i); - Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); - } - } -} diff --git a/lib/libesp32/lib_mail/examples/ESP32_Ethernet_Send_Text/ESP32_Ethernet_Send_Text.ino b/lib/libesp32/lib_mail/examples/ESP32_Ethernet_Send_Text/ESP32_Ethernet_Send_Text.ino deleted file mode 100644 index 3dc3192de..000000000 --- a/lib/libesp32/lib_mail/examples/ESP32_Ethernet_Send_Text/ESP32_Ethernet_Send_Text.ino +++ /dev/null @@ -1,307 +0,0 @@ - - -/** - * This example will send the Email in plain text version using ESP32 and LAN8720 Ethernet module. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -/** - * There are many sources for LAN8720 and ESP32 interconnection on the internet which may - * work for your LAN8720 board. - * - * Some methods worked unless no IP is available. - * - * This modification and interconnection provided in this example are mostly worked as - * the 50 MHz clock was created internally in ESP32 which GPIO 17 is set to be output of this clock - * and feeds to the LAN8720 chip XTAL input. - * - * The on-board LAN8720 50 MHz XTAL chip will be disabled by connect its enable pin or pin 1 to GND. - * - * Please see the images in the folder "modified_LAN8720_board_images" for how to modify the LAN8720 board. - * - * The LAN8720 Ethernet modified board and ESP32 board wiring connection. - * - * ESP32 LAN8720 - * - * GPIO17 - EMAC_CLK_OUT_180 nINT/REFCLK - LAN8720 XTAL1/CLKIN 4k7 Pulldown - * GPIO22 - EMAC_TXD1 TX1 - * GPIO19 - EMAC_TXD0 TX0 - * GPIO21 - EMAC_TX_EN TX_EN - * GPIO26 - EMAC_RXD1 RX1 - * GPIO25 - EMAC_RXD0 RX0 - * GPIO27 - EMAC_RX_DV CRS - * GPIO23 - MDC MDC - * GPIO18 - MDIO MDIO - * GND GND - * 3V3 VCC - * -*/ - -//In case of Gmail, to send the Email via port 465 (SSL), less secure app option should be enabled in the account settings. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#include - -#ifdef ETH_CLK_MODE -#undef ETH_CLK_MODE -#endif -#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT //RMII clock output from GPIO17 - -// Pin# of the enable signal for the external crystal oscillator (-1 to disable) -#define ETH_POWER_PIN -1 - -// Type of the Ethernet PHY (LAN8720 or TLK110) -#define ETH_TYPE ETH_PHY_LAN8720 - -// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110) -#define ETH_ADDR 1 - -// Pin# of the I²C clock signal for the Ethernet PHY -#define ETH_MDC_PIN 23 - -// Pin# of the I²C IO signal for the Ethernet PHY -#define ETH_MDIO_PIN 18 - -static bool eth_connected = false; - - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT 25 - -/* The sign in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -unsigned long sendMillis = 0; - -void WiFiEvent(WiFiEvent_t event) -{ - //Do not run any function here to prevent stack overflow or nested interrupt - switch (event) - { - case SYSTEM_EVENT_ETH_START: - Serial.println("ETH Started"); - //set eth hostname here - ETH.setHostname("esp32-ethernet"); - - break; - case SYSTEM_EVENT_ETH_CONNECTED: - Serial.println("ETH Connected"); - break; - case SYSTEM_EVENT_ETH_GOT_IP: - Serial.print("ETH MAC: "); - Serial.print(ETH.macAddress()); - Serial.print(", IPv4: "); - Serial.print(ETH.localIP()); - if (ETH.fullDuplex()) - { - Serial.print(", FULL_DUPLEX"); - } - Serial.print(", "); - Serial.print(ETH.linkSpeed()); - Serial.println("Mbps"); - eth_connected = true; - - break; - case SYSTEM_EVENT_ETH_DISCONNECTED: - Serial.println("ETH Disconnected"); - eth_connected = false; - break; - case SYSTEM_EVENT_ETH_STOP: - Serial.println("ETH Stopped"); - eth_connected = false; - break; - default: - break; - } -} - -void sendMail() -{ - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /** ######################################################## - * Some properties of SMTPSession data and parameters pass to - * SMTP_Message class accept the pointer to constant char - * i.e. const char*. - * - * You may assign a string literal to that properties or function - * like below example. - * - * session.login.user_domain = "mydomain.net"; - * session.login.user_domain = String("mydomain.net").c_str(); - * - * or - * - * String doman = "mydomain.net"; - * session.login.user_domain = domain.c_str(); - * - * And - * - * String name = "Jack " + String("dawson"); - * String email = "jack_dawson" + String(123) + "@mail.com"; - * - * message.addRecipient(name.c_str(), email.c_str()); - * - * message.addHeader(String("Message-ID: ").c_str()); - * - * or - * - * String header = "Message-ID: "; - * message.addHeader(header.c_str()); - * - * ########################################################### - */ - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Test sending plain text Email"; - message.addRecipient("Someone", "####@#####_dot_com"); - - String textMsg = "This is simple plain text message"; - message.text.content = textMsg.c_str(); - - /** The Plain text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.text.charSet = "us-ascii"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void setup() -{ - Serial.begin(115200); - Serial.println(); - - WiFi.onEvent(WiFiEvent); - - ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE); -} - -void loop() -{ - if (eth_connected && (millis() - sendMillis > 300000 || sendMillis == 0)) - { - sendMillis = millis(); - sendMail(); - } -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Read_Email_Access_Token/Read_Email_Access_Token.ino b/lib/libesp32/lib_mail/examples/Read_Email_Access_Token/Read_Email_Access_Token.ino deleted file mode 100644 index 6778e6cbe..000000000 --- a/lib/libesp32/lib_mail/examples/Read_Email_Access_Token/Read_Email_Access_Token.ino +++ /dev/null @@ -1,370 +0,0 @@ -/** - * This example will log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha - * -*/ - -/** For ESP8266, with BearSSL WiFi Client - * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which - * may cause your device out of memory reset in case the memory - * allocation error. -*/ - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ -#define IMAP_HOST "################" - -/** The imap port e.g. - * 143 or esp_mail_imap_port_143 - * 993 or esp_mail_imap_port_993 -*/ -#define IMAP_PORT 993 - -/* The user Email for OAuth2.0 access token */ -#define AUTHOR_EMAIL "################" - -/** The OAuth2.0 access token - * The generation, exchange and refresh of the access token are not available - * in this library. - * - * To test this using GMail, get the OAuth2.0 access token from this web site - * https://developers.google.com/oauthplayground/ - * - * 1. Select the following scope (in Step 1) from Gmail API V1 - * https://mail.google.com/ - * https://mail.google.com/ - * - * 2. Click Authorize APIs button. - * 3. Cick Exchangeauthorization code for tokens. - * 4. From the response, look at access_token from the JSON payload node. - * 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value. - * - * The token will be expired in 3600 seconds (1 Hr). - * The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services. -*/ -#define AUTHOR_ACCESS_TOKEN "################" - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status); - -/* Print the list of mailbox folders */ -void printAllMailboxesInfo(IMAPSession &imap); - -/* Print the selected folder info */ -void printSelectedMailboxInfo(IMAPSession &imap); - -/* Print all messages from the message list */ -void printMessages(IMAPSession &imap); - -/* Print all rfc822 messages included in the message */ -void printRFC822Messages(IMAP_MSG_Item &msg); - -/* Print all attachments info from the message */ -void printAttacements(IMAP_MSG_Item &msg); - -/* The IMAP Session object used for Email reading */ -IMAPSession imap; - - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - imap.debug(1); - - /* Set the callback function to get the reading results */ - imap.callback(imapCallback); - - /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from - * MailClient.sdBegin function which may be different for ESP32 and ESP8266 - * For ESP32, assign all of SPI pins - * MailClient.sdBegin(14,2,15,13) - * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 - * And for ESP8266, assign the CS pins of SPI port - * MailClient.sdBegin(15) - * Which pin 15 is the CS pin of SD card adapter - */ - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = IMAP_HOST; - session.server.port = IMAP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.accessToken = AUTHOR_ACCESS_TOKEN; - - - /* Setup the configuration for searching or fetching operation and its result */ - IMAP_Config config; - - /* Message UID to fetch or read e.g. 100 */ - config.fetch.uid = "100"; - - /* Set seen flag*/ - //config.fetch.set_seen = true; - - /* Search criteria */ - config.search.criteria = ""; - - /* Also search the unseen message */ - config.search.unseen_msg = true; - - /* Set the storage to save the downloaded files and attachments */ - config.storage.saved_path = "/email_data"; - - /** The file storage type e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - config.storage.type = esp_mail_file_storage_type_flash; - - /** Set to download heades, text and html messaeges, - * attachments and inline images respectively. - */ - config.download.header = true; - config.download.text = true; - config.download.html = true; - config.download.attachment = true; - config.download.inlineImg = true; - - /** Set to enable the results i.e. html and text messaeges - * which the content stored in the IMAPSession object is limited - * by the option config.limit.msg_size. - * The whole message can be download through config.download.text - * or config.download.html which not depends on these enable options. - */ - config.enable.html = true; - config.enable.text = true; - - /* Set to enable the sort the result by message UID in the ascending order */ - config.enable.recent_sort = true; - - /* Set to report the download progress via the default serial port */ - config.enable.download_status = true; - - /* Set the limit of number of messages in the search results */ - config.limit.search = 5; - - /** Set the maximum size of message stored in - * IMAPSession object in byte - */ - config.limit.msg_size = 512; - - /** Set the maximum attachments and inline images files size - * that can be downloaded in byte. - * The file which its size is largger than this limit may be saved - * as truncated file. - */ - config.limit.attachment_size = 1024 * 1024 * 5; - - - /* Connect to server with the session and config */ - if (!imap.connect(&session, &config)) - return; - - /* {Optional] */ - printAllMailboxesInfo(imap); - - /* Open or select the mailbox folder to read or search the message */ - if (!imap.selectFolder("INBOX")) - return; - - /* {Optional] */ - printSelectedMailboxInfo(imap); - - /* Read or search the Email and close the session */ - MailClient.readMail(&imap); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); -} - -void loop() -{ - -} - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Show the result when reading finished */ - if (status.success()) - { - /* Print the result */ - printMessages(imap); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); - Serial.printf("Free Heap: %d", ESP.getFreeHeap()); - } -} - -void printAllMailboxesInfo(IMAPSession &imap) -{ - /* Declare the folder collection class to get the list of mailbox folders */ - FoldersCollection folders; - - /* Get the mailbox folders */ - if (imap.getFolders(folders)) - { - for (size_t i = 0; i < folders.size(); i++) - { - /* Iterate each folder info using the folder info item data */ - FolderInfo folderInfo = folders.info(i); - Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); - } - } -} - -void printSelectedMailboxInfo(IMAPSession &imap) -{ - /* Declare the selected folder info class to get the info of selected mailbox folder */ - SelectedFolderInfo sFolder = imap.selectedFolder(); - - /* Show the mailbox info */ - Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); - Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); - for (size_t i = 0; i < sFolder.flagCount(); i++) - Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); -} - -void printRFC822Messages(IMAP_MSG_Item &msg) -{ - Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); - for (size_t j = 0; j < msg.rfc822.size(); j++) - { - IMAP_MSG_Item rfc822 = msg.rfc822[j]; - Serial.printf("%d. \n", j + 1); - Serial.printf("Messsage ID: %s\n", rfc822.messageID); - Serial.printf("From: %s\n", rfc822.from); - Serial.printf("Sender: %s\n", rfc822.sender); - Serial.printf("To: %s\n", rfc822.to); - Serial.printf("CC: %s\n", rfc822.cc); - Serial.printf("Subject: %s\n", rfc822.subject); - Serial.printf("Date: %s\n", rfc822.date); - Serial.printf("Reply-To: %s\n", rfc822.reply_to); - Serial.printf("Return-Path: %s\n", rfc822.return_path); - Serial.printf("Comment: %s\n", rfc822.comment); - Serial.printf("Keyword: %s\n", rfc822.keyword); - Serial.printf("Text Message: %s\n", rfc822.text.content); - Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", rfc822.html.content); - Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); - - if (rfc822.attachments.size() > 0) - printAttacements(rfc822); - } -} - -void printAttacements(IMAP_MSG_Item &msg) -{ - Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); - for (size_t j = 0; j < msg.attachments.size(); j++) - { - IMAP_Attach_Item att = msg.attachments[j]; - /** att.type can be - * esp_mail_att_type_none or 0 - * esp_mail_att_type_attachment or 1 - * esp_mail_att_type_inline or 2 - */ - Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); - } - Serial.println(); -} - -void printMessages(IMAPSession &imap) -{ - /* Get the message list from the message list data */ - IMAP_MSG_List msgList = imap.data(); - - for (size_t i = 0; i < msgList.msgItems.size(); i++) - { - /* Iterate to get each message data through the message item data */ - IMAP_MSG_Item msg = msgList.msgItems[i]; - - Serial.println("################################"); - Serial.printf("Messsage Number: %s\n", msg.msgNo); - Serial.printf("Messsage UID: %s\n", msg.UID); - Serial.printf("Messsage ID: %s\n", msg.ID); - Serial.printf("Accept Language: %s\n", msg.acceptLang); - Serial.printf("Content Language: %s\n", msg.contentLang); - Serial.printf("From: %s\n", msg.from); - Serial.printf("From Charset: %s\n", msg.fromCharset); - Serial.printf("To: %s\n", msg.to); - Serial.printf("To Charset: %s\n", msg.toCharset); - Serial.printf("CC: %s\n", msg.cc); - Serial.printf("CC Charset: %s\n", msg.ccCharset); - Serial.printf("Date: %s\n", msg.date); - Serial.printf("Subject: %s\n", msg.subject); - Serial.printf("Subject Charset: %s\n", msg.subjectCharset); - - /* If the result contains the message info (Fetch mode) */ - if (!imap.headerOnly()) - { - Serial.printf("Text Message: %s\n", msg.text.content); - Serial.printf("Text Message Charset: %s\n", msg.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", msg.html.content); - Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); - - if (msg.attachments.size() > 0) - printAttacements(msg); - - if (msg.rfc822.size() > 0) - printRFC822Messages(msg); - } - - Serial.println(); - } -} diff --git a/lib/libesp32/lib_mail/examples/Read_Single_Email/Read_Single_Email.ino b/lib/libesp32/lib_mail/examples/Read_Single_Email/Read_Single_Email.ino deleted file mode 100644 index 31fa6348c..000000000 --- a/lib/libesp32/lib_mail/examples/Read_Single_Email/Read_Single_Email.ino +++ /dev/null @@ -1,364 +0,0 @@ -/** - * This example will fetch or read the Email which the known message UID - * was used for fetching. - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha - * -*/ - -/** For ESP8266, with BearSSL WiFi Client - * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which - * may cause your device out of memory reset in case the memory - * allocation error. -*/ - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ -#define IMAP_HOST "################" - -/** The imap port e.g. - * 143 or esp_mail_imap_port_143 - * 993 or esp_mail_imap_port_993 -*/ -#define IMAP_PORT 993 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status); - -/* Print the list of mailbox folders */ -void printAllMailboxesInfo(IMAPSession &imap); - -/* Print the selected folder info */ -void printSelectedMailboxInfo(IMAPSession &imap); - -/* Print all messages from the message list */ -void printMessages(IMAPSession &imap); - -/* Print all rfc822 messages included in the message */ -void printRFC822Messages(IMAP_MSG_Item &msg); - -/* Print all attachments info from the message */ -void printAttacements(IMAP_MSG_Item &msg); - -/* The IMAP Session object used for Email reading */ -IMAPSession imap; - - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - imap.debug(1); - - /* Set the callback function to get the reading results */ - imap.callback(imapCallback); - - /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from - * MailClient.sdBegin function which may be different for ESP32 and ESP8266 - * For ESP32, assign all of SPI pins - * MailClient.sdBegin(14,2,15,13) - * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 - * And for ESP8266, assign the CS pins of SPI port - * MailClient.sdBegin(15) - * Which pin 15 is the CS pin of SD card adapter - */ - - /* Declare the session config data */ - ESP_Mail_Session session; - - /** ######################################################## - * Some properties of IMAP_Config and ESP_Mail_Session data - * accept the pointer to constant char i.e. const char*. - * - * You may assign a string literal to that properties like - * below example. - * - * config.storage.saved_path = String("/email_data").c_str(); - * - * String folder = "INBOX"; - * imap.selectFolder(folder.c_str()); - * - * ########################################################### - */ - - /* Set the session config */ - session.server.host_name = IMAP_HOST; - session.server.port = IMAP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - - - /* Setup the configuration for searching or fetching operation and its result */ - IMAP_Config config; - - /* Message UID to fetch or read e.g. 100 */ - config.fetch.uid = "100"; - - /* Set seen flag */ - //config.fetch.set_seen = true; - - /* Search criteria */ - config.search.criteria = ""; - - /* Also search the unseen message */ - config.search.unseen_msg = true; - - /* Set the storage to save the downloaded files and attachments */ - config.storage.saved_path = "/email_data"; - - /** The file storage type e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - config.storage.type = esp_mail_file_storage_type_flash; - - /** Set to download heades, text and html messaeges, - * attachments and inline images respectively. - */ - config.download.header = true; - config.download.text = true; - config.download.html = true; - config.download.attachment = true; - config.download.inlineImg = true; - - /** Set to enable the results i.e. html and text messaeges - * which the content stored in the IMAPSession object is limited - * by the option config.limit.msg_size. - * The whole message can be download through config.download.text - * or config.download.html which not depends on these enable options. - */ - config.enable.html = true; - config.enable.text = true; - - /* Set to enable the sort the result by message UID in the ascending order */ - config.enable.recent_sort = true; - - /* Set to report the download progress via the default serial port */ - config.enable.download_status = true; - - /* Set the limit of number of messages in the search results */ - config.limit.search = 5; - - /** Set the maximum size of message stored in - * IMAPSession object in byte - */ - config.limit.msg_size = 512; - - /** Set the maximum attachments and inline images files size - * that can be downloaded in byte. - * The file which its size is largger than this limit may be saved - * as truncated file. - */ - config.limit.attachment_size = 1024 * 1024 * 5; - - - /* Connect to server with the session and config */ - if (!imap.connect(&session, &config)) - return; - - /* {Optional] */ - printAllMailboxesInfo(imap); - - /* Open or select the mailbox folder to read or search the message */ - if (!imap.selectFolder("INBOX")) - return; - - /* {Optional] */ - printSelectedMailboxInfo(imap); - - /* Read or search the Email and close the session */ - MailClient.readMail(&imap); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); -} - -void loop() -{ - -} - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Show the result when reading finished */ - if (status.success()) - { - /* Print the result */ - printMessages(imap); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); - Serial.printf("Free Heap: %d", ESP.getFreeHeap()); - } -} - -void printAllMailboxesInfo(IMAPSession &imap) -{ - /* Declare the folder collection class to get the list of mailbox folders */ - FoldersCollection folders; - - /* Get the mailbox folders */ - if (imap.getFolders(folders)) - { - for (size_t i = 0; i < folders.size(); i++) - { - /* Iterate each folder info using the folder info item data */ - FolderInfo folderInfo = folders.info(i); - Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); - } - } -} - -void printSelectedMailboxInfo(IMAPSession &imap) -{ - /* Declare the selected folder info class to get the info of selected mailbox folder */ - SelectedFolderInfo sFolder = imap.selectedFolder(); - - /* Show the mailbox info */ - Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); - Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); - for (size_t i = 0; i < sFolder.flagCount(); i++) - Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); -} - -void printRFC822Messages(IMAP_MSG_Item &msg) -{ - Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); - for (size_t j = 0; j < msg.rfc822.size(); j++) - { - IMAP_MSG_Item rfc822 = msg.rfc822[j]; - Serial.printf("%d. \n", j + 1); - Serial.printf("Messsage ID: %s\n", rfc822.messageID); - Serial.printf("From: %s\n", rfc822.from); - Serial.printf("Sender: %s\n", rfc822.sender); - Serial.printf("To: %s\n", rfc822.to); - Serial.printf("CC: %s\n", rfc822.cc); - Serial.printf("Subject: %s\n", rfc822.subject); - Serial.printf("Date: %s\n", rfc822.date); - Serial.printf("Reply-To: %s\n", rfc822.reply_to); - Serial.printf("Return-Path: %s\n", rfc822.return_path); - Serial.printf("Comment: %s\n", rfc822.comment); - Serial.printf("Keyword: %s\n", rfc822.keyword); - Serial.printf("Text Message: %s\n", rfc822.text.content); - Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", rfc822.html.content); - Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); - - if (rfc822.attachments.size() > 0) - printAttacements(rfc822); - } -} - -void printAttacements(IMAP_MSG_Item &msg) -{ - Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); - for (size_t j = 0; j < msg.attachments.size(); j++) - { - IMAP_Attach_Item att = msg.attachments[j]; - /** att.type can be - * esp_mail_att_type_none or 0 - * esp_mail_att_type_attachment or 1 - * esp_mail_att_type_inline or 2 - */ - Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); - } - Serial.println(); -} - -void printMessages(IMAPSession &imap) -{ - /* Get the message list from the message list data */ - IMAP_MSG_List msgList = imap.data(); - - for (size_t i = 0; i < msgList.msgItems.size(); i++) - { - /* Iterate to get each message data through the message item data */ - IMAP_MSG_Item msg = msgList.msgItems[i]; - - Serial.println("################################"); - Serial.printf("Messsage Number: %s\n", msg.msgNo); - Serial.printf("Messsage UID: %s\n", msg.UID); - Serial.printf("Messsage ID: %s\n", msg.ID); - Serial.printf("Accept Language: %s\n", msg.acceptLang); - Serial.printf("Content Language: %s\n", msg.contentLang); - Serial.printf("From: %s\n", msg.from); - Serial.printf("From Charset: %s\n", msg.fromCharset); - Serial.printf("To: %s\n", msg.to); - Serial.printf("To Charset: %s\n", msg.toCharset); - Serial.printf("CC: %s\n", msg.cc); - Serial.printf("CC Charset: %s\n", msg.ccCharset); - Serial.printf("Date: %s\n", msg.date); - Serial.printf("Subject: %s\n", msg.subject); - Serial.printf("Subject Charset: %s\n", msg.subjectCharset); - - /* If the result contains the message info (Fetch mode) */ - if (!imap.headerOnly()) - { - Serial.printf("Text Message: %s\n", msg.text.content); - Serial.printf("Text Message Charset: %s\n", msg.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", msg.html.content); - Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); - - if (msg.attachments.size() > 0) - printAttacements(msg); - - if (msg.rfc822.size() > 0) - printRFC822Messages(msg); - } - - Serial.println(); - } -} diff --git a/lib/libesp32/lib_mail/examples/Read_Single_Email_Loop/Read_Single_Email_Loop.ino b/lib/libesp32/lib_mail/examples/Read_Single_Email_Loop/Read_Single_Email_Loop.ino deleted file mode 100644 index b6b484a29..000000000 --- a/lib/libesp32/lib_mail/examples/Read_Single_Email_Loop/Read_Single_Email_Loop.ino +++ /dev/null @@ -1,376 +0,0 @@ -/** - * This example will repeatedly fetch or read the Email via the loop function - * using the predict next message UID as the starting count down message UID. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha - * -*/ - -/** For ESP8266, with BearSSL WiFi Client - * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which - * may cause your device out of memory reset in case the memory - * allocation error. -*/ - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ -#define IMAP_HOST "################" - -/** The imap port e.g. - * 143 or esp_mail_imap_port_143 - * 993 or esp_mail_imap_port_993 -*/ -#define IMAP_PORT 993 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status); - -/* Print the list of mailbox folders */ -void printAllMailboxesInfo(IMAPSession &imap); - -/* Print the selected folder info */ -void printSelectedMailboxInfo(IMAPSession &imap); - -/* Print all messages from the message list */ -void printMessages(IMAPSession &imap); - -/* Print all rfc822 messages included in the message */ -void printRFC822Messages(IMAP_MSG_Item &msg); - -/* Print all attachments info from the message */ -void printAttacements(IMAP_MSG_Item &msg); - -/* The IMAP Session object used for Email reading */ -IMAPSession imap; - -unsigned long readMillis = 0; - -int nextMsgUID = 0; -int msgUID = 0; -int sign = -1; - -/* Declare the session config data */ -ESP_Mail_Session session; - -/* Setup the configuration for searching or fetching operation and its result */ -IMAP_Config config; - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - imap.debug(1); - - /* Set the callback function to get the reading results */ - imap.callback(imapCallback); - - /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from - * MailClient.sdBegin function which may be different for ESP32 and ESP8266 - * For ESP32, assign all of SPI pins - * MailClient.sdBegin(14,2,15,13) - * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 - * And for ESP8266, assign the CS pins of SPI port - * MailClient.sdBegin(15) - * Which pin 15 is the CS pin of SD card adapter - */ - - /* Set the session config */ - session.server.host_name = IMAP_HOST; - session.server.port = IMAP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - - - /* Message UID to fetch or read */ - config.fetch.uid = ""; - - /* Search criteria */ - config.search.criteria = ""; - - /* Also search the unseen message */ - config.search.unseen_msg = true; - - /* Set the storage to save the downloaded files and attachments */ - config.storage.saved_path = "/email_data"; - - /** The file storage type e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - config.storage.type = esp_mail_file_storage_type_flash; - - /** Set to download heades, text and html messaeges, - * attachments and inline images respectively. - */ - config.download.header = false; - config.download.text = false; - config.download.html = false; - config.download.attachment = false; - config.download.inlineImg = false; - - /** Set to enable the results i.e. html and text messaeges - * which the content stored in the IMAPSession object is limited - * by the option config.limit.msg_size. - * The whole message can be download through config.download.text - * or config.download.html which not depends on these enable options. - */ - config.enable.html = true; - config.enable.text = true; - - /* Set to enable the sort the result by message UID in the ascending order */ - config.enable.recent_sort = true; - - /* Set to report the download progress via the default serial port */ - config.enable.download_status = true; - - /* Set the limit of number of messages in the search results */ - config.limit.search = 5; - - /** Set the maximum size of message stored in - * IMAPSession object in byte - */ - config.limit.msg_size = 512; - - /** Set the maximum attachments and inline images files size - * that can be downloaded in byte. - * The file which its size is largger than this limit may be saved - * as truncated file. - */ - config.limit.attachment_size = 1024 * 1024 * 5; - - - /* Connect to server with the session and config */ - if (!imap.connect(&session, &config)) - return; - - /* {Optional] */ - printAllMailboxesInfo(imap); - - /* Open or select the mailbox folder to read or search the message */ - if (!imap.selectFolder("INBOX")) - return; - - /* {Optional] */ - printSelectedMailboxInfo(imap); -} - -void loop() -{ - if (millis() - readMillis > 10000 || readMillis == 0) - { - readMillis = millis(); - - if (msgUID == 0) - sign = 1; - else if (msgUID >= nextMsgUID) - sign = -1; - - msgUID += sign; - - String uid = String(msgUID); - - /* Message UID to fetch or read */ - config.fetch.uid = uid.c_str(); - - /* Set seen flag */ - //config.fetch.set_seen = true; - - /** Read or search the Email and keep the TCP session to open - * The second parameter is for close the session. - */ - MailClient.readMail(&imap, false); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); - } -} - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Show the result when reading finished */ - if (status.success()) - { - /* Print the result */ - printMessages(imap); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); - Serial.printf("Free Heap: %d", ESP.getFreeHeap()); - } -} - -void printAllMailboxesInfo(IMAPSession &imap) -{ - /* Declare the folder collection class to get the list of mailbox folders */ - FoldersCollection folders; - - /* Get the mailbox folders */ - if (imap.getFolders(folders)) - { - for (size_t i = 0; i < folders.size(); i++) - { - /* Iterate each folder info using the folder info item data */ - FolderInfo folderInfo = folders.info(i); - Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); - } - } -} - -void printSelectedMailboxInfo(IMAPSession &imap) -{ - /* Declare the selected folder info class to get the info of selected mailbox folder */ - SelectedFolderInfo sFolder = imap.selectedFolder(); - - nextMsgUID = sFolder.nextUID(); - msgUID = nextMsgUID; - - /* Show the mailbox info */ - Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); - Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); - for (size_t i = 0; i < sFolder.flagCount(); i++) - Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); -} - -void printRFC822Messages(IMAP_MSG_Item &msg) -{ - Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); - for (size_t j = 0; j < msg.rfc822.size(); j++) - { - IMAP_MSG_Item rfc822 = msg.rfc822[j]; - Serial.printf("%d. \n", j + 1); - Serial.printf("Messsage ID: %s\n", rfc822.messageID); - Serial.printf("From: %s\n", rfc822.from); - Serial.printf("Sender: %s\n", rfc822.sender); - Serial.printf("To: %s\n", rfc822.to); - Serial.printf("CC: %s\n", rfc822.cc); - Serial.printf("Subject: %s\n", rfc822.subject); - Serial.printf("Date: %s\n", rfc822.date); - Serial.printf("Reply-To: %s\n", rfc822.reply_to); - Serial.printf("Return-Path: %s\n", rfc822.return_path); - Serial.printf("Comment: %s\n", rfc822.comment); - Serial.printf("Keyword: %s\n", rfc822.keyword); - Serial.printf("Text Message: %s\n", rfc822.text.content); - Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", rfc822.html.content); - Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); - - if (rfc822.attachments.size() > 0) - printAttacements(rfc822); - } -} - -void printAttacements(IMAP_MSG_Item &msg) -{ - Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); - for (size_t j = 0; j < msg.attachments.size(); j++) - { - IMAP_Attach_Item att = msg.attachments[j]; - /** att.type can be - * esp_mail_att_type_none or 0 - * esp_mail_att_type_attachment or 1 - * esp_mail_att_type_inline or 2 - */ - Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); - } - Serial.println(); -} - -void printMessages(IMAPSession &imap) -{ - /* Get the message list from the message list data */ - IMAP_MSG_List msgList = imap.data(); - - for (size_t i = 0; i < msgList.msgItems.size(); i++) - { - /* Iterate to get each message data through the message item data */ - IMAP_MSG_Item msg = msgList.msgItems[i]; - - Serial.println("################################"); - Serial.printf("Messsage Number: %s\n", msg.msgNo); - Serial.printf("Messsage UID: %s\n", msg.UID); - Serial.printf("Messsage ID: %s\n", msg.ID); - Serial.printf("Accept Language: %s\n", msg.acceptLang); - Serial.printf("Content Language: %s\n", msg.contentLang); - Serial.printf("From: %s\n", msg.from); - Serial.printf("From Charset: %s\n", msg.fromCharset); - Serial.printf("To: %s\n", msg.to); - Serial.printf("To Charset: %s\n", msg.toCharset); - Serial.printf("CC: %s\n", msg.cc); - Serial.printf("CC Charset: %s\n", msg.ccCharset); - Serial.printf("Date: %s\n", msg.date); - Serial.printf("Subject: %s\n", msg.subject); - Serial.printf("Subject Charset: %s\n", msg.subjectCharset); - - /* If the result contains the message info (Fetch mode) */ - if (!imap.headerOnly()) - { - Serial.printf("Text Message: %s\n", msg.text.content); - Serial.printf("Text Message Charset: %s\n", msg.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", msg.html.content); - Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); - - if (msg.attachments.size() > 0) - printAttacements(msg); - - if (msg.rfc822.size() > 0) - printRFC822Messages(msg); - } - - Serial.println(); - } -} diff --git a/lib/libesp32/lib_mail/examples/Search_Emails/Search_Emails.ino b/lib/libesp32/lib_mail/examples/Search_Emails/Search_Emails.ino deleted file mode 100644 index e82c84b6f..000000000 --- a/lib/libesp32/lib_mail/examples/Search_Emails/Search_Emails.ino +++ /dev/null @@ -1,402 +0,0 @@ -/** - * This example will search all Emails in the opened mailbox folder. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha - * -*/ - -/** For ESP8266, with BearSSL WiFi Client - * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which - * may cause your device out of memory reset in case the memory - * allocation error. -*/ - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ -#define IMAP_HOST "################" - -/** The imap port e.g. - * 143 or esp_mail_imap_port_143 - * 993 or esp_mail_imap_port_993 -*/ -#define IMAP_PORT 993 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status); - -/* Print the list of mailbox folders */ -void printAllMailboxesInfo(IMAPSession &imap); - -/* Print the selected folder info */ -void printSelectedMailboxInfo(IMAPSession &imap); - -/* Print all messages from the message list */ -void printMessages(IMAPSession &imap); - -/* Print all rfc822 messages included in the message */ -void printRFC822Messages(IMAP_MSG_Item &msg); - -/* Print all attachments info from the message */ -void printAttacements(IMAP_MSG_Item &msg); - -/* The IMAP Session object used for Email reading */ -IMAPSession imap; - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - imap.debug(1); - - /* Set the callback function to get the reading results */ - imap.callback(imapCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from - * MailClient.sdBegin function which may be different for ESP32 and ESP8266 - * For ESP32, assign all of SPI pins - * MailClient.sdBegin(14,2,15,13) - * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 - * And for ESP8266, assign the CS pins of SPI port - * MailClient.sdBegin(15) - * Which pin 15 is the CS pin of SD card adapter - */ - - /** ######################################################## - * Some properties of IMAP_Config and ESP_Mail_Session data - * accept the pointer to constant char i.e. const char*. - * - * You may assign a string literal to that properties like - * below example. - * - * config.search.criteria = String("UID SEARCH ALL").c_str(); - * - * String folder = "INBOX"; - * imap.selectFolder(folder.c_str()); - * - * ########################################################### - */ - - /* Set the session config */ - session.server.host_name = IMAP_HOST; - session.server.port = IMAP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - - /* Setup the configuration for searching or fetching operation and its result */ - IMAP_Config config; - - /* Message UID to fetch or read */ - config.fetch.uid = ""; - - /** Search criteria - * - * A search key can also be a parenthesized list of one or more search keys - * (e.g., for use with the OR and NOT keys). - * - * Since IMAP protocol uses Polish notation, the search criteria which in the polish notation form can be. - * - * To search the message from "someone@email.com" with the subject "my subject" since 1 Jan 2021, your search criteria can be - * UID SEARCH (OR SUBJECT "my subject" FROM "someone@email.com") SINCE "Fri, 1 Jan 2021 21:52:25 -0800" - * - * To search the message from "mail1@domain.com" or from "mail2@domain.com", the search criteria will be - * UID SEARCH OR FROM mail1@domain.com FROM mail2@domain.com - * - * For more details on using parentheses, AND, OR and NOT search keys in search criteria. - * https://www.limilabs.com/blog/imap-search-requires-parentheses - * - * - */ - config.search.criteria = "UID SEARCH ALL"; - - /* Also search the unseen message */ - config.search.unseen_msg = true; - - /* Set the storage to save the downloaded files and attachments */ - config.storage.saved_path = "/email_data"; - - /** The file storage type e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - config.storage.type = esp_mail_file_storage_type_flash; - - /** Set to download heades, text and html messaeges, - * attachments and inline images respectively. - */ - config.download.header = true; - config.download.text = true; - config.download.html = true; - config.download.attachment = true; - config.download.inlineImg = true; - - /** Set to enable the results i.e. html and text messaeges - * which the content stored in the IMAPSession object is limited - * by the option config.limit.msg_size. - * The whole message can be download through config.download.text - * or config.download.html which not depends on these enable options. - */ - config.enable.html = true; - config.enable.text = true; - - /* Set to enable the sort the result by message UID in the ascending order */ - config.enable.recent_sort = true; - - /* Set to report the download progress via the default serial port */ - config.enable.download_status = true; - - /* Set the limit of number of messages in the search results */ - config.limit.search = 5; - - /** Set the maximum size of message stored in - * IMAPSession object in byte - */ - config.limit.msg_size = 512; - - /** Set the maximum attachments and inline images files size - * that can be downloaded in byte. - * The file which its size is largger than this limit may be saved - * as truncated file. - */ - config.limit.attachment_size = 1024 * 1024 * 5; - - - /* Connect to server with the session and config */ - if (!imap.connect(&session, &config)) - return; - - /* {Optional] */ - printAllMailboxesInfo(imap); - - /* Open or select the mailbox folder to read or search the message */ - if (!imap.selectFolder("INBOX")) - return; - - /* {Optional] */ - printSelectedMailboxInfo(imap); - - /** Read or search the Email and keep the TCP session to open - * The second parameter is for close the session. - */ - MailClient.readMail(&imap, false); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); - - /** Open or select other mailbox folder - * The folder that previousely opened will be closed - */ - if (imap.selectFolder("Junk")) - { - /* {Optional] */ - printSelectedMailboxInfo(imap); - - /* Config to search all messages in the opened mailboax (Search mode) */ - config.search.criteria = "UID SEARCH ALL"; // or "UID SEARCH NEW" for recent received messages - - /* No message UID provide for fetching */ - config.fetch.uid = ""; - - /* Search the Email and close the session */ - MailClient.readMail(&imap); - } - - /* Close the seeion in case the session is still open */ - imap.closeSession(); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); -} - -void loop() -{ -} - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Show the result when reading finished */ - if (status.success()) - { - /* Print the result */ - printMessages(imap); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); - } -} - -void printAllMailboxesInfo(IMAPSession &imap) -{ - /* Declare the folder collection class to get the list of mailbox folders */ - FoldersCollection folders; - - /* Get the mailbox folders */ - if (imap.getFolders(folders)) - { - for (size_t i = 0; i < folders.size(); i++) - { - /* Iterate each folder info using the folder info item data */ - FolderInfo folderInfo = folders.info(i); - Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); - } - } -} - -void printSelectedMailboxInfo(IMAPSession &imap) -{ - /* Declare the selected folder info class to get the info of selected mailbox folder */ - SelectedFolderInfo sFolder = imap.selectedFolder(); - - /* Show the mailbox info */ - Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); - Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); - for (size_t i = 0; i < sFolder.flagCount(); i++) - Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); -} - -void printRFC822Messages(IMAP_MSG_Item &msg) -{ - Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); - for (size_t j = 0; j < msg.rfc822.size(); j++) - { - IMAP_MSG_Item rfc822 = msg.rfc822[j]; - Serial.printf("%d. \n", j + 1); - Serial.printf("Messsage ID: %s\n", rfc822.messageID); - Serial.printf("From: %s\n", rfc822.from); - Serial.printf("Sender: %s\n", rfc822.sender); - Serial.printf("To: %s\n", rfc822.to); - Serial.printf("CC: %s\n", rfc822.cc); - Serial.printf("Subject: %s\n", rfc822.subject); - Serial.printf("Date: %s\n", rfc822.date); - Serial.printf("Reply-To: %s\n", rfc822.reply_to); - Serial.printf("Return-Path: %s\n", rfc822.return_path); - Serial.printf("Comment: %s\n", rfc822.comment); - Serial.printf("Keyword: %s\n", rfc822.keyword); - Serial.printf("Text Message: %s\n", rfc822.text.content); - Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", rfc822.html.content); - Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); - - if (rfc822.attachments.size() > 0) - printAttacements(rfc822); - } -} - -void printAttacements(IMAP_MSG_Item &msg) -{ - Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); - for (size_t j = 0; j < msg.attachments.size(); j++) - { - IMAP_Attach_Item att = msg.attachments[j]; - /** att.type can be - * esp_mail_att_type_none or 0 - * esp_mail_att_type_attachment or 1 - * esp_mail_att_type_inline or 2 - */ - Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); - } - Serial.println(); -} - -void printMessages(IMAPSession &imap) -{ - /* Get the message list from the message list data */ - IMAP_MSG_List msgList = imap.data(); - - for (size_t i = 0; i < msgList.msgItems.size(); i++) - { - /* Iterate to get each message data through the message item data */ - IMAP_MSG_Item msg = msgList.msgItems[i]; - - Serial.println("################################"); - Serial.printf("Messsage Number: %s\n", msg.msgNo); - Serial.printf("Messsage UID: %s\n", msg.UID); - Serial.printf("Messsage ID: %s\n", msg.ID); - Serial.printf("Accept Language: %s\n", msg.acceptLang); - Serial.printf("Content Language: %s\n", msg.contentLang); - Serial.printf("From: %s\n", msg.from); - Serial.printf("From Charset: %s\n", msg.fromCharset); - Serial.printf("To: %s\n", msg.to); - Serial.printf("To Charset: %s\n", msg.toCharset); - Serial.printf("CC: %s\n", msg.cc); - Serial.printf("CC Charset: %s\n", msg.ccCharset); - Serial.printf("Date: %s\n", msg.date); - Serial.printf("Subject: %s\n", msg.subject); - Serial.printf("Subject Charset: %s\n", msg.subjectCharset); - - /* If the result contains the message info (Fetch mode) */ - if (!imap.headerOnly()) - { - Serial.printf("Text Message: %s\n", msg.text.content); - Serial.printf("Text Message Charset: %s\n", msg.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", msg.html.content); - Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); - - if (msg.attachments.size() > 0) - printAttacements(msg); - - if (msg.rfc822.size() > 0) - printRFC822Messages(msg); - } - - Serial.println(); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Access_Token/Send_Access_Token.ino b/lib/libesp32/lib_mail/examples/Send_Access_Token/Send_Access_Token.ino deleted file mode 100644 index bdebd82a5..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Access_Token/Send_Access_Token.ino +++ /dev/null @@ -1,203 +0,0 @@ - - -/** - *This example will log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - - -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT 25 - -/* The user Email for OAuth2.0 access token */ -#define AUTHOR_EMAIL "################" - -/** The OAuth2.0 access token - * The generation, exchange and refresh of the access token are not available - * in this library. - * - * To test this using GMail, get the OAuth2.0 access token from this web site - * https://developers.google.com/oauthplayground/ - * - * You can use the ESP Signer library to generate OAuth2.0 access token - * The library is available here https://github.com/mobizt/ESP-Signer - * - * 1. Select the following scope (in Step 1) from Gmail API V1 - * https://mail.google.com/ - * https://mail.google.com/ - * - * 2. Click Authorize APIs button. - * 3. Cick Exchangeauthorization code for tokens. - * 4. From the response, look at access_token from the JSON payload node. - * 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value. - * - * The token will be expired in 3600 seconds (1 Hr). - * The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services. -*/ -#define AUTHOR_ACCESS_TOKEN "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.accessToken = AUTHOR_ACCESS_TOKEN; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Test sending Email using Access token"; - message.addRecipient("Admin", "####@#####_dot_com"); - - message.text.content = "This is simple plain text message"; - - /** The Plain text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.text.charSet = "us-ascii"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Attachment_Blob/Send_Attachment_Blob.ino b/lib/libesp32/lib_mail/examples/Send_Attachment_Blob/Send_Attachment_Blob.ino deleted file mode 100644 index 7ff054a80..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Attachment_Blob/Send_Attachment_Blob.ino +++ /dev/null @@ -1,268 +0,0 @@ - - -/** - * This example will send the Email with attachments and - * inline images stored in heap and flash memories. - * - * The html and text version messages will be sent. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -/* This is for attachment data */ -#include "image.h" - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT esp_mail_smtp_port_587 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Enable the chunked data transfer with pipelining for large message if server supported */ - message.enable.chunking = true; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - - message.subject = "Test sending Email with attachments and inline images"; - message.addRecipient("user1", "####@#####_dot_com"); - - message.html.content = "This message contains 3 inline images and 1 attachment file.

"; - - /** The HTML text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.html.charSet = "utf-8"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; - - message.text.content = "This message contains 3 inline images and 1 attachment file.\r\nThe inline images were not shown in the plain text message."; - message.text.charSet = "utf-8"; - message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* The attachment data item */ - SMTP_Attachment att; - - /** Set the inline image info e.g. - * file name, MIME type, BLOB data, BLOB data size, - * transfer encoding (should be base64 for inline image) - */ - att.descr.filename = "firebase_logo.png"; - att.descr.mime = "image/png"; - att.blob.data = firebase_png; - att.blob.size = sizeof(firebase_png); - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /* Add inline image to the message */ - message.addInlineImage(att); - - /** Set the inline image info e.g. - * file name, MIME type, BLOB data, BLOB data size. - * The default transfer encoding is base64. - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "tree.gif"; - att.descr.mime = "image/gif"; - att.blob.data = tree_gif; - att.blob.size = sizeof(tree_gif); - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /* Add inline image to the message */ - message.addInlineImage(att); - - /** Set the inline image info e.g. - * file name, MIME type, BLOB data, BLOB data size. - * The default transfer encoding is base64. - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "bird.gif"; - att.descr.mime = "image/gif"; - att.blob.data = bird_gif; - att.blob.size = sizeof(bird_gif); - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /* Add inline image to the message */ - message.addInlineImage(att); - - /* Prepare the attachment data (from ram) */ - uint8_t *a = new uint8_t[512]; - int j = 0; - - for (int i = 0; i < 512; i++) - { - a[i] = j; - j++; - if (j > 255) - j = 0; - } - - /** Set the attachment info e.g. - * file name, MIME type, BLOB data, BLOB data size. - * The default transfer encoding is base64. - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "test.dat"; - att.descr.mime = "application/octet-stream"; - att.blob.data = a; - att.blob.size = 512; - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - /* Add attachment to the message */ - message.addAttachment(att); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending the Email and close the session */ - if (!MailClient.sendMail(&smtp, &message, true)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Attachment_File/Send_Attachment_File.ino b/lib/libesp32/lib_mail/examples/Send_Attachment_File/Send_Attachment_File.ino deleted file mode 100644 index 3dcd0fc9e..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Attachment_File/Send_Attachment_File.ino +++ /dev/null @@ -1,427 +0,0 @@ - - -/** - * This example will send the Email with attachments and - * inline images stored in flash and SD card. - * - * The html and text version messages will be sent. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -//The file systems for flash and sd memory can be changed in ESP_Mail_FS.h. - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT esp_mail_smtp_port_587 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - static uint8_t buf[512]; - - /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from - * MailClient.sdBegin function which may be different for ESP32 and ESP8266 - * For ESP32, assign all of SPI pins - * MailClient.sdBegin(14,2,15,13) - * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 - * And for ESP8266, assign the CS pins of SPI port - * MailClient.sdBegin(15) - * Which pin 15 is the CS pin of SD card adapter - */ - - Serial.println("Mounting SD Card..."); - -#if defined(ESP32) - if (SD.begin()) // MailClient.sdBegin(14,2,15,13) for TTGO T8 v1.7 or 1.8 -#elif defined(ESP8266) - if (SD.begin(15)) -#endif - { - - if (SD.exists("/orange.png")) - SD.remove("/orange.png"); - if (SD.exists("/bin1.dat")) - SD.remove("/bin1.dat"); - - Serial.println("Preparing SD file attachments..."); - - const char *orangeImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RMQ0AMAgAsCFgftHLiQpsENJaaFT+fqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBGi/oCaOpTXoAAAAASUVORK5CYII="; - - File file = SD.open("/orange.png", FILE_WRITE); - file.print(orangeImg); - file.close(); - - file = SD.open("/bin1.dat", FILE_WRITE); - - buf[0] = 'H'; - buf[1] = 'E'; - buf[2] = 'A'; - buf[3] = 'D'; - file.write(buf, 4); - - size_t i; - - for (i = 0; i < 4; i++) - { - memset(buf, i + 1, 512); - file.write(buf, 512); - } - - buf[0] = 'T'; - buf[1] = 'A'; - buf[2] = 'I'; - buf[3] = 'L'; - file.write(buf, 4); - file.close(); - } - else - { - Serial.println("SD Card Monting Failed"); - } - - Serial.println("Mounting SPIFFS..."); - -#if defined(ESP32) - if (SPIFFS.begin(true)) -#elif defined(ESP8266) - if (SPIFFS.begin()) -#endif - { - //SPIFFS.format(); - - if (SPIFFS.exists("/green.png")) - SPIFFS.remove("/green.png"); - if (SPIFFS.exists("/bin2.dat")) - SPIFFS.remove("/bin2.dat"); - - Serial.println("Preparing SPIFFS attachments..."); - - const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII="; - -#if defined(ESP32) - File file = SPIFFS.open("/green.png", FILE_WRITE); -#elif defined(ESP8266) - File file = SPIFFS.open("/green.png", "w"); -#endif - - file.print(greenImg); - file.close(); - -#if defined(ESP32) - file = SPIFFS.open("/bin2.dat", FILE_WRITE); -#elif defined(ESP8266) - file = SPIFFS.open("/bin2.dat", "w"); -#endif - - buf[0] = 'H'; - buf[1] = 'E'; - buf[2] = 'L'; - buf[3] = 'L'; - buf[4] = 'O'; - file.write(buf, 5); - - size_t i; - for (i = 0; i < 4; i++) - { - memset(buf, i + 1, 512); - file.write(buf, 512); - } - - buf[0] = 'G'; - buf[1] = 'O'; - buf[2] = 'O'; - buf[3] = 'D'; - buf[4] = 'B'; - buf[5] = 'Y'; - buf[6] = 'E'; - file.write(buf, 7); - file.close(); - } - else - { - Serial.println("SPIFFS Monting Failed"); - } - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /** ######################################################## - * Some properties of SMTPSession data and parameters pass to - * SMTP_Message class accept the pointer to constant char - * i.e. const char*. - * - * You may assign a string literal to that properties or function - * like below example. - * - * session.login.user_domain = "mydomain.net"; - * session.login.user_domain = String("mydomain.net").c_str(); - * - * or - * - * String doman = "mydomain.net"; - * session.login.user_domain = domain.c_str(); - * - * And - * - * String name = "Jack " + String("dawson"); - * String email = "jack_dawson" + String(123) + "@mail.com"; - * - * message.addRecipient(name.c_str(), email.c_str()); - * - * message.addHeader(String("Message-ID: ").c_str()); - * - * or - * - * String header = "Message-ID: "; - * message.addHeader(header.c_str()); - * - * ########################################################### - */ - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Enable the chunked data transfer with pipelining for large message if server supported */ - message.enable.chunking = true; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - - message.subject = "Test sending Email with attachments and inline images from SD card and Flash"; - message.addRecipient("user1", "####@#####_dot_com"); - - /** Two alternative content versions are sending in this example e.g. plain text and html */ - String htmlMsg = "This message contains 2 inline images and 2 attachment files.

"; - message.html.content = htmlMsg.c_str(); - - /** The HTML text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.html.charSet = "utf-8"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; - - message.text.content = "This message contains 2 inline images and 2 attachment files.\r\nThe inline images were not shown in the plain text message."; - message.text.charSet = "utf-8"; - message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* The attachment data item */ - SMTP_Attachment att; - - /** Set the inline image info e.g. - * file name, MIME type, file path, file storage type, - * transfer encoding and content encoding - */ - att.descr.filename = "orange.png"; - att.descr.mime = "image/png"; - att.file.path = "/orange.png"; - - /** The file storage type e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - att.file.storage_type = esp_mail_file_storage_type_sd; - - /* Need to be base64 transfer encoding for inline image */ - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /** The orange.png file is already base64 encoded file. - * Then set the content encoding to match the transfer encoding - * which no encoding was taken place prior to sending. - */ - att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; - - /* Add inline image to the message */ - message.addInlineImage(att); - - /** Set the attachment info e.g. - * file name, MIME type, file path, file storage type, - * transfer encoding and content encoding - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "bin1.dat"; - att.descr.mime = "application/octet-stream"; //binary data - att.file.path = "/bin1.dat"; - att.file.storage_type = esp_mail_file_storage_type_sd; - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /* Add attachment to the message */ - message.addAttachment(att); - - /** Set the inline image info e.g. - * file name, MIME type, file path, file storage type, - * transfer encoding and content encoding - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "green.png"; - att.descr.mime = "image/png"; - att.file.path = "/green.png"; - att.file.storage_type = esp_mail_file_storage_type_flash; - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; - message.addInlineImage(att); - - /** Set the attachment info e.g. - * file name, MIME type, file path, file storage type, - * transfer encoding and content encoding - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "bin2.dat"; - att.descr.mime = "application/octet-stream"; - att.file.path = "/bin2.dat"; - att.file.storage_type = esp_mail_file_storage_type_flash; - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - message.addAttachment(att); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending the Email and close the session */ - if (!MailClient.sendMail(&smtp, &message, true)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Embedded_Message/Send_Embedded_Message.ino b/lib/libesp32/lib_mail/examples/Send_Embedded_Message/Send_Embedded_Message.ino deleted file mode 100644 index 8cc3b5e36..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Embedded_Message/Send_Embedded_Message.ino +++ /dev/null @@ -1,203 +0,0 @@ - - -/** - * This example will send the Email which the - * message html and text body will be embedded as - * attachment or inline content. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT 25 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Test sending message as embedded files"; - message.addRecipient("Admin", "####@#####_dot_com"); - - message.html.content = "This is html message"; - - /** The Plain text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.html.charSet = "utf-8"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; - - /* Enable to send this message body as file */ - message.html.embed.enable = true; - - /* The name of embedded file */ - message.html.embed.filename = "test.html"; - - /** The embedded type - * esp_mail_smtp_embed_message_type_attachment or 0 - * esp_mail_smtp_embed_message_type_inline or 1 - */ - message.html.embed.type = esp_mail_smtp_embed_message_type_attachment; - - - - message.text.content = "This is simple plain text message"; - message.text.charSet = "utf-8"; - message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; - message.text.embed.enable = true; - message.text.embed.filename = "test.txt"; - message.text.embed.type = esp_mail_smtp_embed_message_type_inline; - - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Enriched_Text/Send_Enriched_Text.ino b/lib/libesp32/lib_mail/examples/Send_Enriched_Text/Send_Enriched_Text.ino deleted file mode 100644 index be8f2578d..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Enriched_Text/Send_Enriched_Text.ino +++ /dev/null @@ -1,187 +0,0 @@ - - -/** - * This example will send the Email in enriched text version. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT 25 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Test sending enriched text Email"; - message.addRecipient("Someone", "####@#####_dot_com"); - - message.text.content = "This is enriched as defined in RFC 1896\r\n\r\nIsn't it cool?"; - - message.text.content_type = "text/enriched"; - - /** The Plain text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.text.charSet = "us-ascii"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Flash_Message_with_Inline_Image/Send_Flash_Message_with_Inline_Image.ino b/lib/libesp32/lib_mail/examples/Send_Flash_Message_with_Inline_Image/Send_Flash_Message_with_Inline_Image.ino deleted file mode 100644 index 1ba0a3ec5..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Flash_Message_with_Inline_Image/Send_Flash_Message_with_Inline_Image.ino +++ /dev/null @@ -1,287 +0,0 @@ - - -/** - * This example will send the Email with inline images stored in flash memory. - * The message content stores as HTML data in flash memory - * - * The html and text version messages will be sent. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -//The file systems for flash and sd memory can be changed in ESP_Mail_FS.h. - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT esp_mail_smtp_port_587 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - Serial.println("Mounting SPIFFS..."); - - const char *html = "This message contains 2 inline images.

\"orange \"green"; - const char *orangeImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RMQ0AMAgAsCFgftHLiQpsENJaaFT+fqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBGi/oCaOpTXoAAAAASUVORK5CYII="; - const char *greenImg = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAoUlEQVR42u3RAQ0AMAgAoJviyWxtAtNYwzmoQGT/eqwRQoQgRAhChCBECEKECBGCECEIEYIQIQgRghCECEGIEIQIQYgQhCBECEKEIEQIQoQgBCFCECIEIUIQIgQhCBGCECEIEYIQIQhBiBCECEGIEIQIQQhChCBECEKEIEQIQhAiBCFCECIEIUIQghAhCBGCECEIEYIQIUKEIEQIQoQg5LoBBaDPbQYiMoMAAAAASUVORK5CYII="; - -#if defined(ESP32) - if (SPIFFS.begin(true)) -#elif defined(ESP8266) - if (SPIFFS.begin()) -#endif - { - - //SPIFFS.format(); - - if (SPIFFS.exists("/orange.png")) - SPIFFS.remove("/orange.png"); - if (SPIFFS.exists("/green.png")) - SPIFFS.remove("/green.png"); - if (SPIFFS.exists("/msg.html")) - SPIFFS.remove("/msg.html"); - - Serial.println("Preparing SPIFFS attachments..."); - -#if defined(ESP32) - File file = SPIFFS.open("/orange.png", FILE_WRITE); -#elif defined(ESP8266) - File file = SPIFFS.open("/orange.png", "w"); -#endif - file.print(orangeImg); - file.close(); - -#if defined(ESP32) - file = SPIFFS.open("/green.png", FILE_WRITE); -#elif defined(ESP8266) - file = SPIFFS.open("/green.png", "w"); -#endif - file.print(greenImg); - file.close(); - -#if defined(ESP32) - file = SPIFFS.open("/msg.html", FILE_WRITE); -#elif defined(ESP8266) - file = SPIFFS.open("/msg.html", "w"); -#endif - file.print(html); - file.close(); - } - else - { - Serial.println("SPIFFS Monting Failed"); - } - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Enable the chunked data transfer with pipelining for large message if server supported */ - message.enable.chunking = true; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - - message.subject = "Test sending Email with message content and inline images stored in flash memory"; - message.addRecipient("user1", "####@#####_dot_com"); - - /* Two alternative content versions are sending in this example e.g. plain text and html */ - - /* Assign blob data (in flash or ram) as HTML message */ - message.html.blob.data = (const uint8_t *)html; - message.html.blob.size = strlen(html); - - //Or get the content from file - //message.html.file.name = "/msg.html"; - //message.html.file.type = esp_mail_file_storage_type_flash; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) <- not supported for message from blob and file - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - /** The HTML text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.html.charSet = "utf-8"; - - message.text.content = "This message contains 2 inline images.\r\nThe inline images were not shown in the plain text message."; - message.text.charSet = "utf-8"; - message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* The attachment data item */ - SMTP_Attachment att; - - /** Set the inline image info e.g. - * file name, MIME type, file path, file storage type, - * transfer encoding and content encoding - */ - att.descr.filename = "orange.png"; - att.descr.mime = "image/png"; - att.file.path = "/orange.png"; - att.descr.content_id = "image-001"; //The content id (cid) of orange image in the src tag - - /** The file storage type e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - att.file.storage_type = esp_mail_file_storage_type_flash; - - /* Need to be base64 transfer encoding for inline image */ - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /** The orange.png file is already base64 encoded file. - * Then set the content encoding to match the transfer encoding - * which no encoding was taken place prior to sending. - */ - att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; - - /* Add inline image to the message */ - message.addInlineImage(att); - - /** Set the inline image info e.g. - * file name, MIME type, file path, file storage type, - * transfer encoding and content encoding - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "green.png"; - att.descr.mime = "image/png"; - att.file.path = "/green.png"; - att.descr.content_id = "image-002"; //The content id (cid) of green image in the src tag - att.file.storage_type = esp_mail_file_storage_type_flash; - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - att.descr.content_encoding = Content_Transfer_Encoding::enc_base64; - message.addInlineImage(att); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending the Email and close the session */ - if (!MailClient.sendMail(&smtp, &message, true)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_HTML/Send_HTML.ino b/lib/libesp32/lib_mail/examples/Send_HTML/Send_HTML.ino deleted file mode 100644 index 81b0a5998..000000000 --- a/lib/libesp32/lib_mail/examples/Send_HTML/Send_HTML.ino +++ /dev/null @@ -1,221 +0,0 @@ - - -/** - * This example will send the Email in - * the html version. - * - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT 25 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /** ######################################################## - * Some properties of SMTPSession data and parameters pass to - * SMTP_Message class accept the pointer to constant char - * i.e. const char*. - * - * You may assign a string literal to that properties or function - * like below example. - * - * session.login.user_domain = "mydomain.net"; - * session.login.user_domain = String("mydomain.net").c_str(); - * - * or - * - * String doman = "mydomain.net"; - * session.login.user_domain = domain.c_str(); - * - * And - * - * String name = "Jack " + String("dawson"); - * String email = "jack_dawson" + String(123) + "@mail.com"; - * - * message.addRecipient(name.c_str(), email.c_str()); - * - * message.addHeader(String("Message-ID: ").c_str()); - * - * or - * - * String header = "Message-ID: "; - * message.addHeader(header.c_str()); - * - * ########################################################### - */ - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Test sending html Email"; - message.addRecipient("Admin", "####@#####_dot_com"); - - String htmlMsg = "

This is the html text message.

The message was sent via ESP device.

"; - message.html.content = htmlMsg.c_str(); - - /** The html text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.html.charSet = "us-ascii"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Parallel_Attachment/Send_Parallel_Attachment.ino b/lib/libesp32/lib_mail/examples/Send_Parallel_Attachment/Send_Parallel_Attachment.ino deleted file mode 100644 index 65f6d3536..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Parallel_Attachment/Send_Parallel_Attachment.ino +++ /dev/null @@ -1,229 +0,0 @@ - - -/** - * This example will send the Email with media as parallen attachments - * e.g. audio and images and play or display them simultaneously on the Email client. - * - * This depends on the Mail client supports. - * - * The html and text version messages will be sent. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -//The file systems for flash and sd memory can be changed in ESP_Mail_FS.h. - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -/* This is for attachment data */ -#include "data.h" - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT esp_mail_smtp_port_587 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Enable the chunked data transfer with pipelining for large message if server supported */ - message.enable.chunking = true; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - - message.subject = "Test sending Email with parallel attachments"; - message.addRecipient("user1", "####@#####_dot_com"); - - message.html.content = "This message contains image and audio file which will play on the Mail client in parallel or simultaneously (depends on the client supports)."; - - /** The HTML text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.html.charSet = "utf-8"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; - - message.text.content = "This message contains image and audio file which will play on the Mail client in parallel or simultaneously (depends on the client supports)."; - message.text.charSet = "us-ascii"; - message.text.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* The attachment data item */ - SMTP_Attachment att; - - /** Set the attachment info e.g. - * file name, MIME type, file path, file storage type, - * transfer encoding and content encoding - */ - att.descr.filename = "haun.png"; - att.descr.mime = "image/png"; - att.blob.data = shaun_png; - att.blob.size = sizeof(shaun_png); - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - message.addParallelAttachment(att); - - /** Set the attachment info e.g. - * file name, MIME type, file path, file storage type, - * transfer encoding and content encoding - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "mu_law.wav"; - att.descr.mime = "audio/basic"; - att.blob.data = mu_law_wave; - att.blob.size = sizeof(mu_law_wave); - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - message.addParallelAttachment(att); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending the Email and close the session */ - if (!MailClient.sendMail(&smtp, &message, true)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_RFC822_Attachment/Send_RFC822_Attachment.ino b/lib/libesp32/lib_mail/examples/Send_RFC822_Attachment/Send_RFC822_Attachment.ino deleted file mode 100644 index 371515fe1..000000000 --- a/lib/libesp32/lib_mail/examples/Send_RFC822_Attachment/Send_RFC822_Attachment.ino +++ /dev/null @@ -1,252 +0,0 @@ - - -/** - * This example will send the Email in plain text version - * with rfc822 message attachment which the rfc822 message - * also contains its attachement. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -/* This is for attachment data */ -#include "image.h" - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT 25 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - Serial.println("Connect to NTP server and set the device time\r\nPlease wait...\r\n"); - float timeZone = 3;//GMT+3 - float daylightOffset = 0; - - /* Set the device time */ - MailClient.Time.setClock(timeZone, daylightOffset); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Test sending Email with rfc822 attachment"; - message.addRecipient("Someone", "####@#####_dot_com"); - - message.text.content = "This is simple plain text message with rfc822 attachment"; - - /** The Plain text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.text.charSet = "us-ascii"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - SMTP_Message rfc822; - rfc822.messageID = "1234@local.machine.example"; - rfc822.from.name = "rob"; - rfc822.from.email = "rob@example.com"; - rfc822.sender.name = "steve"; - rfc822.sender.email = "steve@example.com"; - String dt = MailClient.Time.getDateTimeString(); - rfc822.date = dt.c_str(); - rfc822.subject = "Test rfc822 message"; - rfc822.comment = "This is comment"; - rfc822.addRecipient("joe", "joe@example.com"); - rfc822.response.reply_to = "rob@example.com"; - rfc822.text.charSet = "utf-8"; - rfc822.text.content = "This is rfc822 text message"; - rfc822.text.transfer_encoding = Content_Transfer_Encoding::enc_qp; - - rfc822.html.charSet = "utf-8"; - rfc822.html.content = "This is rfc822 html message"; - rfc822.html.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /* The attachment data item */ - SMTP_Attachment att; - - /** Set the attachment info e.g. - * file name, MIME type, BLOB data, BLOB data size, - * and transfer encoding - */ - att.descr.filename = "firebase_logo.png"; - att.descr.mime = "image/png"; - att.blob.data = firebase_png; - att.blob.size = sizeof(firebase_png); - att.descr.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /* Add the attachment to the rfc822 message */ - rfc822.addAttachment(att); - - /* Prepare other attachment data */ - uint8_t *a = new uint8_t[512]; - int j = 0; - - for (int i = 0; i < 512; i++) - { - a[i] = j; - j++; - if (j > 255) - j = 0; - } - - /** Set the attachment info e.g. - * file name, MIME type, BLOB data, BLOB data size. - * The default transfer encoding is base64. - */ - message.resetAttachItem(att); //Clear the attach item data to reuse - att.descr.filename = "test.dat"; - att.descr.mime = "application/octet-stream"; - att.blob.data = a; - att.blob.size = 512; - - /* Add this attachment to the message */ - message.addAttachment(att); - - /* Add rfc822 message in the message */ - message.addMessage(rfc822); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Reuse_Session/Send_Reuse_Session.ino b/lib/libesp32/lib_mail/examples/Send_Reuse_Session/Send_Reuse_Session.ino deleted file mode 100644 index 45bd373f0..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Reuse_Session/Send_Reuse_Session.ino +++ /dev/null @@ -1,245 +0,0 @@ - - -/** - * This example will send multiple messages which - * the session was keep open during sending. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT esp_mail_smtp_port_587 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "First Email with session reusage"; - message.addRecipient("Admin1", "####@#####_dot_com"); - message.addRecipient("Admin2", "####@#####_dot_com"); - message.addCc("####@#####_dot_com"); - message.addBcc("####@#####_dot_com"); - - message.html.content = "

This is the first message.

"; - - /** The HTML text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.html.charSet = "utf-8"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.html.transfer_encoding = Content_Transfer_Encoding::enc_qp; - - /** The option to add soft line break to to the message for - * the long text message > 78 characters (rfc 3676) - * Some Servers may not compliant with the standard. - */ - message.text.flowed = true; - - message.text.content = "This is the first message"; - message.text.charSet = "us-ascii"; - - message.html.transfer_encoding = Content_Transfer_Encoding::enc_base64; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - Serial.println(); - Serial.println("Sending first Email..."); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /** Start sending the first Email and keep open the session - * The third parameter is for close the session. - */ - if (!MailClient.sendMail(&smtp, &message, false)) - Serial.println("Error sending Email, " + smtp.errorReason()); - - - /* To clear all message data */ - //message.clear(); - - /** Clear primary recipients, Cc recipients, Bcc recipients, custom headers - * attachments and inline images - */ - message.clearRecipients(); - message.clearCc(); - message.clearBcc(); - //message.clearAttachments(); - //message.clearInlineimages(); - - message.subject = "Second Email with session reusage"; - - message.addRecipient("Admin3", "####@#####_dot_com"); - message.addRecipient("Admin4", "####@#####_dot_com"); - message.addCc("####@#####_dot_com"); - message.addBcc("####@#####_dot_com"); - - message.html.content = "

This is the second message.

"; - message.html.charSet = "us-ascii"; - - message.html.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - message.text.content = "This is the second message"; - message.text.charSet = "UTF-8"; - message.text.transfer_encoding = Content_Transfer_Encoding::enc_qp; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - Serial.println(); - Serial.println("Sending second Email..."); - - /* Start sending the second mail and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Text/Send_Text.ino b/lib/libesp32/lib_mail/examples/Send_Text/Send_Text.ino deleted file mode 100644 index 8c7cfc418..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Text/Send_Text.ino +++ /dev/null @@ -1,219 +0,0 @@ - - -/** - * This example will send the Email in plain text version. - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT 25 - -/* The sign in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /** ######################################################## - * Some properties of SMTPSession data and parameters pass to - * SMTP_Message class accept the pointer to constant char - * i.e. const char*. - * - * You may assign a string literal to that properties or function - * like below example. - * - * session.login.user_domain = "mydomain.net"; - * session.login.user_domain = String("mydomain.net").c_str(); - * - * or - * - * String doman = "mydomain.net"; - * session.login.user_domain = domain.c_str(); - * - * And - * - * String name = "Jack " + String("dawson"); - * String email = "jack_dawson" + String(123) + "@mail.com"; - * - * message.addRecipient(name.c_str(), email.c_str()); - * - * message.addHeader(String("Message-ID: ").c_str()); - * - * or - * - * String header = "Message-ID: "; - * message.addHeader(header.c_str()); - * - * ########################################################### - */ - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Test sending plain text Email"; - message.addRecipient("Someone", "####@#####_dot_com"); - - String textMsg = "This is simple plain text message"; - message.text.content = textMsg.c_str(); - - /** The Plain text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.text.charSet = "us-ascii"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Send_Text_Flowed/Send_Text_Flowed.ino b/lib/libesp32/lib_mail/examples/Send_Text_Flowed/Send_Text_Flowed.ino deleted file mode 100644 index a1ea2f4fe..000000000 --- a/lib/libesp32/lib_mail/examples/Send_Text_Flowed/Send_Text_Flowed.ino +++ /dev/null @@ -1,229 +0,0 @@ - - -/** - * This example will send the Email in plain text version - * with the quoted text and long line text. - * - * - * Created by K. Suwatchai (Mobizt) - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -//To use send Email for Gmail to port 465 (SSL), less secure app option should be enabled. https://myaccount.google.com/lesssecureapps?pli=1 - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/** The smtp host name e.g. smtp.gmail.com for GMail or smtp.office365.com for Outlook or smtp.mail.yahoo.com - * For yahoo mail, log in to your yahoo mail in web browser and generate app password by go to - * https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc - * and use the app password as password with your yahoo mail account to login. - * The google app password signin is also available https://support.google.com/mail/answer/185833?hl=en -*/ -#define SMTP_HOST "################" - -/** The smtp port e.g. - * 25 or esp_mail_smtp_port_25 - * 465 or esp_mail_smtp_port_465 - * 587 or esp_mail_smtp_port_587 -*/ -#define SMTP_PORT 25 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* The SMTP Session object used for Email sending */ -SMTPSession smtp; - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status); - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - smtp.debug(1); - - /* Set the callback function to get the sending results */ - smtp.callback(smtpCallback); - - /* Declare the session config data */ - ESP_Mail_Session session; - - /** ######################################################## - * Some properties of SMTPSession data and parameters pass to - * SMTP_Message class accept the pointer to constant char - * i.e. const char*. - * - * You may assign a string literal to that properties or function - * like below example. - * - * session.login.user_domain = "mydomain.net"; - * session.login.user_domain = String("mydomain.net").c_str(); - * - * or - * - * String doman = "mydomain.net"; - * session.login.user_domain = domain.c_str(); - * - * And - * - * String name = "Jack " + String("dawson"); - * String email = "jack_dawson" + String(123) + "@mail.com"; - * - * message.addRecipient(name.c_str(), email.c_str()); - * - * message.addHeader(String("Message-ID: ").c_str()); - * - * or - * - * String header = "Message-ID: "; - * message.addHeader(header.c_str()); - * - * ########################################################### - */ - - /* Set the session config */ - session.server.host_name = SMTP_HOST; - session.server.port = SMTP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - session.login.user_domain = "mydomain.net"; - - /* Declare the message class */ - SMTP_Message message; - - /* Set the message headers */ - message.sender.name = "ESP Mail"; - message.sender.email = AUTHOR_EMAIL; - message.subject = "Test sending flowed plain text Email"; - message.addRecipient("Someone", "####@#####_dot_com"); - - /** The option to add soft line break to to the message for - * the long text message > 78 characters (rfc 3676) - * Some Servers may not compliant with the standard. - */ - message.text.flowed = true; - - /** if the option message.text.flowed is true, - * the following plain text message will be wrapped. - */ - message.text.content = "The text below is the long quoted text which breaks into several lines.\r\n\r\n>> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\r\n\r\nThis is the normal short text.\r\n\r\nAnother long text, abcdefg hijklmnop qrstuv wxyz abcdefg hijklmnop qrstuv wxyz abcdefg hijklmnop qrstuv wxyz."; - - /** The Plain text message character set e.g. - * us-ascii - * utf-8 - * utf-7 - * The default value is utf-8 - */ - message.text.charSet = "us-ascii"; - - /** The content transfer encoding e.g. - * enc_7bit or "7bit" (not encoded) - * enc_qp or "quoted-printable" (encoded) - * enc_base64 or "base64" (encoded) - * enc_binary or "binary" (not encoded) - * enc_8bit or "8bit" (not encoded) - * The default value is "7bit" - */ - message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit; - - /** The message priority - * esp_mail_smtp_priority_high or 1 - * esp_mail_smtp_priority_normal or 3 - * esp_mail_smtp_priority_low or 5 - * The default value is esp_mail_smtp_priority_low - */ - message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_low; - - /** The Delivery Status Notifications e.g. - * esp_mail_smtp_notify_never - * esp_mail_smtp_notify_success - * esp_mail_smtp_notify_failure - * esp_mail_smtp_notify_delay - * The default value is esp_mail_smtp_notify_never - */ - message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay; - - /* Set the custom message header */ - message.addHeader("Message-ID: "); - - /* Connect to server with the session config */ - if (!smtp.connect(&session)) - return; - - /* Start sending Email and close the session */ - if (!MailClient.sendMail(&smtp, &message)) - Serial.println("Error sending Email, " + smtp.errorReason()); -} - -void loop() -{ -} - -/* Callback function to get the Email sending status */ -void smtpCallback(SMTP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Print the sending result */ - if (status.success()) - { - Serial.println("----------------"); - Serial.printf("Message sent success: %d\n", status.completedCount()); - Serial.printf("Message sent failled: %d\n", status.failedCount()); - Serial.println("----------------\n"); - struct tm dt; - - for (size_t i = 0; i < smtp.sendingResult.size(); i++) - { - /* Get the result item */ - SMTP_Result result = smtp.sendingResult.getItem(i); - localtime_r(&result.timesstamp, &dt); - - Serial.printf("Message No: %d\n", i + 1); - Serial.printf("Status: %s\n", result.completed ? "success" : "failed"); - Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec); - Serial.printf("Recipient: %s\n", result.recipients); - Serial.printf("Subject: %s\n", result.subject); - } - Serial.println("----------------\n"); - } -} diff --git a/lib/libesp32/lib_mail/examples/Set_Flags/Set_Flags.ino b/lib/libesp32/lib_mail/examples/Set_Flags/Set_Flags.ino deleted file mode 100644 index 238a17ddf..000000000 --- a/lib/libesp32/lib_mail/examples/Set_Flags/Set_Flags.ino +++ /dev/null @@ -1,363 +0,0 @@ -/** - * This example will set the argument to the flags and read the message. - * - * Email: suwatchai@outlook.com - * - * Github: https://github.com/mobizt/ESP-Mail-Client - * - * Copyright (c) 2021 mobizt - * -*/ - -/** To receive Email using Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en - * and also https://accounts.google.com/b/0/DisplayUnlockCaptcha - * -*/ - -/** For ESP8266, with BearSSL WiFi Client - * The memory reserved for completed valid SSL response from IMAP is 16 kbytes which - * may cause your device out of memory reset in case the memory - * allocation error. -*/ - -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#endif -#include - -#define WIFI_SSID "################" -#define WIFI_PASSWORD "################" - -/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */ -#define IMAP_HOST "################" - -/** The imap port e.g. - * 143 or esp_mail_imap_port_143 - * 993 or esp_mail_imap_port_993 -*/ -#define IMAP_PORT 993 - -/* The log in credentials */ -#define AUTHOR_EMAIL "################" -#define AUTHOR_PASSWORD "################" - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status); - -/* Print the list of mailbox folders */ -void printAllMailboxesInfo(IMAPSession &imap); - -/* Print the selected folder info */ -void printSelectedMailboxInfo(IMAPSession &imap); - -/* Print all messages from the message list */ -void printMessages(IMAPSession &imap); - -/* Print all rfc822 messages included in the message */ -void printRFC822Messages(IMAP_MSG_Item &msg); - -/* Print all attachments info from the message */ -void printAttacements(IMAP_MSG_Item &msg); - -/* The IMAP Session object used for Email reading */ -IMAPSession imap; - - -void setup() -{ - - Serial.begin(115200); - Serial.println(); - - Serial.print("Connecting to AP"); - - WiFi.begin(WIFI_SSID, WIFI_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - Serial.print("."); - delay(200); - } - - Serial.println(""); - Serial.println("WiFi connected."); - Serial.println("IP address: "); - Serial.println(WiFi.localIP()); - Serial.println(); - - /** Enable the debug via Serial port - * none debug or 0 - * basic debug or 1 - */ - imap.debug(1); - - /* Set the callback function to get the reading results */ - imap.callback(imapCallback); - - /** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from - * MailClient.sdBegin function which may be different for ESP32 and ESP8266 - * For ESP32, assign all of SPI pins - * MailClient.sdBegin(14,2,15,13) - * Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13 - * And for ESP8266, assign the CS pins of SPI port - * MailClient.sdBegin(15) - * Which pin 15 is the CS pin of SD card adapter - */ - - /* Declare the session config data */ - ESP_Mail_Session session; - - /* Set the session config */ - session.server.host_name = IMAP_HOST; - session.server.port = IMAP_PORT; - session.login.email = AUTHOR_EMAIL; - session.login.password = AUTHOR_PASSWORD; - - - /* Setup the configuration for searching or fetching operation and its result */ - IMAP_Config config; - - /* Message UID to fetch or read e.g. 100 */ - config.fetch.uid = "100"; - - /* Set seen flag */ - //config.fetch.set_seen = true; - - /* Search criteria */ - config.search.criteria = ""; - - /* Also search the unseen message */ - config.search.unseen_msg = true; - - /* Set the storage to save the downloaded files and attachments */ - config.storage.saved_path = "/email_data"; - - /** The file storage type e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - config.storage.type = esp_mail_file_storage_type_flash; - - /** Set to download heades, text and html messaeges, - * attachments and inline images respectively. - */ - config.download.header = true; - config.download.text = true; - config.download.html = true; - config.download.attachment = true; - config.download.inlineImg = true; - - /** Set to enable the results i.e. html and text messaeges - * which the content stored in the IMAPSession object is limited - * by the option config.limit.msg_size. - * The whole message can be download through config.download.text - * or config.download.html which not depends on these enable options. - */ - config.enable.html = true; - config.enable.text = true; - - /* Set to enable the sort the result by message UID in the ascending order */ - config.enable.recent_sort = true; - - /* Set to report the download progress via the default serial port */ - config.enable.download_status = true; - - /* Set the limit of number of messages in the search results */ - config.limit.search = 5; - - /** Set the maximum size of message stored in - * IMAPSession object in byte - */ - config.limit.msg_size = 512; - - /** Set the maximum attachments and inline images files size - * that can be downloaded in byte. - * The file which its size is largger than this limit may be saved - * as truncated file. - */ - config.limit.attachment_size = 1024 * 1024 * 5; - - - - /* Connect to server with the session and config */ - if (!imap.connect(&session, &config)) - return; - - /* {Optional] */ - printAllMailboxesInfo(imap); - - /* Open or select the mailbox folder to read or search the message */ - if (!imap.selectFolder("INBOX")) - return; - - /* {Optional] */ - printSelectedMailboxInfo(imap); - - /** Set \Seen and \Answered to flags for message with UID 100 - * The seesion will keep open. - */ - if (MailClient.setFlag(&imap, 100, "\\Seen \\Answered", false)) - Serial.println("Setting FLAG success"); - else - Serial.println("Error, setting FLAG"); - - /* Add \Seen and \Answered to flags for message with UID 100 */ - //MailClient.addFlag(imap, 100, "\\Seen \\Answered", false); - - /* Remove \Seen and \Answered from flags for message with UID 100 */ - //MailClient.removeFlag(imap, 100, "\\Seen \\Answered", false); - - /* Read or search the Email and close the session */ - MailClient.readMail(&imap); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); -} - -void loop() -{ - -} - -/* Callback function to get the Email reading status */ -void imapCallback(IMAP_Status status) -{ - /* Print the current status */ - Serial.println(status.info()); - - /* Show the result when reading finished */ - if (status.success()) - { - /* Print the result */ - printMessages(imap); - - /* Clear all stored data in IMAPSession object */ - imap.empty(); - Serial.printf("Free Heap: %d", ESP.getFreeHeap()); - } -} - -void printAllMailboxesInfo(IMAPSession &imap) -{ - /* Declare the folder collection class to get the list of mailbox folders */ - FoldersCollection folders; - - /* Get the mailbox folders */ - if (imap.getFolders(folders)) - { - for (size_t i = 0; i < folders.size(); i++) - { - /* Iterate each folder info using the folder info item data */ - FolderInfo folderInfo = folders.info(i); - Serial.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : ""); - } - } -} - -void printSelectedMailboxInfo(IMAPSession &imap) -{ - /* Declare the selected folder info class to get the info of selected mailbox folder */ - SelectedFolderInfo sFolder = imap.selectedFolder(); - - /* Show the mailbox info */ - Serial.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount()); - Serial.printf("Predicted next UID: %d\n", sFolder.nextUID()); - for (size_t i = 0; i < sFolder.flagCount(); i++) - Serial.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : ""); -} - -void printRFC822Messages(IMAP_MSG_Item &msg) -{ - Serial.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size()); - for (size_t j = 0; j < msg.rfc822.size(); j++) - { - IMAP_MSG_Item rfc822 = msg.rfc822[j]; - Serial.printf("%d. \n", j + 1); - Serial.printf("Messsage ID: %s\n", rfc822.messageID); - Serial.printf("From: %s\n", rfc822.from); - Serial.printf("Sender: %s\n", rfc822.sender); - Serial.printf("To: %s\n", rfc822.to); - Serial.printf("CC: %s\n", rfc822.cc); - Serial.printf("Subject: %s\n", rfc822.subject); - Serial.printf("Date: %s\n", rfc822.date); - Serial.printf("Reply-To: %s\n", rfc822.reply_to); - Serial.printf("Return-Path: %s\n", rfc822.return_path); - Serial.printf("Comment: %s\n", rfc822.comment); - Serial.printf("Keyword: %s\n", rfc822.keyword); - Serial.printf("Text Message: %s\n", rfc822.text.content); - Serial.printf("Text Message Charset: %s\n", rfc822.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", rfc822.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", rfc822.html.content); - Serial.printf("HTML Message Charset: %s\n", rfc822.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", rfc822.html.transfer_encoding); - - if (rfc822.attachments.size() > 0) - printAttacements(rfc822); - } -} - -void printAttacements(IMAP_MSG_Item &msg) -{ - Serial.printf("Attachment: %d file(s)\n****************************\n", msg.attachments.size()); - for (size_t j = 0; j < msg.attachments.size(); j++) - { - IMAP_Attach_Item att = msg.attachments[j]; - /** att.type can be - * esp_mail_att_type_none or 0 - * esp_mail_att_type_attachment or 1 - * esp_mail_att_type_inline or 2 - */ - Serial.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.creationDate); - } - Serial.println(); -} - -void printMessages(IMAPSession &imap) -{ - /* Get the message list from the message list data */ - IMAP_MSG_List msgList = imap.data(); - - for (size_t i = 0; i < msgList.msgItems.size(); i++) - { - /* Iterate to get each message data through the message item data */ - IMAP_MSG_Item msg = msgList.msgItems[i]; - - Serial.println("################################"); - Serial.printf("Messsage Number: %s\n", msg.msgNo); - Serial.printf("Messsage UID: %s\n", msg.UID); - Serial.printf("Messsage ID: %s\n", msg.ID); - Serial.printf("Accept Language: %s\n", msg.acceptLang); - Serial.printf("Content Language: %s\n", msg.contentLang); - Serial.printf("From: %s\n", msg.from); - Serial.printf("From Charset: %s\n", msg.fromCharset); - Serial.printf("To: %s\n", msg.to); - Serial.printf("To Charset: %s\n", msg.toCharset); - Serial.printf("CC: %s\n", msg.cc); - Serial.printf("CC Charset: %s\n", msg.ccCharset); - Serial.printf("Date: %s\n", msg.date); - Serial.printf("Subject: %s\n", msg.subject); - Serial.printf("Subject Charset: %s\n", msg.subjectCharset); - - /* If the result contains the message info (Fetch mode) */ - if (!imap.headerOnly()) - { - Serial.printf("Text Message: %s\n", msg.text.content); - Serial.printf("Text Message Charset: %s\n", msg.text.charSet); - Serial.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding); - Serial.printf("HTML Message: %s\n", msg.html.content); - Serial.printf("HTML Message Charset: %s\n", msg.html.charSet); - Serial.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding); - - if (msg.attachments.size() > 0) - printAttacements(msg); - - if (msg.rfc822.size() > 0) - printRFC822Messages(msg); - } - - Serial.println(); - } -} diff --git a/lib/libesp32/lib_mail/library.json b/lib/libesp32/lib_mail/library.json deleted file mode 100644 index 30dac17bb..000000000 --- a/lib/libesp32/lib_mail/library.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "ESP Mail Client", - "version": "1.2.0", - "keywords": "communication, email, imap, smtp, esp32, esp8266, arduino", - "description": "Mail Client Arduino Library for Espressif ESP32 and ESP8266 devices. This library allows the ESP32 and ESP8266 devices to send and read Email with the many options and features e.g. the attachments, inline images, embeded rfc822 messages are supported for upload when sending and download when reading the Emails.", - "repository": { - "type": "git", - "url": "https://github.com/mobizt/ESP-Mail-Client.git" - }, - "authors": [{ - "name": "Mobizt", - "email": "suwatchai@outlook.com" - }], - "frameworks": "arduino", - "platforms": "espressif32, espressif8266" -} diff --git a/lib/libesp32/lib_mail/library.properties b/lib/libesp32/lib_mail/library.properties deleted file mode 100644 index a574456bd..000000000 --- a/lib/libesp32/lib_mail/library.properties +++ /dev/null @@ -1,17 +0,0 @@ -name=ESP Mail Client - -version=1.2.0 - -author=Mobizt - -maintainer=Mobizt - -sentence=Mail Client Arduino Library for Espressif ESP32 and ESP8266 devices. - -paragraph=This library allows the ESP32 and ESP8266 devices to send and read Email with the many options and features e.g. the attachments, inline images, embeded rfc822 messages are supported for upload when sending and download when reading the Emails. - -category=Communication - -url=https://github.com/mobizt/ESP-Mail-Client - -architectures=esp32,esp8266 diff --git a/lib/libesp32/lib_mail/src/ESP_Mail_Client.cpp b/lib/libesp32/lib_mail/src/ESP_Mail_Client.cpp deleted file mode 100644 index 897d832b8..000000000 --- a/lib/libesp32/lib_mail/src/ESP_Mail_Client.cpp +++ /dev/null @@ -1,8548 +0,0 @@ -/** - * Mail Client Arduino Library for Espressif's ESP32 and ESP8266 - * - * Version: 1.2.0 - * Released: May 17, 2021 - * - * Updates: - * - Add support ESP8266 Core SDK v3.x.x. - * - * - * This library allows Espressif's ESP32 and ESP8266 devices to send and read Email - * through the SMTP and IMAP servers. - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef ESP_Mail_Client_CPP -#define ESP_Mail_Client_CPP - -#include "ESP_Mail_Client.h" - -#if defined(ESP32) -extern "C" -{ -#include -#include -} -#endif - -bool ESP_Mail_Client::sendIMAPCommand(IMAPSession *imap, int msgIndex, int cmdCase) -{ - - std::string cmd; - if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0) - appendP(cmd, esp_mail_str_142, true); - else - appendP(cmd, esp_mail_str_143, true); - - char *tmp = intStr(imap->_msgNum[msgIndex]); - cmd += tmp; - delS(tmp); - appendP(cmd, esp_mail_str_147, false); - if (!imap->_config->fetch.set_seen) - { - appendP(cmd, esp_mail_str_152, false); - appendP(cmd, esp_mail_str_214, false); - } - appendP(cmd, esp_mail_str_218, false); - - switch (cmdCase) - { - case 1: - - appendP(cmd, esp_mail_str_269, false); - break; - - case 2: - - if (cPart(imap)->partNumFetchStr.length() > 0) - cmd += cPart(imap)->partNumFetchStr; - else - appendP(cmd, esp_mail_str_215, false); - appendP(cmd, esp_mail_str_156, false); - break; - - case 3: - - cmd += cPart(imap)->partNumFetchStr; - appendP(cmd, esp_mail_str_156, false); - break; - - default: - break; - } - - if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - return true; -} - -bool ESP_Mail_Client::readMail(IMAPSession *imap, bool closeSession) -{ - - imap->checkUID(); - imap->checkPath(); - - if (!imap->_tcpConnected) - imap->_mailboxOpened = false; - - std::string buf; - std::string command; - std::string _uid; - appendP(command, esp_mail_str_27, true); - char *tmp = nullptr; - size_t readCount = 0; - imap->_multipart_levels.clear(); - - if (!reconnect(imap)) - return false; - - int cmem = ESP.getFreeHeap(); - - if (cmem < ESP_MAIL_MIN_MEM) - { - if (imap->_debug) - { - esp_mail_debug(""); - errorStatusCB(imap, MAIL_CLIENT_ERROR_OUT_OF_MEMORY); - } - goto out; - } - - //new session - if (!imap->_tcpConnected) - { - //authenticate new - if (!imapAuth(imap)) - { - closeTCP(imap); - return false; - } - } - else - { - //reuse session - for (size_t i = 0; i < imap->_headers.size(); i++) - imap->_headers[i].part_headers.clear(); - imap->_headers.clear(); - - if (strlen(imap->_config->fetch.uid) > 0) - imap->_headerOnly = false; - else - imap->_headerOnly = true; - } - imap->_rfc822_part_count = 0; - imap->_mbif._availableItems = 0; - imap->_msgNum.clear(); - imap->_uidSearch = false; - imap->_mbif._searchCount = 0; - - if (imap->_currentFolder.length() == 0) - return handleIMAPError(imap, IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED, false); - - if (!imap->_mailboxOpened || (imap->_config->fetch.set_seen && !imap->_headerOnly && imap->_readOnlyMode)) - { - if (!imap->openFolder(imap->_currentFolder.c_str(), imap->_readOnlyMode && !imap->_config->fetch.set_seen)) - return handleIMAPError(imap, IMAP_STATUS_OPEN_MAILBOX_FAILED, false); - } - - if (imap->_headerOnly) - { - if (strlen(imap->_config->search.criteria) > 0) - { - - if (imap->_readCallback) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_66, false); - } - - if (imap->_debug) - debugInfoP(esp_mail_str_232); - - if (strposP(imap->_config->search.criteria, esp_mail_str_137, 0) != -1) - { - imap->_uidSearch = true; - appendP(command, esp_mail_str_138, false); - } - - appendP(command, esp_mail_str_139, false); - - for (size_t i = 0; i < strlen(imap->_config->search.criteria); i++) - { - if (imap->_config->search.criteria[i] != ' ' && imap->_config->search.criteria[i] != '\r' && imap->_config->search.criteria[i] != '\n' && imap->_config->search.criteria[i] != '$') - buf.append(1, imap->_config->search.criteria[i]); - - if (imap->_config->search.criteria[i] == ' ') - { - tmp = strP(esp_mail_str_140); - char *tmp2 = strP(esp_mail_str_224); - - if ((imap->_uidSearch && strcmp(buf.c_str(), tmp) == 0) || (imap->_unseen && buf.find(tmp2) != std::string::npos)) - buf.clear(); - delS(tmp); - delS(tmp2); - - tmp = strP(esp_mail_str_141); - if (strcmp(buf.c_str(), tmp) != 0 && buf.length() > 0) - { - appendP(command, esp_mail_str_131, false); - command += buf; - } - delS(tmp); - buf.clear(); - } - } - - tmp = strP(esp_mail_str_223); - if (imap->_unseen && strpos(imap->_config->search.criteria, tmp, 0) == -1) - appendP(command, esp_mail_str_223, false); - delS(tmp); - - if (buf.length() > 0) - { - appendP(command, esp_mail_str_131, false); - command += buf; - } - - if (imapSend(imap, command.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - std::string().swap(command); - - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_search; - - if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, closeSession)) - return false; - - if (imap->_readCallback) - { - std::string s; - appendP(s, esp_mail_str_34, true); - appendP(s, esp_mail_str_68, false); - char *tmp = intStr(imap->_config->limit.search); - s += tmp; - delS(tmp); - imapCB(imap, s.c_str(), false); - - if (imap->_msgNum.size() > 0) - { - - appendP(s, esp_mail_str_69, true); - tmp = intStr(imap->_mbif._searchCount); - s += tmp; - delS(tmp); - appendP(s, esp_mail_str_70, false); - imapCB(imap, s.c_str(), false); - - appendP(s, esp_mail_str_71, true); - tmp = intStr(imap->_msgNum.size()); - s += tmp; - delS(tmp); - appendP(s, esp_mail_str_70, false); - imapCB(imap, s.c_str(), false); - } - else - imapCBP(imap, esp_mail_str_72, false); - } - } - else - { - imap->_mbif._availableItems++; - imap->_msgNum.push_back(imap->_mbif._nextUID - 1); - imap->_headerOnly = false; - char *tmp = intStr(imap->_mbif._nextUID - 1); - _uid = tmp; - delS(tmp); - imap->_config->fetch.uid = _uid.c_str(); - - if (imap->_readCallback) - imapCBP(imap, esp_mail_str_73, false); - } - } - else - { - imap->_mbif._availableItems++; - imap->_msgNum.push_back(atoi(imap->_config->fetch.uid)); - } - - for (size_t i = 0; i < imap->_msgNum.size(); i++) - { - - imap->_cMsgIdx = i; - imap->_totalRead++; - - if (ESP.getFreeHeap() - (imap->_config->limit.msg_size * (i + 1)) < ESP_MAIL_MIN_MEM) - { - if (imap->_debug) - errorStatusCB(imap, MAIL_CLIENT_ERROR_OUT_OF_MEMORY); - goto out; - } - - if (imap->_readCallback) - { - readCount++; - - std::string s; - appendP(s, esp_mail_str_74, true); - char *tmp = intStr(imap->_totalRead); - s += tmp; - delS(tmp); - - if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0) - appendP(s, esp_mail_str_75, false); - else - appendP(s, esp_mail_str_76, false); - - tmp = intStr(imap->_msgNum[i]); - s += tmp; - delS(tmp); - imapCB(imap, "", false); - imapCB(imap, s.c_str(), false); - } - - if (imap->_debug) - debugInfoP(esp_mail_str_233); - - std::string cmd; - if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0) - appendP(cmd, esp_mail_str_142, true); - else - appendP(cmd, esp_mail_str_143, true); - - if (imap->_debug) - debugInfoP(esp_mail_str_77); - - char *tmp = intStr(imap->_msgNum[i]); - cmd += tmp; - delS(tmp); - - appendP(cmd, esp_mail_str_147, false); - if (!imap->_config->fetch.set_seen) - { - appendP(cmd, esp_mail_str_152, false); - appendP(cmd, esp_mail_str_214, false); - } - appendP(cmd, esp_mail_str_218, false); - - appendP(cmd, esp_mail_str_144, false); - appendP(cmd, esp_mail_str_156, false); - if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_header; - - int err = IMAP_STATUS_BAD_COMMAND; - if (imap->_headerOnly) - err = IMAP_STATUS_IMAP_RESPONSE_FAILED; - - if (!handleIMAPResponse(imap, err, closeSession)) - return false; - - if (!imap->_headerOnly) - { - imap->_cPartIdx = 0; - - //multipart - if (cHeader(imap)->multipart) - { - struct esp_mail_imap_multipart_level_t mlevel; - mlevel.level = 1; - mlevel.fetch_rfc822_header = false; - mlevel.append_body_text = false; - imap->_multipart_levels.push_back(mlevel); - - if (!fetchMultipartBodyHeader(imap, i)) - return false; - } - else - { - //singlepart - if (imap->_debug) - { - std::string s; - appendP(s, esp_mail_str_81, true); - s += '1'; - esp_mail_debug(s.c_str()); - } - - cHeader(imap)->partNumStr.clear(); - if (!sendIMAPCommand(imap, i, 1)) - return false; - - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_mime; - if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, closeSession)) - return false; - } - - if (imap->_config->download.text || imap->_config->download.html || imap->_config->download.attachment || imap->_config->download.inlineImg) - { - if (!_sdOk && imap->_storageType == esp_mail_file_storage_type_sd) - { - _sdOk = sdTest(); - if (_sdOk) - if (!ESP_MAIL_SD_FS.exists(imap->_config->storage.saved_path)) - createDirs(imap->_config->storage.saved_path); - } - else if (!_flashOk && imap->_storageType == esp_mail_file_storage_type_flash) -#if defined(ESP32) - _flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH); -#elif defined(ESP8266) - _flashOk = ESP_MAIL_FLASH_FS.begin(); -#endif - } - - if (cHeader(imap)->part_headers.size() > 0) - { - if (cHeader(imap)->attachment_count > 0 && imap->_readCallback) - { - std::string s; - appendP(s, esp_mail_str_34, true); - appendP(s, esp_mail_str_78, false); - char *tmp = intStr(cHeader(imap)->attachment_count); - s += tmp; - delS(tmp); - appendP(s, esp_mail_str_79, false); - imapCB(imap, s.c_str(), false); - - for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) - { - imap->_cPartIdx = j; - if (!cPart(imap)->rfc822_part && cPart(imap)->attach_type != esp_mail_att_type_none) - imapCB(imap, cPart(imap)->filename.c_str(), false); - } - } - - std::string s1, s2; - int _idx1 = 0; - for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) - { - imap->_cPartIdx = j; - if (cPart(imap)->rfc822_part) - { - s1 = cPart(imap)->partNumStr; - _idx1 = cPart(imap)->rfc822_msg_Idx; - } - else if (s1.length() > 0) - { - if (multipartMember(s1, cPart(imap)->partNumStr)) - { - cPart(imap)->message_sub_type = esp_mail_imap_message_sub_type_rfc822; - cPart(imap)->rfc822_msg_Idx = _idx1; - } - } - - if (cPart(imap)->multipart_sub_type == esp_mail_imap_multipart_sub_type_parallel) - s2 = cPart(imap)->partNumStr; - else if (s2.length() > 0) - { - if (multipartMember(s2, cPart(imap)->partNumStr)) - { - cPart(imap)->attach_type = esp_mail_att_type_attachment; - if (cPart(imap)->filename.length() == 0) - { - if (cPart(imap)->name.length() > 0) - cPart(imap)->filename = cPart(imap)->name; - else - { - char *tmp = getUID(); - cPart(imap)->filename = tmp; - appendP(cPart(imap)->filename, esp_mail_str_40, false); - delS(tmp); - } - } - } - } - } - - int acnt = 0; - int ccnt = 0; - - for (size_t j = 0; j < cHeader(imap)->part_headers.size(); j++) - { - imap->_cPartIdx = j; - - if (cPart(imap)->rfc822_part || cPart(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_none) - continue; - - bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822; - - if (cPart(imap)->attach_type == esp_mail_att_type_none || cPart(imap)->msg_type == esp_mail_msg_type_html || cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) - { - - bool ret = ((imap->_config->enable.rfc822 || imap->_config->download.rfc822) && rfc822_body_subtype) || (!rfc822_body_subtype && ((imap->_config->enable.text && (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched)) || (imap->_config->enable.html && cPart(imap)->msg_type == esp_mail_msg_type_html) || (cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text))); - if (!ret) - continue; - - if ((imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)))) - { - - if (ccnt == 0) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_57, false); - } - - if (imap->_debug) - { - if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) - debugInfoP(esp_mail_str_59); - else if (cPart(imap)->msg_type == esp_mail_msg_type_html) - debugInfoP(esp_mail_str_60); - } - } - else - { - if (ccnt == 0) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_307, false); - } - - if (imap->_debug) - { - if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) - debugInfoP(esp_mail_str_308); - else if (cPart(imap)->msg_type == esp_mail_msg_type_html) - debugInfoP(esp_mail_str_309); - } - } - - ccnt++; - - if (!sendIMAPCommand(imap, i, 2)) - return false; - - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_text; - if (!handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, closeSession)) - return false; - } - else if (cPart(imap)->attach_type != esp_mail_att_type_none && (_sdOk || _flashOk)) - { - - if (imap->_config->download.attachment || imap->_config->download.inlineImg) - { - if (acnt == 0) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_80, false); - } - - if (imap->_debug) - debugInfoP(esp_mail_str_55); - - acnt++; - if (cPart(imap)->octetLen <= (int)imap->_config->limit.attachment_size) - { - - if (_sdOk || _flashOk) - { - - if ((int)j < (int)cHeader(imap)->part_headers.size() - 1) - if (cHeader(imap)->part_headers[j + 1].octetLen > (int)imap->_config->limit.attachment_size) - cHeader(imap)->downloaded_bytes += cHeader(imap)->part_headers[j + 1].octetLen; - - if (!sendIMAPCommand(imap, i, 3)) - return false; - - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_fetch_body_attachment; - if (!handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, closeSession)) - return false; - delay(0); - } - } - else - { - if ((int)j == (int)cHeader(imap)->part_headers.size() - 1) - cHeader(imap)->downloaded_bytes += cPart(imap)->octetLen; - } - } - } - } - } - - if (imap->_config->download.header && !imap->_headerSaved) - { - if (imap->_readCallback) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_124, false); - } - saveHeader(imap); - } - - if (closeSession) - { - if (imap->_storageType == esp_mail_file_storage_type_sd) - { - if (_sdOk) - ESP_MAIL_SD_FS.end(); - _sdOk = false; - } - else if (imap->_storageType == esp_mail_file_storage_type_flash) - { - if (_flashOk) - ESP_MAIL_FLASH_FS.end(); - - _flashOk = false; - } - } - - imap->_cMsgIdx++; - } - - if (imap->_debug) - { - std::string s; - appendP(s, esp_mail_str_261, true); - appendP(s, esp_mail_str_84, false); - char *tmp = intStr(ESP.getFreeHeap()); - s += tmp; - delS(tmp); - esp_mail_debug(s.c_str()); - } - } - -out: - - if (readCount < imap->_msgNum.size()) - { - imap->_mbif._availableItems = readCount; - imap->_msgNum.erase(imap->_msgNum.begin() + readCount, imap->_msgNum.end()); - } - - if (closeSession) - { - if (!imap->closeSession()) - return false; - } - else - { - if (imap->_readCallback) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_87, false); - } - - if (imap->_debug) - debugInfoP(esp_mail_str_88); - } - - if (imap->_readCallback) - imapCB(imap, "", true); - - return true; -} -bool ESP_Mail_Client::getMultipartFechCmd(IMAPSession *imap, int msgIdx, std::string &partText) -{ - if (imap->_multipart_levels.size() == 0) - return false; - - int cLevel = imap->_multipart_levels.size() - 1; - - cHeader(imap)->partNumStr.clear(); - - if (imap->_uidSearch || strlen(imap->_config->fetch.uid) > 0) - appendP(partText, esp_mail_str_142, true); - else - appendP(partText, esp_mail_str_143, true); - - char *tmp = intStr(imap->_msgNum[msgIdx]); - partText += tmp; - delS(tmp); - - appendP(partText, esp_mail_str_147, false); - if (!imap->_config->fetch.set_seen) - { - appendP(partText, esp_mail_str_152, false); - appendP(partText, esp_mail_str_214, false); - } - appendP(partText, esp_mail_str_218, false); - - for (size_t i = 0; i < imap->_multipart_levels.size(); i++) - { - if (i > 0) - { - appendP(partText, esp_mail_str_152, false); - appendP(cHeader(imap)->partNumStr, esp_mail_str_152, false); - } - - tmp = intStr(imap->_multipart_levels[i].level); - partText += tmp; - cHeader(imap)->partNumStr += tmp; - delS(tmp); - } - - if (imap->_multipart_levels[cLevel].fetch_rfc822_header) - { - appendP(partText, esp_mail_str_51, false); - imap->_multipart_levels[cLevel].append_body_text = true; - } - else - appendP(partText, esp_mail_str_148, false); - - imap->_multipart_levels[cLevel].fetch_rfc822_header = false; - - return true; -} - -bool ESP_Mail_Client::multipartMember(const std::string &part, const std::string &check) -{ - if (part.length() > check.length()) - return false; - - for (size_t i = 0; i < part.length(); i++) - if (part[i] != check[i]) - return false; - - return true; -} - -bool ESP_Mail_Client::fetchMultipartBodyHeader(IMAPSession *imap, int msgIdx) -{ - bool ret = true; - - if (!connected(imap)) - { - closeTCP(imap); - return false; - } - int cLevel = 0; - - do - { - - struct esp_mail_message_part_info_t *_cpart = &cHeader(imap)->part_headers[cHeader(imap)->message_data_count - 1]; - bool rfc822_body_subtype = _cpart->message_sub_type == esp_mail_imap_message_sub_type_rfc822; - - std::string cmd; - - if (!getMultipartFechCmd(imap, msgIdx, cmd)) - return true; - - if (imap->_debug) - { - std::string s; - if (imap->_multipart_levels.size() > 1) - appendP(s, esp_mail_str_86, true); - else - appendP(s, esp_mail_str_81, true); - s += cHeader(imap)->partNumStr; - esp_mail_debug(s.c_str()); - } - - if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - imap->_imap_cmd = esp_mail_imap_cmd_fetch_body_mime; - - ret = handleIMAPResponse(imap, IMAP_STATUS_IMAP_RESPONSE_FAILED, false); - - _cpart = &cHeader(imap)->part_headers[cHeader(imap)->message_data_count - 1]; - rfc822_body_subtype = _cpart->message_sub_type == esp_mail_imap_message_sub_type_rfc822; - cLevel = imap->_multipart_levels.size() - 1; - - if (ret) - { - - if (_cpart->multipart) - { - if (_cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_parallel || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_alternative || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_related || _cpart->multipart_sub_type == esp_mail_imap_multipart_sub_type_mixed) - { - struct esp_mail_imap_multipart_level_t mlevel; - mlevel.level = 1; - mlevel.fetch_rfc822_header = false; - mlevel.append_body_text = false; - imap->_multipart_levels.push_back(mlevel); - fetchMultipartBodyHeader(imap, msgIdx); - } - else - imap->_multipart_levels[cLevel].level++; - } - else - { - if (rfc822_body_subtype) - { - //to get additional rfc822 message header - imap->_multipart_levels[cLevel].fetch_rfc822_header = true; - fetchMultipartBodyHeader(imap, msgIdx); - } - else - { - if (imap->_multipart_levels[cLevel].append_body_text) - { - //single part rfc822 message body, append TEXT to the body fetch command - appendP(_cpart->partNumFetchStr, esp_mail_str_152, false); - appendP(_cpart->partNumFetchStr, esp_mail_str_215, false); - imap->_multipart_levels[cLevel].append_body_text = false; - } - imap->_multipart_levels[cLevel].level++; - } - } - } - - } while (ret); - - imap->_multipart_levels.pop_back(); - - if (imap->_multipart_levels.size() > 0) - { - cLevel = imap->_multipart_levels.size() - 1; - imap->_multipart_levels[cLevel].level++; - } - - return true; -} - -bool ESP_Mail_Client::connected(IMAPSession *imap) -{ - if (!imap->_secure) - { - if (!imap->httpClient._stream()) - return false; - return imap->httpClient._stream()->_ns_connected(); - } - else - { - if (!imap->httpClient.stream()) - return false; - return imap->httpClient.stream()->connected(); - } -} - -bool ESP_Mail_Client::imapAuth(IMAPSession *imap) -{ - - bool ssl = false; - std::string buf; -#if defined(ESP32) - imap->httpClient.setDebugCallback(NULL); -#elif defined(ESP8266) - -#endif - - if (imap->_config != nullptr) - { - if (strlen(imap->_config->fetch.uid) > 0) - imap->_headerOnly = false; - else - imap->_headerOnly = true; - } - - imap->_totalRead = 0; - imap->_secure = true; - bool secureMode = true; - -#if defined(ESP32) - if (imap->_debug) - imap->httpClient.setDebugCallback(esp_mail_debug); -#elif defined(ESP8266) - imap->httpClient.txBufDivider = 16; //minimum, tx buffer size for ssl data and request command data - imap->httpClient.rxBufDivider = 1; - if (imap->_config != nullptr) - { - if (!imap->_headerOnly && !imap->_config->enable.html && !imap->_config->enable.text && !imap->_config->download.attachment && !imap->_config->download.inlineImg && !imap->_config->download.html && !imap->_config->download.text) - imap->httpClient.rxBufDivider = 16; // minimum rx buffer size for only message header - } -#endif - - if (imap->_sesson_cfg->server.port == esp_mail_imap_port_143) - { - imap->_secure = false; - secureMode = false; - } - else - secureMode = !imap->_sesson_cfg->secure.startTLS; - - setSecure(imap->httpClient, imap->_sesson_cfg, imap->_caCert); - - if (imap->_readCallback) - imapCBP(imap, esp_mail_str_50, false); - - if (imap->_debug) - { - std::string s; - appendP(s, esp_mail_str_314, true); - s += ESP_MAIL_VERSION; - esp_mail_debug(s.c_str()); - - debugInfoP(esp_mail_str_225); - appendP(s, esp_mail_str_261, true); - appendP(s, esp_mail_str_211, false); - s += imap->_sesson_cfg->server.host_name; - esp_mail_debug(s.c_str()); - char *tmp = intStr(imap->_sesson_cfg->server.port); - appendP(s, esp_mail_str_261, true); - appendP(s, esp_mail_str_201, false); - s += tmp; - delS(tmp); - esp_mail_debug(s.c_str()); - } - - imap->httpClient.begin(imap->_sesson_cfg->server.host_name, imap->_sesson_cfg->server.port); - - if (!imap->httpClient.connect(secureMode)) - return handleIMAPError(imap, IMAP_STATUS_SERVER_CONNECT_FAILED, false); - - imap->_tcpConnected = true; - WiFiClient *stream = imap->httpClient.stream(); -#if defined(ESP32) - stream->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC); -#elif defined(ESP8266) - stream->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000); -#endif - imap->httpClient.tcpTimeout = ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000; - - if (imap->_readCallback) - imapCBP(imap, esp_mail_str_54, false); - - if (imap->_debug) - debugInfoP(esp_mail_str_228); - -init: - - if (!imap->checkCapability()) - return false; - - //start TLS when needed or the server issue - if ((imap->_auth_capability.start_tls || imap->_sesson_cfg->secure.startTLS) && !ssl) - { - std::string s; - if (imap->_readCallback) - { - appendP(s, esp_mail_str_34, true); - appendP(s, esp_mail_str_209, false); - esp_mail_debug(s.c_str()); - } - - if (imap->_debug) - { - appendP(s, esp_mail_str_196, true); - esp_mail_debug(s.c_str()); - } - - imapSendP(imap, esp_mail_str_311, false); - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_starttls; - if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false)) - return false; - - if (imap->_debug) - { - debugInfoP(esp_mail_str_310); - } - - //connect in secure mode - //do ssl handshaking - if (!imap->httpClient._stream()->_ns_connect_ssl()) - return handleIMAPError(imap, MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP, false); - - //set the secure mode - imap->_sesson_cfg->secure.startTLS = false; - ssl = true; - imap->_secure = true; - - //check the capabilitiy again - goto init; - } - - imap->clearMessageData(); - imap->_mailboxOpened = false; - - bool creds = strlen(imap->_sesson_cfg->login.email) > 0 && strlen(imap->_sesson_cfg->login.password) > 0; - bool xoauth_auth = strlen(imap->_sesson_cfg->login.accessToken) > 0 && imap->_auth_capability.xoauth2; - bool login_auth = creds; - bool plain_auth = imap->_auth_capability.plain && creds; - - bool supported_auth = xoauth_auth || login_auth || plain_auth; - - if (!supported_auth) - return handleIMAPError(imap, IMAP_STATUS_NO_SUPPORTED_AUTH, false); - - //rfc4959 - if (supported_auth) - { - if (imap->_readCallback) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_56, false); - } - } - - if (xoauth_auth) - { - if (!imap->_auth_capability.xoauth2) - return handleIMAPError(imap, IMAP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED, false); - - if (imap->_debug) - debugInfoP(esp_mail_str_291); - - std::string cmd; - appendP(cmd, esp_mail_str_292, true); - cmd += getEncodedToken(imap); - if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_auth; - if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, false)) - return false; - } - else if (login_auth) - { - - if (imap->_debug) - debugInfoP(esp_mail_str_229); - - std::string cmd; - - appendP(cmd, esp_mail_str_130, true); - cmd += imap->_sesson_cfg->login.email; - appendP(cmd, esp_mail_str_131, false); - cmd += imap->_sesson_cfg->login.password; - - if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_login; - if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, true)) - return false; - } - else if (plain_auth) - { - if (imap->_debug) - debugInfoP(esp_mail_str_290); - - const char *usr = imap->_sesson_cfg->login.email; - const char *psw = imap->_sesson_cfg->login.password; - int len = strlen(usr) + strlen(psw) + 2; - uint8_t *tmp = new uint8_t[len]; - memset(tmp, 0, len); - int p = 1; - memcpy(tmp + p, usr, strlen(usr)); - p += strlen(usr) + 1; - memcpy(tmp + p, psw, strlen(psw)); - p += strlen(psw); - - std::string s; - appendP(s, esp_mail_str_41, true); - s += encodeBase64Str(tmp, p); - delete[] tmp; - - if (imapSend(imap, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - imap->_imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_login; - if (!handleIMAPResponse(imap, IMAP_STATUS_LOGIN_FAILED, true)) - return false; - } - - return true; -} - -std::string ESP_Mail_Client::getEncodedToken(IMAPSession *imap) -{ - std::string raw; - appendP(raw, esp_mail_str_285, true); - raw += imap->_sesson_cfg->login.email; - appendP(raw, esp_mail_str_286, false); - raw += imap->_sesson_cfg->login.accessToken; - appendP(raw, esp_mail_str_287, false); - std::string s = encodeBase64Str((const unsigned char *)raw.c_str(), raw.length()); - return s; -} - -bool ESP_Mail_Client::imapLogout(IMAPSession *imap) -{ - if (imap->_readCallback) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_85, false); - } - - if (imap->_debug) - debugInfoP(esp_mail_str_234); - - if (imapSendP(imap, esp_mail_str_146, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - imap->_imap_cmd = esp_mail_imap_cmd_logout; - if (!handleIMAPResponse(imap, IMAP_STATUS_BAD_COMMAND, false)) - return false; - - if (imap->_readCallback) - { - imapCB(imap, "", false); - imapCBP(imap, esp_mail_str_187, false); - } - - if (imap->_debug) - debugInfoP(esp_mail_str_235); - - return true; -} - -void ESP_Mail_Client::errorStatusCB(IMAPSession *imap, int error) -{ - imap->_imapStatus.statusCode = error; - std::string s; - if (imap->_readCallback) - { - appendP(s, esp_mail_str_53, true); - s += imap->errorReason().c_str(); - imapCB(imap, s.c_str(), false); - } - - if (imap->_debug) - { - appendP(s, esp_mail_str_185, true); - s += imap->errorReason().c_str(); - esp_mail_debug(s.c_str()); - } -} - -size_t ESP_Mail_Client::imapSendP(IMAPSession *imap, PGM_P v, bool newline) -{ - if (!reconnect(imap)) - { - closeTCP(imap); - return 0; - } - - if (!connected(imap)) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return 0; - } - - if (!imap->_tcpConnected) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - return 0; - } - - char *tmp = strP(v); - size_t len = 0; - - if (newline) - { - if (imap->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug(tmp); - if (!imap->_secure) - len = imap->httpClient._ns_println(tmp); - else - len = imap->httpClient.stream()->println(tmp); - } - else - { - if (imap->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug_line(tmp, false); - if (!imap->_secure) - len = imap->httpClient._ns_print(tmp); - else - len = imap->httpClient.stream()->print(tmp); - } - - if (len != strlen(tmp) && len != strlen(tmp) + 2) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - len = 0; - } - - delS(tmp); - - return len; -} - -size_t ESP_Mail_Client::imapSend(IMAPSession *imap, const char *data, bool newline) -{ - if (!reconnect(imap)) - { - closeTCP(imap); - return 0; - } - - if (!connected(imap)) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return 0; - } - - if (!imap->_tcpConnected) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - return 0; - } - - size_t len = 0; - - if (newline) - { - if (imap->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug(data); - if (!imap->_secure) - len = imap->httpClient._ns_println(data); - else - len = imap->httpClient.stream()->println(data); - } - else - { - if (imap->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug_line(data, false); - if (!imap->_secure) - len = imap->httpClient._ns_print(data); - else - len = imap->httpClient.stream()->print(data); - } - - if (len != strlen(data) && len != strlen(data) + 2) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - len = 0; - } - return len; -} - -size_t ESP_Mail_Client::imapSend(IMAPSession *imap, int data, bool newline) -{ - if (!reconnect(imap)) - { - closeTCP(imap); - return 0; - } - - if (!connected(imap)) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return 0; - } - - if (!imap->_tcpConnected) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - return 0; - } - - char *tmp = intStr(data); - size_t len = 0; - - if (newline) - { - if (imap->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug(tmp); - if (!imap->_secure) - len = imap->httpClient._ns_println(tmp); - else - len = imap->httpClient.stream()->println(tmp); - } - else - { - if (imap->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug_line(tmp, false); - if (!imap->_secure) - len = imap->httpClient._ns_print(tmp); - else - len = imap->httpClient.stream()->print(tmp); - } - - if (len != strlen(tmp) && len != strlen(tmp) + 2) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - len = 0; - } - - delS(tmp); - - return len; -} - -bool ESP_Mail_Client::setFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession) -{ - return _setFlag(imap, msgUID, flag, 0, closeSession); -} - -bool ESP_Mail_Client::addFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession) -{ - return _setFlag(imap, msgUID, flag, 1, closeSession); -} - -bool ESP_Mail_Client::removeFlag(IMAPSession *imap, int msgUID, const char *flag, bool closeSession) -{ - return _setFlag(imap, msgUID, flag, 2, closeSession); -} - -bool ESP_Mail_Client::_setFlag(IMAPSession *imap, int msgUID, const char *flag, uint8_t action, bool closeSession) -{ - if (!reconnect(imap)) - return false; - - if (!imap->_tcpConnected) - { - imap->_mailboxOpened = false; - return false; - } - - if (imap->_currentFolder.length() == 0) - { - if (imap->_readCallback) - debugInfoP(esp_mail_str_153); - - if (imap->_debug) - { - std::string e; - appendP(e, esp_mail_str_185, true); - appendP(e, esp_mail_str_151, false); - esp_mail_debug(e.c_str()); - } - } - else - { - if (imap->_readOnlyMode || !imap->_mailboxOpened) - { - if (!imap->selectFolder(imap->_currentFolder.c_str(), false)) - return false; - } - } - - if (imap->_readCallback) - { - imapCB(imap, "", false); - if (action == 0) - debugInfoP(esp_mail_str_157); - else if (action == 1) - debugInfoP(esp_mail_str_155); - else - debugInfoP(esp_mail_str_154); - } - - if (imap->_debug) - { - if (action == 0) - debugInfoP(esp_mail_str_253); - else if (action == 1) - debugInfoP(esp_mail_str_254); - else - debugInfoP(esp_mail_str_255); - } - - std::string cmd; - appendP(cmd, esp_mail_str_249, true); - char *tmp = intStr(msgUID); - cmd += tmp; - delS(tmp); - if (action == 0) - appendP(cmd, esp_mail_str_250, false); - else if (action == 1) - appendP(cmd, esp_mail_str_251, false); - else - appendP(cmd, esp_mail_str_252, false); - cmd += flag; - appendP(cmd, esp_mail_str_192, false); - - if (imapSend(imap, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - imap->_imap_cmd = esp_mail_imap_cmd_store; - - if (!handleIMAPResponse(imap, IMAP_STATUS_PARSE_FLAG_FAILED, false)) - return false; - - if (closeSession) - imap->closeSession(); - - return true; -} - -void ESP_Mail_Client::createDirs(std::string dirs) -{ - std::string dir = ""; - int count = 0; - for (size_t i = 0; i < dirs.length(); i++) - { - dir.append(1, dirs[i]); - count++; - if (dirs[i] == '/') - { - if (dir.length() > 0) - ESP_MAIL_SD_FS.mkdir(dir.substr(0, dir.length() - 1).c_str()); - count = 0; - } - } - if (count > 0) - ESP_MAIL_SD_FS.mkdir(dir.c_str()); - std::string().swap(dir); -} - -bool ESP_Mail_Client::sdTest() -{ -#if defined(CARD_TYPE_SD) - if (_sdConfigSet) - sdBegin(_sck, _miso, _mosi, _ss); - else - sdBegin(); -#endif - -#if defined(ESP32) -#if defined(CARD_TYPE_SD_MMC) - if (_sdConfigSet) - sdMMCBegin(sd_mmc_mountpoint, sd_mmc_mode1bit, sd_mmc_format_if_mount_failed); -#endif -#endif - - file = ESP_MAIL_SD_FS.open(esp_mail_str_204, FILE_WRITE); - if (!file) - return false; - - if (!file.write(32)) - return false; - file.close(); - - file = ESP_MAIL_SD_FS.open(esp_mail_str_204); - if (!file) - return false; - - while (file.available()) - { - if (file.read() != 32) - return false; - } - file.close(); - - ESP_MAIL_SD_FS.remove(esp_mail_str_204); - - return true; -} - -std::string ESP_Mail_Client::getEncodedToken(SMTPSession *smtp) -{ - std::string raw; - appendP(raw, esp_mail_str_285, true); - raw += smtp->_sesson_cfg->login.email; - appendP(raw, esp_mail_str_286, false); - raw += smtp->_sesson_cfg->login.accessToken; - appendP(raw, esp_mail_str_287, false); - return encodeBase64Str((const unsigned char *)raw.c_str(), raw.length()); -} - -bool ESP_Mail_Client::smtpAuth(SMTPSession *smtp) -{ - - if (!reconnect(smtp)) - return false; - - bool ssl = false; - smtp->_secure = true; - bool secureMode = true; - - std::string s; - -#if defined(ESP32) - smtp->httpClient.setDebugCallback(NULL); -#elif defined(ESP8266) - smtp->httpClient.rxBufDivider = 16; // minimum rx buffer for smtp status response - smtp->httpClient.txBufDivider = 8; // medium tx buffer for faster attachment/inline data transfer -#endif - - if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_25) - { - smtp->_secure = false; - secureMode = false; - } - else - { - if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_587) - smtp->_sesson_cfg->secure.startTLS = true; - - secureMode = !smtp->_sesson_cfg->secure.startTLS; - - //to prevent to send the connection upgrade command when some server promotes - //the starttls capability even the current connection was already secured. - if (smtp->_sesson_cfg->server.port == esp_mail_smtp_port_465) - ssl = true; - } - - setSecure(smtp->httpClient, smtp->_sesson_cfg, smtp->_caCert); - - //Server connection attempt: no status code - if (smtp->_sendCallback) - smtpCBP(smtp, esp_mail_str_120); - - if (smtp->_debug) - { - appendP(s, esp_mail_str_314, true); - s += ESP_MAIL_VERSION; - esp_mail_debug(s.c_str()); - - debugInfoP(esp_mail_str_236); - appendP(s, esp_mail_str_261, true); - appendP(s, esp_mail_str_211, false); - s += smtp->_sesson_cfg->server.host_name; - esp_mail_debug(s.c_str()); - char *tmp = intStr(smtp->_sesson_cfg->server.port); - appendP(s, esp_mail_str_261, true); - appendP(s, esp_mail_str_201, false); - s += tmp; - delS(tmp); - esp_mail_debug(s.c_str()); - } -#if defined(ESP32) - if (smtp->_debug) - smtp->httpClient.setDebugCallback(esp_mail_debug); -#endif - - smtp->httpClient.begin(smtp->_sesson_cfg->server.host_name, smtp->_sesson_cfg->server.port); - - if (!smtp->httpClient.connect(secureMode)) - return handleSMTPError(smtp, SMTP_STATUS_SERVER_CONNECT_FAILED); - - //server connected - smtp->_tcpConnected = true; - - if (smtp->_debug) - debugInfoP(esp_mail_str_238); - - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - smtpCBP(smtp, esp_mail_str_121); - } - -#if defined(ESP32) - smtp->httpClient.stream()->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC); -#elif defined(ESP8266) - smtp->httpClient.stream()->setTimeout(ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000); -#endif - smtp->httpClient.tcpTimeout = ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC * 1000; - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state; - - //expected status code 220 for ready to service - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_220, SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED)) - return false; - -init: - - //Sending greeting hello response - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - smtpCBP(smtp, esp_mail_str_122); - } - - if (smtp->_debug) - debugInfoP(esp_mail_str_239); - - appendP(s, esp_mail_str_6, true); - if (strlen(smtp->_sesson_cfg->login.user_domain) > 0) - s += smtp->_sesson_cfg->login.user_domain; - else - appendP(s, esp_mail_str_44, false); - - if (smtpSendP(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_greeting; - - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, 0)) - { - appendP(s, esp_mail_str_5, true); - if (strlen(smtp->_sesson_cfg->login.user_domain) > 0) - s += smtp->_sesson_cfg->login.user_domain; - else - appendP(s, esp_mail_str_44, false); - - if (smtpSend(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED)) - return false; - smtp->_send_capability.esmtp = false; - smtp->_auth_capability.login = true; - } - else - smtp->_send_capability.esmtp = true; - - //start TLS when needed - if ((smtp->_auth_capability.start_tls || smtp->_sesson_cfg->secure.startTLS) && !ssl) - { - //send starttls command - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - smtpCBP(smtp, esp_mail_str_209); - } - - if (smtp->_debug) - { - appendP(s, esp_mail_str_196, true); - esp_mail_debug(s.c_str()); - } - - //expected status code 250 for complete the request - //some server returns 220 to restart to initial state - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_start_tls; - smtpSendP(smtp, esp_mail_str_311, false); - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED)) - return false; - - if (smtp->_debug) - { - debugInfoP(esp_mail_str_310); - } - - //connect using secure mode - //do ssl handshaking - if (!smtp->httpClient._stream()->_ns_connect_ssl()) - return handleSMTPError(smtp, MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP); - - //set the secure mode - smtp->_sesson_cfg->secure.startTLS = false; - ssl = true; - smtp->_secure = true; - - //return to initial state if the response status is 220. - if (smtp->_smtpStatus.respCode == esp_mail_smtp_status_code_220) - goto init; - } - - bool creds = strlen(smtp->_sesson_cfg->login.email) > 0 && strlen(smtp->_sesson_cfg->login.password) > 0; - bool xoauth_auth = strlen(smtp->_sesson_cfg->login.accessToken) > 0 && smtp->_auth_capability.xoauth2; - bool login_auth = smtp->_auth_capability.login && creds; - bool plain_auth = smtp->_auth_capability.plain && creds; - - if (xoauth_auth || login_auth || plain_auth) - { - if (smtp->_sendCallback) - { - smtpCB(smtp, "", false); - smtpCBP(smtp, esp_mail_str_56, false); - } - - //log in - if (xoauth_auth) - { - if (smtp->_debug) - debugInfoP(esp_mail_str_288); - - if (!smtp->_auth_capability.xoauth2) - return handleSMTPError(smtp, SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED, false); - - if (smtpSendP(smtp, esp_mail_str_289, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - if (smtpSend(smtp, getEncodedToken(smtp).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_auth; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_AUTHEN_FAILED)) - return false; - - return true; - } - else if (plain_auth) - { - - if (smtp->_debug) - debugInfoP(esp_mail_str_241); - - if (smtp->_debug) - { - appendP(s, esp_mail_str_261, true); - s += smtp->_sesson_cfg->login.email; - esp_mail_debug(s.c_str()); - - appendP(s, esp_mail_str_131, false); - for (size_t i = 0; i < strlen(smtp->_sesson_cfg->login.password); i++) - appendP(s, esp_mail_str_183, false); - esp_mail_debug(s.c_str()); - } - - //rfc4616 - const char *usr = smtp->_sesson_cfg->login.email; - const char *psw = smtp->_sesson_cfg->login.password; - int len = strlen(usr) + strlen(psw) + 2; - uint8_t *tmp = new uint8_t[len]; - memset(tmp, 0, len); - int p = 1; - memcpy(tmp + p, usr, strlen(usr)); - p += strlen(usr) + 1; - memcpy(tmp + p, psw, strlen(psw)); - p += strlen(psw); - - std::string s; - appendP(s, esp_mail_str_45, true); - appendP(s, esp_mail_str_131, false); - s += encodeBase64Str(tmp, p); - delete[] tmp; - - if (smtpSend(smtp, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_auth_plain; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_USER_LOGIN_FAILED)) - return false; - - return true; - } - else if (login_auth) - { - if (smtp->_debug) - debugInfoP(esp_mail_str_240); - - if (smtpSendP(smtp, esp_mail_str_4, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_334, SMTP_STATUS_AUTHEN_FAILED)) - return false; - - if (smtp->_debug) - { - appendP(s, esp_mail_str_261, true); - s += smtp->_sesson_cfg->login.email; - esp_mail_debug(s.c_str()); - } - - if (smtpSend(smtp, encodeBase64Str((const unsigned char *)smtp->_sesson_cfg->login.email, strlen(smtp->_sesson_cfg->login.email)).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_login_user; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_334, SMTP_STATUS_USER_LOGIN_FAILED)) - return false; - - if (smtp->_debug) - { - appendP(s, esp_mail_str_261, true); - for (size_t i = 0; i < strlen(smtp->_sesson_cfg->login.password); i++) - appendP(s, esp_mail_str_183, false); - esp_mail_debug(s.c_str()); - } - - if (smtpSend(smtp, encodeBase64Str((const unsigned char *)smtp->_sesson_cfg->login.password, strlen(smtp->_sesson_cfg->login.password)).c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_login_psw; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_235, SMTP_STATUS_PASSWORD_LOGIN_FAILED)) - return false; - - return true; - } - } - - return true; -} - -void ESP_Mail_Client::mimeFromFile(const char *name, std::string &mime) -{ - std::string ext = name; - size_t p = ext.find_last_of("."); - if (p != std::string::npos) - { - ext = ext.substr(p, ext.length() - p); - if (ext.length() > 0) - getMIME(ext.c_str(), mime); - } -} - -bool ESP_Mail_Client::connected(SMTPSession *smtp) -{ - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - { - if (!smtp->httpClient._stream()) - return false; - return smtp->httpClient._stream()->_ns_connected(); - } - else - { - if (!smtp->httpClient.stream()) - return false; - return smtp->httpClient.stream()->connected(); - } -} - -bool ESP_Mail_Client::setSendingResult(SMTPSession *smtp, SMTP_Message *msg, bool result) -{ - if (result) - smtp->_sentSuccessCount++; - else - smtp->_sentFailedCount++; - - if (smtp->_sendCallback) - { - struct esp_mail_smtp_send_status_t status; - status.completed = result; - status.timesstamp = time(nullptr); - status.subject = msg->subject; - status.recipients = msg->_rcp[0].email; - - smtp->sendingResult.add(status); - - smtp->_cbData._sentSuccess = smtp->_sentSuccessCount; - smtp->_cbData._sentFailed = smtp->_sentFailedCount; - } - - return result; -} - -bool ESP_Mail_Client::sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession) -{ - - if (strlen(msg->html.content) > 0 || msg->html.blob.size > 0 || strlen(msg->html.file.name) > 0) - msg->type |= esp_mail_msg_type_html; - - if (strlen(msg->text.content) > 0 || msg->text.blob.size > 0 || strlen(msg->text.file.name) > 0) - msg->type |= esp_mail_msg_type_plain; - - for (size_t i = 0; i < msg->_rfc822.size(); i++) - { - if (strlen(msg->_rfc822[i].html.content) > 0) - msg->_rfc822[i].type |= esp_mail_msg_type_html; - - if (strlen(msg->_rfc822[i].text.content) > 0) - msg->_rfc822[i].type |= esp_mail_msg_type_plain; - } - - return _sendMail(smtp, msg, closeSession); -} - -void ESP_Mail_Client::getMIME(const char *ext, std::string &mime) -{ - mime = ""; - for (int i = 0; i < esp_mail_file_extension_maxType; i++) - { - if (strcmp_P(ext, mimeinfo[i].endsWith) == 0) - { - char *tmp = strP(mimeinfo[i].mimeType); - mime = tmp; - delS(tmp); - break; - } - } -} - -size_t ESP_Mail_Client::numAtt(SMTPSession *smtp, esp_mail_attach_type type, SMTP_Message *msg) -{ - size_t count = 0; - for (size_t i = 0; i < msg->_att.size(); i++) - { - if (msg->_att[i]._int.att_type == type) - count++; - } - return count; -} - -bool ESP_Mail_Client::validEmail(const char *s) -{ - std::string str(s); - auto at = std::find(str.begin(), str.end(), '@'); - auto dot = std::find(at, str.end(), '.'); - return (at != str.end()) && (dot != str.end()); -} -bool ESP_Mail_Client::checkEmail(SMTPSession *smtp, SMTP_Message *msg) -{ - bool validRecipient = false; - - if (!validEmail(msg->sender.email)) - { - errorStatusCB(smtp, SMTP_STATUS_NO_VALID_SENDER_EXISTED); - return setSendingResult(smtp, msg, false); - } - - for (uint8_t i = 0; i < msg->_rcp.size(); i++) - { - if (validEmail(msg->_rcp[i].email)) - validRecipient = true; - } - - if (!validRecipient) - { - errorStatusCB(smtp, SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED); - return setSendingResult(smtp, msg, false); - } - - return true; -} - -bool ESP_Mail_Client::_sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession) -{ - - smtp->_smtpStatus.statusCode = 0; - smtp->_smtpStatus.respCode = 0; - smtp->_smtpStatus.text.clear(); - bool rfc822MSG = false; - - if (!checkEmail(smtp, msg)) - return false; - - smtp->_chunkedEnable = false; - smtp->_chunkCount = 0; - - //new session - if (!smtp->_tcpConnected) - { - if (!smtpAuth(smtp)) - { - closeTCP(smtp); - return setSendingResult(smtp, msg, false); - } - smtp->_sentSuccessCount = 0; - smtp->_sentFailedCount = 0; - smtp->sendingResult.clear(); - } - else - { - //reuse session - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - if (smtp->_sentSuccessCount || smtp->_sentFailedCount) - smtpCBP(smtp, esp_mail_str_267); - else - smtpCBP(smtp, esp_mail_str_208); - } - - if (smtp->_debug) - { - if (smtp->_sentSuccessCount || smtp->_sentFailedCount) - debugInfoP(esp_mail_str_268); - else - debugInfoP(esp_mail_str_207); - } - } - - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - smtpCBP(smtp, esp_mail_str_125); - } - - if (smtp->_debug) - debugInfoP(esp_mail_str_242); - - std::string buf; - std::string buf2; - checkBinaryData(smtp, msg); - - if (msg->priority >= esp_mail_smtp_priority_high && msg->priority <= esp_mail_smtp_priority_low) - { - char *tmp = intStr(msg->priority); - appendP(buf2, esp_mail_str_17, true); - buf2 += tmp; - delS(tmp); - appendP(buf2, esp_mail_str_34, false); - - if (msg->priority == esp_mail_smtp_priority_high) - { - appendP(buf2, esp_mail_str_18, false); - appendP(buf2, esp_mail_str_21, false); - } - else if (msg->priority == esp_mail_smtp_priority_normal) - { - appendP(buf2, esp_mail_str_19, false); - appendP(buf2, esp_mail_str_22, false); - } - else if (msg->priority == esp_mail_smtp_priority_low) - { - appendP(buf2, esp_mail_str_20, false); - appendP(buf2, esp_mail_str_23, false); - } - } - - appendP(buf2, esp_mail_str_10, false); - - if (strlen(msg->sender.name) > 0) - buf2 += msg->sender.name; - - appendP(buf2, esp_mail_str_14, false); - buf2 += msg->sender.email; - appendP(buf2, esp_mail_str_15, false); - appendP(buf2, esp_mail_str_34, false); - - appendP(buf, esp_mail_str_8, true); - appendP(buf, esp_mail_str_14, false); - buf += msg->sender.email; - appendP(buf, esp_mail_str_15, false); - - if (smtp->_send_capability.binaryMIME && smtp->_send_capability.chunking && msg->enable.chunking && (msg->text._int.binary || msg->html._int.binary)) - appendP(buf, esp_mail_str_104, false); - - if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_sender; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_SENDER_FAILED)) - return setSendingResult(smtp, msg, false); - - for (uint8_t i = 0; i < msg->_rcp.size(); i++) - { - if (i == 0) - { - appendP(buf2, esp_mail_str_11, false); - if (strlen(msg->_rcp[i].name) > 0) - buf2 += msg->_rcp[i].name; - - appendP(buf2, esp_mail_str_14, false); - buf2 += msg->_rcp[i].email; - appendP(buf2, esp_mail_str_15, false); - } - else - { - if (strlen(msg->_rcp[i].name) > 0) - { - appendP(buf2, esp_mail_str_263, false); - buf2 += msg->_rcp[i].name; - appendP(buf2, esp_mail_str_14, false); - } - else - appendP(buf2, esp_mail_str_13, false); - buf2 += msg->_rcp[i].email; - appendP(buf2, esp_mail_str_15, false); - } - - if (i == msg->_rcp.size() - 1) - appendP(buf2, esp_mail_str_34, false); - - buf.clear(); - //only address - appendP(buf, esp_mail_str_9, false); - appendP(buf, esp_mail_str_14, false); - buf += msg->_rcp[i].email; - appendP(buf, esp_mail_str_15, false); - - //rfc3461, rfc3464 - if (smtp->_send_capability.dsn) - { - if (msg->response.notify != esp_mail_smtp_notify::esp_mail_smtp_notify_never) - { - appendP(buf, esp_mail_str_262, false); - int opcnt = 0; - if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_success) - { - if (opcnt > 0) - appendP(buf, esp_mail_str_263, false); - appendP(buf, esp_mail_str_264, false); - opcnt++; - } - if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_failure) - { - if (opcnt > 0) - appendP(buf, esp_mail_str_263, false); - appendP(buf, esp_mail_str_265, false); - opcnt++; - } - if (msg->response.notify && esp_mail_smtp_notify::esp_mail_smtp_notify_delay) - { - if (opcnt > 0) - appendP(buf, esp_mail_str_263, false); - appendP(buf, esp_mail_str_266, false); - opcnt++; - } - } - } - - if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) - return setSendingResult(smtp, msg, false); - } - - for (uint8_t i = 0; i < msg->_cc.size(); i++) - { - if (i == 0) - { - appendP(buf2, esp_mail_str_12, false); - appendP(buf2, esp_mail_str_14, false); - buf2 += msg->_cc[i].email; - appendP(buf2, esp_mail_str_15, false); - } - else - { - appendP(buf2, esp_mail_str_13, false); - buf2 += msg->_cc[i].email; - appendP(buf2, esp_mail_str_15, false); - } - - if (i == msg->_cc.size() - 1) - appendP(buf2, esp_mail_str_34, false); - - buf.clear(); - - appendP(buf, esp_mail_str_9, false); - appendP(buf, esp_mail_str_14, false); - buf += msg->_cc[i].email; - appendP(buf, esp_mail_str_15, false); - - if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) - return setSendingResult(smtp, msg, false); - } - - for (uint8_t i = 0; i < msg->_bcc.size(); i++) - { - appendP(buf, esp_mail_str_9, true); - appendP(buf, esp_mail_str_14, false); - buf += msg->_bcc[i].email; - appendP(buf, esp_mail_str_15, false); - if (smtpSend(smtp, buf.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_header_recipient; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED)) - return setSendingResult(smtp, msg, false); - } - - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - smtpCBP(smtp, esp_mail_str_126); - } - - if (smtp->_debug) - debugInfoP(esp_mail_str_243); - - if (smtp->_send_capability.chunking && msg->enable.chunking) - { - smtp->_chunkedEnable = true; - if (!bdat(smtp, msg, buf2.length(), false)) - return false; - } - else - { - if (smtpSendP(smtp, esp_mail_str_16, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_354, SMTP_STATUS_SEND_BODY_FAILED)) - return setSendingResult(smtp, msg, false); - } - - if (smtpSend(smtp, buf2.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - std::string s; - appendP(s, esp_mail_str_24, true); - s += msg->subject; - appendP(s, esp_mail_str_34, false); - - if (msg->_hdr.size() > 0) - { - for (uint8_t k = 0; k < msg->_hdr.size(); k++) - { - s += msg->_hdr[k]; - appendP(s, esp_mail_str_34, false); - } - } - - if (strlen(msg->response.reply_to) > 0) - { - appendP(s, esp_mail_str_184, false); - appendP(s, esp_mail_str_14, false); - s += msg->response.reply_to; - appendP(s, esp_mail_str_15, false); - appendP(s, esp_mail_str_34, false); - } - - if (strlen(msg->response.return_path) > 0) - { - appendP(s, esp_mail_str_46, false); - appendP(s, esp_mail_str_14, false); - s += msg->response.return_path; - appendP(s, esp_mail_str_15, false); - appendP(s, esp_mail_str_34, false); - } - - appendP(s, esp_mail_str_3, false); - - if (!bdat(smtp, msg, s.length(), false)) - return false; - - if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - return sendMSGData(smtp, msg, closeSession, rfc822MSG); -} - -bool ESP_Mail_Client::sendMSGData(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, bool rfc822MSG) -{ - std::string s; - std::string mixed = getBoundary(15); - std::string alt = getBoundary(15); - - if (numAtt(smtp, esp_mail_att_type_attachment, msg) == 0 && msg->_parallel.size() == 0 && msg->_rfc822.size() == 0) - { - if (msg->type == (esp_mail_msg_type_plain | esp_mail_msg_type_html | esp_mail_msg_type_enriched) || numAtt(smtp, esp_mail_att_type_inline, msg) > 0) - { - if (!sendMSG(smtp, msg, alt)) - return setSendingResult(smtp, msg, false); - } - else if (msg->type != esp_mail_msg_type_none) - { - if (!sendPartText(smtp, msg, msg->type, "")) - return setSendingResult(smtp, msg, false); - } - } - else - { - appendP(s, esp_mail_str_1, true); - s += mixed; - appendP(s, esp_mail_str_35, false); - - appendP(s, esp_mail_str_33, false); - s += mixed; - appendP(s, esp_mail_str_34, false); - - if (!bdat(smtp, msg, s.length(), false)) - return false; - - if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - if (!sendMSG(smtp, msg, alt)) - return setSendingResult(smtp, msg, false); - - if (!bdat(smtp, msg, 2, false)) - return false; - - if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - smtpCBP(smtp, esp_mail_str_127); - } - - if (smtp->_debug) - debugInfoP(esp_mail_str_244); - - if (smtp->_sendCallback && numAtt(smtp, esp_mail_att_type_attachment, msg) > 0) - esp_mail_debug(""); - - if (!sendAttachments(smtp, msg, mixed)) - return setSendingResult(smtp, msg, false); - - if (!sendParallelAttachments(smtp, msg, mixed)) - return setSendingResult(smtp, msg, false); - - if (!sendRFC822Msg(smtp, msg, mixed, closeSession, msg->_rfc822.size() > 0)) - return setSendingResult(smtp, msg, false); - - appendP(s, esp_mail_str_33, true); - s += mixed; - appendP(s, esp_mail_str_33, false); - - if (!bdat(smtp, msg, s.length(), false)) - return false; - - if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - } - - if (!rfc822MSG) - { - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - smtpCBP(smtp, esp_mail_str_303); - } - - if (smtp->_debug) - debugInfoP(esp_mail_str_304); - - if (smtp->_chunkedEnable) - { - - if (!bdat(smtp, msg, 0, true)) - return false; - - smtp->_smtp_cmd = esp_mail_smtp_cmd_chunk_termination; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) - return false; - } - else - { - if (smtpSendP(smtp, esp_mail_str_37, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) - return setSendingResult(smtp, msg, false); - } - - setSendingResult(smtp, msg, true); - - if (closeSession) - if (!smtp->closeSession()) - return false; - } - - return true; -} - -bool ESP_Mail_Client::sendRFC822Msg(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, bool closeSession, bool rfc822MSG) -{ - if (msg->_rfc822.size() == 0) - return true; - std::string buf; - for (uint8_t i = 0; i < msg->_rfc822.size(); i++) - { - buf.clear(); - getRFC822PartHeader(smtp, buf, boundary); - - getRFC822MsgEnvelope(smtp, &msg->_rfc822[i], buf); - - if (!bdat(smtp, msg, buf.length(), false)) - return false; - - if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - if (!sendMSGData(smtp, &msg->_rfc822[i], closeSession, rfc822MSG)) - return false; - } - - return true; -} - -void ESP_Mail_Client::getRFC822MsgEnvelope(SMTPSession *smtp, SMTP_Message *msg, std::string &buf) -{ - if (strlen(msg->date) > 0) - { - appendP(buf, esp_mail_str_99, false); - buf += msg->date; - appendP(buf, esp_mail_str_34, false); - } - - if (strlen(msg->from.email) > 0) - { - appendP(buf, esp_mail_str_10, false); - - if (strlen(msg->from.name) > 0) - buf += msg->from.name; - - appendP(buf, esp_mail_str_14, false); - buf += msg->from.email; - appendP(buf, esp_mail_str_15, false); - appendP(buf, esp_mail_str_34, false); - } - - if (strlen(msg->sender.email) > 0) - { - appendP(buf, esp_mail_str_150, false); - - if (strlen(msg->sender.name) > 0) - buf += msg->sender.name; - - appendP(buf, esp_mail_str_14, false); - buf += msg->sender.email; - appendP(buf, esp_mail_str_15, false); - appendP(buf, esp_mail_str_34, false); - } - - if (strlen(msg->response.reply_to) > 0) - { - appendP(buf, esp_mail_str_184, false); - appendP(buf, esp_mail_str_14, false); - buf += msg->response.reply_to; - appendP(buf, esp_mail_str_15, false); - appendP(buf, esp_mail_str_34, false); - } - - if (strlen(msg->response.return_path) > 0) - { - appendP(buf, esp_mail_str_46, false); - appendP(buf, esp_mail_str_14, false); - buf += msg->response.return_path; - appendP(buf, esp_mail_str_15, false); - appendP(buf, esp_mail_str_34, false); - } - - for (uint8_t i = 0; i < msg->_rcp.size(); i++) - { - if (i == 0) - { - appendP(buf, esp_mail_str_11, false); - if (strlen(msg->_rcp[i].name) > 0) - buf += msg->_rcp[i].name; - - appendP(buf, esp_mail_str_14, false); - buf += msg->_rcp[i].email; - appendP(buf, esp_mail_str_15, false); - } - else - { - if (strlen(msg->_rcp[i].name) > 0) - { - appendP(buf, esp_mail_str_263, false); - buf += msg->_rcp[i].name; - appendP(buf, esp_mail_str_14, false); - } - else - appendP(buf, esp_mail_str_13, false); - buf += msg->_rcp[i].email; - appendP(buf, esp_mail_str_15, false); - } - - if (i == msg->_rcp.size() - 1) - appendP(buf, esp_mail_str_34, false); - } - - for (uint8_t i = 0; i < msg->_cc.size(); i++) - { - if (i == 0) - { - appendP(buf, esp_mail_str_12, false); - appendP(buf, esp_mail_str_14, false); - buf += msg->_cc[i].email; - appendP(buf, esp_mail_str_15, false); - } - else - { - appendP(buf, esp_mail_str_13, false); - buf += msg->_cc[i].email; - appendP(buf, esp_mail_str_15, false); - } - - if (i == msg->_cc.size() - 1) - appendP(buf, esp_mail_str_34, false); - } - - for (uint8_t i = 0; i < msg->_bcc.size(); i++) - { - if (i == 0) - { - appendP(buf, esp_mail_str_149, false); - appendP(buf, esp_mail_str_14, false); - buf += msg->_bcc[i].email; - appendP(buf, esp_mail_str_15, false); - } - else - { - appendP(buf, esp_mail_str_13, false); - buf += msg->_bcc[i].email; - appendP(buf, esp_mail_str_15, false); - } - - if (i == msg->_bcc.size() - 1) - appendP(buf, esp_mail_str_34, false); - } - - if (strlen(msg->subject) > 0) - { - appendP(buf, esp_mail_str_279, false); - buf += msg->subject; - appendP(buf, esp_mail_str_34, false); - } - - if (strlen(msg->keyword) > 0) - { - appendP(buf, esp_mail_str_145, false); - buf += msg->keyword; - appendP(buf, esp_mail_str_34, false); - } - - if (strlen(msg->comment) > 0) - { - appendP(buf, esp_mail_str_134, false); - buf += msg->comment; - appendP(buf, esp_mail_str_34, false); - } - - if (strlen(msg->messageID) > 0) - { - appendP(buf, esp_mail_str_274, false); - appendP(buf, esp_mail_str_14, false); - buf += msg->messageID; - appendP(buf, esp_mail_str_15, false); - appendP(buf, esp_mail_str_34, false); - } -} - -bool ESP_Mail_Client::bdat(SMTPSession *smtp, SMTP_Message *msg, int len, bool last) -{ - if (!smtp->_chunkedEnable || !msg->enable.chunking) - return true; - - smtp->_chunkCount++; - - std::string bdat; - appendP(bdat, esp_mail_str_106, true); - char *tmp = intStr(len); - bdat += tmp; - if (last) - appendP(bdat, esp_mail_str_173, false); - delS(tmp); - if (smtpSend(smtp, bdat.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - if (!smtp->_send_capability.pipelining) - { - smtp->_smtp_cmd = esp_mail_smtp_command::esp_mail_smtp_cmd_send_body; - if (!handleSMTPResponse(smtp, esp_mail_smtp_status_code_250, SMTP_STATUS_SEND_BODY_FAILED)) - return setSendingResult(smtp, msg, false); - smtp->_chunkCount = 0; - } - return true; -} - -void ESP_Mail_Client::checkBinaryData(SMTPSession *smtp, SMTP_Message *msg) -{ - if (msg->type & esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type & esp_mail_msg_type_html) - { - if ((msg->type & esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched) > 0) - { - if (strlen(msg->text.transfer_encoding) > 0) - { - if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_binary) == 0) - { - msg->text._int.binary = true; - } - } - } - - if ((msg->type & esp_mail_msg_type_html) > 0) - { - if (strlen(msg->html.transfer_encoding) > 0) - { - if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_binary) == 0) - { - msg->html._int.binary = true; - } - } - } - } - - for (size_t i = 0; i < msg->_att.size(); i++) - { - if (strcmpP(msg->_att[i].descr.transfer_encoding, 0, esp_mail_str_166)) - { - msg->_att[i]._int.binary = true; - } - } -} - -bool ESP_Mail_Client::sendBlob(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att) -{ - if (strcmp(att->descr.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0 && strcmp(att->descr.transfer_encoding, att->descr.content_encoding) != 0) - { - if (!sendBase64(smtp, msg, (const unsigned char *)att->blob.data, att->blob.size, att->_int.flash_blob, att->descr.filename, smtp->_sendCallback != NULL)) - return false; - return true; - } - else - { - if (att->blob.size > 0) - { - size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE; - size_t writeLen = 0; - uint8_t *buf = new uint8_t[chunkSize]; - int pg = 0, _pg = 0; - while (writeLen < att->blob.size) - { - if (writeLen > att->blob.size - chunkSize) - chunkSize = att->blob.size - writeLen; - - if (!bdat(smtp, msg, chunkSize, false)) - break; - memcpy_P(buf, att->blob.data, chunkSize); - if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - break; - - if (smtp->_sendCallback) - { - pg = (float)(100.0f * writeLen / att->blob.size); - if (pg != _pg) - uploadReport(att->descr.filename, pg); - _pg = pg; - } - writeLen += chunkSize; - } - delete[] buf; - if (smtp->_sendCallback && _pg < 100) - uploadReport(att->descr.filename, 100); - - return writeLen >= att->blob.size; - } - } - return false; -} - -bool ESP_Mail_Client::sendFile(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, File &file) -{ - if (strcmp(att->descr.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0 && strcmp(att->descr.transfer_encoding, att->descr.content_encoding) != 0) - { - if (!sendBase64Stream(smtp, msg, file, att->descr.filename, smtp->_sendCallback != NULL)) - return false; - return true; - } - else - { - if (file.size() > 0) - { - size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE; - size_t writeLen = 0; - if (file.size() < chunkSize) - chunkSize = file.size(); - uint8_t *buf = new uint8_t[chunkSize]; - int pg = 0, _pg = 0; - while (writeLen < file.size() && file.available()) - { - if (writeLen > file.size() - chunkSize) - chunkSize = file.size() - writeLen; - size_t readLen = file.read(buf, chunkSize); - if (readLen != chunkSize) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); - break; - } - - if (!bdat(smtp, msg, chunkSize, false)) - break; - - if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - break; - - if (smtp->_sendCallback) - { - pg = (float)(100.0f * writeLen / file.size()); - if (pg != _pg) - uploadReport(att->descr.filename, pg); - _pg = pg; - } - writeLen += chunkSize; - } - delete[] buf; - if (smtp->_sendCallback && _pg < 100) - uploadReport(att->descr.filename, 100); - return writeLen == file.size(); - } - return false; - } - return false; -} - -bool ESP_Mail_Client::sendParallelAttachments(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary) -{ - if (msg->_parallel.size() == 0) - return true; - - std::string buf; - std::string parallel = getBoundary(15); - appendP(buf, esp_mail_str_33, true); - buf += boundary; - appendP(buf, esp_mail_str_34, false); - - appendP(buf, esp_mail_str_28, false); - buf += parallel; - appendP(buf, esp_mail_str_35, false); - - if (!bdat(smtp, msg, buf.length(), false)) - return false; - - if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - if (!sendAttachments(smtp, msg, parallel, true)) - return setSendingResult(smtp, msg, false); - - appendP(buf, esp_mail_str_33, true); - buf += parallel; - appendP(buf, esp_mail_str_33, false); - - if (!bdat(smtp, msg, buf.length(), false)) - return false; - - if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return setSendingResult(smtp, msg, false); - - return true; -} - -bool ESP_Mail_Client::sendAttachments(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, bool parallel) -{ - std::string s; - std::string buf; - int cnt = 0; - - SMTP_Attachment *att = nullptr; - - size_t sz = msg->_att.size(); - if (parallel) - sz = msg->_parallel.size(); - - for (size_t i = 0; i < sz; i++) - { - if (parallel) - att = &msg->_parallel[i]; - else - att = &msg->_att[i]; - - if (att->_int.att_type == esp_mail_att_type_attachment) - { - appendP(s, esp_mail_str_261, true); - s += att->descr.filename; - - if (smtp->_sendCallback) - { - if (cnt > 0) - smtpCB(smtp, ""); - smtpCB(smtp, att->descr.filename); - } - - if (smtp->_debug) - esp_mail_debug(s.c_str()); - - cnt++; - - if (att->file.storage_type == esp_mail_file_storage_type_none) - { - if (!att->blob.data) - continue; - - if (smtp->_sendCallback) - smtpCB(smtp, att->descr.filename); - - if (smtp->_debug) - esp_mail_debug(s.c_str()); - - buf.clear(); - getAttachHeader(buf, boundary, att, att->blob.size); - - if (!bdat(smtp, msg, buf.length(), false)) - return false; - - if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - if (!sendBlob(smtp, msg, att)) - return false; - - if (!bdat(smtp, msg, 2, false)) - return false; - - if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - } - else - { - - if (!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) - _sdOk = sdTest(); - - if (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash) -#if defined(ESP32) - _flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH); -#elif defined(ESP8266) - _flashOk = ESP_MAIL_FLASH_FS.begin(); -#endif - - if ((!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) || (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash)) - { - - if (smtp->_sendCallback) - debugInfoP(esp_mail_str_158); - - if (smtp->_debug) - { - std::string e; - appendP(e, esp_mail_str_185, true); - appendP(e, esp_mail_str_158, false); - esp_mail_debug(e.c_str()); - } - - continue; - } - - if (openFileRead(smtp, msg, att, file, s, buf, boundary, false)) - { - if (file) - { - - if (!sendFile(smtp, msg, att, file)) - return false; - - if (!bdat(smtp, msg, 2, false)) - return false; - - if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - } - } - } - } - } - return true; -} - -bool ESP_Mail_Client::openFileRead(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, File &file, std::string &s, std::string &buf, const std::string &boundary, bool inlined) -{ - bool file_existed = false; - std::string filepath; - - if (strlen(att->file.path) > 0) - { - if (att->file.path[0] != '/') - appendP(filepath, esp_mail_str_202, true); - filepath += att->file.path; - } - - if (att->file.storage_type == esp_mail_file_storage_type_sd) { - file_existed = ESP_MAIL_SD_FS.exists(filepath.c_str()); - } else if (att->file.storage_type == esp_mail_file_storage_type_flash) { - file_existed = ESP_MAIL_FLASH_FS.exists(filepath.c_str()); - } else if (att->file.storage_type == esp_mail_file_storage_type_univ) { - file_existed = ufsp->exists(filepath.c_str()); - } - - if (!file_existed) - { - - if (strlen(att->descr.filename) > 0) - { - filepath.clear(); - if (att->descr.filename[0] != '/') - appendP(filepath, esp_mail_str_202, true); - filepath += att->descr.filename; - } - - if (att->file.storage_type == esp_mail_file_storage_type_sd) { - file_existed = ESP_MAIL_SD_FS.exists(filepath.c_str()); - } else if (att->file.storage_type == esp_mail_file_storage_type_flash) { - file_existed = ESP_MAIL_FLASH_FS.exists(filepath.c_str()); - } else if (att->file.storage_type == esp_mail_file_storage_type_univ) { - file_existed = ufsp->exists(filepath.c_str()); - } - } - - if (!file_existed) - { - if (smtp->_sendCallback) - debugInfoP(esp_mail_str_158); - - if (smtp->_debug) - { - std::string e; - appendP(e, esp_mail_str_185, true); - appendP(e, esp_mail_str_158, false); - esp_mail_debug(e.c_str()); - } - } - - if (file_existed) - { - - buf.clear(); - - if (att->file.storage_type == esp_mail_file_storage_type_sd) { - file = ESP_MAIL_SD_FS.open(filepath.c_str(), FILE_READ); - } else if (att->file.storage_type == esp_mail_file_storage_type_flash) { -#if defined(ESP32) - file = ESP_MAIL_FLASH_FS.open(filepath.c_str(), FILE_READ); -#elif defined(ESP8266) - file = ESP_MAIL_FLASH_FS.open(filepath.c_str(), "r"); -#endif - } else if (att->file.storage_type == esp_mail_file_storage_type_univ) { - file = ufsp->open(filepath.c_str(), "r"); - } - - if (!file) - return false; - - if (inlined) - getInlineHeader(buf, boundary, att, file.size()); - else - getAttachHeader(buf, boundary, att, file.size()); - - if (!bdat(smtp, msg, buf.length(), false)) - return false; - - if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - return true; - } - - return false; -} - -bool ESP_Mail_Client::openFileRead2(SMTPSession *smtp, SMTP_Message *msg, File &file, const char *path, esp_mail_file_storage_type storageType) -{ - bool file_existed = false; - std::string filepath; - - if (strlen(path) > 0) - { - if (path[0] != '/') - appendP(filepath, esp_mail_str_202, true); - filepath += path; - } - - if (storageType == esp_mail_file_storage_type_sd) { - file_existed = ESP_MAIL_SD_FS.exists(filepath.c_str()); - } else if (storageType == esp_mail_file_storage_type_flash) { - file_existed = ESP_MAIL_FLASH_FS.exists(filepath.c_str()); - } else if (storageType == esp_mail_file_storage_type_univ) { - file_existed = ufsp->exists(filepath.c_str()); - } - - if (!file_existed) - { - if (smtp->_sendCallback) - debugInfoP(esp_mail_str_158); - - if (smtp->_debug) - { - std::string e; - appendP(e, esp_mail_str_185, true); - appendP(e, esp_mail_str_158, false); - esp_mail_debug(e.c_str()); - } - } - - if (file_existed) - { - if (storageType == esp_mail_file_storage_type_sd) - file = ESP_MAIL_SD_FS.open(filepath.c_str(), FILE_READ); - else if (storageType == esp_mail_file_storage_type_flash) -#if defined(ESP32) - file = ESP_MAIL_FLASH_FS.open(filepath.c_str(), FILE_READ); -#elif defined(ESP8266) - file = ESP_MAIL_FLASH_FS.open(filepath.c_str(), "r"); -#endif - return true; - } - - return false; -} - -bool ESP_Mail_Client::sendInline(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary, byte type) -{ - size_t num = numAtt(smtp, esp_mail_att_type_inline, msg) > 0; - - if (num > 0) - { - if (smtp->_sendCallback) - { - smtpCB(smtp, ""); - smtpCBP(smtp, esp_mail_str_167); - } - - if (smtp->_debug) - debugInfoP(esp_mail_str_271); - } - - std::string s; - std::string buf; - std::string related = getBoundary(15); - int cnt = 0; - SMTP_Attachment *att = nullptr; - - appendP(s, esp_mail_str_33, true); - s += boundary; - appendP(s, esp_mail_str_34, false); - - appendP(s, esp_mail_str_298, false); - s += related; - appendP(s, esp_mail_str_35, false); - - if (!bdat(smtp, msg, s.length(), false)) - return false; - - if (smtpSend(smtp, s.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - if (!sendPartText(smtp, msg, type, related.c_str())) - return false; - - if (smtp->_sendCallback && numAtt(smtp, esp_mail_att_type_inline, msg) > 0) - esp_mail_debug(""); - - if (num > 0) - { - for (uint8_t i = 0; i < msg->_att.size(); i++) - { - att = &msg->_att[i]; - if (att->_int.att_type == esp_mail_att_type_inline) - { - appendP(s, esp_mail_str_261, true); - s += att->descr.filename; - - if (smtp->_sendCallback) - { - if (cnt > 0) - smtpCB(smtp, ""); - smtpCB(smtp, att->descr.filename); - } - - if (smtp->_debug) - esp_mail_debug(s.c_str()); - - cnt++; - - if (att->file.storage_type == esp_mail_file_storage_type_none) - { - if (!att->blob.data) - continue; - - if (smtp->_sendCallback) - smtpCB(smtp, att->descr.filename); - - if (smtp->_debug) - esp_mail_debug(s.c_str()); - - buf.clear(); - getInlineHeader(buf, related, att, att->blob.size); - - if (!bdat(smtp, msg, buf.length(), false)) - return false; - - if (smtpSend(smtp, buf.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - if (!sendBlob(smtp, msg, att)) - return false; - - if (!bdat(smtp, msg, 2, false)) - return false; - - if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - } - else - { - if (!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) - _sdOk = sdTest(); - - if (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash) -#if defined(ESP32) - _flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH); -#elif defined(ESP8266) - _flashOk = ESP_MAIL_FLASH_FS.begin(); -#endif - - if ((!_sdOk && att->file.storage_type == esp_mail_file_storage_type_sd) || (!_flashOk && att->file.storage_type == esp_mail_file_storage_type_flash)) - { - - if (smtp->_sendCallback) - debugInfoP(esp_mail_str_158); - - if (smtp->_debug) - { - std::string e; - appendP(e, esp_mail_str_185, true); - appendP(e, esp_mail_str_158, false); - esp_mail_debug(e.c_str()); - } - - continue; - } - - if (openFileRead(smtp, msg, att, file, s, buf, related, true)) - { - if (!file) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); - return false; - } - - if (!sendFile(smtp, msg, att, file)) - return false; - - if (!bdat(smtp, msg, 2, false)) - return false; - - if (smtpSendP(smtp, esp_mail_str_34, false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - } - } - } - } - } - - appendP(s, esp_mail_str_34, true); - appendP(s, esp_mail_str_33, false); - s += related; - appendP(s, esp_mail_str_33, false); - appendP(s, esp_mail_str_34, false); - - if (!bdat(smtp, msg, s.length(), false)) - return false; - - if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - return true; -} - -void ESP_Mail_Client::errorStatusCB(SMTPSession *smtp, int error) -{ - smtp->_smtpStatus.statusCode = error; - std::string s; - - if (smtp->_sendCallback) - { - appendP(s, esp_mail_str_53, true); - s += smtp->errorReason().c_str(); - smtpCB(smtp, s.c_str(), false); - } - - if (smtp->_debug) - { - appendP(s, esp_mail_str_185, true); - s += smtp->errorReason().c_str(); - esp_mail_debug(s.c_str()); - } -} - -size_t ESP_Mail_Client::smtpSendP(SMTPSession *smtp, PGM_P v, bool newline) -{ - if (!reconnect(smtp)) - { - closeTCP(smtp); - return 0; - } - - if (!connected(smtp)) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return 0; - } - - if (!smtp->_tcpConnected) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - return 0; - } - - char *tmp = strP(v); - size_t len = 0; - - if (newline) - { - if (smtp->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug(tmp); - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - len = smtp->httpClient._ns_println(tmp); - else - len = smtp->httpClient.stream()->println(tmp); - } - else - { - if (smtp->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug_line(tmp, false); - - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - len = smtp->httpClient._ns_print(tmp); - else - len = smtp->httpClient.stream()->print(tmp); - } - - if (len != strlen(tmp) && len != strlen(tmp) + 2) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - len = 0; - } - - delS(tmp); - - return len; -} - -size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, const char *data, bool newline) -{ - if (!reconnect(smtp)) - { - closeTCP(smtp); - return 0; - } - - if (!connected(smtp)) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return 0; - } - - if (!smtp->_tcpConnected) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - return 0; - } - - size_t len = 0; - - if (newline) - { - if (smtp->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug(data); - - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - len = smtp->httpClient._ns_println(data); - else - len = smtp->httpClient.stream()->println(data); - } - else - { - if (smtp->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug_line(data, false); - - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - len = smtp->httpClient._ns_print(data); - else - len = smtp->httpClient.stream()->print(data); - } - - if (len != strlen(data) && len != strlen(data) + 2) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - len = 0; - } - - return len; -} - -size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, int data, bool newline) -{ - if (!reconnect(smtp)) - { - closeTCP(smtp); - return 0; - } - - if (!connected(smtp)) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return 0; - } - - if (!smtp->_tcpConnected) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - return 0; - } - - char *tmp = intStr(data); - size_t len = 0; - - if (newline) - { - if (smtp->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug(tmp); - - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - len = smtp->httpClient._ns_println(tmp); - else - len = smtp->httpClient.stream()->println(tmp); - } - else - { - if (smtp->_debugLevel > esp_mail_debug_level_2) - esp_mail_debug_line(tmp, false); - - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - len = smtp->httpClient._ns_print(tmp); - else - len = smtp->httpClient.stream()->print(tmp); - } - - if (len != strlen(tmp) && len != strlen(tmp) + 2) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - len = 0; - } - - delS(tmp); - - return len; -} - -size_t ESP_Mail_Client::smtpSend(SMTPSession *smtp, uint8_t *data, size_t size) -{ - if (!reconnect(smtp)) - { - closeTCP(smtp); - return 0; - } - - if (!connected(smtp)) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return 0; - } - - if (!smtp->_tcpConnected) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - return 0; - } - - size_t len = 0; - - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - len = smtp->httpClient._stream()->write(data, size); - else - len = smtp->httpClient.stream()->write(data, size); - - if (len != size) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED); - len = 0; - } - - return len; -} - -bool ESP_Mail_Client::handleSMTPError(SMTPSession *smtp, int err, bool ret) -{ - if (err < 0) - errorStatusCB(smtp, err); - - if (smtp->_tcpConnected) - closeTCP(smtp); - - return ret; -} - -void ESP_Mail_Client::debugInfoP(PGM_P info) -{ - char *tmp = strP(info); - esp_mail_debug(tmp); - delS(tmp); -} - -bool ESP_Mail_Client::sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss) -{ - _sck = sck; - _miso = miso; - _mosi = mosi; - _ss = ss; - _sdConfigSet = true; -#if defined(ESP32) -#if defined(CARD_TYPE_SD) - SPI.begin(_sck, _miso, _mosi, _ss); - return ESP_MAIL_SD_FS.begin(_ss, SPI); -#endif -#elif defined(ESP8266) - return ESP_MAIL_SD_FS.begin(_ss); -#endif - return false; -} - -bool ESP_Mail_Client::sdBegin(void) -{ - _sdConfigSet = false; -#if defined(ESP32) - return ESP_MAIL_SD_FS.begin(); -#elif defined(ESP8266) - return ESP_MAIL_SD_FS.begin(SD_CS_PIN); -#endif - return false; -} - -bool ESP_Mail_Client::sdMMCBegin(const char *mountpoint, bool mode1bit, bool format_if_mount_failed) -{ -#if defined(ESP32) -#if defined(CARD_TYPE_SD_MMC) - _sdConfigSet = true; - sd_mmc_mountpoint = mountpoint; - sd_mmc_mode1bit = mode1bit; - sd_mmc_format_if_mount_failed = format_if_mount_failed; - return ESP_MAIL_SD_FS.begin(mountpoint, mode1bit, format_if_mount_failed); -#endif -#endif - return false; -} - -bool ESP_Mail_Client::sendPartText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, const char *boundary) -{ - std::string header; - - if (strlen(boundary) > 0) - { - appendP(header, esp_mail_str_33, false); - header += boundary; - appendP(header, esp_mail_str_34, false); - } - - if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) - { - if (strlen(msg->text.content_type) > 0) - { - appendP(header, esp_mail_str_25, false); - header += msg->text.content_type; - - if (strlen(msg->text.charSet) > 0) - { - appendP(header, esp_mail_str_97, false); - appendP(header, esp_mail_str_131, false); - appendP(header, esp_mail_str_168, false); - header += msg->text.charSet; - appendP(header, esp_mail_str_136, false); - } - - if (msg->text.flowed) - { - appendP(header, esp_mail_str_97, false); - appendP(header, esp_mail_str_131, false); - appendP(header, esp_mail_str_270, false); - - appendP(header, esp_mail_str_97, false); - appendP(header, esp_mail_str_131, false); - appendP(header, esp_mail_str_110, false); - } - - if (msg->text.embed.enable) - { - appendP(header, esp_mail_str_26, false); - appendP(header, esp_mail_str_164, false); - appendP(header, esp_mail_str_136, false); - char *tmp = getUID(); - msg->text._int.cid = tmp; - delS(tmp); - } - - appendP(header, esp_mail_str_34, false); - } - - if (strlen(msg->text.transfer_encoding) > 0) - { - appendP(header, esp_mail_str_272, false); - header += msg->text.transfer_encoding; - appendP(header, esp_mail_str_34, false); - } - } - else if (type == esp_mail_msg_type_html) - { - if (strlen(msg->text.content_type) > 0) - { - appendP(header, esp_mail_str_25, false); - header += msg->html.content_type; - - if (strlen(msg->html.charSet) > 0) - { - appendP(header, esp_mail_str_97, false); - appendP(header, esp_mail_str_131, false); - appendP(header, esp_mail_str_168, false); - header += msg->html.charSet; - appendP(header, esp_mail_str_136, false); - } - if (msg->html.embed.enable) - { - appendP(header, esp_mail_str_26, false); - appendP(header, esp_mail_str_159, false); - appendP(header, esp_mail_str_136, false); - char *tmp = getUID(); - msg->html._int.cid = tmp; - delS(tmp); - } - appendP(header, esp_mail_str_34, false); - } - - if (strlen(msg->html.transfer_encoding) > 0) - { - appendP(header, esp_mail_str_272, false); - header += msg->html.transfer_encoding; - appendP(header, esp_mail_str_34, false); - } - } - - if ((type == esp_mail_msg_type_html && msg->html.embed.enable) || ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.embed.enable)) - { - - if ((type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) && msg->text.embed.enable) - { - if (msg->text.embed.type == esp_mail_smtp_embed_message_type_attachment) - appendP(header, esp_mail_str_30, false); - else if (msg->text.embed.type == esp_mail_smtp_embed_message_type_inline) - appendP(header, esp_mail_str_299, false); - - if (strlen(msg->text.embed.filename) > 0) - header += msg->text.embed.filename; - else - appendP(header, esp_mail_str_164, false); - appendP(header, esp_mail_str_36, false); - - if (msg->text.embed.type == esp_mail_smtp_embed_message_type_inline) - { - appendP(header, esp_mail_str_300, false); - if (strlen(msg->text.embed.filename) > 0) - header += msg->text.embed.filename; - else - appendP(header, esp_mail_str_159, false); - appendP(header, esp_mail_str_34, false); - - appendP(header, esp_mail_str_301, false); - header += msg->text._int.cid; - appendP(header, esp_mail_str_15, false); - appendP(header, esp_mail_str_34, false); - } - } - else if (type == esp_mail_msg_type_html && msg->html.embed.enable) - { - if (msg->html.embed.type == esp_mail_smtp_embed_message_type_attachment) - appendP(header, esp_mail_str_30, false); - else if (msg->html.embed.type == esp_mail_smtp_embed_message_type_inline) - appendP(header, esp_mail_str_299, false); - - if (strlen(msg->html.embed.filename) > 0) - header += msg->html.embed.filename; - else - appendP(header, esp_mail_str_159, false); - appendP(header, esp_mail_str_36, false); - - if (msg->html.embed.type == esp_mail_smtp_embed_message_type_inline) - { - appendP(header, esp_mail_str_300, false); - if (strlen(msg->html.embed.filename) > 0) - header += msg->html.embed.filename; - else - appendP(header, esp_mail_str_159, false); - appendP(header, esp_mail_str_34, false); - - appendP(header, esp_mail_str_301, false); - header += msg->html._int.cid; - appendP(header, esp_mail_str_15, false); - appendP(header, esp_mail_str_34, false); - } - } - } - - appendP(header, esp_mail_str_34, false); - - if ((msg->text.blob.size > 0 && (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)) || (msg->html.blob.size > 0 && type == esp_mail_msg_type_html)) - { - if (!bdat(smtp, msg, header.length(), false)) - return false; - - if (smtpSend(smtp, header.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - header.clear(); - - if (!sendBlobBody(smtp, msg, type)) - return false; - } - else if ((strlen(msg->text.file.name) > 0 && (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched)) || (strlen(msg->html.file.name) > 0 && type == esp_mail_msg_type_html)) - { - if (!bdat(smtp, msg, header.length(), false)) - return false; - - if (smtpSend(smtp, header.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - header.clear(); - - if (!sendFileBody(smtp, msg, type)) - return false; - } - else - encodingText(smtp, msg, type, header); - - appendP(header, esp_mail_str_34, false); - - if (strlen(boundary) > 0) - appendP(header, esp_mail_str_34, false); - - if (!bdat(smtp, msg, header.length(), false)) - return false; - - if (smtpSend(smtp, header.c_str()) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - return true; -} - -char *ESP_Mail_Client::getUID() -{ - char *tmp = new char[36]; - memset(tmp, 0, 36); - itoa(random(10000000, 20000000), tmp, 10); - return tmp; -} - -bool ESP_Mail_Client::sendBlobBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type) -{ - - if (msg->text.blob.size == 0 && msg->html.blob.size == 0) - return true; - - bool ret = true; - int bufLen = 512; - size_t pos = 0; - int pg = 0, _pg = 0; - - if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) - { - char *tmp = strP(esp_mail_str_325); - - if (strlen(msg->text.transfer_encoding) > 0) - { - if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0) - { - ret = sendBase64(smtp, msg, (const unsigned char *)msg->text.blob.data, msg->text.blob.size, true, tmp, smtp->_sendCallback != NULL); - delS(tmp); - return ret; - } - } - - int len = msg->text.blob.size; - int available = len; - uint8_t *buf = new uint8_t[bufLen + 1]; - while (available) - { - if (available > bufLen) - available = bufLen; - - memcpy_P(buf, msg->text.blob.data + pos, available); - - if (!bdat(smtp, msg, available, false)) - break; - if (smtpSend(smtp, buf, available) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - break; - pos += available; - len -= available; - available = len; - if (smtp->_sendCallback) - { - pg = (float)(100.0f * pos / msg->text.blob.size); - if (pg != _pg) - uploadReport(tmp, pg); - _pg = pg; - } - } - delete[] buf; - delS(tmp); - } - else if (type == esp_mail_message_type::esp_mail_msg_type_html) - { - char *tmp = strP(esp_mail_str_325); - - if (strlen(msg->html.transfer_encoding) > 0) - { - if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0) - { - ret = sendBase64(smtp, msg, (const unsigned char *)msg->html.blob.data, msg->html.blob.size, true, tmp, smtp->_sendCallback != NULL); - delS(tmp); - return ret; - } - } - int len = msg->html.blob.size; - int available = len; - uint8_t *buf = new uint8_t[bufLen + 1]; - while (available) - { - - if (available > bufLen) - available = bufLen; - - memcpy_P(buf, msg->html.blob.data + pos, available); - - if (!bdat(smtp, msg, available, false)) - { - ret = false; - break; - } - - if (smtpSend(smtp, buf, available) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - { - ret = false; - break; - } - pos += available; - len -= available; - available = len; - if (smtp->_sendCallback) - { - pg = (float)(100.0f * pos / msg->html.blob.size); - if (pg != _pg) - uploadReport(tmp, pg); - _pg = pg; - } - } - delete[] buf; - delS(tmp); - } - return ret; -} - -bool ESP_Mail_Client::sendFileBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type) -{ - - if (strlen(msg->text.file.name) == 0 && strlen(msg->html.file.name) == 0) - return true; - - bool ret = true; - size_t chunkSize = ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE; - size_t writeLen = 0; - int pg = 0, _pg = 0; - - if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) - { - - if (!openFileRead2(smtp, msg, file, msg->text.file.name, msg->text.file.type)) - return false; - - char *tmp = strP(esp_mail_str_326); - - if (strlen(msg->text.transfer_encoding) > 0) - { - if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0) - { - ret = sendBase64Stream(smtp, msg, file, tmp, smtp->_sendCallback != NULL); - delS(tmp); - return ret; - } - } - - if (file.size() > 0) - { - - if (file.size() < chunkSize) - chunkSize = file.size(); - uint8_t *buf = new uint8_t[chunkSize]; - while (writeLen < file.size() && file.available()) - { - if (writeLen > file.size() - chunkSize) - chunkSize = file.size() - writeLen; - size_t readLen = file.read(buf, chunkSize); - - if (readLen != chunkSize) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); - break; - } - - if (!bdat(smtp, msg, chunkSize, false)) - { - ret = false; - break; - } - - if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - { - ret = false; - break; - } - - if (smtp->_sendCallback) - { - pg = (float)(100.0f * writeLen / file.size()); - if (pg != _pg) - uploadReport(tmp, pg); - _pg = pg; - } - writeLen += chunkSize; - } - delete[] buf; - if (smtp->_sendCallback && _pg < 100) - uploadReport(tmp, 100); - - delS(tmp); - return ret && writeLen == file.size(); - } - } - else if (type == esp_mail_message_type::esp_mail_msg_type_html) - { - - if (!openFileRead2(smtp, msg, file, msg->html.file.name, msg->html.file.type)) - return false; - - char *tmp = strP(esp_mail_str_326); - - if (strlen(msg->html.transfer_encoding) > 0) - { - if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0) - { - ret = sendBase64Stream(smtp, msg, file, tmp, smtp->_sendCallback != NULL); - delS(tmp); - return ret; - } - } - - if (file.size() > 0) - { - - if (file.size() < chunkSize) - chunkSize = file.size(); - uint8_t *buf = new uint8_t[chunkSize]; - while (writeLen < file.size() && file.available()) - { - if (writeLen > file.size() - chunkSize) - chunkSize = file.size() - writeLen; - size_t readLen = file.read(buf, chunkSize); - - if (readLen != chunkSize) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); - break; - } - - if (!bdat(smtp, msg, chunkSize, false)) - { - ret = false; - break; - } - - if (smtpSend(smtp, buf, chunkSize) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - { - ret = false; - break; - } - - if (smtp->_sendCallback) - { - pg = (float)(100.0f * writeLen / file.size()); - if (pg != _pg) - uploadReport(tmp, pg); - _pg = pg; - } - writeLen += chunkSize; - } - delete[] buf; - if (smtp->_sendCallback && _pg < 100) - uploadReport(tmp, 100); - - delS(tmp); - return ret && writeLen == file.size(); - } - } - - return false; -} - -void ESP_Mail_Client::encodingText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, std::string &content) -{ - if (type == esp_mail_msg_type_plain || type == esp_mail_msg_type_enriched) - { - std::string s = msg->text.content; - - if (msg->text.flowed) - formatFlowedText(s); - - if (strlen(msg->text.transfer_encoding) > 0) - { - if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0) - content += encodeBase64Str((const unsigned char *)s.c_str(), s.length()); - else if (strcmp(msg->text.transfer_encoding, Content_Transfer_Encoding::enc_qp) == 0) - { - char *out = newS(s.length() * 3 + 1); - encodeQP(s.c_str(), out); - content += out; - delS(out); - } - else - content += s; - } - else - content += s; - } - else if (type == esp_mail_message_type::esp_mail_msg_type_html) - { - char *tmp = nullptr; - std::string s = msg->html.content; - std::string fnd, rep; - SMTP_Attachment *att = nullptr; - for (uint8_t i = 0; i < msg->_att.size(); i++) - { - att = &msg->_att[i]; - if (att->_int.att_type == esp_mail_att_type_inline) - { - std::string filename(att->descr.filename); - - size_t found = filename.find_last_of("/\\"); - if (found != std::string::npos) - filename = filename.substr(found + 1); - - appendP(fnd, esp_mail_str_136, true); - fnd += filename; - appendP(fnd, esp_mail_str_136, false); - - appendP(rep, esp_mail_str_136, true); - appendP(rep, esp_mail_str_302, false); - if (strlen(att->descr.content_id) > 0) - rep += att->descr.content_id; - else - rep += att->_int.cid; - appendP(rep, esp_mail_str_136, false); - - tmp = strReplace((char *)s.c_str(), (char *)fnd.c_str(), (char *)rep.c_str()); - s = tmp; - delS(tmp); - } - } - - if (strlen(msg->html.transfer_encoding) > 0) - { - if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_base64) == 0) - content += encodeBase64Str((const unsigned char *)s.c_str(), s.length()); - else if (strcmp(msg->html.transfer_encoding, Content_Transfer_Encoding::enc_qp) == 0) - { - char *out = newS(strlen(msg->html.content) * 3 + 1); - encodeQP(msg->html.content, out); - content += out; - delS(out); - } - else - content += s; - } - else - content += s; - std::string().swap(s); - } -} - -/* Safe string splitter to avoid strsep bugs*/ -void ESP_Mail_Client::splitTk(std::string &str, std::vector &tk, const char *delim) -{ - std::size_t current, previous = 0; - current = str.find(delim, previous); - std::string s; - while (current != std::string::npos) - { - s = str.substr(previous, current - previous); - tk.push_back(s); - previous = current + strlen(delim); - current = str.find(delim, previous); - } - s = str.substr(previous, current - previous); - tk.push_back(s); - std::string().swap(s); -} - -/** Add the soft line break to the long text line (rfc 3676) - * and add Format=flowed parameter in the plain text content-type header. - * We use the existing white space as a part of this soft line break - * and set delSp="no" parameter to the header. - * - * Some servers are not rfc 3676 compliant. - * This causes the text lines are wrapped instead of joined. - * - * Some mail clients trim the space before the line break - * which makes the soft line break cannot be seen. -*/ -void ESP_Mail_Client::formatFlowedText(std::string &content) -{ - int count = 0; - std::string qms; - int j = 0; - std::vector tokens = std::vector(); - char *stk = strP(esp_mail_str_34); - char *qm = strP(esp_mail_str_15); - splitTk(content, tokens, stk); - content.clear(); - for (size_t i = 0; i < tokens.size(); i++) - { - if (tokens[i].length() > 0) - { - j = 0; - qms.clear(); - while (tokens[i][j] == qm[0]) - { - qms += qm; - j++; - } - softBreak(tokens[i], qms.c_str()); - if (count > 0) - content += stk; - content += tokens[i]; - } - else if (count > 0) - content += stk; - count++; - } - - delS(stk); - delS(qm); - tokens.clear(); -} - -void ESP_Mail_Client::softBreak(std::string &content, const char *quoteMarks) -{ - size_t len = 0; - char *stk = strP(esp_mail_str_131); - std::vector tokens = std::vector(); - splitTk(content, tokens, stk); - content.clear(); - for (size_t i = 0; i < tokens.size(); i++) - { - if (tokens[i].length() > 0) - { - if (len + tokens[i].length() + 3 > FLOWED_TEXT_LEN) - { - /* insert soft crlf */ - content += stk; - appendP(content, esp_mail_str_34, false); - - /* insert quote marks */ - if (strlen(quoteMarks) > 0) - content += quoteMarks; - content += tokens[i]; - len = tokens[i].length(); - } - else - { - if (len > 0) - { - content += stk; - len += strlen(stk); - } - content += tokens[i]; - len += tokens[i].length(); - } - } - } - delS(stk); - tokens.clear(); -} - -bool ESP_Mail_Client::sendMSG(SMTPSession *smtp, SMTP_Message *msg, const std::string &boundary) -{ - std::string alt = getBoundary(15); - std::string s; - - if (numAtt(smtp, esp_mail_att_type_inline, msg) > 0) - { - appendP(s, esp_mail_str_297, true); - s += alt; - appendP(s, esp_mail_str_35, false); - - if (!bdat(smtp, msg, s.length(), false)) - return false; - - if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - if (msg->type == esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type == esp_mail_msg_type_html) - { - if (!sendInline(smtp, msg, alt, msg->type)) - return false; - } - else if (msg->type == (esp_mail_msg_type_html | esp_mail_msg_type_enriched | esp_mail_msg_type_plain)) - { - if (!sendPartText(smtp, msg, esp_mail_msg_type_plain, alt.c_str())) - return false; - if (!sendInline(smtp, msg, alt, esp_mail_msg_type_html)) - return false; - } - - appendP(s, esp_mail_str_33, true); - s += alt; - appendP(s, esp_mail_str_33, false); - appendP(s, esp_mail_str_34, false); - - if (!bdat(smtp, msg, s.length(), false)) - return false; - - if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - } - else - { - if (msg->type == esp_mail_msg_type_plain || msg->type == esp_mail_msg_type_enriched || msg->type == esp_mail_msg_type_html) - { - if (!sendPartText(smtp, msg, msg->type, "")) - return false; - } - else if (msg->type == (esp_mail_msg_type_html | esp_mail_msg_type_enriched | esp_mail_msg_type_plain)) - { - appendP(s, esp_mail_str_33, true); - s += boundary; - appendP(s, esp_mail_str_34, false); - appendP(s, esp_mail_str_297, false); - s += alt; - appendP(s, esp_mail_str_35, false); - - if (!bdat(smtp, msg, s.length(), false)) - return false; - - if (smtpSend(smtp, s.c_str(), false) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - if (!sendPartText(smtp, msg, esp_mail_msg_type_plain, alt.c_str())) - return false; - - if (!sendPartText(smtp, msg, esp_mail_msg_type_html, alt.c_str())) - return false; - } - } - return true; -} - -void ESP_Mail_Client::getInlineHeader(std::string &header, const std::string &boundary, SMTP_Attachment *inlineAttach, size_t size) -{ - appendP(header, esp_mail_str_33, false); - header += boundary; - appendP(header, esp_mail_str_34, false); - - appendP(header, esp_mail_str_25, false); - - if (strlen(inlineAttach->descr.mime) == 0) - { - std::string mime; - mimeFromFile(inlineAttach->descr.filename, mime); - if (mime.length() > 0) - header += mime; - else - appendP(header, esp_mail_str_32, false); - } - else - header += inlineAttach->descr.mime; - - appendP(header, esp_mail_str_26, false); - - std::string filename = inlineAttach->descr.filename; - - size_t found = filename.find_last_of("/\\"); - - if (found != std::string::npos) - filename = filename.substr(found + 1); - - header += filename; - appendP(header, esp_mail_str_36, false); - - appendP(header, esp_mail_str_299, false); - header += filename; - appendP(header, esp_mail_str_327, false); - char *tmp = intStr(size); - header += tmp; - delS(tmp); - appendP(header, esp_mail_str_34, false); - - appendP(header, esp_mail_str_300, false); - header += filename; - appendP(header, esp_mail_str_34, false); - - appendP(header, esp_mail_str_301, false); - if (strlen(inlineAttach->descr.content_id) > 0) - header += inlineAttach->descr.content_id; - else - header += inlineAttach->_int.cid; - - appendP(header, esp_mail_str_15, false); - - appendP(header, esp_mail_str_34, false); - - if (strlen(inlineAttach->descr.transfer_encoding) > 0) - { - appendP(header, esp_mail_str_272, false); - header += inlineAttach->descr.transfer_encoding; - appendP(header, esp_mail_str_34, false); - } - appendP(header, esp_mail_str_34, false); - - std::string().swap(filename); -} - -void ESP_Mail_Client::getAttachHeader(std::string &header, const std::string &boundary, SMTP_Attachment *attach, size_t size) -{ - appendP(header, esp_mail_str_33, false); - header += boundary; - appendP(header, esp_mail_str_34, false); - - appendP(header, esp_mail_str_25, false); - - if (strlen(attach->descr.mime) == 0) - { - std::string mime; - mimeFromFile(attach->descr.filename, mime); - if (mime.length() > 0) - header += mime; - else - appendP(header, esp_mail_str_32, false); - } - else - header += attach->descr.mime; - - appendP(header, esp_mail_str_26, false); - - std::string filename = attach->descr.filename; - - size_t found = filename.find_last_of("/\\"); - if (found != std::string::npos) - filename = filename.substr(found + 1); - - header += filename; - appendP(header, esp_mail_str_36, false); - - if (!attach->_int.parallel) - { - appendP(header, esp_mail_str_30, false); - header += filename; - appendP(header, esp_mail_str_327, false); - char *tmp = intStr(size); - header += tmp; - delS(tmp); - appendP(header, esp_mail_str_34, false); - } - - if (strlen(attach->descr.transfer_encoding) > 0) - { - appendP(header, esp_mail_str_272, false); - header += attach->descr.transfer_encoding; - appendP(header, esp_mail_str_34, false); - } - - appendP(header, esp_mail_str_34, false); - - std::string().swap(filename); -} - -void ESP_Mail_Client::getRFC822PartHeader(SMTPSession *smtp, std::string &header, const std::string &boundary) -{ - appendP(header, esp_mail_str_33, false); - header += boundary; - appendP(header, esp_mail_str_34, false); - - appendP(header, esp_mail_str_25, false); - - appendP(header, esp_mail_str_123, false); - appendP(header, esp_mail_str_34, false); - - appendP(header, esp_mail_str_98, false); - - appendP(header, esp_mail_str_34, false); -} - -void ESP_Mail_Client::smtpCBP(SMTPSession *smtp, PGM_P info, bool success) -{ - std::string s; - appendP(s, info, true); - smtp->_cbData._info = s; - smtp->_cbData._success = success; - smtp->_sendCallback(smtp->_cbData); - std::string().swap(s); -} - -void ESP_Mail_Client::smtpCB(SMTPSession *smtp, const char *info, bool success) -{ - smtp->_cbData._info = info; - smtp->_cbData._success = success; - smtp->_sendCallback(smtp->_cbData); -} - -void ESP_Mail_Client::imapCBP(IMAPSession *imap, PGM_P info, bool success) -{ - char *tmp = strP(info); - imap->_cbData._info = tmp; - imap->_cbData._success = success; - imap->_readCallback(imap->_cbData); - delS(tmp); -} - -void ESP_Mail_Client::imapCB(IMAPSession *imap, const char *info, bool success) -{ - imap->_cbData._info = info; - imap->_cbData._success = success; - imap->_readCallback(imap->_cbData); -} - -void ESP_Mail_Client::strcat_c(char *str, char c) -{ - for (; *str; str++) - ; - *str++ = c; - *str++ = 0; -} -int ESP_Mail_Client::strpos(const char *haystack, const char *needle, int offset) -{ - size_t len = strlen(haystack); - size_t len2 = strlen(needle); - if (len == 0 || len < len2 || len2 == 0 || offset >= (int)len || offset < 0) - return -1; - char *_haystack = newS(len - offset + 1); - _haystack[len - offset] = 0; - strncpy(_haystack, haystack + offset, len - offset); - char *p = stristr(_haystack, needle); - int r = -1; - if (p) - r = p - _haystack + offset; - delS(_haystack); - return r; -} - -char *ESP_Mail_Client::stristr(const char *str1, const char *str2) -{ - const char *p1 = str1; - const char *p2 = str2; - const char *r = *p2 == 0 ? str1 : 0; - - while (*p1 != 0 && *p2 != 0) - { - if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) - { - if (r == 0) - r = p1; - p2++; - } - else - { - p2 = str2; - if (r != 0) - p1 = r + 1; - - if (tolower((unsigned char)*p1) == tolower((unsigned char)*p2)) - { - r = p1; - p2++; - } - else - r = 0; - } - - p1++; - } - - return *p2 == 0 ? (char *)r : 0; -} - -char *ESP_Mail_Client::rstrstr(const char *haystack, const char *needle) -{ - size_t needle_length = strlen(needle); - const char *haystack_end = haystack + strlen(haystack) - needle_length; - const char *p; - size_t i; - for (p = haystack_end; p >= haystack; --p) - { - for (i = 0; i < needle_length; ++i) - { - if (p[i] != needle[i]) - goto next; - } - return (char *)p; - next:; - } - return 0; -} - -int ESP_Mail_Client::rstrpos(const char *haystack, const char *needle, int offset) -{ - size_t len = strlen(haystack); - size_t len2 = strlen(needle); - if (len == 0 || len < len2 || len2 == 0 || offset >= (int)len) - return -1; - char *_haystack = newS(len - offset + 1); - _haystack[len - offset] = 0; - strncpy(_haystack, haystack + offset, len - offset); - char *p = rstrstr(_haystack, needle); - int r = -1; - if (p) - r = p - _haystack + offset; - delS(_haystack); - return r; -} - -int ESP_Mail_Client::readLine(WiFiClient *stream, char *buf, int bufLen, bool crlf, int &count) -{ - int ret = -1; - char c = 0; - char _c = 0; - int idx = 0; - if (!stream) - return idx; - while (stream->available() && idx < bufLen) - { - ret = stream->read(); - if (ret > -1) - { - if (idx >= bufLen - 1) - return idx; - - c = (char)ret; - strcat_c(buf, c); - idx++; - count++; - if (_c == '\r' && c == '\n') - { - if (!crlf) - { - buf[idx - 2] = 0; - idx -= 2; - } - return idx; - } - _c = c; - } - if (!stream) - return idx; - } - return idx; -} - -#if defined(ESP32) -int ESP_Mail_Client::_readLine(ESP_Mail_WCS32 *stream, char *buf, int bufLen, bool crlf, int &count) -#elif defined(ESP8266) -int ESP_Mail_Client::_readLine(ESP_Mail::ESP_Mail_WCS *stream, char *buf, int bufLen, bool crlf, int &count) -#endif -{ - int ret = -1; - char c = 0; - char _c = 0; - int idx = 0; - if (!stream) - return idx; - while (stream->_ns_available() && idx < bufLen) - { - ret = stream->_ns_read(); - if (ret > -1) - { - if (idx >= bufLen - 1) - return idx; - - c = (char)ret; - strcat_c(buf, c); - idx++; - count++; - if (_c == '\r' && c == '\n') - { - if (!crlf) - { - buf[idx - 2] = 0; - idx -= 2; - } - return idx; - } - _c = c; - } - if (!stream) - return idx; - } - return idx; -} - -int ESP_Mail_Client::getMSGNUM(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, bool &endSearch, int &nump, const char *key, const char *pc) -{ - int ret = -1; - char c = 0; - int idx = 0; - int num = 0; - while (available(imap) > 0 && idx < bufLen) - { - delay(0); - if (!imap->_secure) - ret = imap->httpClient._stream()->read(); - else - ret = imap->httpClient.stream()->read(); - - if (ret > -1) - { - - if (idx >= bufLen - 1) - return idx; - - c = (char)ret; - - if (c == '\n') - c = ' '; - - strcat_c(buf, c); - idx++; - - if (chunkIdx == 0) - { - if (strcmp(buf, key) == 0) - { - chunkIdx++; - return 0; - } - - if (strposP(buf, esp_mail_imap_response_1, 0) > -1) - goto end_search; - } - else - { - if (c == ' ') - { - imap->_mbif._searchCount++; - if (imap->_config->enable.recent_sort) - { - imap->_msgNum.push_back(atoi(buf)); - if (imap->_msgNum.size() > imap->_config->limit.search) - imap->_msgNum.erase(imap->_msgNum.begin()); - } - else - { - if (imap->_msgNum.size() < imap->_config->limit.search) - imap->_msgNum.push_back(atoi(buf)); - } - - if (imap->_debug) - { - num = (float)(100.0f * imap->_mbif._searchCount / imap->_mbif._msgCount); - if (nump != num) - { - nump = num; - searchReport(num, pc); - } - } - - chunkIdx++; - return idx; - } - else if (c == '$') - { - if (imap->_config->enable.recent_sort) - std::sort(imap->_msgNum.begin(), imap->_msgNum.end(), compFunc); - - goto end_search; - } - } - } - } - - return idx; - -end_search: - - endSearch = true; - int read = available(imap); - - if (!imap->_secure) - idx = imap->httpClient._stream()->readBytes(buf + idx, read); - else - idx = imap->httpClient.stream()->readBytes(buf + idx, read); - - return idx; -} - -struct esp_mail_message_part_info_t *ESP_Mail_Client::cPart(IMAPSession *imap) -{ - return &cHeader(imap)->part_headers[imap->_cPartIdx]; -} - -struct esp_mail_message_header_t *ESP_Mail_Client::cHeader(IMAPSession *imap) -{ - return &imap->_headers[cIdx(imap)]; -} - -void ESP_Mail_Client::handleHeader(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, struct esp_mail_message_header_t &header, int &headerState, int &octetCount) -{ - - char *tmp = nullptr; - if (chunkIdx == 0) - { - if (strposP(buf, esp_mail_str_324, 0) != -1 && buf[0] == '*') - chunkIdx++; - - tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0); - if (tmp) - { - octetCount = 2; - header.header_data_len = atoi(tmp); - delS(tmp); - } - } - else - { - if (octetCount > header.header_data_len + 2) - return; - - if (strcmpP(buf, 0, esp_mail_str_10)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_from; - tmp = subStr(buf, esp_mail_str_10, NULL, 0, -1); - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - else if (strcmpP(buf, 0, esp_mail_str_11)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_to; - tmp = subStr(buf, esp_mail_str_11, NULL, 0, -1); - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - else if (strcmpP(buf, 0, esp_mail_str_276)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_cc; - tmp = subStr(buf, esp_mail_str_276, NULL, 0, -1); - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - else if (strcmpP(buf, 0, esp_mail_str_279)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_subject; - tmp = subStr(buf, esp_mail_str_279, NULL, 0, -1); - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - else if (strcmpP(buf, 0, esp_mail_str_25)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_type; - tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0); - if (tmp) - { - setHeader(imap, buf, header, headerState); - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_172)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_transfer_encoding; - tmp = subStr(buf, esp_mail_str_172, NULL, 0, -1); - if (tmp) - { - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_190)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_accept_language; - tmp = subStr(buf, esp_mail_str_190, NULL, 0, -1); - if (tmp) - { - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_191)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_language; - tmp = subStr(buf, esp_mail_str_191, NULL, 0, -1); - if (tmp) - { - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_273)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_date; - tmp = subStr(buf, esp_mail_str_273, NULL, 0, -1); - if (tmp) - { - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_274)) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_msg_id; - tmp = subStr(buf, esp_mail_str_274, NULL, 0, -1); - if (tmp) - { - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - } - chunkIdx++; - } -} - -void ESP_Mail_Client::setHeader(IMAPSession *imap, char *buf, struct esp_mail_message_header_t &header, int state) -{ - switch (state) - { - case esp_mail_imap_header_state::esp_mail_imap_state_from: - header.from += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_to: - header.to += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_cc: - header.cc += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_subject: - header.subject += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_content_type: - header.content_type += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_content_transfer_encoding: - header.content_transfer_encoding += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_accept_language: - header.accept_language += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_content_language: - header.content_language += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_date: - header.date += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_msg_id: - header.message_id += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_char_set: - header.char_set += buf; - break; - case esp_mail_imap_header_state::esp_mail_imap_state_boundary: - header.boundary += buf; - break; - default: - break; - } -} - -void ESP_Mail_Client::handlePartHeader(IMAPSession *imap, char *buf, int &chunkIdx, struct esp_mail_message_part_info_t &part) -{ - char *tmp = nullptr; - if (chunkIdx == 0) - { - tmp = subStr(buf, esp_mail_imap_response_7, NULL, 0, -1); - if (tmp) - { - delS(tmp); - tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0); - if (tmp) - { - chunkIdx++; - part.octetLen = atoi(tmp); - delS(tmp); - } - } - } - else - { - if (strcmpP(buf, 0, esp_mail_str_25)) - { - tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0); - bool con_type = false; - if (tmp) - { - con_type = true; - part.content_type = tmp; - delS(tmp); - int p1 = strposP(part.content_type.c_str(), esp_mail_imap_composite_media_type_t::multipart, 0); - if (p1 != -1) - { - p1 += strlen(esp_mail_imap_composite_media_type_t::multipart) + 1; - part.multipart = true; - //inline or embedded images - if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::related, p1) != -1) - part.multipart_sub_type = esp_mail_imap_multipart_sub_type_related; - //multiple text formats e.g. plain, html, enriched - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::alternative, p1) != -1) - part.multipart_sub_type = esp_mail_imap_multipart_sub_type_alternative; - //medias - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::parallel, p1) != -1) - part.multipart_sub_type = esp_mail_imap_multipart_sub_type_parallel; - //rfc822 encapsulated - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::digest, p1) != -1) - part.multipart_sub_type = esp_mail_imap_multipart_sub_type_digest; - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::report, p1) != -1) - part.multipart_sub_type = esp_mail_imap_multipart_sub_type_report; - //others can be attachments - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::mixed, p1) != -1) - part.multipart_sub_type = esp_mail_imap_multipart_sub_type_mixed; - } - - p1 = strposP(part.content_type.c_str(), esp_mail_imap_composite_media_type_t::message, 0); - if (p1 != -1) - { - p1 += strlen(esp_mail_imap_composite_media_type_t::message) + 1; - if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::rfc822, p1) != -1) - part.message_sub_type = esp_mail_imap_message_sub_type_rfc822; - else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::Partial, p1) != -1) - part.message_sub_type = esp_mail_imap_message_sub_type_partial; - else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::External_Body, p1) != -1) - part.message_sub_type = esp_mail_imap_message_sub_type_external_body; - else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::delivery_status, p1) != -1) - part.message_sub_type = esp_mail_imap_message_sub_type_delivery_status; - } - - p1 = strpos(part.content_type.c_str(), esp_mail_imap_descrete_media_type_t::text, 0); - if (p1 != -1) - { - p1 += strlen(esp_mail_imap_descrete_media_type_t::text) + 1; - if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::plain, p1) != -1) - part.msg_type = esp_mail_msg_type_plain; - else if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::enriched, p1) != -1) - part.msg_type = esp_mail_msg_type_enriched; - else if (strpos(part.content_type.c_str(), esp_mail_imap_media_text_sub_type_t::html, p1) != -1) - part.msg_type = esp_mail_msg_type_html; - else - part.msg_type = esp_mail_msg_type_plain; - } - } - - if (con_type) - { - if (part.msg_type == esp_mail_msg_type_plain || part.msg_type == esp_mail_msg_type_enriched) - { - tmp = subStr(buf, esp_mail_str_168, esp_mail_str_136, 0); - if (tmp) - { - part.charset = tmp; - delS(tmp); - } - else - { - tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1); - if (tmp) - { - part.charset = tmp; - delS(tmp); - } - } - - if (strposP(buf, esp_mail_str_275, 0) > -1 || strposP(buf, esp_mail_str_270, 0) > -1) - part.plain_flowed = true; - if (strposP(buf, esp_mail_str_259, 0) > -1 || strposP(buf, esp_mail_str_257, 0) > -1) - part.plain_delsp = true; - } - - if (part.charset.length() == 0) - { - tmp = subStr(buf, esp_mail_str_168, esp_mail_str_136, 0); - if (tmp) - { - part.charset = tmp; - delS(tmp); - } - else - { - tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1); - if (tmp) - { - part.charset = tmp; - delS(tmp); - } - } - } - - tmp = subStr(buf, esp_mail_str_170, esp_mail_str_136, 0); - if (tmp) - { - part.name = tmp; - delS(tmp); - } - else - { - tmp = subStr(buf, esp_mail_str_171, NULL, 0, -1); - if (tmp) - { - part.name = tmp; - delS(tmp); - } - } - } - } - else if (strcmpP(buf, 0, esp_mail_str_172)) - { - tmp = subStr(buf, esp_mail_str_172, NULL, 0, -1); - if (tmp) - { - part.content_transfer_encoding = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_174)) - { - tmp = subStr(buf, esp_mail_str_174, NULL, 0, -1); - if (tmp) - { - part.descr = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_175)) - { - tmp = subStr(buf, esp_mail_str_175, esp_mail_str_97, 0); - if (tmp) - { - //don't count altenative part text and html as embedded contents - if (cHeader(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_alternative) - { - part.content_disposition = tmp; - if (strcmp(tmp, esp_mail_imap_content_disposition_type_t::attachment) == 0) - part.attach_type = esp_mail_att_type_attachment; - else if (strcmp(tmp, esp_mail_imap_content_disposition_type_t::inline_) == 0) - part.attach_type = esp_mail_att_type_inline; - } - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_150)) - { - tmp = subStr(buf, esp_mail_str_150, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.sender = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_10)) - { - tmp = subStr(buf, esp_mail_str_10, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.from = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_11)) - { - tmp = subStr(buf, esp_mail_str_11, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.to = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_12)) - { - tmp = subStr(buf, esp_mail_str_12, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.cc = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_184)) - { - tmp = subStr(buf, esp_mail_str_184, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.reply_to = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_134)) - { - tmp = subStr(buf, esp_mail_str_134, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.comment = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_24)) - { - tmp = subStr(buf, esp_mail_str_24, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.subject = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_189)) - { - tmp = subStr(buf, esp_mail_str_189, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.messageID = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_46)) - { - tmp = subStr(buf, esp_mail_str_46, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.return_path = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_99)) - { - tmp = subStr(buf, esp_mail_str_99, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.date = tmp; - delS(tmp); - } - } - else if (strcmpP(buf, 0, esp_mail_str_145)) - { - tmp = subStr(buf, esp_mail_str_145, NULL, 0, -1); - if (tmp) - { - part.rfc822_header.keyword = tmp; - delS(tmp); - } - } - - if (part.content_disposition.length() > 0) - { - tmp = subStr(buf, esp_mail_str_176, esp_mail_str_136, 0); - if (tmp) - { - part.filename = tmp; - delS(tmp); - } - else - { - tmp = subStr(buf, esp_mail_str_177, NULL, 0, -1); - if (tmp) - { - part.filename = tmp; - delS(tmp); - } - } - - tmp = subStr(buf, esp_mail_str_178, esp_mail_str_97, 0); - if (tmp) - { - part.attach_data_size = atoi(tmp); - delS(tmp); - cHeader(imap)->total_attach_data_size += part.attach_data_size; - part.sizeProp = true; - } - else - { - tmp = subStr(buf, esp_mail_str_178, NULL, 0, -1); - if (tmp) - { - part.attach_data_size = atoi(tmp); - delS(tmp); - cHeader(imap)->total_attach_data_size += part.attach_data_size; - part.sizeProp = true; - } - } - - tmp = subStr(buf, esp_mail_str_179, esp_mail_str_136, 0); - if (tmp) - { - part.creation_date = tmp; - delS(tmp); - } - else - { - tmp = subStr(buf, esp_mail_str_180, NULL, 0, -1); - if (tmp) - { - part.creation_date = tmp; - delS(tmp); - } - } - - tmp = subStr(buf, esp_mail_str_181, esp_mail_str_136, 0); - if (tmp) - { - part.modification_date = tmp; - delS(tmp); - } - else - { - tmp = subStr(buf, esp_mail_str_182, NULL, 0, -1); - if (tmp) - { - part.modification_date = tmp; - delS(tmp); - } - } - } - - chunkIdx++; - } -} - -char *ESP_Mail_Client::subStr(const char *buf, PGM_P beginH, PGM_P endH, int beginPos, int endPos) -{ - - char *tmp = nullptr; - int p1 = strposP(buf, beginH, beginPos); - if (p1 != -1) - { - int p2 = -1; - if (endPos == 0) - p2 = strposP(buf, endH, p1 + strlen_P(beginH)); - - if (p2 == -1) - p2 = strlen(buf); - - int len = p2 - p1 - strlen_P(beginH); - tmp = newS(len + 1); - memcpy(tmp, &buf[p1 + strlen_P(beginH)], len); - return tmp; - } - - return nullptr; -} - -void ESP_Mail_Client::handleAuth(SMTPSession *smtp, char *buf) -{ - if (strposP(buf, esp_mail_smtp_response_1, 0) > -1) - { - if (strposP(buf, esp_mail_smtp_response_2, 0) > -1) - smtp->_auth_capability.login = true; - if (strposP(buf, esp_mail_smtp_response_3, 0) > -1) - smtp->_auth_capability.plain = true; - if (strposP(buf, esp_mail_smtp_response_4, 0) > -1) - smtp->_auth_capability.xoauth2 = true; - if (strposP(buf, esp_mail_smtp_response_11, 0) > -1) - smtp->_auth_capability.cram_md5 = true; - if (strposP(buf, esp_mail_smtp_response_12, 0) > -1) - smtp->_auth_capability.digest_md5 = true; - } - else if (strposP(buf, esp_mail_smtp_response_5, 0) > -1) - smtp->_auth_capability.start_tls = true; - else if (strposP(buf, esp_mail_smtp_response_6, 0) > -1) - smtp->_send_capability._8bitMIME = true; - else if (strposP(buf, esp_mail_smtp_response_7, 0) > -1) - smtp->_send_capability.binaryMIME = true; - else if (strposP(buf, esp_mail_smtp_response_8, 0) > -1) - smtp->_send_capability.chunking = true; - else if (strposP(buf, esp_mail_smtp_response_9, 0) > -1) - smtp->_send_capability.utf8 = true; - else if (strposP(buf, esp_mail_smtp_response_10, 0) > -1) - smtp->_send_capability.pipelining = true; - else if (strposP(buf, esp_mail_smtp_response_13, 0) > -1) - smtp->_send_capability.dsn = true; -} - -int ESP_Mail_Client::available(SMTPSession *smtp) -{ - int sz = 0; - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - { - if (smtp->httpClient._stream()) - sz = smtp->httpClient._stream()->_ns_available(); - } - else - { - if (smtp->httpClient.stream()) - sz = smtp->httpClient.stream()->available(); - } - - return sz; -} - -bool ESP_Mail_Client::handleSMTPResponse(SMTPSession *smtp, esp_mail_smtp_status_code respCode, int errCode) -{ - if (!reconnect(smtp)) - return false; - - bool ret = false; - char *response = nullptr; - int readLen = 0; - long dataTime = millis(); - int chunkBufSize = 0; - std::string s, r; - int chunkIndex = 0; - int count = 0; - bool completedResponse = false; - smtp->_smtpStatus.statusCode = 0; - smtp->_smtpStatus.respCode = 0; - smtp->_smtpStatus.text.clear(); - uint8_t minResLen = 5; - struct esp_mail_smtp_response_status_t status; - - chunkBufSize = available(smtp); - - while (smtp->_tcpConnected && chunkBufSize <= 0) - { - if (!reconnect(smtp, dataTime)) - return false; - if (!connected(smtp)) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return false; - } - chunkBufSize = available(smtp); - delay(0); - } - - dataTime = millis(); - - if (chunkBufSize > 1) - { - while (!completedResponse) - { - delay(0); - - if (!reconnect(smtp, dataTime)) - return false; - - if (!connected(smtp)) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return false; - } - - chunkBufSize = available(smtp); - - if (chunkBufSize <= 0) - break; - - if (chunkBufSize > 0) - { - chunkBufSize = 512; - response = newS(chunkBufSize + 1); - - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - readLen = _readLine(smtp->httpClient._stream(), response, chunkBufSize, false, count); - else - readLen = readLine(smtp->httpClient.stream(), response, chunkBufSize, false, count); - - if (readLen) - { - if (smtp->_smtp_cmd != esp_mail_smtp_command::esp_mail_smtp_cmd_initial_state) - { - //sometimes server sent multiple lines response - //sometimes rx buffer may not ready for a while - if (strlen(response) < minResLen) - { - r += response; - chunkBufSize = 0; - while (chunkBufSize == 0) - { - delay(0); - if (!reconnect(smtp, dataTime)) - return false; - chunkBufSize = available(smtp); - } - } - else - { - if (r.length() > 0) - { - r += response; - memset(response, 0, chunkBufSize); - strcpy(response, r.c_str()); - } - - if (smtp->_debugLevel > esp_mail_debug_level_1) - esp_mail_debug((const char *)response); - } - - if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_greeting) - handleAuth(smtp, response); - } - - getResponseStatus(response, respCode, 0, status); - - //get the status code again for unexpected return code - if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_start_tls || status.respCode == 0) - getResponseStatus(response, esp_mail_smtp_status_code_0, 0, status); - - ret = respCode == status.respCode; - smtp->_smtpStatus = status; - - if (status.respCode > 0 && (status.respCode < 400 || status.respCode == respCode)) - ret = true; - - if (smtp->_debug && strlen(response) >= minResLen) - { - appendP(s, esp_mail_str_260, true); - if (smtp->_smtpStatus.respCode != esp_mail_smtp_status_code_334) - s += response; - else - { - //base64 response - size_t olen; - char *decoded = (char *)decodeBase64((const unsigned char *)status.text.c_str(), status.text.length(), &olen); - if (decoded && olen > 0) - { - olen += s.length(); - s += decoded; - s[olen] = 0; - delete[] decoded; - } - } - esp_mail_debug(s.c_str()); - r.clear(); - } - - completedResponse = smtp->_smtpStatus.respCode > 0 && status.text.length() > minResLen; - - if (smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_auth && smtp->_smtpStatus.respCode == esp_mail_smtp_status_code_334) - { - if (authFailed(response, readLen, chunkIndex, 4)) - { - smtp->_smtpStatus.statusCode = -1; - ret = false; - } - } - - chunkIndex++; - - if (smtp->_chunkedEnable && smtp->_smtp_cmd == esp_mail_smtp_command::esp_mail_smtp_cmd_chunk_termination) - completedResponse = smtp->_chunkCount == chunkIndex; - } - delS(response); - } - } - - if (!ret) - handleSMTPError(smtp, errCode, false); - } - - return ret; -} - -void ESP_Mail_Client::getResponseStatus(const char *buf, esp_mail_smtp_status_code respCode, int beginPos, struct esp_mail_smtp_response_status_t &status) -{ - std::string s; - char *tmp = nullptr; - int p1 = 0; - if (respCode > esp_mail_smtp_status_code_0) - { - tmp = intStr((int)respCode); - s = tmp; - appendP(s, esp_mail_str_131, false); - delS(tmp); - p1 = strpos(buf, (const char *)s.c_str(), beginPos); - } - - if (p1 != -1) - { - int ofs = s.length() - 2; - if (ofs < 0) - ofs = 1; - - int p2 = strposP(buf, esp_mail_str_131, p1 + ofs); - - if (p2 < 4 && p2 > -1) - { - tmp = newS(p2 + 1); - memcpy(tmp, &buf[p1], p2); - status.respCode = atoi(tmp); - delS(tmp); - - p1 = p2 + 1; - p2 = strlen(buf); - if (p2 > p1) - { - tmp = newS(p2 + 1); - memcpy(tmp, &buf[p1], p2 - p1); - status.text = tmp; - delS(tmp); - } - } - } -} - -void ESP_Mail_Client::closeTCP(SMTPSession *smtp) -{ - - if (smtp->_tcpConnected) - { - if (smtp->httpClient.stream()) - { - if (connected(smtp)) - { - if (smtp->_sesson_cfg->secure.startTLS || !smtp->_secure) - smtp->httpClient._stream()->stop(); - else - smtp->httpClient.stream()->stop(); - } - } - _lastReconnectMillis = millis(); - } - smtp->_tcpConnected = false; -} - -void ESP_Mail_Client::closeTCP(IMAPSession *imap) -{ - - if (imap->_tcpConnected) - { - if (imap->httpClient.stream()) - { - if (connected(imap)) - { - if (!imap->_secure) - imap->httpClient._stream()->stop(); - else - imap->httpClient.stream()->stop(); - } - } - _lastReconnectMillis = millis(); - } - imap->_tcpConnected = false; -} - -#if defined(ESP32) -void ESP_Mail_Client::setSecure(ESP_Mail_HTTPClient32 &httpClient, ESP_Mail_Session *session, std::shared_ptr caCert) -#elif defined(ESP8266) -void ESP_Mail_Client::setSecure(ESP_Mail_HTTPClient &httpClient, ESP_Mail_Session *session, std::shared_ptr caCert) -#endif -{ - -#if defined(ESP32) - if (httpClient._certType == -1) - { - if (strlen(session->certificate.cert_file) == 0) - { - if (caCert != nullptr) - httpClient.setCACert(caCert.get()); - else - httpClient.setCACert(nullptr); - } - else - { - httpClient.setCertFile(session->certificate.cert_file, session->certificate.cert_file_storage_type); - } - } -#elif defined(ESP8266) - - if (httpClient._certType == -1) - { - -#ifndef USING_AXTLS - if (!MailClient._clockReady && (strlen(session->certificate.cert_file) > 0 || caCert != nullptr)) - { - MailClient.setClock(MailClient._gmtOffset); - httpClient._clockReady = MailClient._clockReady; - } -#endif - if (strlen(session->certificate.cert_file) == 0) - { - if (caCert != nullptr) - httpClient.setCACert(caCert.get()); - else - httpClient.setCACert(nullptr); - } - else - { - httpClient.setCertFile(session->certificate.cert_file, session->certificate.cert_file_storage_type, MailClient._sdPin); - } - } -#endif -} - -bool ESP_Mail_Client::ethLinkUp() -{ - bool ret = false; -#if defined(ESP32) - char *ip = strP(esp_mail_str_328); - if (strcmp(ETH.localIP().toString().c_str(), ip) != 0) -// ret = ETH.linkUp(); - ret = true; - delS(ip); -#endif - return ret; -} - -bool ESP_Mail_Client::reconnect(SMTPSession *smtp, unsigned long dataTime) -{ - - bool status = WiFi.status() == WL_CONNECTED || ethLinkUp(); - - if (dataTime > 0) - { - if (millis() - dataTime > smtp->httpClient.tcpTimeout) - { - closeTCP(smtp); - errorStatusCB(smtp, MAIL_CLIENT_ERROR_READ_TIMEOUT); - return false; - } - } - - if (!status) - { - if (smtp->_tcpConnected) - closeTCP(smtp); - - errorStatusCB(smtp, MAIL_CLIENT_ERROR_CONNECTION_LOST); - - if (millis() - _lastReconnectMillis > _reconnectTimeout && !smtp->_tcpConnected) - { -#if defined(ESP32) - esp_wifi_connect(); -#elif defined(ESP8266) - WiFi.reconnect(); -#endif - _lastReconnectMillis = millis(); - } - - status = WiFi.status() == WL_CONNECTED || ethLinkUp(); - } - - return status; -} - -bool ESP_Mail_Client::reconnect(IMAPSession *imap, unsigned long dataTime, bool downloadRequest) -{ - - bool status = WiFi.status() == WL_CONNECTED || ethLinkUp(); - - if (dataTime > 0) - { - if (millis() - dataTime > imap->httpClient.tcpTimeout) - { - - closeTCP(imap); - - if (imap->_headers.size() > 0) - { - if (downloadRequest) - { - errorStatusCB(imap, IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT); - if (cHeader(imap)->part_headers.size() > 0) - cPart(imap)->download_error = imap->errorReason().c_str(); - } - else - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_READ_TIMEOUT); - cHeader(imap)->error_msg = imap->errorReason().c_str(); - } - } - return false; - } - } - - if (!status) - { - - if (imap->_tcpConnected) - closeTCP(imap); - - errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); - - if (imap->_headers.size() > 0) - { - if (downloadRequest) - cPart(imap)->download_error = imap->errorReason().c_str(); - else - cHeader(imap)->error_msg = imap->errorReason().c_str(); - } - - if (millis() - _lastReconnectMillis > _reconnectTimeout && !imap->_tcpConnected) - { -#if defined(ESP32) - esp_wifi_connect(); -#elif defined(ESP8266) - WiFi.reconnect(); -#endif - _lastReconnectMillis = millis(); - } - - status = WiFi.status() == WL_CONNECTED || ethLinkUp(); - } - - return status; -} - -void ESP_Mail_Client::delS(char *p) -{ - if (p != nullptr) - delete[] p; -} - -char *ESP_Mail_Client::newS(size_t len) -{ - char *p = new char[len]; - memset(p, 0, len); - return p; -} - -char *ESP_Mail_Client::newS(char *p, size_t len) -{ - delS(p); - p = newS(len); - return p; -} - -char *ESP_Mail_Client::newS(char *p, size_t len, char *d) -{ - delS(p); - p = newS(len); - strcpy(p, d); - return p; -} - -bool ESP_Mail_Client::strcmpP(const char *buf, int ofs, PGM_P beginH) -{ - char *tmp = nullptr; - if (ofs < 0) - { - int p = strposP(buf, beginH, 0); - if (p == -1) - return false; - ofs = p; - } - tmp = strP(beginH); - char *tmp2 = newS(strlen_P(beginH) + 1); - memcpy(tmp2, &buf[ofs], strlen_P(beginH)); - tmp2[strlen_P(beginH)] = 0; - bool ret = (strcasecmp(tmp, tmp2) == 0); - delS(tmp); - delS(tmp2); - return ret; -} - -int ESP_Mail_Client::strposP(const char *buf, PGM_P beginH, int ofs) -{ - char *tmp = strP(beginH); - int p = strpos(buf, tmp, ofs); - delS(tmp); - return p; -} - -char *ESP_Mail_Client::strP(PGM_P pgm) -{ - size_t len = strlen_P(pgm) + 1; - char *buf = newS(len); - strcpy_P(buf, pgm); - buf[len - 1] = 0; - return buf; -} - -void ESP_Mail_Client::appendP(std::string &buf, PGM_P p, bool empty) -{ - if (empty) - buf.clear(); - char *b = strP(p); - buf += b; - delS(b); -} - -char *ESP_Mail_Client::intStr(int value) -{ - char *buf = newS(36); - memset(buf, 0, 36); - itoa(value, buf, 10); - return buf; -} - -int ESP_Mail_Client::available(IMAPSession *imap) -{ - int sz = 0; - if (!imap->_secure) - { - if (imap->httpClient._stream()) - sz = imap->httpClient._stream()->_ns_available(); - } - else - { - if (imap->httpClient.stream()) - sz = imap->httpClient.stream()->available(); - } - return sz; -} - -bool ESP_Mail_Client::handleIMAPResponse(IMAPSession *imap, int errCode, bool closeSession) -{ - - if (!reconnect(imap)) - return false; - - esp_mail_imap_response_status imapResp = esp_mail_imap_response_status::esp_mail_imap_resp_unknown; - char *response = nullptr; - int readLen = 0; - long dataTime = millis(); - int chunkBufSize = available(imap); - int chunkIdx = 0; - std::string s; - bool completedResponse = false; - bool endSearch = false; - struct esp_mail_message_header_t header; - struct esp_mail_message_part_info_t part; - - std::string filePath = ""; - bool downloadRequest = false; - int reportState = 0; - int octetCount = 0; - int octetLength = 0; - int oCount = 0; - bool tmo = false; - int headerState = 0; - int scnt = 0; - int dcnt = -1; - char *skey = nullptr; - char *spc = nullptr; - char *lastBuf = nullptr; - char *tmp = nullptr; - bool crLF = imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text && strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31); - - while (imap->_tcpConnected && chunkBufSize <= 0) - { - if (!reconnect(imap, dataTime)) - return false; - if (!connected(imap)) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return false; - } - chunkBufSize = available(imap); - delay(0); - } - - dataTime = millis(); - - if (chunkBufSize > 1) - { - if (imap->_imap_cmd == esp_mail_imap_cmd_examine) - { - imap->_mbif.clear(); - imap->_mbif._msgCount = 0; - imap->_nextUID = ""; - } - - if (imap->_imap_cmd == esp_mail_imap_cmd_search) - { - imap->_mbif._searchCount = 0; - imap->_msgNum.clear(); - } - - chunkBufSize = 512; - response = newS(chunkBufSize + 1); - - if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search) - { - skey = strP(esp_mail_imap_response_6); - spc = strP(esp_mail_str_92); - } - - if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) - lastBuf = newS(BASE64_CHUNKED_LEN + 1); - - while (!completedResponse) - { - delay(0); - if (!reconnect(imap, dataTime) || !connected(imap)) - { - if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search) - { - delS(skey); - delS(spc); - } - - if (!connected(imap)) - { - errorStatusCB(imap, MAIL_CLIENT_ERROR_CONNECTION_LOST); - return false; - } - return false; - } - chunkBufSize = available(imap); - - if (chunkBufSize > 0) - { - chunkBufSize = 512; - - if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search) - { - readLen = getMSGNUM(imap, response, chunkBufSize, chunkIdx, endSearch, scnt, skey, spc); - imap->_mbif._availableItems = imap->_msgNum.size(); - } - else - { - if (!imap->_secure) - readLen = _readLine(imap->httpClient._stream(), response, chunkBufSize, crLF, octetCount); - else - readLen = readLine(imap->httpClient.stream(), response, chunkBufSize, crLF, octetCount); - } - - if (readLen) - { - - if (imap->_debugLevel > esp_mail_debug_level_1) - { - if (imap->_imap_cmd != esp_mail_imap_cmd_search && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_text && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_attachment && imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_inline) - esp_mail_debug((const char *)response); - } - - if (imap->_imap_cmd != esp_mail_imap_cmd_search || (imap->_imap_cmd == esp_mail_imap_cmd_search && endSearch)) - imapResp = imapResponseStatus(imap, response); - - if (imapResp != esp_mail_imap_response_status::esp_mail_imap_resp_unknown) - { - if (imap->_debugLevel > esp_mail_debug_level_1) - { - if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) - esp_mail_debug((const char *)response); - } - - if (imap->_imap_cmd == esp_mail_imap_cmd_close) - completedResponse = true; - else - { - //some IMAP servers advertise CAPABILITY in their responses - //try to read the next available response - memset(response, 0, chunkBufSize); - if (!imap->_secure) - readLen = _readLine(imap->httpClient._stream(), response, chunkBufSize, true, octetCount); - else - readLen = readLine(imap->httpClient.stream(), response, chunkBufSize, true, octetCount); - if (readLen) - { - completedResponse = false; - imapResp = imapResponseStatus(imap, response); - if (imapResp > esp_mail_imap_response_status::esp_mail_imap_resp_unknown) - completedResponse = true; - } - else - completedResponse = true; - } - } - else - { - if (imap->_imap_cmd == esp_mail_imap_cmd_auth) - { - if (authFailed(response, readLen, chunkIdx, 2)) - completedResponse = true; - } - else if (imap->_imap_cmd == esp_mail_imap_cmd_capability) - handleCapability(imap, response, chunkIdx); - else if (imap->_imap_cmd == esp_mail_imap_cmd_list) - handleFolders(imap, response); - else if (imap->_imap_cmd == esp_mail_imap_cmd_select || imap->_imap_cmd == esp_mail_imap_cmd_examine) - handleExamine(imap, response); - else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header) - { - char *tmp = intStr(cMSG(imap)); - header.message_uid = tmp; - delS(tmp); - - tmp = intStr(imap->_totalRead); - header.message_no = tmp; - delS(tmp); - - int _st = headerState; - handleHeader(imap, response, readLen, chunkIdx, header, headerState, octetCount); - if (_st == headerState && headerState > 0 && octetCount <= header.header_data_len) - setHeader(imap, response, header, headerState); - } - else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_mime) - handlePartHeader(imap, response, chunkIdx, part); - else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text) - decodeText(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetLength, octetCount, dcnt); - else if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) - { - - if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31)) - { - //multi-line chunked base64 string attachment handle - if (octetCount < octetLength && readLen < BASE64_CHUNKED_LEN) - { - if (strlen(lastBuf) > 0) - { - tmp = newS(readLen + strlen(lastBuf) + 2); - strcpy(tmp, lastBuf); - strcat(tmp, response); - readLen = strlen(tmp); - tmo = handleAttachment(imap, tmp, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt); - delS(tmp); - memset(lastBuf, 0, BASE64_CHUNKED_LEN + 1); - if (!tmo) - break; - } - else if (readLen < BASE64_CHUNKED_LEN + 1) - strcpy(lastBuf, response); - } - else - { - tmo = handleAttachment(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt); - if (!tmo) - break; - } - } - else - tmo = handleAttachment(imap, response, readLen, chunkIdx, file, filePath, downloadRequest, octetCount, octetLength, oCount, reportState, dcnt); - } - dataTime = millis(); - } - } - memset(response, 0, chunkBufSize); - } - } - delS(response); - if (imap->_imap_cmd == esp_mail_imap_command::esp_mail_imap_cmd_search) - { - if (imap->_debug && scnt > 0 && scnt < 100) - searchReport(100, spc); - delS(skey); - delS(spc); - } - if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment) - delS(lastBuf); - } - - if ((imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header && header.header_data_len == 0) || imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_no) - { - if (imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_no) - imap->_imapStatus.statusCode = IMAP_STATUS_IMAP_RESPONSE_FAILED; - else - imap->_imapStatus.statusCode = IMAP_STATUS_NO_MESSAGE; - - if (imap->_readCallback) - { - std::string s; - appendP(s, esp_mail_str_53, true); - s += imap->errorReason().c_str(); - imapCB(imap, s.c_str(), false); - } - - if (imap->_debug) - { - std::string s; - appendP(s, esp_mail_str_185, true); - s += imap->errorReason().c_str(); - esp_mail_debug_line(s.c_str(), true); - } - - return false; - } - - if (imapResp == esp_mail_imap_response_status::esp_mail_imap_resp_ok) - { - if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_header) - { - char *buf = newS(header.content_type.length() + 1); - strcpy(buf, header.content_type.c_str()); - header.content_type.clear(); - - tmp = subStr(buf, esp_mail_str_25, esp_mail_str_97, 0); - if (tmp) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_content_type; - setHeader(imap, tmp, header, headerState); - delS(tmp); - - int p1 = strposP(header.content_type.c_str(), esp_mail_imap_composite_media_type_t::multipart, 0); - if (p1 != -1) - { - p1 += strlen(esp_mail_imap_composite_media_type_t::multipart) + 1; - header.multipart = true; - //inline or embedded images - if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::related, p1) != -1) - header.multipart_sub_type = esp_mail_imap_multipart_sub_type_related; - //multiple text formats e.g. plain, html, enriched - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::alternative, p1) != -1) - header.multipart_sub_type = esp_mail_imap_multipart_sub_type_alternative; - //medias - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::parallel, p1) != -1) - header.multipart_sub_type = esp_mail_imap_multipart_sub_type_parallel; - //rfc822 encapsulated - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::digest, p1) != -1) - header.multipart_sub_type = esp_mail_imap_multipart_sub_type_digest; - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::report, p1) != -1) - header.multipart_sub_type = esp_mail_imap_multipart_sub_type_report; - //others can be attachments - else if (strpos(part.content_type.c_str(), esp_mail_imap_multipart_sub_type_t::mixed, p1) != -1) - header.multipart_sub_type = esp_mail_imap_multipart_sub_type_mixed; - } - - p1 = strposP(header.content_type.c_str(), esp_mail_imap_composite_media_type_t::message, 0); - if (p1 != -1) - { - p1 += strlen(esp_mail_imap_composite_media_type_t::message) + 1; - if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::rfc822, p1) != -1) - { - header.rfc822_part = true; - header.message_sub_type = esp_mail_imap_message_sub_type_rfc822; - } - else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::Partial, p1) != -1) - header.message_sub_type = esp_mail_imap_message_sub_type_partial; - else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::External_Body, p1) != -1) - header.message_sub_type = esp_mail_imap_message_sub_type_external_body; - else if (strpos(part.content_type.c_str(), esp_mail_imap_message_sub_type_t::delivery_status, p1) != -1) - header.message_sub_type = esp_mail_imap_message_sub_type_delivery_status; - } - - tmp = subStr(buf, esp_mail_str_169, NULL, 0, -1); - if (tmp) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_char_set; - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - - if (header.multipart) - { - if (strcmpP(buf, 0, esp_mail_str_277)) - { - tmp = subStr(buf, esp_mail_str_277, esp_mail_str_136, 0); - if (tmp) - { - headerState = esp_mail_imap_header_state::esp_mail_imap_state_boundary; - setHeader(imap, tmp, header, headerState); - delS(tmp); - } - } - } - } - - delS(buf); - - decodeHeader(header.from, header.from_charset); - decodeHeader(header.to, header.to_charset); - decodeHeader(header.cc, header.cc_charset); - decodeHeader(header.subject, header.subject_charset); - - imap->_headers.push_back(header); - } - - if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_mime) - { - //expect the octet length in the response for the existent part - if (part.octetLen > 0) - { - - part.partNumStr = cHeader(imap)->partNumStr; - part.partNumFetchStr = cHeader(imap)->partNumStr; - if (cHeader(imap)->part_headers.size() > 0) - { - - struct esp_mail_message_part_info_t *_part = &cHeader(imap)->part_headers[cHeader(imap)->part_headers.size() - 1]; - bool rfc822_body_subtype = _part->message_sub_type == esp_mail_imap_message_sub_type_rfc822; - - if (rfc822_body_subtype) - { - if (!_part->rfc822_part) - { - //additional rfc822 message header, store it to the rfc822 part header - _part->rfc822_part = true; - _part->rfc822_header = part.rfc822_header; - imap->_rfc822_part_count++; - _part->rfc822_msg_Idx = imap->_rfc822_part_count; - } - } - } - - cHeader(imap)->part_headers.push_back(part); - cHeader(imap)->message_data_count = cHeader(imap)->part_headers.size(); - - if (part.msg_type == esp_mail_msg_type_plain || part.msg_type == esp_mail_msg_type_enriched || part.msg_type == esp_mail_msg_type_html || part.attach_type == esp_mail_att_type_none || (part.attach_type == esp_mail_att_type_attachment && imap->_config->download.attachment) || (part.attach_type == esp_mail_att_type_inline && imap->_config->download.inlineImg)) - { - if (part.message_sub_type != esp_mail_imap_message_sub_type_rfc822) - { - if (part.attach_type != esp_mail_att_type_none && cHeader(imap)->multipart_sub_type != esp_mail_imap_multipart_sub_type_alternative) - cHeader(imap)->attachment_count++; - } - } - } - else - { - //nonexistent part - //return false to exit the loop without closing the connection - if (closeSession) - imap->closeSession(); - return false; - } - } - - if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) - { - if (cPart(imap)->file_open_write) - file.close(); - } - - if (imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_text) - cPart(imap)->text[cPart(imap)->textLen] = 0; - } - else - { - //some server responses NO and should exit (false) from MIME feching loop without - //closing the session - if (imap->_imap_cmd != esp_mail_imap_cmd_fetch_body_mime) - return handleIMAPError(imap, errCode, false); - - if (closeSession) - imap->closeSession(); - return false; - } - - return true; -} - -void ESP_Mail_Client::saveHeader(IMAPSession *imap) -{ - - std::string headerFilePath; - prepareFilePath(imap, headerFilePath, true); - if (imap->_storageType == esp_mail_file_storage_type_sd && !_sdOk) - _sdOk = sdTest(); - else if (imap->_storageType == esp_mail_file_storage_type_flash && !_flashOk) -#if defined(ESP32) - _flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH); -#elif defined(ESP8266) - _flashOk = ESP_MAIL_FLASH_FS.begin(); -#endif - - if (_sdOk || _flashOk) - { - if (file) - file.close(); - - if (imap->_storageType == esp_mail_file_storage_type_sd) { - file = ESP_MAIL_SD_FS.open(headerFilePath.c_str(), FILE_WRITE); - } else if (imap->_storageType == esp_mail_file_storage_type_flash) { -#if defined(ESP32) - file = ESP_MAIL_FLASH_FS.open(headerFilePath.c_str(), FILE_WRITE); -#elif defined(ESP8266) - file = ESP_MAIL_FLASH_FS.open(headerFilePath.c_str(), "w"); -#endif - } else if (imap->_storageType == esp_mail_file_storage_type_univ) { - file = ufsp->open(headerFilePath.c_str(), "w"); - } - - if (file) - { - std::string s; - appendP(s, esp_mail_str_99, true); - file.print(s.c_str()); - file.println(cHeader(imap)->date.c_str()); - - appendP(s, esp_mail_str_100, true); - file.print(s.c_str()); - if (imap->_uidSearch) - file.println(cMSG(imap)); - else - file.println(); - - appendP(s, esp_mail_str_101, true); - file.print(s.c_str()); - file.println(cMSG(imap)); - - appendP(s, esp_mail_str_102, true); - file.print(s.c_str()); - file.println(cHeader(imap)->accept_language.c_str()); - - appendP(s, esp_mail_str_103, true); - file.print(s.c_str()); - file.println(cHeader(imap)->content_language.c_str()); - - appendP(s, esp_mail_str_10, true); - file.print(s.c_str()); - file.println(cHeader(imap)->from.c_str()); - - appendP(s, esp_mail_str_105, true); - file.print(s.c_str()); - file.println(cHeader(imap)->from_charset.c_str()); - - appendP(s, esp_mail_str_11, true); - file.print(s.c_str()); - file.println(cHeader(imap)->to.c_str()); - - appendP(s, esp_mail_str_107, true); - file.print(s.c_str()); - file.println(cHeader(imap)->to_charset.c_str()); - - appendP(s, esp_mail_str_108, true); - file.print(s.c_str()); - file.println(cHeader(imap)->cc.c_str()); - - appendP(s, esp_mail_str_109, true); - file.print(s.c_str()); - file.println(cHeader(imap)->cc_charset.c_str()); - - appendP(s, esp_mail_str_24, true); - file.print(s.c_str()); - file.println(cHeader(imap)->subject.c_str()); - - appendP(s, esp_mail_str_111, true); - file.print(s.c_str()); - file.println(cHeader(imap)->subject_charset.c_str()); - - appendP(s, esp_mail_str_112, true); - file.print(s.c_str()); - file.println(cPart(imap)->charset.c_str()); - - if (cHeader(imap)->attachment_count > 0) - { - - appendP(s, esp_mail_str_113, true); - file.print(s.c_str()); - file.println(cHeader(imap)->attachment_count); - - for (int j = 0; j < cHeader(imap)->attachment_count; j++) - { - if (imap->_headers[cIdx(imap)].part_headers[j].attach_type == esp_mail_att_type_none || imap->_headers[cIdx(imap)].part_headers[j].rfc822_part) - continue; - struct esp_mail_attacment_info_t att; - att.filename = imap->_headers[cIdx(imap)].part_headers[j].filename.c_str(); - att.mime = imap->_headers[cIdx(imap)].part_headers[j].content_type.c_str(); - att.name = imap->_headers[cIdx(imap)].part_headers[j].name.c_str(); - att.size = imap->_headers[cIdx(imap)].part_headers[j].attach_data_size; - att.creationDate = imap->_headers[cIdx(imap)].part_headers[j].creation_date.c_str(); - att.type = imap->_headers[cIdx(imap)].part_headers[j].attach_type; - - appendP(s, esp_mail_str_114, true); - file.print(s.c_str()); - file.println(j + 1); - - appendP(s, esp_mail_str_115, true); - file.print(s.c_str()); - file.println(att.filename); - - appendP(s, esp_mail_str_116, true); - file.print(s.c_str()); - file.println(att.name); - - appendP(s, esp_mail_str_117, true); - file.print(s.c_str()); - file.println(att.size); - - appendP(s, esp_mail_str_118, true); - file.print(s.c_str()); - file.println(att.mime); - - appendP(s, esp_mail_str_119, true); - file.print(s.c_str()); - file.println(att.creationDate); - } - } - - file.close(); - } - imap->_headerSaved = true; - } -} - -esp_mail_imap_response_status ESP_Mail_Client::imapResponseStatus(IMAPSession *imap, char *response) -{ - imap->_imapStatus.text.clear(); - if (strposP(response, esp_mail_imap_response_1, 0) > -1) - return esp_mail_imap_response_status::esp_mail_imap_resp_ok; - else if (strposP(response, esp_mail_imap_response_2, 0) > -1) - { - imap->_imapStatus.text = response; - imap->_imapStatus.text = imap->_imapStatus.text.substr(strlen_P(esp_mail_imap_response_2)); - return esp_mail_imap_response_status::esp_mail_imap_resp_no; - } - else if (strposP(response, esp_mail_imap_response_3, 0) > -1) - { - imap->_imapStatus.text = response; - imap->_imapStatus.text = imap->_imapStatus.text.substr(strlen_P(esp_mail_imap_response_3)); - return esp_mail_imap_response_status::esp_mail_imap_resp_bad; - } - return esp_mail_imap_response_status::esp_mail_imap_resp_unknown; -} - -void ESP_Mail_Client::decodeHeader(std::string &headerField, std::string &headerEnc) -{ - - size_t p1 = 0, p2 = 0; - - while (headerField[p1] == ' ' && p1 < headerField.length() - 1) - p1++; - - if (headerField[p1] == '=' && headerField[p1 + 1] == '?') - { - p2 = headerField.find("?", p1 + 2); - if (p2 != std::string::npos) - headerEnc = headerField.substr(p1 + 2, p2 - p1 - 2); - } - - int bufSize = 512; - char *buf = newS(bufSize); - - RFC2047Decoder.rfc2047Decode(buf, headerField.c_str(), bufSize); - - if (getEncodingFromCharset(headerEnc.c_str()) == esp_mail_char_decoding_scheme_iso8859_1) - { - int len = strlen(buf); - int olen = (len + 1) * 2; - unsigned char *out = (unsigned char *)newS(olen); - decodeLatin1_UTF8(out, &olen, (unsigned char *)buf, &len); - delS(buf); - buf = (char *)out; - } - else if (getEncodingFromCharset(headerEnc.c_str()) == esp_mail_char_decoding_scheme_tis620) - { - size_t len2 = strlen(buf); - char *tmp = newS((len2 + 1) * 3); - decodeTIS620_UTF8(tmp, buf, len2); - delS(buf); - buf = tmp; - } - - headerField = buf; - delS(buf); -} - -esp_mail_char_decoding_scheme ESP_Mail_Client::getEncodingFromCharset(const char *enc) -{ - esp_mail_char_decoding_scheme scheme = esp_mail_char_decoding_scheme_default; - - if (strposP(enc, esp_mail_str_237, 0) > -1 || strposP(enc, esp_mail_str_231, 0) > -1 || strposP(enc, esp_mail_str_226, 0) > -1) - scheme = esp_mail_char_decoding_scheme_tis620; - else if (strposP(enc, esp_mail_str_227, 0) > -1) - scheme = esp_mail_char_decoding_scheme_iso8859_1; - - return scheme; -} - -bool ESP_Mail_Client::handleAttachment(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, File &file, std::string &filePath, bool &downloadRequest, int &octetCount, int &octetLength, int &oCount, int &reportState, int &downloadCount) -{ - if (chunkIdx == 0) - { - char *tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0); - if (tmp) - { - octetCount = 2; //CRLF counted from first line - octetLength = atoi(tmp); - delS(tmp); - chunkIdx++; - cHeader(imap)->total_download_size += octetLength; - } - return true; - } - - if (octetLength == 0) - return true; - - chunkIdx++; - - delay(0); - - if (!cPart(imap)->file_open_write) - { - - cPart(imap)->file_open_write = true; - - if (imap->_storageType == esp_mail_file_storage_type_sd && !_sdOk) - _sdOk = sdTest(); - else if (imap->_storageType == esp_mail_file_storage_type_flash && !_flashOk) -#if defined(ESP32) - _flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH); -#elif defined(ESP8266) - _flashOk = ESP_MAIL_FLASH_FS.begin(); -#endif - - if (_sdOk || _flashOk) - { - - downloadRequest = true; - - filePath.clear(); - filePath += imap->_config->storage.saved_path; - appendP(filePath, esp_mail_str_202, false); - - char *tmp = intStr(cMSG(imap)); - filePath += tmp; - delS(tmp); - - if (imap->_storageType == esp_mail_file_storage_type_sd) - if (!ESP_MAIL_SD_FS.exists(filePath.c_str())) - createDirs(filePath); - - appendP(filePath, esp_mail_str_202, false); - - filePath += cPart(imap)->filename; - - if (imap->_storageType == esp_mail_file_storage_type_sd) - file = ESP_MAIL_SD_FS.open(filePath.c_str(), FILE_WRITE); - else if (imap->_storageType == esp_mail_file_storage_type_flash) -#if defined(ESP32) - file = ESP_MAIL_FLASH_FS.open(filePath.c_str(), FILE_WRITE); -#elif defined(ESP8266) - file = ESP_MAIL_FLASH_FS.open(filePath.c_str(), "w"); -#endif - } - } - - if (_sdOk || _flashOk) - { - int nOctet = oCount + bufLen + 2; - if (nOctet > octetLength) - { - if (imap->_readCallback) - downloadReport(imap, 100); - - if (oCount < octetLength) - { - int dLen = nOctet - 2 - octetLength; - bufLen -= dLen; - buf[bufLen] = 0; - } - else - return true; - } - - oCount += bufLen + 2; - - if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31)) - { - - size_t olen = 0; - unsigned char *decoded = decodeBase64((const unsigned char *)buf, bufLen, &olen); - - if (decoded) - { - - if (!cPart(imap)->sizeProp) - { - cPart(imap)->attach_data_size += olen; - cHeader(imap)->total_attach_data_size += cPart(imap)->attach_data_size; - } - - file.write((const uint8_t *)decoded, olen); - delay(0); - delete[] decoded; - - if (imap->_config->enable.download_status) - { - int p = 0; - if (cHeader(imap)->total_download_size > 0) - p = 100 * octetCount / cHeader(imap)->total_download_size; - - if ((p != downloadCount) && (p <= 100)) - { - downloadCount = p; - if (imap->_readCallback && reportState != -1) - downloadReport(imap, p); - reportState = -1; - } - else - reportState = 0; - } - } - - if (!reconnect(imap)) - return false; - } - else - { - //binary content - if (!cPart(imap)->sizeProp) - { - cPart(imap)->attach_data_size += bufLen; - cHeader(imap)->total_attach_data_size += cPart(imap)->attach_data_size; - } - - file.write((const uint8_t *)buf, bufLen); - delay(0); - - if (imap->_config->enable.download_status) - { - int p = 0; - if (cHeader(imap)->total_download_size > 0) - p = 100 * octetCount / cHeader(imap)->total_download_size; - - if ((p != downloadCount) && (p <= 100)) - { - downloadCount = p; - if (imap->_readCallback && reportState != -1) - downloadReport(imap, p); - reportState = -1; - } - else - reportState = 0; - } - - if (!reconnect(imap)) - return false; - } - } - return true; -} - -void ESP_Mail_Client::downloadReport(IMAPSession *imap, int progress) -{ - if (imap->_readCallback && progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0) - { - std::string s; - char *tmp = intStr(progress); - appendP(s, esp_mail_str_90, true); - appendP(s, esp_mail_str_131, false); - s += cPart(imap)->filename; - appendP(s, esp_mail_str_91, false); - s += tmp; - delS(tmp); - appendP(s, esp_mail_str_92, false); - appendP(s, esp_mail_str_34, false); - esp_mail_debug_line(s.c_str(), false); - std::string().swap(s); - } -} - -void ESP_Mail_Client::fetchReport(IMAPSession *imap, int progress, bool download) -{ - if (imap->_readCallback && progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0) - { - std::string s; - char *tmp = intStr(progress); - if (download) - appendP(s, esp_mail_str_90, true); - else - appendP(s, esp_mail_str_83, true); - appendP(s, esp_mail_str_131, false); - if (cPart(imap)->filename.length() > 0) - { - s += cPart(imap)->filename; - appendP(s, esp_mail_str_91, false); - } - s += tmp; - delS(tmp); - appendP(s, esp_mail_str_92, false); - appendP(s, esp_mail_str_34, false); - esp_mail_debug_line(s.c_str(), false); - std::string().swap(s); - } -} - -void ESP_Mail_Client::searchReport(int progress, const char *percent) -{ - if (progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0) - { - char *tmp = intStr(progress); - std::string s; - appendP(s, esp_mail_str_261, true); - s += tmp; - s += percent; - appendP(s, esp_mail_str_34, false); - esp_mail_debug_line(s.c_str(), false); - delS(tmp); - } -} - -void ESP_Mail_Client::uploadReport(const char *filename, int progress) -{ - if (progress % ESP_MAIL_PROGRESS_REPORT_STEP == 0) - { - std::string s; - char *tmp = intStr(progress); - appendP(s, esp_mail_str_160, true); - s += filename; - appendP(s, esp_mail_str_91, false); - s += tmp; - delS(tmp); - appendP(s, esp_mail_str_92, false); - appendP(s, esp_mail_str_34, false); - esp_mail_debug_line(s.c_str(), false); - std::string().swap(s); - } -} - -int ESP_Mail_Client::cMSG(IMAPSession *imap) -{ - return imap->_msgNum[cIdx(imap)]; -} - -int ESP_Mail_Client::cIdx(IMAPSession *imap) -{ - return imap->_cMsgIdx; -} - -void ESP_Mail_Client::decodeTIS620_UTF8(char *out, const char *in, size_t len) -{ - //output is the 3-byte value UTF-8 - int j = 0; - for (size_t i = 0; i < len; i++) - { - if (in[i] < 0x80) - out[j++] = in[i]; - else if ((in[i] >= 0xa0 && in[i] < 0xdb) || (in[i] > 0xde && in[i] < 0xfc)) - { - int unicode = 0x0e00 + in[i] - 0xa0; - out[j++] = 0xe0 | ((unicode >> 12) & 0xf); - out[j++] = 0x80 | ((unicode >> 6) & 0x3f); - out[j++] = 0x80 | (unicode & 0x3f); - } - } -} - -int ESP_Mail_Client::decodeLatin1_UTF8(unsigned char *out, int *outlen, const unsigned char *in, int *inlen) -{ - unsigned char *outstart = out; - const unsigned char *base = in; - const unsigned char *processed = in; - unsigned char *outend = out + *outlen; - const unsigned char *inend; - unsigned int c; - int bits; - - inend = in + (*inlen); - while ((in < inend) && (out - outstart + 5 < *outlen)) - { - c = *in++; - - /* assertion: c is a single UTF-4 value */ - if (out >= outend) - break; - if (c < 0x80) - { - *out++ = c; - bits = -6; - } - else - { - *out++ = ((c >> 6) & 0x1F) | 0xC0; - bits = 0; - } - - for (; bits >= 0; bits -= 6) - { - if (out >= outend) - break; - *out++ = ((c >> bits) & 0x3F) | 0x80; - } - processed = (const unsigned char *)in; - } - *outlen = out - outstart; - *inlen = processed - base; - return (0); -} - -void ESP_Mail_Client::decodeText(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, File &file, std::string &filePath, bool &downloadRequest, int &octetLength, int &octetCount, int &readCount) -{ - bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822; - if (chunkIdx == 0) - { - char *tmp = subStr(buf, esp_mail_str_193, esp_mail_str_194, 0); - if (tmp) - { - octetCount = 2; - octetLength = atoi(tmp); - delS(tmp); - chunkIdx++; - cPart(imap)->octetLen = octetLength; - - if ((rfc822_body_subtype && imap->_config->download.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)))) - prepareFilePath(imap, filePath, false); - - if (filePath.length() == 0) - { - if (!rfc822_body_subtype) - appendP(filePath, esp_mail_str_67, false); - else - { - appendP(filePath, esp_mail_str_82, false); - appendP(filePath, esp_mail_str_131, false); - appendP(filePath, esp_mail_str_67, false); - } - } - cPart(imap)->filename = filePath; - - return; - } - else - { - if (imap->_debug) - { - char *tmp = strP(esp_mail_str_280); - esp_mail_debug_line(tmp, false); - delS(tmp); - } - } - } - - delay(0); - - if (octetLength == 0) - return; - - if (imap->_config->download.rfc822 || imap->_config->download.html || imap->_config->download.text || (rfc822_body_subtype && imap->_config->enable.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->enable.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->enable.text)))) - { - if (imap->_readCallback && octetCount > octetLength + 2 && readCount < 100) - fetchReport(imap, 100, (imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)))); - - if (octetCount <= octetLength + 2) - { - size_t olen = 0; - char *decoded = nullptr; - bool newC = true; - if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_31)) - { - decoded = (char *)decodeBase64((const unsigned char *)buf, bufLen, &olen); - } - else if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_278)) - { - decoded = newS(bufLen + 10); - decodeQP(buf, decoded); - olen = strlen(decoded); - } - else if (strcmpP(cPart(imap)->content_transfer_encoding.c_str(), 0, esp_mail_str_29)) - { - decoded = decode7Bit(buf); - olen = strlen(decoded); - } - else - { - //8bit and binary - newC = false; - decoded = buf; - olen = bufLen; - } - - if (decoded) - { - - if ((rfc822_body_subtype && imap->_config->enable.rfc822) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->enable.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->enable.text)))) - { - - if (getEncodingFromCharset(cPart(imap)->charset.c_str()) == esp_mail_char_decoding_scheme_iso8859_1) - { - int ilen = olen; - int olen2 = (ilen + 1) * 2; - unsigned char *tmp = (unsigned char *)newS(olen2); - decodeLatin1_UTF8(tmp, &olen2, (unsigned char *)decoded, &ilen); - delS(decoded); - olen = olen2; - decoded = (char *)tmp; - } - else if (getEncodingFromCharset(cPart(imap)->charset.c_str()) == esp_mail_char_decoding_scheme_tis620) - { - char *out = newS((olen + 1) * 3); - delS(decoded); - decodeTIS620_UTF8(out, decoded, olen); - olen = strlen(out); - decoded = out; - } - - int p = 0; - - if (octetLength > 0) - p = 100 * octetCount / octetLength; - - if ((p != readCount) && (p <= 100)) - { - readCount = p; - if (imap->_readCallback) - fetchReport(imap, p, (imap->_config->download.rfc822 && rfc822_body_subtype) || (!rfc822_body_subtype && ((cPart(imap)->msg_type == esp_mail_msg_type_html && imap->_config->download.html) || ((cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) && imap->_config->download.text)))); - } - - if (cPart(imap)->text.length() < imap->_config->limit.msg_size) - { - - if (cPart(imap)->text.length() + olen < imap->_config->limit.msg_size) - { - cPart(imap)->textLen += olen; - cPart(imap)->text.append(decoded, olen); - } - else - { - int d = imap->_config->limit.msg_size - cPart(imap)->text.length(); - cPart(imap)->textLen += d; - if (d > 0) - cPart(imap)->text.append(decoded, d); - } - } - } - - if (filePath.length() > 0) - { - if (!cPart(imap)->file_open_write) - { - cPart(imap)->file_open_write = true; - - if (_sdOk || _flashOk) - { - downloadRequest = true; - - if (imap->_storageType == esp_mail_file_storage_type_sd) - file = ESP_MAIL_SD_FS.open(filePath.c_str(), FILE_WRITE); - else if (imap->_storageType == esp_mail_file_storage_type_flash) -#if defined(ESP32) - file = ESP_MAIL_FLASH_FS.open(filePath.c_str(), FILE_WRITE); -#elif defined(ESP8266) - file = ESP_MAIL_FLASH_FS.open(filePath.c_str(), "w"); -#endif - } - } - - if (_sdOk || _flashOk) - file.write((const uint8_t *)decoded, olen); - } - - if (newC) - delS(decoded); - } - } - } -} -void ESP_Mail_Client::prepareFilePath(IMAPSession *imap, std::string &filePath, bool header) -{ - bool rfc822_body_subtype = cPart(imap)->message_sub_type == esp_mail_imap_message_sub_type_rfc822; - std::string fpath = imap->_config->storage.saved_path; - appendP(fpath, esp_mail_str_202, false); - char *tmp = intStr(cMSG(imap)); - fpath += tmp; - delS(tmp); - - if (imap->_storageType == esp_mail_file_storage_type_sd) - if (!ESP_MAIL_SD_FS.exists(fpath.c_str())) - createDirs(fpath); - - if (header) - { - appendP(fpath, esp_mail_str_203, false); - } - else - { - if (!rfc822_body_subtype) - { - appendP(fpath, esp_mail_str_161, false); - if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) - appendP(fpath, esp_mail_str_95, false); - else if (cPart(imap)->msg_type == esp_mail_msg_type_html) - appendP(fpath, esp_mail_str_94, false); - } - else - { - appendP(fpath, esp_mail_str_163, false); - - if (cPart(imap)->rfc822_msg_Idx > 0) - { - char *tmp = intStr(cPart(imap)->rfc822_msg_Idx); - fpath += tmp; - delS(tmp); - } - - if (cPart(imap)->msg_type == esp_mail_msg_type_plain || cPart(imap)->msg_type == esp_mail_msg_type_enriched) - appendP(fpath, esp_mail_str_95, false); - else if (cPart(imap)->msg_type == esp_mail_msg_type_html) - appendP(fpath, esp_mail_str_94, false); - else - //possible rfc822 encapsulated message which cannot fetch its header - appendP(fpath, esp_mail_str_40, false); - } - } - - filePath = fpath; -} - -char *ESP_Mail_Client::strReplace(char *orig, char *rep, char *with) -{ - char *result = nullptr; - char *ins = nullptr; - char *tmp = nullptr; - int len_rep; - int len_with; - int len_front; - int count; - - len_with = strlen(with); - len_rep = strlen(rep); - - ins = orig; - for (count = 0; (tmp = strstr(ins, rep)); ++count) - ins = tmp + len_rep; - - tmp = result = newS(strlen(orig) + (len_with - len_rep) * count + 1); - while (count--) - { - ins = strstr(orig, rep); - len_front = ins - orig; - tmp = strncpy(tmp, orig, len_front) + len_front; - tmp = strcpy(tmp, with) + len_with; - orig += len_front + len_rep; - } - strcpy(tmp, orig); - return result; -} - -int ESP_Mail_Client::decodeChar(const char *s) -{ - assert(s); - assert(*s == '='); - return 16 * hexval(*(s + 1)) + hexval(*(s + 2)); -} - -void ESP_Mail_Client::decodeQP(const char *buf, char *out) -{ - char *tmp = strP(esp_mail_str_295); - while (*buf) - { - if (*buf != '=') - strcat_c(out, *buf++); - else if (*(buf + 1) == '\r' && *(buf + 2) == '\n') - buf += 3; - else if (*(buf + 1) == '\n') - buf += 2; - else if (!strchr(tmp, *(buf + 1))) - strcat_c(out, *buf++); - else if (!strchr(tmp, *(buf + 2))) - strcat_c(out, *buf++); - else - { - strcat_c(out, decodeChar(buf)); - buf += 3; - } - } - delS(tmp); -} - -std::string ESP_Mail_Client::getBoundary(size_t len) -{ - char *tmp = strP(boundary_table); - char *buf = newS(len); - if (len) - { - --len; - buf[0] = tmp[0]; - buf[1] = tmp[1]; - for (size_t n = 2; n < len; n++) - { - int key = rand() % (int)(strlen(tmp) - 1); - buf[n] = tmp[key]; - } - buf[len] = '\0'; - } - std::string s = buf; - delS(buf); - delS(tmp); - return s; -} - -char *ESP_Mail_Client::decode7Bit(char *buf) -{ - char *out = strReplaceP(buf, imap_7bit_key1, imap_7bit_val1); - char *tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key2, imap_7bit_val2); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key3, imap_7bit_val3); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key4, imap_7bit_val4); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key5, imap_7bit_val5); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key6, imap_7bit_val6); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key7, imap_7bit_val7); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key8, imap_7bit_val8); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key9, imap_7bit_val9); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key10, imap_7bit_val10); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key11, imap_7bit_val11); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key12, imap_7bit_val12); - - delS(tmp); - tmp = newS(strlen(out) + 10); - strcpy(tmp, out); - delS(out); - out = strReplaceP(tmp, imap_7bit_key13, imap_7bit_val13); - delS(tmp); - return out; -} - -char *ESP_Mail_Client::strReplaceP(char *buf, PGM_P name, PGM_P value) -{ - char *n = strP(name); - char *v = strP(value); - char *out = strReplace(buf, n, v); - delS(n); - delS(v); - return out; -} - -void ESP_Mail_Client::handleCapability(IMAPSession *imap, char *buf, int &chunkIdx) -{ - if (chunkIdx == 0) - { - if (strposP(buf, esp_mail_imap_response_10, 0) > -1) - { - if (strposP(buf, esp_mail_imap_response_11, 0) > -1) - imap->_auth_capability.login = true; - if (strposP(buf, esp_mail_imap_response_12, 0) > -1) - imap->_auth_capability.plain = true; - if (strposP(buf, esp_mail_imap_response_13, 0) > -1) - imap->_auth_capability.xoauth2 = true; - if (strposP(buf, esp_mail_imap_response_14, 0) > -1) - imap->_auth_capability.start_tls = true; - if (strposP(buf, esp_mail_imap_response_15, 0) > -1) - imap->_auth_capability.cram_md5 = true; - if (strposP(buf, esp_mail_imap_response_16, 0) > -1) - imap->_auth_capability.digest_md5 = true; - } - } -} - -bool ESP_Mail_Client::authFailed(char *buf, int bufLen, int &chunkIdx, int ofs) -{ - bool ret = false; - if (chunkIdx == 0) - { - size_t olen; - unsigned char *decoded = decodeBase64((const unsigned char *)(buf + ofs), bufLen - ofs, &olen); - if (decoded) - { - ret = strposP((char *)decoded, esp_mail_str_294, 0) > -1; - delete[] decoded; - } - chunkIdx++; - } - return ret; -} - -void ESP_Mail_Client::handleFolders(IMAPSession *imap, char *buf) -{ - struct esp_mail_folder_info_t fd; - char *tmp = nullptr; - int p1 = strposP(buf, esp_mail_imap_response_4, 0); - int p2 = 0; - if (p1 != -1) - { - p1 = strposP(buf, esp_mail_str_198, 0); - if (p1 != -1) - { - p2 = strposP(buf, esp_mail_str_192, p1 + 1); - if (p2 != -1) - { - tmp = newS(p2 - p1); - strncpy(tmp, buf + p1 + 1, p2 - p1 - 1); - if (tmp[p2 - p1 - 2] == '\r') - tmp[p2 - p1 - 2] = 0; - fd.attributes = tmp; - delS(tmp); - } - } - - p1 = strposP(buf, esp_mail_str_136, 0); - if (p1 != -1) - { - p2 = strposP(buf, esp_mail_str_136, p1 + 1); - if (p2 != -1) - { - tmp = newS(p2 - p1); - strncpy(tmp, buf + p1 + 1, p2 - p1 - 1); - if (tmp[p2 - p1 - 2] == '\r') - tmp[p2 - p1 - 2] = 0; - fd.delimiter = tmp; - delS(tmp); - } - } - - p1 = strposP(buf, esp_mail_str_131, p2); - if (p1 != -1) - { - p2 = strlen(buf); - tmp = newS(p2 - p1); - if (buf[p1 + 1] == '"') - p1++; - strncpy(tmp, buf + p1 + 1, p2 - p1 - 1); - if (tmp[p2 - p1 - 2] == '\r') - tmp[p2 - p1 - 2] = 0; - if (tmp[strlen(tmp) - 1] == '"') - tmp[strlen(tmp) - 1] = 0; - fd.name = tmp; - delS(tmp); - } - imap->_folders.add(fd); - } -} - -void ESP_Mail_Client::handleExamine(IMAPSession *imap, char *buf) -{ - char *tmp = nullptr; - int p1, p2; - - if (imap->_mbif._msgCount == 0) - { - p1 = strposP(buf, esp_mail_str_199, 0); - if (p1 != -1) - { - tmp = newS(p1); - strncpy(tmp, buf + 2, p1 - 1); - imap->_mbif._msgCount = atoi(tmp); - delS(tmp); - return; - } - } - - if (imap->_mbif._flags.size() == 0) - { - p1 = strposP(buf, esp_mail_imap_response_5, 0); - if (p1 != -1) - { - p1 = strposP(buf, esp_mail_str_198, 0); - if (p1 != -1) - { - p2 = strposP(buf, esp_mail_str_192, p1 + 1); - if (p2 != -1) - { - tmp = newS(p2 - p1); - strncpy(tmp, buf + p1 + 1, p2 - p1 - 1); - char *stk = strP(esp_mail_str_131); - char *end_token; - char *token = strtok_r(tmp, stk, &end_token); - while (token != NULL) - { - imap->_mbif.addFlag(token); - token = strtok_r(NULL, stk, &end_token); - } - if (token) - delS(token); - delS(tmp); - delS(stk); - } - } - return; - } - } - - if (imap->_nextUID.length() == 0) - { - p1 = strposP(buf, esp_mail_str_200, 0); - if (p1 != -1) - { - p2 = strposP(buf, esp_mail_str_156, p1 + strlen_P(esp_mail_str_200)); - if (p2 != -1) - { - tmp = newS(p2 - p1 - strlen_P(esp_mail_str_200) + 1); - strncpy(tmp, buf + p1 + strlen_P(esp_mail_str_200), p2 - p1 - strlen_P(esp_mail_str_200)); - imap->_nextUID = tmp; - imap->_mbif._nextUID = atoi(tmp); - delS(tmp); - } - return; - } - } -} - -bool ESP_Mail_Client::handleIMAPError(IMAPSession *imap, int err, bool ret) -{ - if (err < 0) - { - errorStatusCB(imap, err); - - if (imap->_headers.size() > 0) - { - if ((imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_attachment || imap->_imap_cmd == esp_mail_imap_cmd_fetch_body_inline) && (imap->_config->download.attachment || imap->_config->download.inlineImg)) - { - if (cHeader(imap)->part_headers.size() > 0) - cPart(imap)->download_error = imap->errorReason().c_str(); - } - else - cHeader(imap)->error_msg = imap->errorReason().c_str(); - - cHeader(imap)->error = true; - } - } - - if (imap->_tcpConnected) - closeTCP(imap); - - imap->_cbData.empty(); - - return ret; -} - -unsigned char *ESP_Mail_Client::decodeBase64(const unsigned char *src, size_t len, size_t *out_len) -{ - - unsigned char *out, *pos, block[4], tmp; - size_t i, count, olen; - int pad = 0; - size_t extra_pad; - - unsigned char *dtable = new unsigned char[256]; - - memset(dtable, 0x80, 256); - - for (i = 0; i < sizeof(b64_index_table) - 1; i++) - dtable[b64_index_table[i]] = (unsigned char)i; - dtable['='] = 0; - - count = 0; - for (i = 0; i < len; i++) - { - if (dtable[src[i]] != 0x80) - count++; - } - - if (count == 0) - goto exit; - extra_pad = (4 - count % 4) % 4; - - olen = (count + extra_pad) / 4 * 3; - pos = out = (unsigned char *)malloc(olen); - if (out == NULL) - goto exit; - - count = 0; - for (i = 0; i < len + extra_pad; i++) - { - unsigned char val; - - if (i >= len) - val = '='; - else - val = src[i]; - tmp = dtable[val]; - if (tmp == 0x80) - continue; - - if (val == '=') - pad++; - block[count] = tmp; - count++; - if (count == 4) - { - *pos++ = (block[0] << 2) | (block[1] >> 4); - *pos++ = (block[1] << 4) | (block[2] >> 2); - *pos++ = (block[2] << 6) | block[3]; - count = 0; - if (pad) - { - if (pad == 1) - pos--; - else if (pad == 2) - pos -= 2; - else - { - free(out); - goto exit; - } - break; - } - } - } - - *out_len = pos - out; - delete[] dtable; - return out; -exit: - delete[] dtable; - return nullptr; -} - -std::string ESP_Mail_Client::encodeBase64Str(const unsigned char *src, size_t len) -{ - return encodeBase64Str((uint8_t *)src, len); -} - -std::string ESP_Mail_Client::encodeBase64Str(uint8_t *src, size_t len) -{ - std::string outStr; - unsigned char *out, *pos; - const unsigned char *end, *in; - size_t olen = 4 * ((len + 2) / 3); - if (olen < len) - return outStr; - - outStr.resize(olen); - out = (unsigned char *)&outStr[0]; - - end = src + len; - in = src; - pos = out; - - while (end - in >= 3) - { - *pos++ = b64_index_table[in[0] >> 2]; - *pos++ = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; - *pos++ = b64_index_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; - *pos++ = b64_index_table[in[2] & 0x3f]; - in += 3; - } - - if (end - in) - { - *pos++ = b64_index_table[in[0] >> 2]; - if (end - in == 1) - { - *pos++ = b64_index_table[(in[0] & 0x03) << 4]; - *pos++ = '='; - } - else - { - *pos++ = b64_index_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; - *pos++ = b64_index_table[(in[1] & 0x0f) << 2]; - } - *pos++ = '='; - } - - return outStr; -} - -void ESP_Mail_Client::encodeQP(const char *buf, char *out) -{ - int n = 0, p = 0, pos = 0; - assert(buf); - for (n = 0; *buf; buf++) - { - if (n >= 73 && *buf != 10 && *buf != 13) - { - p = sprintf(out + pos, "=\r\n"); - pos += p; - n = 0; - } - - if (*buf == 10 || *buf == 13) - { - strcat_c(out, *buf); - pos++; - n = 0; - } - else if (*buf < 32 || *buf == 61 || *buf > 126) - { - p = sprintf(out + pos, "=%02X", (unsigned char)*buf); - n += p; - pos += p; - } - else if (*buf != 32 || (*(buf + 1) != 10 && *(buf + 1) != 13)) - { - strcat_c(out, *buf); - n++; - pos++; - } - else - { - p = sprintf(out + pos, "=20"); - n += p; - pos += p; - } - } -} - -bool ESP_Mail_Client::sendBase64(SMTPSession *smtp, SMTP_Message *msg, const unsigned char *data, size_t len, bool flashMem, const char *filename, bool report) -{ - bool ret = false; - const unsigned char *end, *in; - - size_t olen = 4 * ((len + 2) / 3); - - if (olen < len) - return false; - - end = data + len; - in = data; - - size_t chunkSize = 936; - size_t byteAdded = 0; - size_t byteSent = 0; - - int dByte = 0; - unsigned char *buf = new unsigned char[chunkSize]; - memset(buf, 0, chunkSize); - - unsigned char *tmp = new unsigned char[3]; - int bcnt = 0; - int pg = 0, _pg = 0; - - if (report) - uploadReport(filename, bcnt); - - while (end - in >= 3) - { - - memset(tmp, 0, 3); - if (flashMem) - memcpy_P(tmp, in, 3); - else - memcpy(tmp, in, 3); - bcnt += 3; - - buf[byteAdded++] = b64_index_table[tmp[0] >> 2]; - buf[byteAdded++] = b64_index_table[((tmp[0] & 0x03) << 4) | (tmp[1] >> 4)]; - buf[byteAdded++] = b64_index_table[((tmp[1] & 0x0f) << 2) | (tmp[2] >> 6)]; - buf[byteAdded++] = b64_index_table[tmp[2] & 0x3f]; - dByte += 4; - if (dByte == BASE64_CHUNKED_LEN) - { - if (byteAdded + 1 < chunkSize) - { - buf[byteAdded++] = 0x0d; - buf[byteAdded++] = 0x0a; - } - dByte = 0; - } - if (byteAdded >= chunkSize - 4) - { - byteSent += byteAdded; - - if (!bdat(smtp, msg, byteAdded, false)) - goto ex; - - if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - goto ex; - memset(buf, 0, chunkSize); - byteAdded = 0; - } - in += 3; - - if (report) - { - pg = (float)(100.0f * bcnt / len); - if (pg != _pg) - uploadReport(filename, pg); - _pg = pg; - } - } - - if (byteAdded > 0) - { - if (!bdat(smtp, msg, byteAdded, false)) - goto ex; - - if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - goto ex; - } - - if (end - in) - { - memset(buf, 0, chunkSize); - byteAdded = 0; - memset(tmp, 0, 3); - if (flashMem) - { - if (end - in == 1) - memcpy_P(tmp, in, 1); - else - memcpy_P(tmp, in, 2); - } - else - { - if (end - in == 1) - memcpy(tmp, in, 1); - else - memcpy(tmp, in, 2); - } - - buf[byteAdded++] = b64_index_table[tmp[0] >> 2]; - if (end - in == 1) - { - buf[byteAdded++] = b64_index_table[(tmp[0] & 0x03) << 4]; - buf[byteAdded++] = '='; - } - else - { - buf[byteAdded++] = b64_index_table[((tmp[0] & 0x03) << 4) | (tmp[1] >> 4)]; - buf[byteAdded++] = b64_index_table[(tmp[1] & 0x0f) << 2]; - } - buf[byteAdded++] = '='; - - if (!bdat(smtp, msg, byteAdded, false)) - goto ex; - - if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - goto ex; - memset(buf, 0, chunkSize); - } - - if (report && _pg < 100) - uploadReport(filename, 100); - - ret = true; -ex: - if (report) - esp_mail_debug(""); - delete[] tmp; - delete[] buf; - return ret; -} - -bool ESP_Mail_Client::sendBase64Stream(SMTPSession *smtp, SMTP_Message *msg, File file, const char *filename, bool report) -{ - bool ret = false; - - if (!file) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); - return false; - } - - size_t chunkSize = 936; - size_t byteAdded = 0; - size_t byteSent = 0; - - unsigned char *buf = new unsigned char[chunkSize]; - memset(buf, 0, chunkSize); - - size_t len = file.size(); - size_t fbufIndex = 0; - unsigned char *fbuf = new unsigned char[3]; - - int dByte = 0; - - int bcnt = 0; - int pg = 0, _pg = 0; - - if (report) - uploadReport(filename, bcnt); - - while (file.available()) - { - memset(fbuf, 0, 3); - if (len - fbufIndex >= 3) - { - bcnt += 3; - size_t readLen = file.read(fbuf, 3); - if (readLen != 3) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); - break; - } - - buf[byteAdded++] = b64_index_table[fbuf[0] >> 2]; - buf[byteAdded++] = b64_index_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)]; - buf[byteAdded++] = b64_index_table[((fbuf[1] & 0x0f) << 2) | (fbuf[2] >> 6)]; - buf[byteAdded++] = b64_index_table[fbuf[2] & 0x3f]; - dByte += 4; - if (dByte == BASE64_CHUNKED_LEN) - { - if (byteAdded + 1 < chunkSize) - { - buf[byteAdded++] = 0x0d; - buf[byteAdded++] = 0x0a; - } - dByte = 0; - } - if (byteAdded >= chunkSize - 4) - { - byteSent += byteAdded; - - if (!bdat(smtp, msg, byteAdded, false)) - goto ex; - - if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - goto ex; - - memset(buf, 0, chunkSize); - byteAdded = 0; - } - fbufIndex += 3; - - if (report) - { - pg = (float)(100.0f * bcnt / len); - if (pg != _pg) - uploadReport(filename, pg); - _pg = pg; - } - } - else - { - size_t readLen = file.read(fbuf, len - fbufIndex); - if (readLen != len - fbufIndex) - { - errorStatusCB(smtp, MAIL_CLIENT_ERROR_FILE_IO_ERROR); - break; - } - } - } - - file.close(); - if (byteAdded > 0) - { - if (!bdat(smtp, msg, byteAdded, false)) - goto ex; - - if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - goto ex; - } - - if (len - fbufIndex > 0) - { - memset(buf, 0, chunkSize); - byteAdded = 0; - buf[byteAdded++] = b64_index_table[fbuf[0] >> 2]; - if (len - fbufIndex == 1) - { - buf[byteAdded++] = b64_index_table[(fbuf[0] & 0x03) << 4]; - buf[byteAdded++] = '='; - } - else - { - buf[byteAdded++] = b64_index_table[((fbuf[0] & 0x03) << 4) | (fbuf[1] >> 4)]; - buf[byteAdded++] = b64_index_table[(fbuf[1] & 0x0f) << 2]; - } - buf[byteAdded++] = '='; - - if (!bdat(smtp, msg, byteAdded, false)) - goto ex; - - if (smtpSend(smtp, buf, byteAdded) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - goto ex; - } - ret = true; - - if (report && _pg < 100) - uploadReport(filename, 100); - -ex: - delete[] buf; - delete[] fbuf; - file.close(); - return ret; -} - -IMAPSession::IMAPSession() {} -IMAPSession::~IMAPSession() -{ - empty(); - _caCert.reset(); - _caCert = nullptr; -} - -bool IMAPSession::closeSession() -{ - if (!_tcpConnected) - return false; -#if defined(ESP32) - /** - * The strange behavior in ESP8266 SSL client, BearSSLWiFiClientSecure - * The client disposed without memory released after the server close - * the connection due to LOGOUT command, which caused the memory leaks. - */ - if (!MailClient.imapLogout(this)) - return false; -#endif - return MailClient.handleIMAPError(this, 0, true); -} - -bool IMAPSession::connect(ESP_Mail_Session *sesssion, IMAP_Config *config) -{ - if (_tcpConnected) - MailClient.closeTCP(this); - - _sesson_cfg = sesssion; - _config = config; - _caCert = nullptr; - - if (strlen(_sesson_cfg->certificate.cert_data) > 0) - _caCert = std::shared_ptr(_sesson_cfg->certificate.cert_data); - - if (strlen(_sesson_cfg->certificate.cert_file) > 0) - { - if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_sd && !MailClient._sdOk) - MailClient._sdOk = MailClient.sdTest(); - if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_flash && !MailClient._flashOk) -#if defined(ESP32) - MailClient._flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH); -#elif defined(ESP8266) - MailClient._flashOk = ESP_MAIL_FLASH_FS.begin(); -#endif - } - - return MailClient.imapAuth(this); -} - -void IMAPSession::debug(int level) -{ - if (level > esp_mail_debug_level_0) - { - if (level > esp_mail_debug_level_3) - level = esp_mail_debug_level_1; - _debugLevel = level; - _debug = true; - } - else - { - _debugLevel = esp_mail_debug_level_0; - _debug = false; - } -} - -String IMAPSession::errorReason() -{ - std::string ret; - - if (_imapStatus.text.length() > 0) - return _imapStatus.text.c_str(); - - switch (_imapStatus.statusCode) - { - case IMAP_STATUS_SERVER_CONNECT_FAILED: - MailClient.appendP(ret, esp_mail_str_38, true); - break; - case MAIL_CLIENT_ERROR_CONNECTION_LOST: - MailClient.appendP(ret, esp_mail_str_221, true); - break; - case MAIL_CLIENT_ERROR_READ_TIMEOUT: - MailClient.appendP(ret, esp_mail_str_258, true); - break; - case MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED: - MailClient.appendP(ret, esp_mail_str_305, true); - break; - case IMAP_STATUS_NO_MESSAGE: - MailClient.appendP(ret, esp_mail_str_306, true); - break; - case IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT: - MailClient.appendP(ret, esp_mail_str_93, true); - break; - case MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP: - MailClient.appendP(ret, esp_mail_str_132, true); - break; - case IMAP_STATUS_CLOSE_MAILBOX_FAILED: - MailClient.appendP(ret, esp_mail_str_188, true); - break; - case IMAP_STATUS_OPEN_MAILBOX_FAILED: - MailClient.appendP(ret, esp_mail_str_281, true); - break; - case IMAP_STATUS_LIST_MAILBOXS_FAILED: - MailClient.appendP(ret, esp_mail_str_62, true); - break; - case IMAP_STATUS_NO_SUPPORTED_AUTH: - MailClient.appendP(ret, esp_mail_str_42, true); - break; - case IMAP_STATUS_CHECK_CAPABILITIES_FAILED: - MailClient.appendP(ret, esp_mail_str_63, true); - break; - case MAIL_CLIENT_ERROR_OUT_OF_MEMORY: - MailClient.appendP(ret, esp_mail_str_186, true); - break; - case IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED: - MailClient.appendP(ret, esp_mail_str_153, true); - break; - - default: - break; - } - return ret.c_str(); -} - -bool IMAPSession::selectFolder(const char *folderName, bool readOnly) -{ - if (_tcpConnected) - { - if (!openFolder(folderName, readOnly)) - return false; - } - else - { - _currentFolder = folderName; - } - return true; -} - -bool IMAPSession::openFolder(const char *folderName, bool readOnly) -{ - if (!_tcpConnected) - return false; - if (readOnly) - return openMailbox(folderName, esp_mail_imap_auth_mode::esp_mail_imap_mode_examine, true); - else - return openMailbox(folderName, esp_mail_imap_auth_mode::esp_mail_imap_mode_select, true); -} - -bool IMAPSession::getFolders(FoldersCollection &folders) -{ - if (!_tcpConnected) - return false; - return getMailboxes(folders); -} - -bool IMAPSession::closeFolder(const char *folderName) -{ - if (!_tcpConnected) - return false; - return closeMailbox(); -} - -void IMAPSession::checkUID() -{ - if (MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_140) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_212) || - MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_213) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_214) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_215) || - MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_216) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_217) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_218) || - MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_219) || MailClient.strcmpP(_config->fetch.uid, 0, esp_mail_str_220)) - _config->fetch.uid = "*"; -} - -void IMAPSession::checkPath() -{ - std::string path = _config->storage.saved_path; - if (path[0] != '/') - { - path = "/"; - path += _config->storage.saved_path; - path = path.c_str(); - } -} - -bool IMAPSession::headerOnly() -{ - return _headerOnly; -} - -struct esp_mail_imap_msg_list_t IMAPSession::data() -{ - struct esp_mail_imap_msg_list_t ret; - - for (size_t i = 0; i < _headers.size(); i++) - { - if (ESP.getFreeHeap() < ESP_MAIL_MIN_MEM) - continue; - - struct esp_mail_imap_msg_item_t itm; - - itm.UID = _headers[i].message_uid.c_str(); - itm.ID = _headers[i].message_id.c_str(); - itm.msgNo = _headers[i].message_no.c_str(); - itm.from = _headers[i].from.c_str(); - itm.fromCharset = _headers[i].from_charset.c_str(); - itm.to = _headers[i].to.c_str(); - itm.toCharset = _headers[i].to_charset.c_str(); - itm.cc = _headers[i].cc.c_str(); - itm.ccCharset = _headers[i].cc_charset.c_str(); - itm.subject = _headers[i].subject.c_str(); - itm.subjectCharset = _headers[i].subject_charset.c_str(); - itm.date = _headers[i].date.c_str(); - itm.fetchError = _headers[i].error_msg.c_str(); - - getMessages(i, itm); - - getRFC822Messages(i, itm); - - ret.msgItems.push_back(itm); - } - - return ret; -} - -SelectedFolderInfo IMAPSession::selectedFolder() -{ - return _mbif; -} - -void IMAPSession::callback(imapStatusCallback imapCallback) -{ - _readCallback = std::move(imapCallback); -} - -void IMAPSession::getMessages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg) -{ - msg.text.content = ""; - msg.text.charSet = ""; - msg.text.content_type = ""; - msg.text.transfer_encoding = ""; - msg.html.content = ""; - msg.html.charSet = ""; - msg.html.content_type = ""; - msg.html.transfer_encoding = ""; - - if (messageIndex < _headers.size()) - { - int sz = _headers[messageIndex].part_headers.size(); - if (sz > 0) - { - for (int i = 0; i < sz; i++) - { - if (!_headers[messageIndex].part_headers[i].rfc822_part && _headers[messageIndex].part_headers[i].message_sub_type != esp_mail_imap_message_sub_type_rfc822) - { - if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_none) - { - if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_plain || _headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_enriched) - { - msg.text.content = _headers[messageIndex].part_headers[i].text.c_str(); - msg.text.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); - msg.text.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); - msg.text.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); - } - - if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_html) - { - msg.html.content = _headers[messageIndex].part_headers[i].text.c_str(); - msg.html.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); - msg.html.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); - msg.html.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); - } - } - else - { - struct esp_mail_attacment_info_t att; - att.filename = _headers[messageIndex].part_headers[i].filename.c_str(); - att.mime = _headers[messageIndex].part_headers[i].content_type.c_str(); - att.name = _headers[messageIndex].part_headers[i].name.c_str(); - att.size = _headers[messageIndex].part_headers[i].attach_data_size; - att.creationDate = _headers[messageIndex].part_headers[i].creation_date.c_str(); - att.type = _headers[messageIndex].part_headers[i].attach_type; - msg.attachments.push_back(att); - } - } - } - } - } -} - -void IMAPSession::getRFC822Messages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg) -{ - if (messageIndex < _headers.size()) - { - int sz = _headers[messageIndex].part_headers.size(); - int partIdx = 0; - int cIdx = 0; - IMAP_MSG_Item *_rfc822 = nullptr; - if (sz > 0) - { - for (int i = 0; i < sz; i++) - { - if (_headers[messageIndex].part_headers[i].message_sub_type == esp_mail_imap_message_sub_type_rfc822) - { - if (_headers[messageIndex].part_headers[i].rfc822_part) - { - if (partIdx > 0) - msg.rfc822.push_back(*_rfc822); - cIdx = i; - partIdx++; - _rfc822 = new IMAP_MSG_Item(); - - _rfc822->from = _headers[messageIndex].part_headers[i].rfc822_header.from.c_str(); - _rfc822->sender = _headers[messageIndex].part_headers[i].rfc822_header.sender.c_str(); - _rfc822->to = _headers[messageIndex].part_headers[i].rfc822_header.to.c_str(); - _rfc822->cc = _headers[messageIndex].part_headers[i].rfc822_header.cc.c_str(); - _rfc822->bcc = _headers[messageIndex].part_headers[i].rfc822_header.bcc.c_str(); - _rfc822->return_path = _headers[messageIndex].part_headers[i].rfc822_header.return_path.c_str(); - _rfc822->reply_to = _headers[messageIndex].part_headers[i].rfc822_header.reply_to.c_str(); - _rfc822->subject = _headers[messageIndex].part_headers[i].rfc822_header.subject.c_str(); - _rfc822->comment = _headers[messageIndex].part_headers[i].rfc822_header.comment.c_str(); - _rfc822->keyword = _headers[messageIndex].part_headers[i].rfc822_header.keyword.c_str(); - _rfc822->date = _headers[messageIndex].part_headers[i].rfc822_header.date.c_str(); - _rfc822->messageID = _headers[messageIndex].part_headers[i].rfc822_header.messageID.c_str(); - _rfc822->text.charSet = ""; - _rfc822->text.content_type = ""; - _rfc822->text.transfer_encoding = ""; - _rfc822->html.charSet = ""; - _rfc822->html.content_type = ""; - _rfc822->html.transfer_encoding = ""; - } - else - { - if (MailClient.multipartMember(_headers[messageIndex].part_headers[cIdx].partNumStr, _headers[messageIndex].part_headers[i].partNumStr)) - { - if (_headers[messageIndex].part_headers[i].attach_type == esp_mail_att_type_none) - { - if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_plain || _headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_enriched) - { - _rfc822->text.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); - _rfc822->text.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); - _rfc822->text.content = _headers[messageIndex].part_headers[i].text.c_str(); - _rfc822->text.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); - } - if (_headers[messageIndex].part_headers[i].msg_type == esp_mail_msg_type_html) - { - _rfc822->html.charSet = _headers[messageIndex].part_headers[i].charset.c_str(); - _rfc822->html.content_type = _headers[messageIndex].part_headers[i].content_type.c_str(); - _rfc822->html.content = _headers[messageIndex].part_headers[i].text.c_str(); - _rfc822->html.transfer_encoding = _headers[messageIndex].part_headers[i].content_transfer_encoding.c_str(); - } - } - else - { - struct esp_mail_attacment_info_t att; - att.filename = _headers[messageIndex].part_headers[i].filename.c_str(); - att.mime = _headers[messageIndex].part_headers[i].content_type.c_str(); - att.name = _headers[messageIndex].part_headers[i].name.c_str(); - att.size = _headers[messageIndex].part_headers[i].attach_data_size; - att.creationDate = _headers[messageIndex].part_headers[i].creation_date.c_str(); - att.type = _headers[messageIndex].part_headers[i].attach_type; - _rfc822->attachments.push_back(att); - } - } - } - } - } - - if ((int)msg.rfc822.size() < partIdx && _rfc822 != nullptr) - msg.rfc822.push_back(*_rfc822); - } - } -} - -bool IMAPSession::closeMailbox() -{ - - if (!MailClient.reconnect(this)) - return false; - - std::string s; - - if (_readCallback) - { - MailClient.appendP(s, esp_mail_str_210, true); - s += _currentFolder; - MailClient.appendP(s, esp_mail_str_96, false); - MailClient.imapCB(this, "", false); - MailClient.imapCB(this, s.c_str(), false); - } - - if (_debug) - MailClient.debugInfoP(esp_mail_str_197); - - if (MailClient.imapSendP(this, esp_mail_str_195, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - _imap_cmd = esp_mail_imap_cmd_close; - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CLOSE_MAILBOX_FAILED, false)) - return false; - - _currentFolder.clear(); - _mailboxOpened = false; - - return true; -} - -bool IMAPSession::openMailbox(const char *folder, esp_mail_imap_auth_mode mode, bool waitResponse) -{ - - if (!MailClient.reconnect(this)) - return false; - - if (_currentFolder.length() > 0) - { - if (strcmp(_currentFolder.c_str(), folder) != 0) - { - if (!closeMailbox()) - return false; - } - } - - _currentFolder = folder; - std::string s; - if (_readCallback) - { - MailClient.appendP(s, esp_mail_str_61, true); - s += _currentFolder; - MailClient.appendP(s, esp_mail_str_96, false); - MailClient.imapCB(this, "", false); - MailClient.imapCB(this, s.c_str(), false); - } - - if (_debug) - MailClient.debugInfoP(esp_mail_str_248); - - if (mode == esp_mail_imap_mode_examine) - { - MailClient.appendP(s, esp_mail_str_135, true); - _imap_cmd = esp_mail_imap_cmd_examine; - } - else if (mode == esp_mail_imap_mode_select) - { - MailClient.appendP(s, esp_mail_str_247, true); - _imap_cmd = esp_mail_imap_cmd_select; - } - s += _currentFolder; - MailClient.appendP(s, esp_mail_str_136, false); - if (MailClient.imapSend(this, s.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - if (waitResponse) - { - - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_OPEN_MAILBOX_FAILED, false)) - return false; - } - - if (mode == esp_mail_imap_mode_examine) - _readOnlyMode = true; - else if (mode == esp_mail_imap_mode_select) - _readOnlyMode = false; - - _mailboxOpened = true; - - return true; -} - -bool IMAPSession::getMailboxes(FoldersCollection &folders) -{ - _folders.clear(); - - if (_readCallback) - { - MailClient.imapCB(this, "", false); - MailClient.imapCBP(this, esp_mail_str_58, false); - } - - if (_debug) - MailClient.debugInfoP(esp_mail_str_230); - - if (MailClient.imapSendP(this, esp_mail_str_133, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_list; - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_LIST_MAILBOXS_FAILED, false)) - return false; - - folders = _folders; - return true; -} - -bool IMAPSession::checkCapability() -{ - if (_readCallback) - { - MailClient.imapCB(this, "", false); - MailClient.imapCBP(this, esp_mail_str_64, false); - } - - if (_debug) - MailClient.debugInfoP(esp_mail_str_65); - - if (MailClient.imapSendP(this, esp_mail_str_2, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_capability; - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_CHECK_CAPABILITIES_FAILED, false)) - return false; - - return true; -} - -bool IMAPSession::createFolder(const char *folderName) -{ - if (_debug) - { - MailClient.imapCB(this, "", false); - MailClient.debugInfoP(esp_mail_str_320); - } - - std::string cmd; - MailClient.appendP(cmd, esp_mail_str_322, true); - cmd += folderName; - - if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_create; - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) - return false; - - return true; -} - -bool IMAPSession::deleteFolder(const char *folderName) -{ - if (_debug) - { - MailClient.imapCB(this, "", false); - MailClient.debugInfoP(esp_mail_str_321); - } - - std::string cmd; - MailClient.appendP(cmd, esp_mail_str_323, true); - cmd += folderName; - - if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_delete; - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) - return false; - - return true; -} - -bool IMAPSession::deleteMessages(MessageList *toDelete, bool expunge) -{ - if (toDelete->_list.size() > 0) - { - - if (!selectFolder(_currentFolder.c_str(), false)) - return false; - - if (_debug) - { - MailClient.imapCB(this, "", false); - MailClient.debugInfoP(esp_mail_str_316); - } - - std::string cmd; - char *tmp = nullptr; - MailClient.appendP(cmd, esp_mail_str_249, true); - for (size_t i = 0; i < toDelete->_list.size(); i++) - { - if (i > 0) - MailClient.appendP(cmd, esp_mail_str_263, false); - tmp = MailClient.intStr(toDelete->_list[i]); - cmd += tmp; - MailClient.delS(tmp); - } - MailClient.appendP(cmd, esp_mail_str_315, false); - - if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_store; - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) - return false; - - if (expunge) - { - if (MailClient.imapSendP(this, esp_mail_str_317, true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_expunge; - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) - return false; - } - } - - return true; -} - -bool IMAPSession::copyMessages(MessageList *toCopy, const char *dest) -{ - if (toCopy->_list.size() > 0) - { - - if (!selectFolder(_currentFolder.c_str(), false)) - return false; - - if (_debug) - { - MailClient.imapCB(this, "", false); - std::string s; - MailClient.appendP(s, esp_mail_str_318, true); - s += dest; - esp_mail_debug(s.c_str()); - } - - std::string cmd; - char *tmp = nullptr; - MailClient.appendP(cmd, esp_mail_str_319, true); - for (size_t i = 0; i < toCopy->_list.size(); i++) - { - if (i > 0) - MailClient.appendP(cmd, esp_mail_str_263, false); - tmp = MailClient.intStr(toCopy->_list[i]); - cmd += tmp; - MailClient.delS(tmp); - } - MailClient.appendP(cmd, esp_mail_str_131, false); - cmd += dest; - - if (MailClient.imapSend(this, cmd.c_str(), true) == ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED) - return false; - - _imap_cmd = esp_mail_imap_command::esp_mail_imap_cmd_store; - if (!MailClient.handleIMAPResponse(this, IMAP_STATUS_BAD_COMMAND, false)) - return false; - } - - return true; -} - -#if defined(ESP8266) -void ESP_Mail_Client::setClock(float offset) -{ - if (WiFi.status() != WL_CONNECTED) - WiFi.reconnect(); - - time_t now = time(nullptr); - - _clockReady = now > ESP_MAIL_CLIENT_VALID_TS; - - if (!_clockReady) - { - char *server1 = strP(esp_mail_str_283); - char *server2 = strP(esp_mail_str_296); - - configTime(offset * 3600, 0, server1, server2); - - now = time(nullptr); - uint8_t attempts = 0; - while (now < ESP_MAIL_CLIENT_VALID_TS) - { - now = time(nullptr); - attempts++; - if (attempts > 200 || now > ESP_MAIL_CLIENT_VALID_TS) - break; - delay(100); - } - - delS(server1); - delS(server2); - } - - _clockReady = now > ESP_MAIL_CLIENT_VALID_TS; -} -#endif - -void IMAPSession::empty() -{ - std::string().swap(_nextUID); - clearMessageData(); -} - -void IMAPSession::clearMessageData() -{ - for (size_t i = 0; i < _headers.size(); i++) - { - _headers[i].part_headers.clear(); - std::vector().swap(_headers[i].part_headers); - } - std::vector().swap(_headers); - std::vector().swap(_msgNum); - _folders.clear(); - _mbif._flags.clear(); - _mbif._searchCount = 0; -} - -SMTPSession::SMTPSession() -{ -} - -SMTPSession::~SMTPSession() -{ - closeSession(); - _caCert.reset(); - _caCert = nullptr; -} - -bool SMTPSession::connect(ESP_Mail_Session *config) -{ - if (_tcpConnected) - MailClient.closeTCP(this); - - _sesson_cfg = config; - _caCert = nullptr; - - if (strlen(_sesson_cfg->certificate.cert_data) > 0) - _caCert = std::shared_ptr(_sesson_cfg->certificate.cert_data); - - if (strlen(_sesson_cfg->certificate.cert_file) > 0) - { - if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_sd && !MailClient._sdOk) - MailClient._sdOk = MailClient.sdTest(); - if (_sesson_cfg->certificate.cert_file_storage_type == esp_mail_file_storage_type::esp_mail_file_storage_type_flash && !MailClient._flashOk) -#if defined(ESP32) - MailClient._flashOk = ESP_MAIL_FLASH_FS.begin(FORMAT_FLASH); -#elif defined(ESP8266) - MailClient._flashOk = ESP_MAIL_FLASH_FS.begin(); -#endif - } - return MailClient.smtpAuth(this); -} - -void SMTPSession::debug(int level) -{ - if (level > esp_mail_debug_level_0) - { - if (level > esp_mail_debug_level_3) - level = esp_mail_debug_level_1; - _debugLevel = level; - _debug = true; - } - else - { - _debugLevel = esp_mail_debug_level_0; - _debug = false; - } -} - -String SMTPSession::errorReason() -{ - std::string ret; - - switch (_smtpStatus.statusCode) - { - case SMTP_STATUS_SERVER_CONNECT_FAILED: - MailClient.appendP(ret, esp_mail_str_38, true); - break; - case SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED: - MailClient.appendP(ret, esp_mail_str_39, true); - break; - case SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED: - MailClient.appendP(ret, esp_mail_str_39, true); - break; - case SMTP_STATUS_AUTHEN_NOT_SUPPORT: - MailClient.appendP(ret, esp_mail_str_42, true); - break; - case SMTP_STATUS_AUTHEN_FAILED: - MailClient.appendP(ret, esp_mail_str_43, true); - break; - case SMTP_STATUS_USER_LOGIN_FAILED: - MailClient.appendP(ret, esp_mail_str_43, true); - break; - case SMTP_STATUS_PASSWORD_LOGIN_FAILED: - MailClient.appendP(ret, esp_mail_str_47, true); - break; - case SMTP_STATUS_SEND_HEADER_SENDER_FAILED: - MailClient.appendP(ret, esp_mail_str_48, true); - break; - case SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED: - MailClient.appendP(ret, esp_mail_str_222, true); - break; - case SMTP_STATUS_SEND_BODY_FAILED: - MailClient.appendP(ret, esp_mail_str_49, true); - break; - case MAIL_CLIENT_ERROR_CONNECTION_LOST: - MailClient.appendP(ret, esp_mail_str_221, true); - break; - case MAIL_CLIENT_ERROR_READ_TIMEOUT: - MailClient.appendP(ret, esp_mail_str_258, true); - break; - case MAIL_CLIENT_ERROR_FILE_IO_ERROR: - MailClient.appendP(ret, esp_mail_str_282, true); - break; - case SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED: - MailClient.appendP(ret, esp_mail_str_293, true); - break; - case MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED: - MailClient.appendP(ret, esp_mail_str_305, true); - break; - case MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP: - MailClient.appendP(ret, esp_mail_str_132, true); - break; - case SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED: - MailClient.appendP(ret, esp_mail_str_206, true); - break; - case SMTP_STATUS_NO_VALID_SENDER_EXISTED: - MailClient.appendP(ret, esp_mail_str_205, true); - break; - case MAIL_CLIENT_ERROR_OUT_OF_MEMORY: - MailClient.appendP(ret, esp_mail_str_186, true); - break; - case SMTP_STATUS_NO_SUPPORTED_AUTH: - MailClient.appendP(ret, esp_mail_str_42, true); - break; - - default: - break; - } - - if (_smtpStatus.text.length() > 0 && ret.length() == 0) - { - MailClient.appendP(ret, esp_mail_str_312, true); - char *code = MailClient.intStr(_smtpStatus.respCode); - ret += code; - MailClient.delS(code); - MailClient.appendP(ret, esp_mail_str_313, false); - ret += _smtpStatus.text; - return ret.c_str(); - } - return ret.c_str(); -} - -bool SMTPSession::closeSession() -{ - if (!_tcpConnected) - return false; - - if (_sendCallback) - { - _cbData._sentSuccess = _sentSuccessCount; - _cbData._sentFailed = _sentFailedCount; - MailClient.smtpCB(this, ""); - MailClient.smtpCBP(this, esp_mail_str_128); - } - - if (_debug) - MailClient.debugInfoP(esp_mail_str_245); - - bool ret = true; - -/* Sign out */ -#if defined(ESP32) - /** - * The strange behavior in ESP8266 SSL client, BearSSLWiFiClientSecure - * The client disposed without memory released after the server close - * the connection due to QUIT command, which caused the memory leaks. - */ - MailClient.smtpSendP(this, esp_mail_str_7, true); - _smtp_cmd = esp_mail_smtp_cmd_logout; - ret = MailClient.handleSMTPResponse(this, esp_mail_smtp_status_code_221, SMTP_STATUS_SEND_BODY_FAILED); -#endif - - if (ret) - { - - if (_sendCallback) - { - MailClient.smtpCB(this, ""); - MailClient.smtpCBP(this, esp_mail_str_129, false); - } - - if (_debug) - MailClient.debugInfoP(esp_mail_str_246); - - if (_sendCallback) - MailClient.smtpCB(this, "", true); - } - - return MailClient.handleSMTPError(this, 0, ret); -} - -void SMTPSession::callback(smtpStatusCallback smtpCallback) -{ - _sendCallback = std::move(smtpCallback); -} - -IMAP_Status::IMAP_Status() -{ -} -IMAP_Status::~IMAP_Status() -{ - empty(); -} - -const char *IMAP_Status::info() -{ - return _info.c_str(); -} - -bool IMAP_Status::success() -{ - return _success; -} - -void IMAP_Status::empty() -{ - std::string().swap(_info); -} - -SMTP_Status::SMTP_Status() -{ -} - -SMTP_Status::~SMTP_Status() -{ - empty(); -} - -const char *SMTP_Status::info() -{ - return _info.c_str(); -} - -bool SMTP_Status::success() -{ - return _success; -} - -size_t SMTP_Status::completedCount() -{ - return _sentSuccess; -} - -size_t SMTP_Status::failedCount() -{ - return _sentFailed; -} - -void SMTP_Status::empty() -{ - std::string().swap(_info); -} - -ESP_Mail_Client MailClient = ESP_Mail_Client(); - -#endif /* ESP_Mail_Client_CPP */ diff --git a/lib/libesp32/lib_mail/src/ESP_Mail_Client.h b/lib/libesp32/lib_mail/src/ESP_Mail_Client.h deleted file mode 100644 index 88785170a..000000000 --- a/lib/libesp32/lib_mail/src/ESP_Mail_Client.h +++ /dev/null @@ -1,2820 +0,0 @@ -#ifndef ESP_Mail_Client_H -#define ESP_Mail_Client_H - -#define ESP_MAIL_VERSION "1.2.0" - -/** - * Mail Client Arduino Library for Espressif's ESP32 and ESP8266 - * - * Version: 1.2.0 - * Released: May 17, 2021 - * - * Updates: - * - Add support ESP8266 Core SDK v3.x.x. - * - * - * This library allows Espressif's ESP32 and ESP8266 devices to send and read - * Email - * through the SMTP and IMAP servers. - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of - * the Software, and to permit persons to whom the Software is furnished to do - * so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS - * OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include -#include "extras/RFC2047.h" -#include "extras/ESPTimeHelper.h" - -#if defined(ESP32) -#define FORMAT_FLASH FORMAT_FLASH_IF_MOUNT_FAILED -#include -#include -//#include -#include -#include "wcs/esp32/ESP_Mail_HTTPClient32.h" -#elif defined(ESP8266) -#include -#define FS_NO_GLOBALS -#include -#include "wcs/esp8266/ESP_Mail_HTTPClient.h" -#endif - -#include "extras/MIMEInfo.h" - -#include -#include -#include - -#if defined(ESP8266) -#define SD_CS_PIN 15 -#endif - -#define SMTP_STATUS_SERVER_CONNECT_FAILED -100 -#define SMTP_STATUS_SMTP_GREETING_GET_RESPONSE_FAILED -101 -#define SMTP_STATUS_SMTP_GREETING_SEND_ACK_FAILED -102 -#define SMTP_STATUS_AUTHEN_NOT_SUPPORT -103 -#define SMTP_STATUS_AUTHEN_FAILED -104 -#define SMTP_STATUS_USER_LOGIN_FAILED -105 -#define SMTP_STATUS_PASSWORD_LOGIN_FAILED -106 -#define SMTP_STATUS_SEND_HEADER_SENDER_FAILED -107 -#define SMTP_STATUS_SEND_HEADER_RECIPIENT_FAILED -108 -#define SMTP_STATUS_SEND_BODY_FAILED -109 -#define SMTP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED -110 -#define SMTP_STATUS_NO_VALID_RECIPIENTS_EXISTED -111 -#define SMTP_STATUS_NO_VALID_SENDER_EXISTED -112 -#define SMTP_STATUS_NO_SUPPORTED_AUTH -113 - -#define IMAP_STATUS_SERVER_CONNECT_FAILED -200 -#define IMAP_STATUS_IMAP_RESPONSE_FAILED -201 -#define IMAP_STATUS_LOGIN_FAILED -202 -#define IMAP_STATUS_BAD_COMMAND -203 -#define IMAP_STATUS_PARSE_FLAG_FAILED -204 -#define IMAP_STATUS_SERVER_OAUTH2_LOGIN_DISABLED -205 -#define IMAP_STATUS_NO_MESSAGE -206 -#define IMAP_STATUS_ERROR_DOWNLAD_TIMEOUT -207 -#define IMAP_STATUS_CLOSE_MAILBOX_FAILED -208 -#define IMAP_STATUS_OPEN_MAILBOX_FAILED -209 -#define IMAP_STATUS_LIST_MAILBOXS_FAILED -210 -#define IMAP_STATUS_CHECK_CAPABILITIES_FAILED -211 -#define IMAP_STATUS_NO_SUPPORTED_AUTH -212 -#define IMAP_STATUS_NO_MAILBOX_FOLDER_OPENED -213 - -#define MAIL_CLIENT_ERROR_CONNECTION_LOST -28 -#define MAIL_CLIENT_ERROR_READ_TIMEOUT -29 -#define MAIL_CLIENT_ERROR_FILE_IO_ERROR -30 -#define MAIL_CLIENT_ERROR_SERVER_CONNECTION_FAILED -31 -#define MAIL_CLIENT_ERROR_SSL_TLS_STRUCTURE_SETUP -32 -#define MAIL_CLIENT_ERROR_OUT_OF_MEMORY -33 - -#define MAX_EMAIL_SEARCH_LIMIT 1000 -#define BASE64_CHUNKED_LEN 76 -#define FLOWED_TEXT_LEN 78 -#define ESP_MAIL_WIFI_RECONNECT_TIMEOUT 10000 -#define ESP_MAIL_PROGRESS_REPORT_STEP 20 -#define ESP_MAIL_CLIENT_TRANSFER_DATA_FAILED 0 -#define ESP_MAIL_CLIENT_STREAM_CHUNK_SIZE 256 -#define ESP_MAIL_CLIENT_VALID_TS 1577836800 - -#if defined(ESP32) -#define ESP_MAIL_MIN_MEM 70000 -#elif defined(ESP8266) -#define ESP_MAIL_MIN_MEM 4000 -#endif - -class IMAPSession; -class SMTPSession; -class SMTP_Status; -class DownloadProgress; -class MessageData; - -enum esp_mail_smtp_status_code -{ - esp_mail_smtp_status_code_0, // default - - /* Positive Completion */ - esp_mail_smtp_status_code_211 = 221, // System status, or system help reply - esp_mail_smtp_status_code_214 = - 214, // Help message(A response to the HELP command) - esp_mail_smtp_status_code_220 = 220, // Service ready - esp_mail_smtp_status_code_221 = - 221, // Service closing transmission channel [RFC 2034] - esp_mail_smtp_status_code_235 = - 235, // 2.7.0 Authentication succeeded[RFC 4954] - esp_mail_smtp_status_code_250 = 250, // Requested mail action okay, completed - esp_mail_smtp_status_code_251 = 251, // User not local; will forward - esp_mail_smtp_status_code_252 = 252, // Cannot verify the user, but it will - // try to deliver the message anyway - - /* Positive Intermediate */ - esp_mail_smtp_status_code_334 = 334, //(Server challenge - the text part - //contains the Base64 - encoded - //challenge)[RFC 4954] - esp_mail_smtp_status_code_354 = 354, // Start mail input - - /* Transient Negative Completion */ - /* "Transient Negative" means the error condition is temporary, and the action - may be requested again.*/ - esp_mail_smtp_status_code_421 = - 421, // Service is unavailable because the server is shutting down. - esp_mail_smtp_status_code_432 = - 432, // 4.7.12 A password transition is needed [RFC 4954] - esp_mail_smtp_status_code_450 = - 450, // Requested mail action not taken: mailbox unavailable (e.g., - // mailbox busy or temporarily blocked for policy reasons) - esp_mail_smtp_status_code_451 = - 451, // Requested action aborted : local error in processing - // e.g.IMAP server unavailable[RFC 4468] - esp_mail_smtp_status_code_452 = - 452, // Requested action not taken : insufficient system storage - esp_mail_smtp_status_code_454 = - 454, // 4.7.0 Temporary authentication failure[RFC 4954] - esp_mail_smtp_status_code_455 = - 455, // Server unable to accommodate parameters - - /* Permanent Negative Completion */ - esp_mail_smtp_status_code_500 = 500, // Syntax error, command unrecognized - // (This may include errors such as - // command line too long) - // e.g. Authentication Exchange line is too long [RFC 4954] - esp_mail_smtp_status_code_501 = - 501, // Syntax error in parameters or arguments - // e.g. 5.5.2 Cannot Base64-decode Client responses [RFC 4954] - // 5.7.0 Client initiated Authentication Exchange (only when the SASL - // mechanism specified that client does not begin the authentication exchange) - // [RFC 4954] - esp_mail_smtp_status_code_502 = 502, // Command not implemented - esp_mail_smtp_status_code_503 = 503, // Bad sequence of commands - esp_mail_smtp_status_code_504 = 504, // Command parameter is not implemented - // e.g. 5.5.4 Unrecognized authentication type [RFC 4954] - esp_mail_smtp_status_code_521 = 521, // Server does not accept mail [RFC 7504] - esp_mail_smtp_status_code_523 = 523, // Encryption Needed [RFC 5248] - esp_mail_smtp_status_code_530 = - 530, // 5.7.0 Authentication required [RFC 4954] - esp_mail_smtp_status_code_534 = - 534, // 5.7.9 Authentication mechanism is too weak [RFC 4954] - esp_mail_smtp_status_code_535 = - 535, // 5.7.8 Authentication credentials invalid [RFC 4954] - esp_mail_smtp_status_code_538 = 538, // 5.7.11 Encryption required for - // requested authentication mechanism[RFC - // 4954] - esp_mail_smtp_status_code_550 = - 550, // Requested action not taken: mailbox unavailable (e.g., mailbox not - // found, no access, or command rejected for policy reasons) - esp_mail_smtp_status_code_551 = - 551, // User not local; please try - esp_mail_smtp_status_code_552 = - 552, // Requested mail action aborted: exceeded storage allocation - esp_mail_smtp_status_code_553 = - 553, // Requested action not taken: mailbox name not allowed - esp_mail_smtp_status_code_554 = 554, // Transaction has failed (Or, in the - // case of a connection-opening response, - // "No SMTP service here") - // e.g. 5.3.4 Message too big for system [RFC 4468] - esp_mail_smtp_status_code_556 = 556, // Domain does not accept mail[RFC 7504] -}; - -enum esp_mail_smtp_port -{ - esp_mail_smtp_port_25 = 25, // PLAIN/TLS with STARTTLS - esp_mail_smtp_port_465 = 465, // SSL - esp_mail_smtp_port_587 = 587 // TLS with STARTTLS -}; - -enum esp_mail_imap_port -{ - esp_mail_imap_port_143 = 143, // PLAIN/TLS with STARTTLS - esp_mail_imap_port_993 = 993, // SSL -}; - -enum esp_mail_smtp_notify -{ - esp_mail_smtp_notify_never = 0, - esp_mail_smtp_notify_success = 1, - esp_mail_smtp_notify_failure = 2, - esp_mail_smtp_notify_delay = 4 -}; - -enum esp_mail_attach_type -{ - esp_mail_att_type_none, - esp_mail_att_type_attachment, - esp_mail_att_type_inline -}; - -enum esp_mail_message_type -{ - esp_mail_msg_type_none = 0, - esp_mail_msg_type_plain = 1, - esp_mail_msg_type_html = 2, - esp_mail_msg_type_enriched = 1 -}; - -enum esp_mail_auth_type -{ - esp_mail_auth_type_psw, - esp_mail_auth_type_oath2, - esp_mail_auth_type_token -}; - -enum esp_mail_imap_auth_mode -{ - esp_mail_imap_mode_examine, - esp_mail_imap_mode_select -}; - -enum esp_mail_imap_response_status -{ - esp_mail_imap_resp_unknown, - esp_mail_imap_resp_ok, - esp_mail_imap_resp_no, - esp_mail_imap_resp_bad -}; - -enum esp_mail_imap_header_state -{ - esp_mail_imap_state_from = 1, - esp_mail_imap_state_to, - esp_mail_imap_state_cc, - esp_mail_imap_state_subject, - esp_mail_imap_state_content_type, - esp_mail_imap_state_content_transfer_encoding, - esp_mail_imap_state_accept_language, - esp_mail_imap_state_content_language, - esp_mail_imap_state_date, - esp_mail_imap_state_msg_id, - esp_mail_imap_state_char_set, - esp_mail_imap_state_boundary -}; - -enum esp_mail_imap_command -{ - esp_mail_imap_cmd_capability, - esp_mail_imap_cmd_starttls, - esp_mail_imap_cmd_login, - esp_mail_imap_cmd_plain, - esp_mail_imap_cmd_auth, - esp_mail_imap_cmd_list, - esp_mail_imap_cmd_select, - esp_mail_imap_cmd_examine, - esp_mail_imap_cmd_close, - esp_mail_imap_cmd_status, - esp_mail_imap_cmd_search, - esp_mail_imap_cmd_fetch_body_header, - esp_mail_imap_cmd_fetch_body_mime, - esp_mail_imap_cmd_fetch_body_text, - esp_mail_imap_cmd_fetch_body_attachment, - esp_mail_imap_cmd_fetch_body_inline, - esp_mail_imap_cmd_logout, - esp_mail_imap_cmd_store, - esp_mail_imap_cmd_expunge, - esp_mail_imap_cmd_create, - esp_mail_imap_cmd_delete -}; - -enum esp_mail_imap_mime_fetch_type -{ - esp_mail_imap_mime_fetch_type_part, - esp_mail_imap_mime_fetch_type_sub_part1, - esp_mail_imap_mime_fetch_type_sub_part2 -}; - -enum esp_mail_smtp_command -{ - esp_mail_smtp_cmd_initial_state, - esp_mail_smtp_cmd_greeting, - esp_mail_smtp_cmd_start_tls, - esp_mail_smtp_cmd_login_user, - esp_mail_smtp_cmd_auth_plain, - esp_mail_smtp_cmd_auth, - esp_mail_smtp_cmd_login_psw, - esp_mail_smtp_cmd_send_header_sender, - esp_mail_smtp_cmd_send_header_recipient, - esp_mail_smtp_cmd_send_body, - esp_mail_smtp_cmd_chunk_termination, - esp_mail_smtp_cmd_logout -}; - -enum esp_mail_imap_header_type -{ - esp_mail_imap_header_from, - esp_mail_imap_header_to, - esp_mail_imap_header_cc, - esp_mail_imap_header_subject, - esp_mail_imap_header_date, - esp_mail_imap_header_msg_id, - esp_mail_imap_header_cont_lang, - esp_mail_imap_header_accept_lang -}; - -enum esp_mail_char_decoding_scheme -{ - esp_mail_char_decoding_scheme_default, - esp_mail_char_decoding_scheme_iso8859_1, - esp_mail_char_decoding_scheme_tis620 -}; - -enum esp_mail_smtp_priority -{ - esp_mail_smtp_priority_high = 1, - esp_mail_smtp_priority_normal = 3, - esp_mail_smtp_priority_low = 5, -}; - -enum esp_mail_smtp_embed_message_type -{ - esp_mail_smtp_embed_message_type_attachment = 0, - esp_mail_smtp_embed_message_type_inline -}; - -enum esp_mail_debug_level -{ - esp_mail_debug_level_0 = 0, - esp_mail_debug_level_1, - esp_mail_debug_level_2 = 222, - esp_mail_debug_level_3 = 333 -}; - -enum esp_mail_imap_multipart_sub_type -{ - esp_mail_imap_multipart_sub_type_none = 0, - esp_mail_imap_multipart_sub_type_mixed, - esp_mail_imap_multipart_sub_type_alternative, - esp_mail_imap_multipart_sub_type_parallel, - esp_mail_imap_multipart_sub_type_digest, - esp_mail_imap_multipart_sub_type_related, - esp_mail_imap_multipart_sub_type_report, -}; - -enum esp_mail_imap_message_sub_type -{ - esp_mail_imap_message_sub_type_none = 0, - esp_mail_imap_message_sub_type_rfc822, - esp_mail_imap_message_sub_type_delivery_status, - esp_mail_imap_message_sub_type_partial, - esp_mail_imap_message_sub_type_external_body, -}; - -/* descrete media types (rfc 2046) */ -struct esp_mail_imap_descrete_media_type_t -{ - /** textual information with subtypes - * "plain" - * "enriched" (rfc 1896 revised from richtext in rfc 1341) - * - * unrecognized subtypes and charset should be interpreted as - * application/octet-stream - * - * parameters: - * "charset" (rfc 2045) default is us-ascii - * for character set includes 8-bit characters - * and such characters are used in the body, Content-Transfer-Encoding - * header field and a corresponding encoding on the data are required - * - * ISO-8859-X where "X" is to be replaced, as - * necessary, for the parts of ISO-8859 [ISO-8859]. - */ - static constexpr const char *text = "text"; - - /** image data with subtypes (rfc 2048) - * "jpeg" - * "gif" - * - * unrecognized subtypes should be interpreted as application/octet-stream - */ - static constexpr const char *image = "image"; - - /** audio data with initial subtype - * "baic" -- for single channel audio encoded using 8bit ISDN mu-law [PCM] - * at a sample rate of 8000 Hz. - * - * Unrecognized subtypes of "audio" should at a miniumum be treated as - * "application/octet-stream" - */ - static constexpr const char *audio = "audio"; - - /** video data with initial subtype - * "mpeg" - * - * Unrecognized subtypes of "video" should at a minumum be treated as - * "application/octet-stream" - */ - static constexpr const char *video = "video"; - - /** some other kind of data, typically either - * uninterpreted binary data or information to be - * processed by an application with subtypes - * - * "octet-stream" -- uninterpreted binary data - * "PostScript" -- for the transport of PostScript material - * - * Other expected uses include spreadsheets, data for mail-based - * scheduling systems, and languages for "active" (computational) - * messaging, and word processing formats that are not directly readable. - * - * The octet-stream subtype parameters: - * TYPE, PADDING, NAME - */ - static constexpr const char *application = "application"; -}; - -/** composite media types (rfc 2046) - * - * As stated in the definition of the Content-Transfer-Encoding field - * [RFC 2045], no encoding other than "7bit", "8bit", or "binary" is - * permitted for entities of type "multipart". The "multipart" boundary - * delimiters and header fields are always represented as 7bit US-ASCII - * in any case (though the header fields may encode non-US-ASCII header - * text as per RFC 2047) and data within the body parts can be encoded - * on a part-by-part basis, with Content-Transfer-Encoding fields for - * each appropriate body part. -*/ -struct esp_mail_imap_composite_media_type_t -{ - /** data consisting of multiple entities of independent data types - * The Content-Type field for multipart entities requires one parameter, - * "boundary". - * The boundary delimiter line is then defined as a line - * consisting entirely of two hyphen characters ("-", decimal value 45) - * followed by the boundary parameter value from the Content-Type header - * field, optional linear whitespace, and a terminating CRLF. - * - * NOTE: The CRLF preceding the boundary delimiter line is conceptually - * attached to the boundary so that it is possible to have a part that - * does not end with a CRLF (line break). Body parts that must be - * considered to end with line breaks, therefore, must have two CRLFs - * preceding the boundary delimiter line, the first of which is part of - * the preceding body part, and the second of which is part of the - * encapsulation boundary. - * - * Boundary delimiters must not appear within the encapsulated material, - * and must be no longer than 70 characters, not counting the two - * leading hyphens. - * - * The boundary delimiter line following the last body part is a - * distinguished delimiter that indicates that no further body parts - * will follow. Such a delimiter line is identical to the previous - * delimiter lines, with the addition of two more hyphens after the - * boundary parameter value. - * - * See rfc2049 Appendix A for a Complex Multipart Example - */ - static constexpr const char *multipart = "multipart"; - - /* an encapsulated message */ - static constexpr const char *message = "message"; -}; - -struct esp_mail_imap_media_text_sub_type_t -{ - static constexpr const char *plain = "plain"; - static constexpr const char *enriched = "enriched"; - static constexpr const char *html = "html"; -}; - -/* multipart sub types */ -struct esp_mail_imap_multipart_sub_type_t -{ - /* a generic mixed set of parts */ - static constexpr const char *mixed = "mixed"; - - /* the same data in multiple formats */ - static constexpr const char *alternative = "alternative"; - - /* parts intended to be viewed simultaneously */ - static constexpr const char *parallel = "parallel"; - - /* multipart entities in which each part has a default type of - * "message/rfc822" */ - static constexpr const char *digest = "digest"; - - /* for compound objects consisting of several inter-related body parts (rfc - * 2387) */ - static constexpr const char *related = "related"; - - /* rfc 3462 */ - static constexpr const char *report = "report"; -}; - -/* message body sub types */ -struct esp_mail_imap_message_sub_type_t -{ - /* body contains an encapsulated message, with the syntax of an RFC 822 - * message. */ - static constexpr const char *rfc822 = "rfc822"; - - /* to allow large objects to be delivered as several separate pieces of mail - */ - static constexpr const char *Partial = "Partial"; - - /* the actual body data are not included, but merely referenced */ - static constexpr const char *External_Body = "External-Body"; - - static constexpr const char *delivery_status = "delivery-status"; -}; - -/** content disposition rfc 2183 - * - * Parameters: - * "filename", "creation-date","modification-date", - * "read-date", * "size" -*/ -struct esp_mail_imap_content_disposition_type_t -{ - /** if it is intended to be displayed automatically - * upon display of the message. - */ - static constexpr const char *inline_ = "inline"; - - /** to indicate that they are separate from the main body - * of the mail message, and that their display should not - * be automatic, but contingent upon some further action of the user. - */ - static constexpr const char *attachment = "attachment"; -}; - -struct esp_mail_internal_use_t -{ - bool binary = false; - std::string cid = ""; -}; - -struct esp_mail_content_transfer_encoding_t -{ - /* The default 7-bit transfer encoding for US-ACII characters*/ - static constexpr const char *enc_7bit = "7bit"; - - /* The quoted printable transfer encoding for non-US-ASCII characters*/ - static constexpr const char *enc_qp = "quoted-printable"; - - /* The base64 encoded transfer encoding */ - static constexpr const char *enc_base64 = "base64"; - - /* The 8-bit transfer encoding for extended-US-ASCII characters*/ - static constexpr const char *enc_8bit = "8bit"; - - /* The binary transfer encoding for extended-US-ASCII characters with no line - * length limit*/ - static constexpr const char *enc_binary = "binary"; -}; - -struct esp_mail_smtp_response_status_t -{ - int respCode = 0; - int statusCode = 0; - std::string text = ""; -}; - -struct esp_mail_imap_response_status_t -{ - int statusCode = 0; - std::string text = ""; -}; - -/* The option to embed this message content as a file */ -struct esp_mail_smtp_embed_message_body_t -{ - /* Enable to send this message body as file */ - bool enable = false; - - /* The name of embedded file */ - const char *filename = ""; - - /** The embedded type - * esp_mail_smtp_embed_message_type_attachment or 0 - * esp_mail_smtp_embed_message_type_inline or 1 - */ - esp_mail_smtp_embed_message_type type = - esp_mail_smtp_embed_message_type_attachment; -}; - -struct esp_mail_file_message_content_t -{ - /* The file path include its name */ - const char *name = ""; - - /** The type of file storages e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - esp_mail_file_storage_type type = esp_mail_file_storage_type_flash; -}; - -struct esp_mail_blob_message_content_t -{ - /* The array of content in flash memory */ - const uint8_t *data = nullptr; - - /* The array size in bytes */ - size_t size = 0; -}; - -/* The PLAIN text body details of the message */ -struct esp_mail_plain_body_t -{ - /* The option to embed this message content as a file */ - struct esp_mail_smtp_embed_message_body_t embed; - - /* The PLAIN text content of the message */ - const char *content = ""; - - /* The blob that contins PLAIN text content of the message */ - struct esp_mail_blob_message_content_t blob; - - /* The file that contins PLAIN text content of the message */ - struct esp_mail_file_message_content_t file; - - /* The charset of the PLAIN text content of the message */ - const char *charSet = "UTF-8"; - - /* The content type of message */ - const char *content_type = "text/plain"; - - /* The option to encode the content for data transfer */ - const char *transfer_encoding = "7bit"; - - /* The option to send the PLAIN text with wrapping */ - bool flowed = false; - - /* The internal usage data */ - struct esp_mail_internal_use_t _int; -}; - -struct esp_mail_html_body_t -{ - /* The option to embedded the content as a file */ - struct esp_mail_smtp_embed_message_body_t embed; - - /* The HTML content of the message */ - const char *content = ""; - - /* The blob that contins HTML content of the message */ - struct esp_mail_blob_message_content_t blob; - - /* The file that contins HTML content of the message */ - struct esp_mail_file_message_content_t file; - - /* The charset of the HTML content of the message */ - const char *charSet = "UTF-8"; - - /* The content type of message */ - const char *content_type = "text/html"; - - /* The option to encode the content for data transfer */ - const char *transfer_encoding = "7bit"; - - /* The internal usage data */ - struct esp_mail_internal_use_t _int; -}; - -struct esp_mail_link_internal_t -{ - std::string cid = ""; -}; - -struct esp_mail_email_info_t -{ - /* The name of Email author*/ - const char *name = ""; - - /* The Email address */ - const char *email = ""; -}; -struct esp_mail_smtp_msg_response_t -{ - /* The author Email address to reply */ - const char *reply_to = ""; - - /* The sender Email address to return the message */ - const char *return_path = ""; - - /** The Delivery Status Notifications e.g. esp_mail_smtp_notify_never, - * esp_mail_smtp_notify_success, - * esp_mail_smtp_notify_failure, and - * esp_mail_smtp_notify_delay - */ - int notify = esp_mail_smtp_notify::esp_mail_smtp_notify_never; -}; - -struct esp_mail_smtp_enable_option_t -{ - /* Enable chunk data sending for large message */ - bool chunking = false; -}; - -struct esp_mail_attach_blob_t -{ - /* BLOB data (flash or ram) */ - const uint8_t *data = nullptr; - - /* BLOB data size in byte */ - size_t size = 0; -}; - -struct esp_mail_attach_file_t -{ - const char *path = ""; - /** The file storage type e.g. esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - esp_mail_file_storage_type storage_type = esp_mail_file_storage_type_none; -}; - -struct esp_mail_attach_descr_t -{ - /* The name of attachment */ - const char *name = ""; - - /* The attachment file name */ - const char *filename = ""; - - /* The MIME type of attachment */ - const char *mime = ""; - - /* The transfer encoding of attachment e.g. base64 */ - const char *transfer_encoding = "base64"; - - /* The content encoding of attachment e.g. base64 */ - const char *content_encoding = ""; - - /* The content id of attachment file */ - const char *content_id = ""; -}; - -struct esp_mail_attach_internal_t -{ - esp_mail_attach_type att_type = esp_mail_att_type_attachment; - int index = 0; - int msg_uid = 0; - bool flash_blob = false; - bool binary = false; - bool parallel = false; - std::string cid = ""; -}; - -struct esp_mail_attachment_t -{ - /* The attachment description */ - struct esp_mail_attach_descr_t descr; - - /* The BLOB data config */ - struct esp_mail_attach_blob_t blob; - - /* The file data config */ - struct esp_mail_attach_file_t file; - - /* reserved for internal usage */ - struct esp_mail_attach_internal_t _int; -}; - -struct esp_mail_smtp_recipient_t -{ - /* The recipient's name */ - const char *name = ""; - - /* The recipient's Email address */ - const char *email = ""; -}; - -struct esp_mail_smtp_recipient_address_t -{ - /* The recipient's Email address */ - const char *email = ""; -}; - -struct esp_mail_smtp_send_status_t -{ - /* The status of the message */ - bool completed = false; - - /* The primary recipient mailbox of the message */ - const char *recipients = ""; - - /* The topic of the message */ - const char *subject = ""; - - /* The timestamp of the message */ - time_t timesstamp = 0; -}; - -struct esp_mail_attacment_info_t -{ - const char *filename = ""; - const char *name = ""; - const char *creationDate = ""; - const char *mime = ""; - esp_mail_attach_type type = esp_mail_att_type_none; - size_t size; -}; - -struct esp_mail_auth_capability_t -{ - bool plain = false; - bool xoauth2 = false; - bool cram_md5 = false; - bool digest_md5 = false; - bool login = false; - bool start_tls = false; -}; - -struct esp_mail_smtp_capability_t -{ - bool esmtp = false; - bool binaryMIME = false; - bool _8bitMIME = false; - bool chunking = false; - bool utf8 = false; - bool pipelining = false; - bool dsn = false; -}; - -struct esp_mail_imap_rfc822_msg_header_item_t -{ - std::string sender = ""; - std::string from; - std::string subject = ""; - std::string messageID = ""; - std::string keyword = ""; - std::string comment = ""; - std::string date = ""; - std::string return_path = ""; - std::string reply_to; - std::string to = ""; - std::string cc = ""; - std::string bcc = ""; -}; - -struct esp_mail_message_part_info_t -{ - int octetLen = 0; - int attach_data_size = 0; - int textLen = 0; - bool sizeProp = false; - int nestedLevel = 0; - std::string partNumStr = ""; - std::string partNumFetchStr = ""; - std::string text = ""; - std::string filename = ""; - std::string type = ""; - std::string save_path = ""; - std::string name = ""; - std::string content_disposition = ""; - std::string content_type = ""; - std::string descr = ""; - std::string content_transfer_encoding = ""; - std::string creation_date = ""; - std::string modification_date = ""; - std::string charset = ""; - std::string download_error = ""; - esp_mail_attach_type attach_type = esp_mail_att_type_none; - esp_mail_message_type msg_type = esp_mail_msg_type_none; - bool file_open_write = false; - bool multipart = false; - esp_mail_imap_multipart_sub_type multipart_sub_type = - esp_mail_imap_multipart_sub_type_none; - esp_mail_imap_message_sub_type message_sub_type = - esp_mail_imap_message_sub_type_none; - bool rfc822_part = false; - int rfc822_msg_Idx = 0; - struct esp_mail_imap_rfc822_msg_header_item_t rfc822_header; - bool error = false; - bool plain_flowed = false; - bool plain_delsp = false; -}; - -struct esp_mail_message_header_t -{ - int header_data_len = 0; - std::string from = ""; - std::string to = ""; - std::string cc = ""; - std::string subject = ""; - std::string content_type = ""; - std::string content_transfer_encoding = ""; - std::string date = ""; - std::string message_id = ""; - std::string message_uid = ""; - std::string message_no = ""; - std::string boundary = ""; - std::string accept_language = ""; - std::string content_language = ""; - std::string char_set = ""; - bool multipart = false; - bool rfc822_part = false; - int rfc822Idx = 0; - std::string partNumStr = ""; - - esp_mail_imap_multipart_sub_type multipart_sub_type = - esp_mail_imap_multipart_sub_type_none; - esp_mail_imap_message_sub_type message_sub_type = - esp_mail_imap_message_sub_type_none; - std::string from_charset = ""; - std::string to_charset = ""; - std::string cc_charset = ""; - std::string subject_charset = ""; - std::string msgID = ""; - std::string error_msg = ""; - bool error = false; - std::vector part_headers = - std::vector(); - int attachment_count = 0; - int total_download_size = 0; - int downloaded_size = 0; - int total_attach_data_size = 0; - int downloaded_bytes = 0; - int message_data_count = 0; -}; - -/* Internal use */ -struct esp_mail_folder_info_t -{ - std::string name = ""; - std::string attributes = ""; - std::string delimiter = ""; -}; - -struct esp_mail_folder_info_item_t -{ - /* The name of folder */ - const char *name = ""; - - /* The attributes of folder */ - const char *attributes = ""; - - /* The delimeter of folder */ - const char *delimiter = ""; -}; - -struct esp_mail_sesson_cert_config_t -{ - /* The certificate data (base64 data) */ - const char *cert_data = ""; - - /* The certificate file (DER format) */ - const char *cert_file = ""; - - /* The storage type */ - esp_mail_file_storage_type cert_file_storage_type; -}; - -struct esp_mail_sesson_sever_config_t -{ - /* The hostName of the server */ - const char *host_name = ""; - /* The port on the server to connect to */ - uint16_t port = 0; -}; - -/* The log in credentials */ -struct esp_mail_sesson_login_config_t -{ - /* The user Email address to log in */ - const char *email = ""; - - /* The user password to log in */ - const char *password = ""; - - /* The OAuth2.0 access token to log in */ - const char *accessToken = ""; - - /* The user domain or ip of client */ - const char *user_domain = ""; -}; - -struct esp_mail_sesson_secure_config_t -{ - /* The option to send the command to start the TLS connection */ - bool startTLS = false; -}; - -struct esp_mail_session_config_t -{ - /* The server config */ - struct esp_mail_sesson_sever_config_t server; - - /* The log in config */ - struct esp_mail_sesson_login_config_t login; - - /* The secure config */ - struct esp_mail_sesson_secure_config_t secure; - - /* The certificate config */ - struct esp_mail_sesson_cert_config_t certificate; -}; - -struct esp_mail_imap_download_config_t -{ - /* To download the PLAIN text content of the message */ - bool text = false; - - /* To download the HTML content of the message */ - bool html = false; - - /* To download the attachments of the message */ - bool attachment = false; - - /* To download the inline image of the message */ - bool inlineImg = false; - - /* To download the rfc822 mesages in the message */ - bool rfc822 = false; - - /* To download the message header */ - bool header = false; -}; - -struct esp_mail_imap_enable_config_t -{ - /* To store the PLAIN text of the message in the IMAPSession */ - bool text = false; - - /* To store the HTML of the message in the IMAPSession */ - bool html = false; - - /* To store the rfc822 messages in the IMAPSession */ - bool rfc822 = false; - - /* To enable the download status via the serial port */ - bool download_status = false; - - /* To sort the message UID of the search result in descending order */ - bool recent_sort = false; -}; - -struct esp_mail_imap_limit_config_t -{ - /* The maximum messages from the search result */ - size_t search = 10; - - /** The maximum size of the memory buffer to store the message content. - * This is only limit for data to be stored in the IMAPSession. - */ - size_t msg_size = 1024; - - /* The maximum size of each attachment to download */ - size_t attachment_size = 1024 * 1024 * 5; -}; - -struct esp_mail_imap_storage_config_t -{ - /* The path to save the downloaded file */ - const char *saved_path = "/"; - - /** The type of file storages e.g. - * esp_mail_file_storage_type_none, - * esp_mail_file_storage_type_flash, and - * esp_mail_file_storage_type_sd - */ - esp_mail_file_storage_type type = esp_mail_file_storage_type_flash; -}; - -struct esp_mail_imap_search_config_t -{ - /* The search criteria */ - const char *criteria = ""; - - /* The option to search the unseen message */ - bool unseen_msg = false; -}; - -struct esp_mail_imap_fetch_config_t -{ - /* The UID of message to fetch */ - const char *uid = ""; - - /* Set the message flag as seen */ - bool set_seen = false; -}; - -struct esp_mail_imap_read_config_t -{ - /* The config for fetching */ - struct esp_mail_imap_fetch_config_t fetch; - - /* The config for search */ - struct esp_mail_imap_search_config_t search; - - /* The config about the limits */ - struct esp_mail_imap_limit_config_t limit; - - /* The config to enable the features */ - struct esp_mail_imap_enable_config_t enable; - - /* The config about downloads */ - struct esp_mail_imap_download_config_t download; - - /* The config about the storage and path to save the downloaded file */ - struct esp_mail_imap_storage_config_t storage; -}; - -/* Mail and MIME Header Fields */ -struct esp_mail_imap_msg_item_t -{ - /* The message number */ - const char *msgNo = ""; - - /* The message UID */ - const char *UID = ""; - - /* The message identifier (RFC 4021) */ - const char *ID = ""; - - /* The language(s) for auto-responses (RFC 4021) */ - const char *acceptLang = ""; - - /* The language of message content (RFC 4021) */ - const char *contentLang = ""; - - /* The mailbox of message author (RFC 4021) */ - const char *from = ""; - - /* The charset of the mailbox of message author */ - const char *fromCharset = ""; - - /* The primary recipient mailbox (RFC 4021) */ - const char *to = ""; - - /* The charset of the primary recipient mailbox */ - const char *toCharset = ""; - - /* The Carbon-copy recipient mailboxes (RFC 4021) */ - const char *cc = ""; - - /* The charset of the Carbon-copy recipient mailbox header */ - const char *ccCharset = ""; - - /* The message date and time (RFC 4021) */ - const char *date = ""; - - /* The topic of message (RFC 4021) */ - const char *subject = ""; - - /* The topic of message charset */ - const char *subjectCharset = ""; - - /* The PLAIN text content of the message */ - struct esp_mail_plain_body_t text; - - /* The HTML content of the message */ - struct esp_mail_html_body_t html; - - /* rfc822 related */ - - /* The sender Email */ - const char *sender; - - /* The message identifier */ - const char *messageID = ""; - - /* The keywords or phrases, separated by commas */ - const char *keyword = ""; - - /* The comment about message */ - const char *comment = ""; - - /* The return recipient of the message */ - const char *return_path = ""; - - /* The Email address to reply */ - const char *reply_to; - - /* The Blind carbon-copy recipients */ - const char *bcc = ""; - - /* The error description from fetching the message */ - const char *fetchError = ""; - - /* The info about the attachments in the message */ - std::vector attachments = - std::vector(); - - /* The info about the rfc822 messages included in the message */ - std::vector rfc822 = - std::vector(); -}; - -struct esp_mail_imap_msg_list_t -{ - /* The info of a message */ - std::vector msgItems = - std::vector(); -}; - -struct esp_mail_smtp_msg_type_t -{ - bool rfc822 = false; - int rfc822Idx = 0; -}; -struct esp_mail_imap_multipart_level_t -{ - uint8_t level = 0; - bool fetch_rfc822_header = false; - bool append_body_text = false; -}; - -/** The content transfer encoding - * enc_7bit or "7bit" - * enc_qp or "quoted-printable" - * enc_base64 or "base64" - * enc_binary or "binary" - * enc_8bit or "8bit" -*/ -typedef struct esp_mail_content_transfer_encoding_t Content_Transfer_Encoding; - -/* The result from sending the Email */ -typedef struct esp_mail_smtp_send_status_t SMTP_Result; - -/* The attachment item details for a message which returned from fetching the - * Email */ -typedef struct esp_mail_attacment_info_t IMAP_Attach_Item; - -/* The attachment details for sending the Email */ -typedef struct esp_mail_attachment_t SMTP_Attachment; - -/* The info of the selected or open mailbox folder e.g. name, attributes and - * delimiter */ -typedef struct esp_mail_folder_info_item_t FolderInfo; - -/* The session configuations */ -typedef struct esp_mail_session_config_t ESP_Mail_Session; - -/** The IMAP operation configuations */ -typedef struct esp_mail_imap_read_config_t IMAP_Config; - -/* The message item data of the IMAP_MSG_List which contains header, body and - * attachments info for eacch message*/ -typedef struct esp_mail_imap_msg_item_t IMAP_MSG_Item; - -/* The list that contains the message items from searching or fetching the Email - */ -typedef struct esp_mail_imap_msg_list_t IMAP_MSG_List; - -static const char esp_mail_str_1[] PROGMEM = - "Content-Type: multipart/mixed; boundary=\""; -static const char esp_mail_str_2[] PROGMEM = "$ CAPABILITY"; -static const char esp_mail_str_3[] PROGMEM = "Mime-Version: 1.0\r\n"; -static const char esp_mail_str_4[] PROGMEM = "AUTH LOGIN"; -static const char esp_mail_str_5[] PROGMEM = "HELO "; -static const char esp_mail_str_6[] PROGMEM = "EHLO "; -static const char esp_mail_str_7[] PROGMEM = "QUIT"; -static const char esp_mail_str_8[] PROGMEM = "MAIL FROM:"; -static const char esp_mail_str_9[] PROGMEM = "RCPT TO:"; -static const char esp_mail_str_10[] PROGMEM = "From: "; -static const char esp_mail_str_11[] PROGMEM = "To: "; -static const char esp_mail_str_12[] PROGMEM = "Cc: "; -static const char esp_mail_str_13[] PROGMEM = ",<"; -static const char esp_mail_str_14[] PROGMEM = "<"; -static const char esp_mail_str_15[] PROGMEM = ">"; -static const char esp_mail_str_16[] PROGMEM = "DATA"; -static const char esp_mail_str_17[] PROGMEM = "X-Priority: "; -static const char esp_mail_str_18[] PROGMEM = "X-MSMail-Priority: High\r\n"; -static const char esp_mail_str_19[] PROGMEM = "X-MSMail-Priority: Normal\r\n"; -static const char esp_mail_str_20[] PROGMEM = "X-MSMail-Priority: Low\r\n"; -static const char esp_mail_str_21[] PROGMEM = "Importance: High\r\n"; -static const char esp_mail_str_22[] PROGMEM = "Importance: Normal\r\n"; -static const char esp_mail_str_23[] PROGMEM = "Importance: Low\r\n"; -static const char esp_mail_str_24[] PROGMEM = "Subject: "; -static const char esp_mail_str_25[] PROGMEM = "Content-Type: "; -static const char esp_mail_str_26[] PROGMEM = "; Name=\""; -static const char esp_mail_str_27[] PROGMEM = "$"; -static const char esp_mail_str_28[] PROGMEM = - "Content-Type: multipart/parallel; boundary=\""; -static const char esp_mail_str_29[] PROGMEM = "7bit"; -static const char esp_mail_str_30[] PROGMEM = - "Content-Disposition: attachment; filename=\""; -static const char esp_mail_str_31[] PROGMEM = "base64"; -static const char esp_mail_str_32[] PROGMEM = "application/octet-stream"; -static const char esp_mail_str_33[] PROGMEM = "--"; -static const char esp_mail_str_34[] PROGMEM = "\r\n"; -static const char esp_mail_str_35[] PROGMEM = "\"\r\n\r\n"; -static const char esp_mail_str_36[] PROGMEM = "\"\r\n"; -static const char esp_mail_str_37[] PROGMEM = "\r\n.\r\n"; -static const char esp_mail_str_38[] PROGMEM = "unable to connect to server"; -static const char esp_mail_str_39[] PROGMEM = "SMTP server greeting failed"; -static const char esp_mail_str_40[] PROGMEM = ".dat"; -static const char esp_mail_str_41[] PROGMEM = "$ AUTHENTICATE PLAIN "; -static const char esp_mail_str_42[] PROGMEM = - "the provided SASL authentication mechanism is not support"; -static const char esp_mail_str_43[] PROGMEM = "authentication failed"; -static const char esp_mail_str_44[] PROGMEM = "mydomain.com"; -static const char esp_mail_str_45[] PROGMEM = "AUTH PLAIN"; -static const char esp_mail_str_46[] PROGMEM = "Return-Path: "; -static const char esp_mail_str_47[] PROGMEM = "login password is not valid"; -static const char esp_mail_str_48[] PROGMEM = "send header failed"; -static const char esp_mail_str_49[] PROGMEM = "send body failed"; -static const char esp_mail_str_50[] PROGMEM = "Connecting to IMAP server..."; -static const char esp_mail_str_51[] PROGMEM = - ".HEADER.FIELDS (SUBJECT FROM SENDER RETURN-PATH TO REPLY-TO DATE CC " - "Message-ID COMMENT KEYWORD content-type Content-transfer-encoding)]"; -static const char esp_mail_str_52[] PROGMEM = "failed"; -static const char esp_mail_str_53[] PROGMEM = "Error, "; -static const char esp_mail_str_54[] PROGMEM = "IMAP server connected"; -static const char esp_mail_str_55[] PROGMEM = "> C: download attachment"; -static const char esp_mail_str_56[] PROGMEM = "Logging in..."; -static const char esp_mail_str_57[] PROGMEM = "Downloading messages..."; -static const char esp_mail_str_58[] PROGMEM = - "Reading the list of mailboxes..."; -static const char esp_mail_str_59[] PROGMEM = - "> C: download plain TEXT message"; -static const char esp_mail_str_60[] PROGMEM = "> C: download HTML message"; -static const char esp_mail_str_61[] PROGMEM = "Selecting the "; -static const char esp_mail_str_62[] PROGMEM = "fail to list the mailboxes"; -static const char esp_mail_str_63[] PROGMEM = "fail to check the capabilities"; -static const char esp_mail_str_64[] PROGMEM = "Check the capability..."; -static const char esp_mail_str_65[] PROGMEM = "> C: check the capability"; -static const char esp_mail_str_66[] PROGMEM = "Searching messages..."; -static const char esp_mail_str_67[] PROGMEM = "message"; -static const char esp_mail_str_68[] PROGMEM = "Search limit:"; -static const char esp_mail_str_69[] PROGMEM = "Found "; -static const char esp_mail_str_70[] PROGMEM = " messages"; -static const char esp_mail_str_71[] PROGMEM = "Show "; -static const char esp_mail_str_72[] PROGMEM = - "No message found for search criteria"; -static const char esp_mail_str_73[] PROGMEM = - "Search criteria does not set, fetch the recent message"; -static const char esp_mail_str_74[] PROGMEM = "Fetching message "; -static const char esp_mail_str_75[] PROGMEM = ", UID: "; -static const char esp_mail_str_76[] PROGMEM = ", Number: "; -static const char esp_mail_str_77[] PROGMEM = "> C: fetch message header"; -static const char esp_mail_str_78[] PROGMEM = "Attachments ("; -static const char esp_mail_str_79[] PROGMEM = ")"; -static const char esp_mail_str_80[] PROGMEM = "Downloading attachments..."; -static const char esp_mail_str_81[] PROGMEM = "> C: fetch body part header, "; -static const char esp_mail_str_82[] PROGMEM = "rfc822"; -static const char esp_mail_str_83[] PROGMEM = "reading"; -static const char esp_mail_str_84[] PROGMEM = "Free Heap: "; -static const char esp_mail_str_85[] PROGMEM = "Logging out..."; -static const char esp_mail_str_86[] PROGMEM = - "> C: fetch body sub part header, "; -static const char esp_mail_str_87[] PROGMEM = "Finished reading Email"; -static const char esp_mail_str_88[] PROGMEM = "> C: finished reading Email"; -static const char esp_mail_str_89[] PROGMEM = "SD card mount failed"; -static const char esp_mail_str_90[] PROGMEM = "download"; -static const char esp_mail_str_91[] PROGMEM = ", "; -static const char esp_mail_str_92[] PROGMEM = "%"; -static const char esp_mail_str_93[] PROGMEM = "connection timeout"; -static const char esp_mail_str_94[] PROGMEM = ".html"; -static const char esp_mail_str_95[] PROGMEM = ".txt"; -static const char esp_mail_str_96[] PROGMEM = " folder..."; -static const char esp_mail_str_97[] PROGMEM = ";"; -static const char esp_mail_str_98[] PROGMEM = - "Content-Disposition: attachment\r\n"; -static const char esp_mail_str_99[] PROGMEM = "Date: "; -static const char esp_mail_str_100[] PROGMEM = "Messsage UID: "; -static const char esp_mail_str_101[] PROGMEM = "Messsage ID: "; -static const char esp_mail_str_102[] PROGMEM = "Accept Language: "; -static const char esp_mail_str_103[] PROGMEM = "Content Language: "; -static const char esp_mail_str_104[] PROGMEM = " BODY=BINARYMIME"; -static const char esp_mail_str_105[] PROGMEM = "From Charset: "; -static const char esp_mail_str_106[] PROGMEM = "BDAT "; -static const char esp_mail_str_107[] PROGMEM = "To Charset: "; -static const char esp_mail_str_108[] PROGMEM = "CC: "; -static const char esp_mail_str_109[] PROGMEM = "CC Charset: "; -static const char esp_mail_str_110[] PROGMEM = "delsp=\"no\""; -static const char esp_mail_str_111[] PROGMEM = "Subject Charset: "; -static const char esp_mail_str_112[] PROGMEM = "Message Charset: "; -static const char esp_mail_str_113[] PROGMEM = "Attachment: "; -static const char esp_mail_str_114[] PROGMEM = "File Index: "; -static const char esp_mail_str_115[] PROGMEM = "Filename: "; -static const char esp_mail_str_116[] PROGMEM = "Name: "; -static const char esp_mail_str_117[] PROGMEM = "Size: "; -static const char esp_mail_str_118[] PROGMEM = "Type: "; -static const char esp_mail_str_119[] PROGMEM = "Creation Date: "; -static const char esp_mail_str_120[] PROGMEM = "Connecting to SMTP server..."; -static const char esp_mail_str_121[] PROGMEM = - "SMTP server connected, wait for greeting..."; -static const char esp_mail_str_122[] PROGMEM = "Sending greeting response..."; -static const char esp_mail_str_123[] PROGMEM = "message/rfc822"; -static const char esp_mail_str_124[] PROGMEM = - "Saving message header to file..."; -static const char esp_mail_str_125[] PROGMEM = "Sending message header..."; -static const char esp_mail_str_126[] PROGMEM = "Sending message body..."; -static const char esp_mail_str_127[] PROGMEM = "Sending attachments..."; -static const char esp_mail_str_128[] PROGMEM = "Closing the session..."; -static const char esp_mail_str_129[] PROGMEM = "Message sent successfully"; -static const char esp_mail_str_130[] PROGMEM = "$ LOGIN "; -static const char esp_mail_str_131[] PROGMEM = " "; -static const char esp_mail_str_132[] PROGMEM = - "fail to set up the SSL/TLS structure"; -static const char esp_mail_str_133[] PROGMEM = "$ LIST \"\" *"; -static const char esp_mail_str_134[] PROGMEM = "Comment: "; -static const char esp_mail_str_135[] PROGMEM = "$ EXAMINE \""; -static const char esp_mail_str_136[] PROGMEM = "\""; -static const char esp_mail_str_137[] PROGMEM = "UID "; -static const char esp_mail_str_138[] PROGMEM = " UID"; -static const char esp_mail_str_139[] PROGMEM = " SEARCH"; -static const char esp_mail_str_140[] PROGMEM = "UID"; -static const char esp_mail_str_141[] PROGMEM = "SEARCH"; -static const char esp_mail_str_142[] PROGMEM = "$ UID FETCH "; -static const char esp_mail_str_143[] PROGMEM = "$ FETCH "; -static const char esp_mail_str_144[] PROGMEM = - "HEADER.FIELDS (SUBJECT FROM TO DATE CC Message-ID Accept-Language " - "content-type Content-transfer-encoding Content-Language)"; -static const char esp_mail_str_145[] PROGMEM = "Keyword: "; -static const char esp_mail_str_146[] PROGMEM = "$ LOGOUT"; -static const char esp_mail_str_147[] PROGMEM = " BODY"; -static const char esp_mail_str_148[] PROGMEM = ".MIME]"; -static const char esp_mail_str_149[] PROGMEM = "Bcc: "; -static const char esp_mail_str_150[] PROGMEM = "Sender: "; -static const char esp_mail_str_151[] PROGMEM = "no mailbox opened"; -static const char esp_mail_str_152[] PROGMEM = "."; -static const char esp_mail_str_153[] PROGMEM = "No mailbox opened"; -static const char esp_mail_str_154[] PROGMEM = "Remove FLAG"; -static const char esp_mail_str_155[] PROGMEM = "Add FLAG"; -static const char esp_mail_str_156[] PROGMEM = "]"; -static const char esp_mail_str_157[] PROGMEM = "Set FLAG"; -static const char esp_mail_str_158[] PROGMEM = - "file does not exist or can't access"; -static const char esp_mail_str_159[] PROGMEM = "msg.html"; -static const char esp_mail_str_160[] PROGMEM = "upload "; -static const char esp_mail_str_161[] PROGMEM = "/msg"; -static const char esp_mail_str_163[] PROGMEM = "/rfc822_msg"; -static const char esp_mail_str_164[] PROGMEM = "msg.txt"; -static const char esp_mail_str_165[] PROGMEM = "Content-Length: "; -static const char esp_mail_str_166[] PROGMEM = "binary"; -static const char esp_mail_str_167[] PROGMEM = "Sending inline data..."; -static const char esp_mail_str_168[] PROGMEM = "charset=\""; -static const char esp_mail_str_169[] PROGMEM = "charset="; -static const char esp_mail_str_170[] PROGMEM = "name=\""; -static const char esp_mail_str_171[] PROGMEM = "name="; -static const char esp_mail_str_172[] PROGMEM = "content-transfer-encoding: "; -static const char esp_mail_str_173[] PROGMEM = " LAST"; -static const char esp_mail_str_174[] PROGMEM = "content-description: "; -static const char esp_mail_str_175[] PROGMEM = "content-disposition: "; -static const char esp_mail_str_176[] PROGMEM = "filename=\""; -static const char esp_mail_str_177[] PROGMEM = "filename="; -static const char esp_mail_str_178[] PROGMEM = "size="; -static const char esp_mail_str_179[] PROGMEM = "creation-date=\""; -static const char esp_mail_str_180[] PROGMEM = "creation-date="; -static const char esp_mail_str_181[] PROGMEM = "modification-date=\""; -static const char esp_mail_str_182[] PROGMEM = "modification-date="; -static const char esp_mail_str_183[] PROGMEM = "*"; -static const char esp_mail_str_184[] PROGMEM = "Reply-To: "; -static const char esp_mail_str_185[] PROGMEM = "> E: "; -static const char esp_mail_str_186[] PROGMEM = "out of memory"; -static const char esp_mail_str_187[] PROGMEM = "Message fetch cmpleted"; -static const char esp_mail_str_188[] PROGMEM = "fail to close the mailbox"; -static const char esp_mail_str_189[] PROGMEM = "message-id: "; -static const char esp_mail_str_190[] PROGMEM = "accept-language: "; -static const char esp_mail_str_191[] PROGMEM = "content-language: "; -static const char esp_mail_str_192[] PROGMEM = ")"; -static const char esp_mail_str_193[] PROGMEM = "{"; -static const char esp_mail_str_194[] PROGMEM = "}"; -static const char esp_mail_str_195[] PROGMEM = "$ CLOSE\r\n"; -static const char esp_mail_str_196[] PROGMEM = "> C: send STARTTLS command"; -static const char esp_mail_str_197[] PROGMEM = "> C: close the mailbox folder"; -static const char esp_mail_str_198[] PROGMEM = "("; -static const char esp_mail_str_199[] PROGMEM = " EXISTS"; -static const char esp_mail_str_200[] PROGMEM = " [UIDNEXT "; -static const char esp_mail_str_201[] PROGMEM = "port > "; -static const char esp_mail_str_202[] PROGMEM = "/"; -static const char esp_mail_str_203[] PROGMEM = "/header.txt"; -static const char esp_mail_str_204[] PROGMEM = "/esp.32"; -static const char esp_mail_str_205[] PROGMEM = - "sender Email address is not valid"; -static const char esp_mail_str_206[] PROGMEM = - "some of the recipient Email address is not valid"; -static const char esp_mail_str_207[] PROGMEM = "> C: send Email"; -static const char esp_mail_str_208[] PROGMEM = "Sending Email..."; -static const char esp_mail_str_209[] PROGMEM = "Send command, STARTTLS"; -static const char esp_mail_str_210[] PROGMEM = "Closing the "; -static const char esp_mail_str_211[] PROGMEM = "host > "; -static const char esp_mail_str_212[] PROGMEM = "FLAGS"; -static const char esp_mail_str_213[] PROGMEM = "BODY"; -static const char esp_mail_str_214[] PROGMEM = "PEEK"; -static const char esp_mail_str_215[] PROGMEM = "TEXT"; -static const char esp_mail_str_216[] PROGMEM = "HEADER"; -static const char esp_mail_str_217[] PROGMEM = "FIELDS"; -static const char esp_mail_str_218[] PROGMEM = "["; -static const char esp_mail_str_219[] PROGMEM = "]"; -static const char esp_mail_str_220[] PROGMEM = "MIME"; -static const char esp_mail_str_221[] PROGMEM = "connection lost"; -static const char esp_mail_str_222[] PROGMEM = "set recipient failed"; -static const char esp_mail_str_223[] PROGMEM = " NEW"; -static const char esp_mail_str_224[] PROGMEM = "ALL"; -static const char esp_mail_str_225[] PROGMEM = "> C: connect to IMAP server"; -static const char esp_mail_str_226[] PROGMEM = "windows-874"; -static const char esp_mail_str_227[] PROGMEM = "iso-8859-1"; -static const char esp_mail_str_228[] PROGMEM = "> C: server connected"; -static const char esp_mail_str_229[] PROGMEM = "> C: send imap command, LOGIN"; -static const char esp_mail_str_230[] PROGMEM = "> C: send imap command, LIST"; -static const char esp_mail_str_231[] PROGMEM = "iso-8859-11"; -static const char esp_mail_str_232[] PROGMEM = "> C: search messages"; -static const char esp_mail_str_233[] PROGMEM = "> C: send imap command, FETCH"; -static const char esp_mail_str_234[] PROGMEM = "> C: send imap command, LOGOUT"; -static const char esp_mail_str_235[] PROGMEM = "> C: message fetch completed"; -static const char esp_mail_str_236[] PROGMEM = "> C: connect to SMTP server"; -static const char esp_mail_str_237[] PROGMEM = "tis-620"; -static const char esp_mail_str_238[] PROGMEM = "> C: smtp server connected"; -static const char esp_mail_str_239[] PROGMEM = "> C: send smtp command, HELO"; -static const char esp_mail_str_240[] PROGMEM = - "> C: send smtp command, AUTH LOGIN"; -static const char esp_mail_str_241[] PROGMEM = - "> C: send smtp command, AUTH PLAIN"; -static const char esp_mail_str_242[] PROGMEM = "> C: send message header"; -static const char esp_mail_str_243[] PROGMEM = "> C: send message body"; -static const char esp_mail_str_244[] PROGMEM = "> C: send attachments"; -static const char esp_mail_str_245[] PROGMEM = - "> C: terminate the SMTP session"; -static const char esp_mail_str_246[] PROGMEM = "> C: Message sent successfully"; -static const char esp_mail_str_247[] PROGMEM = "$ SELECT \""; -static const char esp_mail_str_248[] PROGMEM = "> C: open the mailbox folder"; -static const char esp_mail_str_249[] PROGMEM = "$ UID STORE "; -static const char esp_mail_str_250[] PROGMEM = " FLAGS ("; -static const char esp_mail_str_251[] PROGMEM = " +FLAGS ("; -static const char esp_mail_str_252[] PROGMEM = " -FLAGS ("; -static const char esp_mail_str_253[] PROGMEM = "> C: set FLAG"; -static const char esp_mail_str_254[] PROGMEM = "> C: add FLAG"; -static const char esp_mail_str_255[] PROGMEM = "> C: remove FLAG"; -static const char esp_mail_str_256[] PROGMEM = "could not parse flag"; -static const char esp_mail_str_257[] PROGMEM = "delsp=\"yes\""; -static const char esp_mail_str_258[] PROGMEM = "session timed out"; -static const char esp_mail_str_259[] PROGMEM = "delsp=yes"; -static const char esp_mail_str_260[] PROGMEM = "< S: "; -static const char esp_mail_str_261[] PROGMEM = "> C: "; -static const char esp_mail_str_262[] PROGMEM = " NOTIFY="; -static const char esp_mail_str_263[] PROGMEM = ","; -static const char esp_mail_str_264[] PROGMEM = "SUCCESS"; -static const char esp_mail_str_265[] PROGMEM = "FAILURE"; -static const char esp_mail_str_266[] PROGMEM = "DELAY"; -static const char esp_mail_str_267[] PROGMEM = "Sending next Email..."; -static const char esp_mail_str_268[] PROGMEM = "> C: send next Email"; -static const char esp_mail_str_269[] PROGMEM = - "header.fields (content-type Content-transfer-encoding)]"; -static const char esp_mail_str_270[] PROGMEM = "format=\"flowed\""; -static const char esp_mail_str_271[] PROGMEM = "> C: send inline data"; -static const char esp_mail_str_272[] PROGMEM = "Content-transfer-encoding: "; -static const char esp_mail_str_273[] PROGMEM = "Date: "; -static const char esp_mail_str_274[] PROGMEM = "Message-ID:"; -static const char esp_mail_str_275[] PROGMEM = "format=flowed"; -static const char esp_mail_str_276[] PROGMEM = "CC: "; -static const char esp_mail_str_277[] PROGMEM = "boundary=\""; -static const char esp_mail_str_278[] PROGMEM = "quoted-printable"; -static const char esp_mail_str_279[] PROGMEM = "Subject:"; -static const char esp_mail_str_280[] PROGMEM = "> C: no content"; -static const char esp_mail_str_281[] PROGMEM = "fail to open the mailbox"; -static const char esp_mail_str_282[] PROGMEM = "file I/O error"; -static const char esp_mail_str_283[] PROGMEM = "time.nist.gov"; -static const char esp_mail_str_284[] PROGMEM = - "log in was disabled for this server"; -static const char esp_mail_str_285[] PROGMEM = "user="; -static const char esp_mail_str_286[] PROGMEM = "\1auth=Bearer "; -static const char esp_mail_str_287[] PROGMEM = "\1\1"; -static const char esp_mail_str_288[] PROGMEM = - "> C: send smtp command, AUTH XOAUTH2"; -static const char esp_mail_str_289[] PROGMEM = "AUTH XOAUTH2 "; -static const char esp_mail_str_290[] PROGMEM = - "> C: send imap command, AUTHENTICATE PLAIN"; -static const char esp_mail_str_291[] PROGMEM = - "> C: send imap command, AUTH XOAUTH2"; -static const char esp_mail_str_292[] PROGMEM = "$ AUTHENTICATE XOAUTH2 "; -static const char esp_mail_str_293[] PROGMEM = - "OAuth2.0 log in was disabled for this server"; -static const char esp_mail_str_294[] PROGMEM = "{\"status\":"; -static const char esp_mail_str_295[] PROGMEM = "0123456789ABCDEF"; -static const char esp_mail_str_296[] PROGMEM = "pool.ntp.org"; -static const char esp_mail_str_297[] PROGMEM = - "Content-Type: multipart/alternative; boundary=\""; -static const char esp_mail_str_298[] PROGMEM = - "Content-Type: multipart/related; boundary=\""; -static const char esp_mail_str_299[] PROGMEM = - "Content-Disposition: inline; filename=\""; -static const char esp_mail_str_300[] PROGMEM = "Content-Location: "; -static const char esp_mail_str_301[] PROGMEM = "Content-ID: <"; -static const char esp_mail_str_302[] PROGMEM = "cid:"; -static const char esp_mail_str_303[] PROGMEM = - "Finishing the message sending..."; -static const char esp_mail_str_304[] PROGMEM = - "> C: Finish the message sending"; -static const char esp_mail_str_305[] PROGMEM = "connection failed"; -static const char esp_mail_str_306[] PROGMEM = - "some of the requested messages no longer exist"; -static const char esp_mail_str_307[] PROGMEM = "Reading messages..."; -static const char esp_mail_str_308[] PROGMEM = - "> C: reading plain TEXT message"; -static const char esp_mail_str_309[] PROGMEM = "> C: reading HTML message"; -static const char esp_mail_str_310[] PROGMEM = - "> C: performing the SSL/TLS handshake"; -static const char esp_mail_str_311[] PROGMEM = "STARTTLS\r\n"; -static const char esp_mail_str_312[] PROGMEM = "code: "; -static const char esp_mail_str_313[] PROGMEM = ", text: "; -static const char esp_mail_str_314[] PROGMEM = "> C: ESP Mail Client v"; -static const char esp_mail_str_315[] PROGMEM = " +FLAGS.SILENT (\\Deleted)"; -static const char esp_mail_str_316[] PROGMEM = "> C: delete message(s)"; -static const char esp_mail_str_317[] PROGMEM = "$ EXPUNGE"; -static const char esp_mail_str_318[] PROGMEM = "> C: copy message(s) to "; -static const char esp_mail_str_319[] PROGMEM = "$ UID COPY "; -static const char esp_mail_str_320[] PROGMEM = "> C: create folder"; -static const char esp_mail_str_321[] PROGMEM = "> C: delete folder"; -static const char esp_mail_str_322[] PROGMEM = "$ CREATE "; -static const char esp_mail_str_323[] PROGMEM = "$ DELETE "; -static const char esp_mail_str_324[] PROGMEM = "HEADER.FIELDS"; -static const char esp_mail_str_325[] PROGMEM = "flash content message"; -static const char esp_mail_str_326[] PROGMEM = "file content message"; -static const char esp_mail_str_327[] PROGMEM = "\"; size="; -static const char esp_mail_str_328[] PROGMEM = "0.0.0.0"; - -static const char esp_mail_smtp_response_1[] PROGMEM = "AUTH "; -static const char esp_mail_smtp_response_2[] PROGMEM = " LOGIN"; -static const char esp_mail_smtp_response_3[] PROGMEM = " PLAIN"; -static const char esp_mail_smtp_response_4[] PROGMEM = " XOAUTH2"; -static const char esp_mail_smtp_response_5[] PROGMEM = "STARTTLS"; -static const char esp_mail_smtp_response_6[] PROGMEM = "8BITMIME"; -static const char esp_mail_smtp_response_7[] PROGMEM = "BINARYMIME"; -static const char esp_mail_smtp_response_8[] PROGMEM = "CHUNKING"; -static const char esp_mail_smtp_response_9[] PROGMEM = "SMTPUTF8"; -static const char esp_mail_smtp_response_10[] PROGMEM = "PIPELINING"; -static const char esp_mail_smtp_response_11[] PROGMEM = " CRAM-MD5"; -static const char esp_mail_smtp_response_12[] PROGMEM = " DIGEST-MD5"; -static const char esp_mail_smtp_response_13[] PROGMEM = "DSN"; -// Tagged -static const char esp_mail_imap_response_1[] PROGMEM = "$ OK "; -static const char esp_mail_imap_response_2[] PROGMEM = "$ NO "; -static const char esp_mail_imap_response_3[] PROGMEM = "$ BAD "; -// Untagged -static const char esp_mail_imap_response_4[] PROGMEM = "* LIST "; -static const char esp_mail_imap_response_5[] PROGMEM = "* FLAGS "; -static const char esp_mail_imap_response_6[] PROGMEM = "* SEARCH "; -static const char esp_mail_imap_response_7[] PROGMEM = " FETCH "; -static const char esp_mail_imap_response_8[] PROGMEM = " NIL "; -static const char esp_mail_imap_response_9[] PROGMEM = " UID "; -static const char esp_mail_imap_response_10[] PROGMEM = "* CAPABILITY "; -static const char esp_mail_imap_response_11[] PROGMEM = "LOGINDISABLED"; -static const char esp_mail_imap_response_12[] PROGMEM = "AUTH=PLAIN"; -static const char esp_mail_imap_response_13[] PROGMEM = "AUTH=XOAUTH2"; -static const char esp_mail_imap_response_14[] PROGMEM = "STARTTLS"; -static const char esp_mail_imap_response_15[] PROGMEM = "CRAM-MD5"; -static const char esp_mail_imap_response_16[] PROGMEM = "DIGEST-MD5"; - -static const char imap_7bit_key1[] PROGMEM = "=20"; -static const char imap_7bit_val1[] PROGMEM = " "; -static const char imap_7bit_key2[] PROGMEM = "=2C"; -static const char imap_7bit_val2[] PROGMEM = ","; -static const char imap_7bit_key3[] PROGMEM = "=E2=80=99"; -static const char imap_7bit_val3[] PROGMEM = "'"; -static const char imap_7bit_key4[] PROGMEM = "=0A"; -static const char imap_7bit_val4[] PROGMEM = "\r\n"; -static const char imap_7bit_key5[] PROGMEM = "=0D"; -static const char imap_7bit_val5[] PROGMEM = "\r\n"; -static const char imap_7bit_key6[] PROGMEM = "=A0"; -static const char imap_7bit_val6[] PROGMEM = " "; -static const char imap_7bit_key7[] PROGMEM = "=B9"; -static const char imap_7bit_val7[] PROGMEM = "$sup1"; -static const char imap_7bit_key8[] PROGMEM = "=C2=A0"; -static const char imap_7bit_val8[] PROGMEM = " "; -static const char imap_7bit_key9[] PROGMEM = "=\r\n"; -static const char imap_7bit_val9[] PROGMEM = ""; -static const char imap_7bit_key10[] PROGMEM = "=E2=80=A6"; -static const char imap_7bit_val10[] PROGMEM = "…"; -static const char imap_7bit_key11[] PROGMEM = "=E2=80=A2"; -static const char imap_7bit_val11[] PROGMEM = "•"; -static const char imap_7bit_key12[] PROGMEM = "=E2=80=93"; -static const char imap_7bit_val12[] PROGMEM = "–"; -static const char imap_7bit_key13[] PROGMEM = "=E2=80=94"; -static const char imap_7bit_val13[] PROGMEM = "—"; - -static const unsigned char b64_index_table[65] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char boundary_table[] PROGMEM = - "=_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -__attribute__((used)) static bool compFunc(uint32_t i, uint32_t j) -{ - return (i > j); -} - -class MessageList -{ -public: - friend class IMAPSession; - MessageList(){}; - ~MessageList() { clear(); }; - void add(int uid) - { - if (uid > 0) - _list.push_back(uid); - } - - void clear() { _list.clear(); } - -private: - std::vector _list = std::vector(); -}; - -/* The class that provides the info of selected or opened mailbox folder */ -class SelectedFolderInfo -{ -public: - friend class ESP_Mail_Client; - friend class IMAPSession; - SelectedFolderInfo(){}; - ~SelectedFolderInfo() { clear(); }; - - /* Get the flags count for this mailbox */ - size_t flagCount() { return _flags.size(); }; - - /* Get the numbers of messages in this mailbox */ - size_t msgCount() { return _msgCount; }; - - /* Get the predict next message UID */ - size_t nextUID() { return _nextUID; }; - - /* Get the numbers of messages from search result based on the search criteria - */ - size_t searchCount() { return _searchCount; }; - - /* Get the numbers of messages to be stored in the ressult */ - size_t availableMessages() { return _availableItems; }; - - /* Get the flag argument at the specified index */ - String flag(size_t index) - { - if (index < _flags.size()) - return _flags[index].c_str(); - return ""; - } - -private: - void addFlag(const char *flag) { _flags.push_back(flag); }; - void clear() - { - for (size_t i = 0; i < _flags.size(); i++) - std::string().swap(_flags[i]); - _flags.clear(); - } - size_t _msgCount = 0; - size_t _nextUID = 0; - size_t _searchCount = 0; - size_t _availableItems = 0; - std::vector _flags = std::vector(); -}; - -/* The class that provides the list of FolderInfo e.g. name, attributes and - * delimiter */ -class FoldersCollection -{ -public: - friend class ESP_Mail_Client; - friend class IMAPSession; - FoldersCollection(){}; - ~FoldersCollection() { clear(); }; - size_t size() { return _folders.size(); }; - - struct esp_mail_folder_info_item_t info(size_t index) - { - struct esp_mail_folder_info_item_t fd; - if (index < _folders.size()) - { - fd.name = _folders[index].name.c_str(); - fd.attributes = _folders[index].attributes.c_str(); - fd.delimiter = _folders[index].delimiter.c_str(); - } - return fd; - } - -private: - void add(struct esp_mail_folder_info_t &fd) { _folders.push_back(fd); }; - void clear() - { - for (size_t i = 0; i < _folders.size(); i++) - { - if (_folders[i].name.length() > 0) - std::string().swap(_folders[i].name); - if (_folders[i].attributes.length() > 0) - std::string().swap(_folders[i].attributes); - if (_folders[i].delimiter.length() > 0) - std::string().swap(_folders[i].delimiter); - } - _folders.clear(); - } - std::vector _folders = - std::vector(); -}; - -/* The class that provides the status of message feching and searching */ -class IMAP_Status -{ -public: - IMAP_Status(); - ~IMAP_Status(); - const char *info(); - bool success(); - void empty(); - friend class IMAPSession; - - std::string _info = ""; - bool _success = false; -}; - -/* The SMTP message class */ -class SMTP_Message -{ -public: - SMTP_Message(){}; - ~SMTP_Message() { clear(); }; - - void resetAttachItem(SMTP_Attachment &att) - { - att.blob.size = 0; - att.blob.data = nullptr; - att.file.path = ""; - att.file.storage_type = esp_mail_file_storage_type_none; - att.descr.name = ""; - att.descr.filename = ""; - att.descr.transfer_encoding = ""; - att.descr.content_encoding = ""; - att.descr.mime = ""; - att.descr.content_id = ""; - att._int.att_type = esp_mail_att_type_none; - att._int.index = 0; - att._int.msg_uid = 0; - att._int.flash_blob = false; - att._int.binary = false; - att._int.parallel = false; - att._int.cid = ""; - } - - void clear() - { - sender.name = ""; - sender.email = ""; - subject = ""; - text.charSet = ""; - text.content = ""; - text.content_type = ""; - text.embed.enable = false; - html.charSet = ""; - html.content = ""; - html.content_type = ""; - html.embed.enable = false; - response.reply_to = ""; - response.notify = esp_mail_smtp_notify::esp_mail_smtp_notify_never; - priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal; - - for (size_t i = 0; i < _rcp.size(); i++) - { - _rcp[i].name = ""; - _rcp[i].email = ""; - } - - for (size_t i = 0; i < _cc.size(); i++) - _cc[i].email = ""; - - for (size_t i = 0; i < _bcc.size(); i++) - _bcc[i].email = ""; - - for (size_t i = 0; i < _hdr.size(); i++) - _hdr[i] = ""; - - for (size_t i = 0; i < _att.size(); i++) - { - _att[i].descr.filename = ""; - _att[i].blob.data = nullptr; - _att[i].descr.mime = ""; - _att[i].descr.name = ""; - _att[i].blob.size = 0; - _att[i].descr.transfer_encoding = ""; - _att[i].file.path = ""; - _att[i].file.storage_type = esp_mail_file_storage_type_none; - } - - for (size_t i = 0; i < _parallel.size(); i++) - { - _parallel[i].descr.filename = ""; - _parallel[i].blob.data = nullptr; - _parallel[i].descr.mime = ""; - _parallel[i].descr.name = ""; - _parallel[i].blob.size = 0; - _parallel[i].descr.transfer_encoding = ""; - _parallel[i].file.path = ""; - _parallel[i].file.storage_type = esp_mail_file_storage_type_none; - } - _rcp.clear(); - _cc.clear(); - _bcc.clear(); - _hdr.clear(); - _att.clear(); - _parallel.clear(); - } - - /** Clear all the inline images - */ - void clearInlineimages() - { - for (int i = (int)_att.size() - 1; i >= 0; i--) - { - if (_att[i]._int.att_type == esp_mail_att_type_inline) - _att.erase(_att.begin() + i); - } - }; - - /* Clear all the attachments */ - void clearAttachments() - { - for (int i = (int)_att.size() - 1; i >= 0; i--) - { - if (_att[i]._int.att_type == esp_mail_att_type_attachment) - _att.erase(_att.begin() + i); - } - - for (int i = (int)_parallel.size() - 1; i >= 0; i--) - _parallel.erase(_parallel.begin() + i); - }; - - /** Clear all rfc822 message attachment - */ - void clearRFC822Messages() - { - for (int i = (int)_rfc822.size() - 1; i >= 0; i--) - { - _rfc822[i].clear(); - _rfc822.erase(_rfc822.begin() + i); - } - }; - - /** Clear the primary recipient mailboxes - */ - void clearRecipients() { _rcp.clear(); }; - - /** Clear the Carbon-copy recipient mailboxes - */ - void clearCc() { _cc.clear(); }; - - /** Clear the Blind-carbon-copy recipient mailboxes - */ - void clearBcc() { _bcc.clear(); }; - - /** Clear the custom message headers - */ - void clearHeader() { _hdr.clear(); }; - - /** Add attachment to the message - * - * @param att The SMTP_Attachment data item - */ - void addAttachment(SMTP_Attachment &att) - { - att._int.att_type = esp_mail_att_type_attachment; - att._int.parallel = false; - att._int.flash_blob = true; - _att.push_back(att); - }; - - /** Add parallel attachment to the message - * - * @param att The SMTP_Attachment data item - */ - void addParallelAttachment(SMTP_Attachment &att) - { - att._int.att_type = esp_mail_att_type_attachment; - att._int.parallel = true; - att._int.flash_blob = true; - _parallel.push_back(att); - }; - - /** Add inline image to the message - * - * @param att The SMTP_Attachment data item - */ - void addInlineImage(SMTP_Attachment &att) - { - att._int.flash_blob = true; - att._int.parallel = false; - att._int.att_type = esp_mail_att_type_inline; - char *tmp = new char[36]; - memset(tmp, 0, 36); - itoa(random(10000000, 20000000), tmp, 10); - att._int.cid = tmp; - delete[] tmp; - _att.push_back(att); - }; - - /** Add rfc822 message to the message - * - * @param msg The RFC822_Message class object - */ - void addMessage(SMTP_Message &msg) { _rfc822.push_back(msg); } - - /** Add the primary recipient mailbox to the message - * - * @param name The name of primary recipient - * @param email The Email address of primary recipient - */ - void addRecipient(const char *name, const char *email) - { - struct esp_mail_smtp_recipient_t rcp; - rcp.name = name; - rcp.email = email; - _rcp.push_back(rcp); - }; - - /** Add Carbon-copy recipient mailbox - * - * @param email The Email address of the secondary recipient - */ - void addCc(const char *email) - { - struct esp_mail_smtp_recipient_address_t cc; - cc.email = email; - _cc.push_back(cc); - }; - - /** Add Blind-carbon-copy recipient mailbox - * - * @param email The Email address of the tertiary recipient - */ - void addBcc(const char *email) - { - struct esp_mail_smtp_recipient_address_t bcc; - bcc.email = email; - _bcc.push_back(bcc); - }; - - /** Add the custom header to the message - * - * @param hdr The header name and value - */ - void addHeader(const char *hdr) { _hdr.push_back(hdr); }; - - /* The message author config */ - struct esp_mail_email_info_t sender; - - /* The topic of message */ - const char *subject = ""; - - /* The message type */ - byte type = esp_mail_msg_type_none; - - /* The PLAIN text message */ - struct esp_mail_plain_body_t text; - - /* The HTML text message */ - struct esp_mail_html_body_t html; - - /* The response config */ - struct esp_mail_smtp_msg_response_t response; - - /* The priority of the message */ - esp_mail_smtp_priority priority = - esp_mail_smtp_priority::esp_mail_smtp_priority_normal; - - /* The enable options */ - struct esp_mail_smtp_enable_option_t enable; - - /* The message from config */ - struct esp_mail_email_info_t from; - - /* The message identifier */ - const char *messageID = ""; - - /* The keywords or phrases, separated by commas */ - const char *keyword = ""; - - /* The comment about message */ - const char *comment = ""; - - /* The date of message */ - const char *date = ""; - - /* The return recipient of the message */ - const char *return_path = ""; - -private: - friend class ESP_Mail_Client; - std::vector _rcp = - std::vector(); - std::vector _cc = - std::vector(); - std::vector _bcc = - std::vector(); - std::vector _hdr = std::vector(); - std::vector _att = std::vector(); - std::vector _parallel = std::vector(); - std::vector _rfc822 = std::vector(); -}; - -class SMTP_Status -{ -public: - friend class SMTPSession; - friend class ESP_Mail_Client; - - SMTP_Status(); - ~SMTP_Status(); - const char *info(); - bool success(); - void empty(); - size_t completedCount(); - size_t failedCount(); - -private: - std::string _info = ""; - bool _success = false; - size_t _sentSuccess = 0; - size_t _sentFailed = 0; -}; - -typedef void (*imapStatusCallback)(IMAP_Status); -typedef void (*smtpStatusCallback)(SMTP_Status); - -class ESP_Mail_Client -{ - -public: - /** Sending Email through the SMTP server - * - * @param smtp The pointer to SMTP session object which holds the data and the - * TCP client. - * @param msg The pointer to SMTP_Message class which contains the header, - * body, and attachments. - * @param closeSession The option to Close the SMTP session after sent. - * @return The boolean value indicates the success of operation. - */ - bool sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true); - - /** Reading Email through IMAP server. - * - * @param imap The pointer to IMAP sesssion object which holds the data and - the TCP client. - - * @param closeSession The option to close the IMAP session after fetching or - searching the Email. - * @return The boolean value indicates the success of operation. - */ - bool readMail(IMAPSession *imap, bool closeSession = true); - - /** Set the argument to the Flags for the specified message. - * - * @param imap The pointer to IMAP session object which holds the data and the - * TCP client. - * @param msgUID The UID of the message. - * @param flags The flag list to set. - * @param closeSession The option to close the IMAP session after set flag. - * @return The boolean value indicates the success of operation. - */ - bool setFlag(IMAPSession *imap, int msgUID, const char *flags, - bool closeSession); - - /** Add the argument to the Flags for the specified message. - * - * @param imap The pointer to IMAP session object which holds the data and the - * TCP client. - * @param msgUID The UID of the message. - * @param flags The flag list to set. - * @param closeSession The option to close the IMAP session after add flag. - * @return The boolean value indicates the success of operation. - */ - bool addFlag(IMAPSession *imap, int msgUID, const char *flags, - bool closeSession); - - /** Remove the argument from the Flags for the specified message. - * - * @param imap The pointer to IMAP session object which holds the data and the - * TCP client. - * @param msgUID The UID of the message that flags to be removed. - * @param flags The flag list to remove. - * @param closeSession The option to close the IMAP session after remove flag. - * @return The boolean value indicates the success of operation. - */ - bool removeFlag(IMAPSession *imap, int msgUID, const char *flags, - bool closeSession); - - /** Initialize the SD card with the SPI port. - * - * @param sck The SPI Clock pin (ESP32 only). - * @param miso The SPI MISO pin (ESSP32 only). - * @param mosi The SPI MOSI pin (ESP32 only). - * @param ss The SPI Chip/Slave Select pin (ESP32 and ESP8266). - * @return The boolean value indicates the success of operation. - */ - bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss); - - /** Initialize the SD card with the default SPI port. - * - * @return The boolean value which indicates the success of operation. - */ - bool sdBegin(); - - /** Initialize the SD_MMC card (ESSP32 only). - * - * @param mountpoint The mounting point. - * @param mode1bit Allow 1 bit data line. - * @param format_if_mount_failed Format SD_MMC card if mount failed. - * @return The boolean value indicates the success of operation. - */ - bool sdMMCBegin(const char *mountpoint = "/sdcard", bool mode1bit = false, bool format_if_mount_failed = false); - - - ESPTimeHelper Time; - -private: - friend class SMTPSession; - friend class IMAPSession; -#if defined(ESP8266) - void setClock(float offset); -#endif - - RFC2047_Decoder RFC2047Decoder; - File file; - - bool _sdOk = false; - bool _flashOk = false; - bool _sdConfigSet = false; - uint8_t _sck, _miso, _mosi, _ss; - const char *sd_mmc_mountpoint = ""; - bool sd_mmc_mode1bit = false; - bool sd_mmc_format_if_mount_failed = false; - -#if defined(ESP8266) - bool _clockReady = false; - uint8_t _sdPin = SD_CS_PIN; - float _gmtOffset = 0.0; -#endif - - unsigned long _lastReconnectMillis = 0; - uint16_t _reconnectTimeout = ESP_MAIL_WIFI_RECONNECT_TIMEOUT; - - bool _sendMail(SMTPSession *smtp, SMTP_Message *msg, - bool closeSession = true); - bool ethLinkUp(); - bool reconnect(SMTPSession *smtp, unsigned long dataTime = 0); - bool reconnect(IMAPSession *imap, unsigned long dataTime = 0, - bool downloadRequestuest = false); - void closeTCP(SMTPSession *smtp); - void closeTCP(IMAPSession *imap); - void getMIME(const char *ext, std::string &mime); - void mimeFromFile(const char *name, std::string &mime); -#if defined(ESP32) - void setSecure(ESP_Mail_HTTPClient32 &httpClient, ESP_Mail_Session *session, - std::shared_ptr caCert); -#elif defined(ESP8266) - void setSecure(ESP_Mail_HTTPClient &httpClient, ESP_Mail_Session *session, - std::shared_ptr caCert); -#endif - void delS(char *p); - char *newS(size_t len); - char *newS(char *p, size_t len); - char *newS(char *p, size_t len, char *d); - bool strcmpP(const char *buf, int ofs, PGM_P beginH); - int strposP(const char *buf, PGM_P beginH, int ofs); - char *strP(PGM_P pgm); - void appendP(std::string &buf, PGM_P p, bool empty); - char *intStr(int value); - void errorStatusCB(SMTPSession *smtp, int error); - size_t smtpSendP(SMTPSession *smtp, PGM_P v, bool newline = false); - size_t smtpSend(SMTPSession *smtp, const char *data, bool newline = false); - size_t smtpSend(SMTPSession *smtp, int data, bool newline = false); - size_t smtpSend(SMTPSession *smtp, uint8_t *data, size_t size); - bool getMultipartFechCmd(IMAPSession *imap, int msgIdx, - std::string &partText); - bool multipartMember(const std::string &part, const std::string &check); - bool fetchMultipartBodyHeader(IMAPSession *imap, int msgIdx); - bool connected(IMAPSession *imap); - bool imapAuth(IMAPSession *imap); - bool sendIMAPCommand(IMAPSession *imap, int msgIndex, int cmdCase); - bool handleSMTPError(SMTPSession *smtp, int err, bool ret = false); - void errorStatusCB(IMAPSession *imap, int error); - size_t imapSendP(IMAPSession *imap, PGM_P v, bool newline = false); - size_t imapSend(IMAPSession *imap, const char *data, bool nwline = false); - size_t imapSend(IMAPSession *imap, int data, bool newline = false); - std::string getBoundary(size_t len); - std::string getEncodedToken(IMAPSession *imap); - bool imapLogout(IMAPSession *imap); - bool sendParallelAttachments(SMTPSession *smtp, SMTP_Message *msg, - const std::string &boundary); - bool sendAttachments(SMTPSession *smtp, SMTP_Message *msg, - const std::string &boundary, bool parallel = false); - - bool sendMSGData(SMTPSession *smtp, SMTP_Message *msg, bool closeSession, - bool rfc822MSG); - bool sendRFC822Msg(SMTPSession *smtp, SMTP_Message *msg, - const std::string &boundary, bool closeSession, - bool rfc822MSG); - void getRFC822MsgEnvelope(SMTPSession *smtp, SMTP_Message *msg, - std::string &buf); - bool bdat(SMTPSession *smtp, SMTP_Message *msg, int len, bool last); - void checkBinaryData(SMTPSession *smtp, SMTP_Message *msg); - bool sendBlob(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att); - bool sendFile(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, - File &file); - bool openFileRead(SMTPSession *smtp, SMTP_Message *msg, SMTP_Attachment *att, - File &file, std::string &s, std::string &buf, - const std::string &boundary, bool inlined); - bool openFileRead2(SMTPSession *smtp, SMTP_Message *msg, File &file, - const char *path, esp_mail_file_storage_type storageType); - bool sendInline(SMTPSession *smtp, SMTP_Message *msg, - const std::string &boundary, byte type); - void debugInfoP(PGM_P info); - size_t numAtt(SMTPSession *smtp, esp_mail_attach_type type, - SMTP_Message *msg); - bool validEmail(const char *s); - bool checkEmail(SMTPSession *smtp, SMTP_Message *msg); - bool sendPartText(SMTPSession *smtp, SMTP_Message *msg, byte type, - const char *boundary); - char *getUID(); - bool sendBlobBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type); - bool sendFileBody(SMTPSession *smtp, SMTP_Message *msg, uint8_t type); - void encodingText(SMTPSession *smtp, SMTP_Message *msg, uint8_t type, - std::string &content); - void splitTk(std::string &str, std::vector &tk, - const char *delim); - void formatFlowedText(std::string &content); - void softBreak(std::string &content, const char *quoteMarks); - bool sendMSG(SMTPSession *smtp, SMTP_Message *msg, - const std::string &boundary); - void getAttachHeader(std::string &header, const std::string &boundary, - SMTP_Attachment *attach, size_t size); - void getRFC822PartHeader(SMTPSession *smtp, std::string &header, - const std::string &boundary); - void getInlineHeader(std::string &header, const std::string &boundary, - SMTP_Attachment *inlineAttach, size_t size); - unsigned char *decodeBase64(const unsigned char *src, size_t len, - size_t *out_len); - std::string encodeBase64Str(const unsigned char *src, size_t len); - std::string encodeBase64Str(uint8_t *src, size_t len); - void encodeQP(const char *buf, char *out); - bool sendBase64(SMTPSession *smtp, SMTP_Message *msg, - const unsigned char *data, size_t len, bool flashMem, - const char *filename, bool report); - bool sendBase64Stream(SMTPSession *smtp, SMTP_Message *msg, File file, - const char *filename, bool report); - void smtpCBP(SMTPSession *smtp, PGM_P info, bool success = false); - void smtpCB(SMTPSession *smtp, const char *info, bool success = false); - void imapCBP(IMAPSession *imap, PGM_P info, bool success); - void imapCB(IMAPSession *imap, const char *info, bool success); - int readLine(WiFiClient *stream, char *buf, int bufLen, bool crlf, - int &count); -#if defined(ESP32) - int _readLine(ESP_Mail_WCS32 *stream, char *buf, int bufLen, bool crlf, - int &count); -#elif defined(ESP8266) - int _readLine(ESP_Mail::ESP_Mail_WCS *stream, char *buf, int bufLen, - bool crlf, int &count); -#endif - int getMSGNUM(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, - bool &endSearch, int &nump, const char *key, const char *pc); - void handleHeader(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, - struct esp_mail_message_header_t &header, int &headerState, - int &octetCount); - void setHeader(IMAPSession *imap, char *buf, - struct esp_mail_message_header_t &header, int state); - void handlePartHeader(IMAPSession *imap, char *buf, int &chunkIdx, - struct esp_mail_message_part_info_t &part); - char *subStr(const char *buf, PGM_P beginH, PGM_P endH, int beginPos, - int endPos = 0); - struct esp_mail_message_part_info_t *cPart(IMAPSession *imap); - struct esp_mail_message_header_t *cHeader(IMAPSession *imap); - void strcat_c(char *str, char c); - int strpos(const char *haystack, const char *needle, int offset); - char *stristr(const char *str1, const char *str2); - char *rstrstr(const char *haystack, const char *needle); - int rstrpos(const char *haystack, const char *needle, int offset); - void getResponseStatus(const char *buf, esp_mail_smtp_status_code respCode, - int beginPos, - struct esp_mail_smtp_response_status_t &status); - void handleAuth(SMTPSession *smtp, char *buf); - std::string getEncodedToken(SMTPSession *smtp); - bool connected(SMTPSession *smtp); - bool setSendingResult(SMTPSession *smtp, SMTP_Message *msg, bool result); - bool smtpAuth(SMTPSession *smtp); - int available(SMTPSession *smtp); - bool handleSMTPResponse(SMTPSession *smtp, esp_mail_smtp_status_code respCode, - int errCode); - int available(IMAPSession *imap); - bool handleIMAPResponse(IMAPSession *imap, int errCode, bool closeSession); - void downloadReport(IMAPSession *imap, int progress); - void fetchReport(IMAPSession *imap, int progress, bool html); - void searchReport(int progress, const char *percent); - void uploadReport(const char *filename, int progress); - int cMSG(IMAPSession *imap); - int cIdx(IMAPSession *imap); - esp_mail_imap_response_status imapResponseStatus(IMAPSession *imap, - char *response); - void saveHeader(IMAPSession *imap); - esp_mail_char_decoding_scheme getEncodingFromCharset(const char *enc); - void decodeHeader(std::string &headerField, std::string &headerEnc); - bool handleAttachment(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, - File &file, std::string &filePath, - bool &downloadRequest, int &octetCount, - int &octetLength, int &oCount, int &reportState, - int &downloadCount); - int decodeLatin1_UTF8(unsigned char *out, int *outlen, - const unsigned char *in, int *inlen); - void decodeTIS620_UTF8(char *out, const char *in, size_t len); - void decodeText(IMAPSession *imap, char *buf, int bufLen, int &chunkIdx, - File &file, std::string &filePath, bool &downloadRequest, - int &octetLength, int &readDataLen, int &readCount); - void prepareFilePath(IMAPSession *imap, std::string &filePath, bool header); - int decodeChar(const char *s); - void decodeQP(const char *buf, char *out); - char *decode7Bit(char *buf); - char *strReplace(char *orig, char *rep, char *with); - char *strReplaceP(char *buf, PGM_P key, PGM_P value); - bool authFailed(char *buf, int bufLen, int &chunkIdx, int ofs); - void handleFolders(IMAPSession *imap, char *buf); - void handleCapability(IMAPSession *imap, char *buf, int &chunkIdx); - void handleExamine(IMAPSession *imap, char *buf); - bool handleIMAPError(IMAPSession *imap, int err, bool ret); - bool _setFlag(IMAPSession *imap, int msgUID, const char *flags, - uint8_t action, bool closeSession); - void createDirs(std::string dirs); - bool sdTest(); -}; - -class IMAPSession -{ -public: - IMAPSession(); - ~IMAPSession(); - - /** Begin the IMAP server connection. - * - * @param session The pointer to ESP_Mail_Session structured data that keeps - * the server and log in details. - * @param config The pointer to IMAP_Config structured data that keeps the - * operation options. - * @return The boolean value which indicates the success of operation. - */ - bool connect(ESP_Mail_Session *session, IMAP_Config *config); - - /** Close the IMAP session. - * - * @return The boolean value which indicates the success of operation. - */ - bool closeSession(); - - /** Set to enable the debug. - * - * @param level The level to enable the debug message - * level = 0, no debug - * level = 1, basic debug - * level = 2, full debug 1 - * level = 333, full debug 2 - */ - void debug(int level); - - /** Get the list of all the mailbox folders since the TCP session was opened - * and user was authenticated. - * - * @param folders The FoldersCollection class that contains the collection of - * the - * FolderInfo structured data. - * @return The boolean value which indicates the success of operation. - */ - bool getFolders(FoldersCollection &folders); - - /** Select or open the mailbox folder to search or fetch the message inside. - * - * @param folderName The known mailbox folder name. The default name is INBOX. - * @param readOnly The option to open the mailbox for read only. Set this - * option to false when you wish - * to modify the Flags using the setFlag, addFlag and removeFlag functions. - * @return The boolean value which indicates the success of operation. - */ - bool selectFolder(const char *folderName, bool readOnly = true); - - /** Open the mailbox folder to read or search the mesages. - * - * @param folderName The name of known mailbox folder to be opened. - * @param readOnly The option to open the mailbox for reading only. Set this - * option to false when you wish - * to modify the flags using the setFlag, addFlag and removeFlag functions. - * @return The boolean value which indicates the success of operation. - */ - bool openFolder(const char *folderName, bool readOnly = true); - - /** Close the mailbox folder that was opened. - * - * @param folderName The known mailbox folder name. - * @return The boolean value which indicates the success of operation. - */ - bool closeFolder(const char *folderName); - - /** Create folder. - * - * @param folderName The name of folder to create. - * @return The boolean value which indicates the success of operation. - */ - bool createFolder(const char *folderName); - - /** Delete folder. - * - * @param folderName The name of folder to delete. - * @return The boolean value which indicates the success of operation. - */ - bool deleteFolder(const char *folderName); - - /** Copy the messages to the defined mailbox folder. - * - * @param toCopy The pointer to the MessageListList class that contains the - * list of messages to copy. - * @param dest The destination folder that the messages to copy to. - * @return The boolean value which indicates the success of operation. - */ - bool copyMessages(MessageList *toCopy, const char *dest); - - /** Delete the messages in the opened mailbox folder. - * - * @param toDelete The pointer to the MessageListList class that contains the - * list of messages to delete. - * @param expunge The boolean option to expunge all messages. - * @return The boolean value which indicates the success of operation. - */ - bool deleteMessages(MessageList *toDelete, bool expunge = false); - - /** Assign the callback function that returns the operating status when - * fetching or reading the Email. - * - * @param imapCallback The function that accepts the imapStatusCallback as - * parameter. - */ - void callback(imapStatusCallback imapCallback); - - /** Determine if no message body contained in the search result and only the - * message header is available. - */ - bool headerOnly(); - - /** Get the message list from search or fetch the Emails - * - * @return The IMAP_MSG_List structured data which contains text and html - * contents, - * attachments, inline images, embedded rfc822 messages details for each - * message. - */ - IMAP_MSG_List data(); - - /** Get the details of the selected or opned mailbox folder - * - * @return The SelectedFolderInfo class which contains the info about flags, - * total messages, next UID, - * search count and the available messages count. - */ - SelectedFolderInfo selectedFolder(); - - /** Get the error details when readingg the Emails - * - * @return The string of error details. - */ - String errorReason(); - - /** Clear all the cache data stored in the IMAP session object. - */ - void empty(); - - friend class ESP_Mail_Client; - friend class foldderList; - -private: - void clearMessageData(); - void checkUID(); - void checkPath(); - void getMessages(uint16_t messageIndex, struct esp_mail_imap_msg_item_t &msg); - void getRFC822Messages(uint16_t messageIndex, - struct esp_mail_imap_msg_item_t &msg); - bool closeMailbox(); - bool openMailbox(const char *folder, esp_mail_imap_auth_mode mode, - bool waitResponse); - bool getMailboxes(FoldersCollection &flders); - bool checkCapability(); - - bool _tcpConnected = false; - struct esp_mail_imap_response_status_t _imapStatus; - int _cMsgIdx = 0; - int _cPartIdx = 0; - int _totalRead = 0; - std::vector _headers = - std::vector(); - - esp_mail_imap_command _imap_cmd = - esp_mail_imap_command::esp_mail_imap_cmd_login; - // std::string _partNumStr = ""; - std::vector _multipart_levels = - std::vector(); - int _rfc822_part_count = 0; - esp_mail_file_storage_type _storageType = - esp_mail_file_storage_type::esp_mail_file_storage_type_flash; - bool _unseen = false; - bool _readOnlyMode = true; - struct esp_mail_auth_capability_t _auth_capability; - ESP_Mail_Session *_sesson_cfg; - std::string _currentFolder = ""; - bool _mailboxOpened = false; - std::string _nextUID = ""; - - struct esp_mail_imap_read_config_t *_config = nullptr; - - bool _headerOnly = true; - bool _uidSearch = false; - bool _headerSaved = false; - bool _debug = false; - int _debugLevel = 0; - bool _secure = false; - imapStatusCallback _readCallback = NULL; - - std::vector _msgNum = std::vector(); - FoldersCollection _folders; - SelectedFolderInfo _mbif; - - int _certType = -1; - std::shared_ptr _caCert = nullptr; - -#if defined(ESP32) - ESP_Mail_HTTPClient32 httpClient; -#elif defined(ESP8266) - ESP_Mail_HTTPClient httpClient; -#endif - - IMAP_Status _cbData; -}; - -class SendingResult -{ -private: - std::vector _result = - std::vector(); - void add(struct esp_mail_smtp_send_status_t r) - { - struct esp_mail_smtp_send_status_t _r = r; - _result.push_back(_r); - } - void clear() - { - for (size_t i = 0; i < _result.size(); i++) - { - _result[i].recipients = ""; - _result[i].subject = ""; - _result[i].timesstamp = 0; - _result[i].completed = false; - } - _result.clear(); - } - -public: - friend class SMTPSession; - friend class ESP_Mail_Client; - SendingResult(){}; - ~SendingResult() { clear(); }; - SMTP_Result getItem(size_t index) - { - struct esp_mail_smtp_send_status_t r; - if (index < _result.size()) - return _result[index]; - return r; - } - size_t size() { return _result.size(); }; -}; - -class SMTPSession -{ -public: - SMTPSession(); - ~SMTPSession(); - - /** Begin the SMTP server connection. - * - * @param session The pointer to ESP_Mail_Session structured data that keeps - * the server and log in details. - * @return The boolean value indicates the success of operation. - */ - bool connect(ESP_Mail_Session *session); - - /** Close the SMTP session. - * - */ - bool closeSession(); - - /** Set to enable the debug. - * - * @param level The level to enable the debug message - * level = 0, no debug - * level = 1, basic debug - * level = 2, full debug 1 - * level = 333, full debug 2 - */ - void debug(int level); - - /** Get the error details when sending the Email - * - * @return The string of error details. - */ - String errorReason(); - - /** Set the Email sending status callback function. - * - * @param smtpCallback The callback function that accept the - * smtpStatusCallback param. - */ - void callback(smtpStatusCallback smtpCallback); - - SendingResult sendingResult; - - friend class ESP_Mail_Client; - -private: - bool _tcpConnected = false; - struct esp_mail_smtp_response_status_t _smtpStatus; - int _sentSuccessCount = 0; - int _sentFailedCount = 0; - bool _chunkedEnable = false; - int _chunkCount = 0; - - esp_mail_smtp_command _smtp_cmd = - esp_mail_smtp_command::esp_mail_smtp_cmd_greeting; - struct esp_mail_auth_capability_t _auth_capability; - struct esp_mail_smtp_capability_t _send_capability; - ESP_Mail_Session *_sesson_cfg = NULL; - - bool _debug = false; - int _debugLevel = 0; - bool _secure = false; - smtpStatusCallback _sendCallback = NULL; - - SMTP_Status _cbData; - struct esp_mail_smtp_msg_type_t _msgType; - - int _certType = -1; - std::shared_ptr _caCert = nullptr; - -#if defined(ESP32) - ESP_Mail_HTTPClient32 httpClient; -#elif defined(ESP8266) - ESP_Mail_HTTPClient httpClient; -#endif -}; - - -//#define EMAIL_DEBUG_PRINTLN Serial.println -//#define EMAIL_DEBUG_PRINT Serial.print -#define EMAIL_DEBUG_PRINTLN Tasmota_print -#define EMAIL_DEBUG_PRINT Tasmota_print - -extern void Tasmota_print(const char *); - -static void __attribute__((used)) esp_mail_debug(const char *msg) -{ - delay(0); - EMAIL_DEBUG_PRINTLN(msg); -} - -static void __attribute__((used)) -esp_mail_debug_line(const char *msg, bool newline) -{ - delay(0); - if (newline) - EMAIL_DEBUG_PRINTLN(msg); - else - EMAIL_DEBUG_PRINT(msg); -} - -extern ESP_Mail_Client MailClient; - -extern FS *ufsp; - -#endif // ESP_Mail_Client_H diff --git a/lib/libesp32/lib_mail/src/ESP_Mail_FS.h b/lib/libesp32/lib_mail/src/ESP_Mail_FS.h deleted file mode 100644 index 0e9007fcb..000000000 --- a/lib/libesp32/lib_mail/src/ESP_Mail_FS.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef ESP_Mail_CONFIG_H -#define ESP_Mail_CONFIG_H -#include - -/** - * To use other flash file systems - * - * LittleFS File system - * - * #include - * #define ESP_Mail_DEFAULT_FLASH_FS LittleFS //For ESP8266 LitteFS - * - * - * FFat File system - * - * #include - * #define ESP_Mail_DEFAULT_FLASH_FS FFat //For ESP32 FFat - * -*/ -// #define ESP_Mail_DEFAULT_FLASH_FS SPIFFS - -#include -#define ESP_Mail_DEFAULT_FLASH_FS LittleFS - -/** - * To use SD card file systems with different hardware interface - * e.g. SDMMC hardware bus on the ESP32 - * https://github.com/espressif/arduino-esp32/tree/master/libraries/SD#faq - * - #include - #define ESP_Mail_DEFAULT_SD_FS SD_MMC //For ESP32 SDMMC - #define CARD_TYPE_SD_MMC 1 - * -*/ -#define ESP_Mail_DEFAULT_SD_FS SD -#define CARD_TYPE_SD 1 - -//For ESP32, format SPIFFS or FFat if mounting failed -#define FORMAT_FLASH_IF_MOUNT_FAILED 1 - - -#endif \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/README.md b/lib/libesp32/lib_mail/src/README.md deleted file mode 100644 index 0e9c5094e..000000000 --- a/lib/libesp32/lib_mail/src/README.md +++ /dev/null @@ -1,2031 +0,0 @@ -# ESP Mail Client Arduino Library for ESP32 and ESP8266 - - -The detail and usage of the available functions in the latest version (1.2.0) are showed below. - - -## Global functions - - -#### Sending Email through the SMTP server. - -param **`smtp`** The pointer to SMTP session object which holds the data and the TCP client. - -param **`msg`** The pointer to SMTP_Message class which contains the header, body, and attachments. - -param **`closeSession`** The option to Close the SMTP session after sent. - -return **`boolean`** The boolean value indicates the success of operation. - -```C++ -bool sendMail(SMTPSession *smtp, SMTP_Message *msg, bool closeSession = true); -``` - - - - - -#### Reading Email through IMAP server. - -param **`imap`** The pointer to IMAP sesssion object which holds the data and the TCP client. - -param **`closeSession`** The option to close the IMAP session after fetching or searching the Email. - -return **`boolean`** The boolean value indicates the success of operation. - -```C++ -bool readMail(IMAPSession *imap, bool closeSession = true); -``` - - - - - -#### Set the argument to the Flags for the specified message. - -param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. - -param **`msgUID`** The UID of the message. - -param **`flags`** The flag list to set. - -param **`closeSession`** The option to close the IMAP session after set flag. - -return **`boolean`** The boolean value indicates the success of operation. - -```C++ -bool setFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); -``` - - - - - -#### Add the argument to the Flags for the specified message. - -param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. - -param **`msgUID`** The UID of the message. - -param **`flags`** The flag list to set. - -param **`closeSession`** The option to close the IMAP session after add flag. - -return **`boolean`** The boolean value indicates the success of operation. - -```C++ -bool addFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); -``` - - - - - - -#### Remove the argument from the Flags for the specified message. - -param **`imap`** The pointer to IMAP session object which holds the data and the TCP client. - -param **`msgUID`** The UID of the message that flags to be removed. - -param **`flags`** The flag list to remove. - -param **`closeSession`** The option to close the IMAP session after remove flag. - -return **`boolean`** The boolean value indicates the success of operation. - -```C++ -bool removeFlag(IMAPSession *imap, int msgUID, const char *flags, bool closeSession); -``` - - - - - - -#### Initialize the SD card with the SPI port. - -param **`sck`** The SPI Clock pin (ESP32 only). - -param **`miso`** The SPI MISO pin (ESSP32 only). - -param **`mosi`** The SPI MOSI pin (ESP32 only). - -param **`ss`** The SPI Chip/Slave Select pin (ESP32 and ESP8266). - -return **`boolean`** The boolean value indicates the success of operation. - -```C++ -bool sdBegin(uint8_t sck, uint8_t miso, uint8_t mosi, uint8_t ss); -``` - - - - - - -#### Initialize the SD_MMC card (ESP32 only). - -param **`mountpoint`** The mounting point. - -param **`mode1bit`** Allow 1 bit data line (SPI mode). - -param **`format_if_mount_failed`** Format SD_MMC card if mount failed. - -return **`Boolean`** type status indicates the success of the operation. - -```C++ -bool sdMMCBegin(const char *mountpoint = "/sdcard", bool mode1bit = false, bool format_if_mount_failed = false); -``` - - - - - - -#### Initialize the SD card with the default SPI port. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool sdBegin(void); -``` - - - - - - -## IMAPSession class functions - - -The following functions are available from the IMAP Session class. - -This class used for controlling IMAP transports and retrieving the data from the IMAP server. - - - - - -#### Begin the IMAP server connection. - -param **`session`** The pointer to ESP_Mail_Session structured data that keeps the server and log in details. - -param **`config`** The pointer to IMAP_Config structured data that keeps the operation options. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool connect(ESP_Mail_Session *session, IMAP_Config *config); -``` - - -#### Close the IMAP session. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool closeSession(); -``` - - - - - - -#### Set to enable the debug. - -param **`level`** The level to enable the debug message - -level = 0, no debug - -level = 1, basic debug - -level = 2, full debug 1 - -level = 333, full debug 2 - -```C++ -void debug(int level); -``` - - - - - -#### Get the list of all the mailbox folders since the TCP session was opened and user was authenticated. - -param **`folders`** The FoldersCollection class that contains the collection of the -FolderInfo structured data. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool getFolders(FoldersCollection &folders); -``` - - - - - -#### Select or open the mailbox folder to search or fetch the message inside. - -param **`folderName`** The known mailbox folder name. The default name is INBOX. - -param **`readOnly`** The option to open the mailbox for read only. Set this option to false when you wish -to modify the Flags using the setFlag, addFlag and removeFlag functions. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool selectFolder(const char *folderName, bool readOnly = true); -``` - - - - - -#### Open the mailbox folder to read or search the mesages. - -param **`folderName`** The name of known mailbox folder to be opened. - -param **`readOnly`** The option to open the mailbox for reading only. Set this option to false when you wish -to modify the flags using the setFlag, addFlag and removeFlag functions. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool openFolder(const char *folderName, bool readOnly = true); -``` - - - - - -#### Close the mailbox folder that was opened. - -param **`folderName`** The mailbox folder name. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool closeFolder(const char *folderName); -``` - - - - - - -#### Create folder. - -param **`folderName`** The name of folder to create. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool createFolder(const char *folderName); -``` - - - - - - -#### Delete folder. - -param **`folderName`** The name of folder to delete.. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool deleteFolder(const char *folderName); -``` - - - - - - -#### Copy the messages to the defined mailbox folder. - -param **`toCopy`** The pointer to the MessageList class that contains the list of messages to copy. - -param **`dest`** The destination folder that the messages to copy to. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool copyMessages(MessageList *toCopy, const char *dest); -``` - - - - - -#### Delete the messages in the opened mailbox folder. - -param **`toDelete`** The pointer to the MessageList class that contains the list of messages to delete. - -param **`expunge`** The boolean option to expunge all messages. - -return **`boolean`** The boolean value which indicates the success of operation. - -```C++ -bool deleteMessages(MessageList *toDelete, bool expunge = false); -``` - - - - - - - -#### Assign the callback function that returns the operating status when fetching or reading the Email. - -param **`imapCallback`** The function that accepts the imapStatusCallback as parameter. - -```C++ -void callback(imapStatusCallback imapCallback); -``` - - - - - -#### Determine if no message body contained in the search result and only the message header is available. - -```C++ -bool headerOnly(); -``` - - - - - -#### Get the message list from search or fetch the Emails - -return **`The IMAP_MSG_List structured`** data which contains the text and html contents, -attachments, inline images, embedded rfc822 messages details for each message. - -```C++ -IMAP_MSG_List data(); -``` - - - - - -#### Get the details of the selected or opned mailbox folder - -return **`The SelectedFolderInfo class`** instance which contains the info about flags, total messages, next UID, -earch count and the available messages count. - -```C++ -SelectedFolderInfo selectedFolder(); -``` - - - - - -#### Get the error details when readingg the Emails - -return **`String`** The string of error details. - -```C++ -String errorReason(); -``` - - - - - -#### Clear all the cache data stored in the IMAP session object. - -```C++ -void empty(); -``` - - - - - -## IMAPSession class functions - - -The following functions are available from the SMTP Session class. - -This class is similar to the IMAP session class, used for controlling SMTP transports -and retrieving the data from the SMTP server. - - - - - - -#### Begin the SMTP server connection. - -param **`session`** The pointer to ESP_Mail_Session structured data that keeps the server and log in details. - -return **`boolean`** The boolean value indicates the success of operation. - -```C++ -bool connect(ESP_Mail_Session *session); -``` - - - - - -### Close the SMTP session. - -```C++ -bool closeSession(); -``` - - - - - -#### Set to enable the debug. - -param **`level`** The level to enable the debug message - -level = 0, no debug - -level = 1, basic debug - -level = 2, full debug 1 - -level = 333, full debug 2 - -```C++ -void debug(int level); -``` - - - - - -#### Get the error details when sending the Email - -return **`String`** The string of error details. - -```C++ -String errorReason(); -``` - - - - - -#### Set the Email sending status callback function. - -param **`smtpCallback`** The callback function that accept the smtpStatusCallback param. - -```C++ -void callback(smtpStatusCallback smtpCallback); -``` - - - - - -## SMTP_Message class functions - - -The following functions are available from the SMTP Message class. - -This class is used for storing the message data including headers, body and attachments -which will be processed with the SMTP session class. - - - - -#### To reset the SMTP_Attachment item data - -param **`att`** The SMTP_Attachment class that stores the info about attachment - -This function was used for clear the internal data of attachment item to be ready for reuse. - -```C++ -void resetAttachItem(SMTP_Attachment &att); -``` - - - -#### To clear all data in SMTP_Message class included headers, bodies and attachments - -```C++ -void clear(); -``` - - - - -#### To clear all the inline images in SMTP_Message class. - -```C++ -void clearInlineimages(); -``` - - - - - -#### To clear all the attachments. - -```C++ -void clearAttachments(); -``` - - - - - -#### To clear all rfc822 message attachment. - -```C++ -void clearRFC822Messages(); -``` - - - - - -#### To clear the primary recipient mailboxes. - -```C++ -void clearRecipients(); -``` - - - - - -#### To clear the Carbon-copy recipient mailboxes. - -```C++ -void clearCc(); -``` - - - - - -#### To clear the Blind-carbon-copy recipient mailboxes. - -```C++ -void clearBcc(); -``` - - -#### To clear the custom message headers. - -```C++ -void clearHeader(); -``` - - - - -#### To add attachment to the message. - -param **`att`** The SMTP_Attachment data item - -```C++ -void addAttachment(SMTP_Attachment &att); -``` - - - - - -#### To add parallel attachment to the message. - -param **`att`** The SMTP_Attachment data item - -```C++ -void addParallelAttachment(SMTP_Attachment &att); -``` - - - - - -#### To add inline image to the message. - -param **`att`** The SMTP_Attachment data item - -```C++ -void addInlineImage(SMTP_Attachment &att); -``` - - - - - -#### To add rfc822 message to the message. - -param **`msg`** The RFC822_Message class object - -```C++ -void addMessage(SMTP_Message &msg); -``` - - - - - -#### To add the primary recipient mailbox to the message. - -param **`name`** The name of primary recipient - -param **`email`** The Email address of primary recipient - -```C++ -void addRecipient(const char *name, const char *email); -``` - - - - - -#### To add Carbon-copy recipient mailbox. - -param **`email`** The Email address of secondary recipient - -```C++ -void addCc(const char *email); -``` - - - - - -#### To add Blind-carbon-copy recipient mailbox. - -param **`email`** The Email address of the tertiary recipient - -```C++ -void addBcc(const char *email); -``` - - - - - -#### To add the custom header to the message. - -param **`hdr`** The header name and value - -```C++ -void addHeader(const char *hdr); -``` - - - - -##### [properties] The message author config - -This property has the sub properties - -###### [const char*] name - The sender name. - -###### [const char*] email - The sender Email address. - -```C++ -esp_mail_email_info_t sender; -``` - - -##### [properties] The topic of message - -```C++ -const char *subject; -``` - - -##### [properties] The message type - -```C++ -byte type; -``` - - -##### [properties] The PLAIN text message - -This property has the sub properties - -###### [esp_mail_smtp_embed_message_body_t] embed - The option to embed this message content as a file. - -###### [const char*] content - The PLAIN text content of the message. - -###### [esp_mail_blob_message_content_t] blob - The blob that contins PLAIN text content of the message. - -###### [esp_mail_file_message_content_t] file - The file that contins PLAIN text content of the message. - -###### [const char*] charSet - The character transcoding of the PLAIN text content of the message. - -###### [const char*] content_type - The content type of message. - -###### [const char*] transfer_encoding - The option to encode the content for data transfer. - -###### [boolean] flowed - The option to send the PLAIN text with wrapping. - -```C++ -esp_mail_plain_body_t text; -``` - - -##### [properties] The HTML text message - -This propery has the sub properties - -###### [const char*] content - The HTML content of the message. - -###### [esp_mail_blob_message_content_t] blob - The blob that contins HTML content of the message. - -###### [esp_mail_file_message_content_t] file - The file that contins HTML content of the message. - -###### [const char*] charSet - The character transcoding of the HTML content of the message. - -###### [const char*] content_type - The content type of message. - -###### [const char*] transfer_encoding - The option to encode the content for data transfer. - -```C++ -esp_mail_html_body_t html; -``` - - -##### [properties] The response config - -This propery has the sub properties - -###### [const char*] reply_to - The author Email address to reply. - -###### [const char*] return_path - The sender Email address to return the message. - -###### [int] notify - The Delivery Status Notifications enumeration e.g. - -esp_mail_smtp_notify_never = 0, - -esp_mail_smtp_notify_success = 1, - -esp_mail_smtp_notify_failure = 2, and - -esp_mail_smtp_notify_delay = 4 - -```C++ -esp_mail_smtp_msg_response_t response; -``` - - -##### [properties] The priority of the message - -This property has the enumeration values - -esp_mail_smtp_priority_high = 1, - -esp_mail_smtp_priority_normal = 3, - -esp_mail_smtp_priority_low = 5 - -```C++ -esp_mail_smtp_priority priority; -``` - - -##### [properties] The enable options - -This propery has the sub property - -###### [boolean] chunking - enable chunk data sending for large message. - -```C++ -esp_mail_smtp_enable_option_t enable; -``` - - -##### [properties] The message from config - -This property has the sub properties - -###### [const char*] name - The messsage author name. - -###### [const char*] email - The message author Email address. - -```C++ -esp_mail_email_info_t from; -``` - - -##### [properties] The message identifier - -```C++ -const char *messageID; -``` - -##### [properties] The keywords or phrases, separated by commas - -```C++ -const char *keyword; -``` - - -##### [properties] The comment about message - -```C++ -const char *comment; -``` - - -##### [properties] The date of message - -```C++ -const char *date; -``` - - -##### [properties] The return recipient of the message - -```C++ -const char *return_path; -``` - - - - - - -## IMAP_Status class functions - - -The following functions are available from the IMAP Status class. - -This class is used as the callback parameter for retrieving the status while reading the Email. - - - - -#### Provide the information of each process in the reading operation. - -return **`string`** The info for each process - -```C++ -const char *info(); -``` - - - - -#### Provide the status of completion. - -return **`boolean`** The bool value indicates that all reading processes are finished - -```C++ -bool success(); -``` - - - - - -#### To clear all data store in this class. - -```C++ -void empty(); -``` - - - - - - -## SMTP_Status class functions - - -The following functions are available from the SMTP Status class. - -This class is used as the callback parameter for retrieving the status while sending the Email. - - - - -#### Provide the information of each process in the sending operation. - -return **`string`** The info for each process - -```C++ -const char *info(); -``` - - - - -#### Provide the status of completion. - -return **`boolean`** The bool value indicates that all sending processes are finished - -```C++ -bool success(); -``` - - - - - -#### To clear all data store in this class. - -```C++ -void empty(); -``` - - - - -#### Provide the number of complete sending message. - -return **`number`** The number of message that was sent - -```C++ -size_t completedCount(); -``` - - - - - -#### Provide the number of failed sending message. - -return **`number`** The number of message that was not sent - -```C++ -size_t failedCount(); -``` - - - - -## SendingResult class functions - - -The following functions are available from the SendingResult class. - -This class is used for retrieving the info about the result of sending the messages. - - - - -#### Provide the information of a message sending status. - -param **`index`** The index number of a message sending status - -return **`SMTP_Result`** The SMTP_Result type data that provides these properties - -##### [bool] completed - The status of the message - -#### [const char *] recipients - The primary recipient mailbox of the message - -#### [const char *] subject - The topic of the message - -#### [time_t] timesstamp - The timestamp of the message - -```C++ -SMTP_Result getItem(size_t index); -``` - - - - - -#### Provide the amount of the result data. - -return **`number`** The number of result item - -```C++ -size_t size(); -``` - - - - -## FoldersCollection class functions - - -The following functions are available from the FoldersCollection class. - -This class is used for retrieving the info about the mailbox folders which available to read or serach -in the user Email mailbox. - - - - -#### Provide the information of a folder in a folder collection. - -param **`index`** The index number of folders - -return **`esp_mail_folder_info_item_t`** The esp_mail_folder_info_item_t structured data that provides these properties - -#### [const char *] name - The name of folder - -#### [const char *] attributes - The attributes of folder - -#### [const char *] delimiter - The delimeter of folder - -```C++ -esp_mail_folder_info_item_t info(size_t index); -``` - - - - - -#### Provide the number of folders in the collection. - -return **`number`** The number of folder in the collection - -```C++ -size_t size(); -``` - - - - - - -## SelectedFolderInfo class functions - - -The following functions are available from the SelectedFolderInfo class. - -This class is used for retrieving the info about the sselected or opened mailbox folder. - - - - -#### Provide the numbers of flags in the user Email mailbox. - -return **`number`** The numbers of flags - -```C++ -size_t flagCount(); -``` - - - - - -#### Provide the numbers of messages in this mailbox. - -return **`number`** The numbers of messages in the selected mailbox folder - -```C++ -size_t msgCount(); -``` - - - - - -#### Provide the predicted next message UID in the sselected folder. - -return **`number`** The number represents the next message UID number - -```C++ -size_t nextUID(); -``` - - - - - -#### Provide the numbers of messages from search result based on the search criteria. - -return **`number`** The total number of messsages from search - -```C++ -size_t searchCount(); -``` - - - - - -#### Provide the numbers of messages to be stored in the ressult. - -return **`number`** The number of messsage stored from search - -```C++ -size_t availableMessages(); -``` - - - - - -#### Provide the flag argument at the specified index. - -return **`index`** The index of flag in the flags list - -return **`String`** The argument of selected flag - -```C++ -String flag(size_t index); -``` - - - - -## ESP_Mail_Session type data - - -The following properties are available from the ESP_Mail_Session data type. - -This data type is used for storing the session info about the server and login credentials. - - -#### [Properties] The server config - -This property has the sub properties - -##### [const char *] host_name - The hostName of the server. - -##### [uint16_t] port - The port on the server to connect to. - -```C++ -esp_mail_sesson_sever_config_t server; -``` - - -#### [Properties] The log in config - -This property has the sub properties - -##### [const char *] email - The user Email address to log in. - -##### [consst char *] password - The user password to log in. - -##### [consst char *] accessToken - The OAuth2.0 access token to log in. - -##### [consst char *] user_domain - The user domain or ip of client. - -```C++ -esp_mail_sesson_login_config_t login; -``` - - -#### [Properties] The secure config - -This property has the sub properties - -##### [bool] startTLS - The option to send the command to start the TLS connection. - -```C++ -esp_mail_sesson_secure_config_t secure; -``` - - - -#### [Properties] The certificate config - -##### [const char *] cert_data - The certificate data (base64 data). - -##### [consst char *] cert_file - The certificate file (DER format). - -##### [esp_mail_file_storage_type] cert_file_storage_type - The storage type. - -```C++ -esp_mail_sesson_cert_config_t certificate; -``` - - - - -## IMAP_Config type data - - -The following properties are available from the IMAP_Config data type. - -This data type is used for storing the IMAP transport and operating options to -control and store the operation result e.g. the messahe contents from search and fetch. - - - - -#### [Properties] The config for fetching - -This property has the sub property - -##### [const char *] uid - The UID of message to fetch. - -```C++ -esp_mail_imap_fetch_config_t fetch; -``` - - -#### [Properties] The config for search - -This property has the sub properties - -##### [const char *] criteria - The search criteria. - -##### [boolean] unseen_msg - The option to search the unseen message. - -```C++ -esp_mail_imap_search_config_t search; -``` - - -#### [Properties] The config about the limits - -This property has the sub properties - -##### [size_t] search - The maximum messages from the search result. - -##### [size_t] msg_size - The maximum size of the memory buffer to store the message content. - -This is only limit for data to be stored in the IMAPSession. - -##### [size_t] attachment_size - The maximum size of each attachment to download. - -```C++ -esp_mail_imap_limit_config_t limit; -``` - - - -#### [Properties] The config to enable the features - -This property has the sub properties - -##### [boolean] text - To store the PLAIN text of the message in the IMAPSession. - -##### [boolean] html - To store the HTML of the message in the IMAPSession. - -##### [boolean] rfc822 - To store the rfc822 messages in the IMAPSession. - -##### [boolean] download_status - To enable the download status via the serial port. - -##### [boolean] recent_sort - To sort the message UID of the search result in descending order. - -```C++ -esp_mail_imap_enable_config_t enable; -``` - - - -#### [Properties] The config about downloads - -This property has the sub properties - -##### [boolean] text - To download the PLAIN text content of the message. - -##### [boolean] html - To download the HTML content of the message. - -##### [boolean] attachment - To download the attachments of the message. - -##### [boolean] inlineImg - To download the inline image of the message. - -##### [boolean] rfc822 - To download the rfc822 mesages in the message. - -##### [boolean] header - To download the message header. - -```C++ -esp_mail_imap_download_config_t download; -``` - - - -#### [Properties] The config about the storage and path to save the downloaded file. - -This property has the sub properties - -##### [const char*] saved_path - The path to save the downloaded file. - -##### [esp_mail_file_storage_type] type - The type of file storages enumeration e.g. - -esp_mail_file_storage_type_none = 0, - -esp_mail_file_storage_type_flash = 1, and - -esp_mail_file_storage_type_sd = 2 - -```C++ -esp_mail_imap_storage_config_t storage; -``` - - - - - -## esp_mail_smtp_embed_message_body_t structured data - - -The following properties are available from the IMAP_Config data type. - -This data type is used for storing the IMAP transport and operating options to -control and store the operation result e.g. the messahe contents from search and fetch. - - - - -##### [Properties] Enable to send this message body as file - -```C++ -bool enable; -``` - - -##### [Properties] The name of embedded file - -```C++ -const char* enable; -``` - - -##### [Properties] The embedded type enumeration - -esp_mail_smtp_embed_message_type_attachment = 0 - -sp_mail_smtp_embed_message_type_inline = 1 - -```C++ -esp_mail_smtp_embed_message_type type; -``` - - - - - - -## esp_mail_blob_message_content_t structured data - - -The following properties are available from the esp_mail_blob_message_content_t data type. - -This data type is used for storing the blob info of message body. - - - - -##### [Properties] The array of content in flash memory. - -```C++ -const uint8_t * data; -``` - - -##### [Properties] The array size in bytes. - -```C++ -size_t size; -``` - - - - - -## esp_mail_file_message_content_t structured data - - -The following properties are available from the esp_mail_file_message_content_t data type. - -This data type is used for storing the file info of message body. - - - - -##### [Properties] The file path include its name. - -```C++ -const char *name; -``` - - -##### [Properties] The type of file storages. - -```C++ -esp_mail_file_storage_type type; -``` - - - - - - -## IMAP_MSG_Item type data - - -The following properties are available from the IMAP_MSG_Item data type. - -This data type is used for message item info and its contents from search and fetch. - - - - -#### [Properties] The message number - -```C++ -const char *msgNo; -``` - - -#### [Properties] The message UID - -```C++ -const char *UID; -``` - - -#### [Properties] The message identifier - -```C++ -const char *ID; -``` - - - -#### [Properties] The language(s) for auto-responses - -```C++ -const char *acceptLang; -``` - - - -#### [Properties] The language of message content - -```C++ -const char *contentLang; -``` - - - -#### [Properties] The mailbox of message author - -```C++ -const char *from; -``` - - -#### [Properties] The charset of the mailbox of message author - -```C++ -const char *fromCharset; -``` - - -#### [Properties] The primary recipient mailbox - -```C++ -const char *to; -``` - - -#### [Properties] The charset of the primary recipient mailbox - -```C++ -const char *toCharset; -``` - - -#### [Properties] The Carbon-copy recipient mailboxes - -```C++ -const char *cc; -``` - - -#### [Properties] The charset of the Carbon-copy recipient mailbox header - -```C++ -const char *ccCharset; -``` - -#### [Properties] The message date and time - -```C++ -const char *date; -``` - -#### [Properties] The topic of message - -```C++ -const char *subject; -``` - -#### [Properties] The topic of message charset - -```C++ -const char *subjectCharset; -``` - -#### [Properties] The PLAIN text content of the message - -```C++ -esp_mail_plain_body_t text; -``` - -#### [Properties] The HTML content of the message - -```C++ -esp_mail_html_body_t html; -``` - -#### [Properties] The sender Email - -```C++ -const char *sender; -``` - -#### [Properties] The message identifier - -```C++ -const char *messageID; -``` - -#### [Properties] The keywords or phrases, separated by commas - -```C++ -const char *keyword; -``` - -#### [Properties] The comment about message - -```C++ -const char *comment; -``` - - -#### [Properties] The return recipient of the message - -```C++ -const char *return_path; -``` - - -#### [Properties] The Email address to reply - -```C++ -const char *reply_to; -``` - - -#### [Properties] The Blind carbon-copy recipients - -```C++ -const char *bcc; -``` - - -#### [Properties] The error description from fetching the message - -```C++ -const char *fetchError; -``` - - -#### [Properties] The info about the attachments in the message - -```C++ -std::vector attachments; -``` - -#### [Properties] The info about the rfc822 messages included in the message - -```C++ -std::vector rfc822; -``` - - - - - - -## Search Criteria - -Search crieria is used for searching the mailbox for messages that match -the given searching criteria. - -Searching criteria consist of one or more search keys. When multiple keys are -specified, the result is the intersection (AND function) of all the messages -that match those keys. - -Example: - - **`DELETED FROM "SMITH" SINCE 1-Feb-1994`** refers -to all deleted messages from Smith that were placed in the mailbox since -February 1, 1994. - -A search key can also be a parenthesized list of one or more search keys -(e.g., for use with the OR and NOT keys). - -**`SINCE 10-Feb-2019`** will search all messages that received since 10 Feb 2019 - -**`UID SEARCH ALL`** will seach all message which will return the message UID -that can be use later for fetch one or more messages. - - -The following keywords can be used for the search criteria. - - -**ALL** - All messages in the mailbox; the default initial key for ANDing. - -**ANSWERED** - Messages with the \Answered flag set. - -**BCC** - Messages that contain the specified string in the envelope structure's BCC field. - -**BEFORE** - Messages whose internal date (disregarding time and timezone) is earlier than the specified date. - -**BODY** - Messages that contain the specified string in the body of the message. - -**CC** - Messages that contain the specified string in the envelope structure's CC field. - -**DELETED** - Messages with the \Deleted flag set. - -**DRAFT** - Messages with the \Draft flag set. - -**FLAGGED** - Messages with the \Flagged flag set. - -**FROM** - Messages that contain the specified string in the envelope structure's FROM field. - -**HEADER** - Messages that have a header with the specified field-name (as defined in [RFC-2822]) - -and that contains the specified string in the text of the header (what comes after the colon). - -If the string to search is zero-length, this matches all messages that have a header line with - -the specified field-name regardless of the contents. - -**KEYWORD** - Messages with the specified keyword flag set. - -**LARGER** - Messages with an (RFC-2822) size larger than the specified number of octets. - -**NEW** - Messages that have the \Recent flag set but not the \Seen flag. - -This is functionally equivalent to **"(RECENT UNSEEN)"**. - -**NOT** - Messages that do not match the specified search key. - -**OLD** - Messages that do not have the \Recent flag set. This is functionally equivalent to - -**"NOT RECENT"** (as opposed to **"NOT NEW"**). - -**ON** - Messages whose internal date (disregarding time and timezone) is within the specified date. - -**OR** - Messages that match either search key. - -**RECENT** - Messages that have the \Recent flag set. - -**SEEN** - Messages that have the \Seen flag set. - -**SENTBEFORE** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is earlier than the specified date. - -**SENTON** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within the specified date. - -**SENTSINCE** - Messages whose (RFC-2822) Date: header (disregarding time and timezone) is within or later than the specified date. - -**SINCE** - Messages whose internal date (disregarding time and timezone) is within or later than the specified date. - -**SMALLER** - Messages with an (RFC-2822) size smaller than the specified number of octets. - -**SUBJECT** - Messages that contain the specified string in the envelope structure's SUBJECT field. - -**TEXT** - Messages that contain the specified string in the header or body of the message. - -**TO** - Messages that contain the specified string in the envelope structure's TO field. - -**UID** - Messages with unique identifiers corresponding to the specified unique identifier set. - -Sequence set ranges are permitted. - -**UNANSWERED** - Messages that do not have the \Answered flag set. - -**UNDELETED** - Messages that do not have the \Deleted flag set. - -**UNDRAFT** - Messages that do not have the \Draft flag set. - -**UNFLAGGED** - Messages that do not have the \Flagged flag set. - -**UNKEYWORD** - Messages that do not have the specified keyword flag set. - -**UNSEEN** - Messages that do not have the \Seen flag set. - - - - - - - - - -## MailClient.Time functions - - -The helper function to set and get the system time. - - - - - -#### Set the system time from the NTP server - -param **`gmtOffset`** The GMT time offset in hour. - -param **`daylightOffset`** The Daylight time offset in hour. - -return **`boolean`** The status indicates the success of operation. - -This requires internet connection - -```C++ -bool setClock(float gmtOffset, float daylightOffset); -``` - - - - - - -#### Provide the Unix time - -return **`uint32_t`** The value of current Unix time. - -```C++ -uint32_t getUnixTime(); -``` - - - - - - -#### Provide the timestamp from the year, month, date, hour, minute, and second provided - -param **`year`** The year. - -param **`mon`** The months from 1 to 12. - -param **`date`** The dates. - -param **`hour`** The hours. - -param **`mins`** The minutes. - -param **`sec`** The seconds. - -return **`time_t`** The value of timestamp. - -```C++ -time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec); -``` - - - - - - -#### Provide the current year. - -return **`int`** The value of current year. - -```C++ -int getYear(); -``` - - - - - - -#### Provide the current month. - -return **`int`** The value of current month. - -```C++ -int getMonth(); -``` - - - - - -#### Provide the current date. - -return **`int`** The value of current date. - -```C++ -int getDay(); -``` - - - - - - -#### Provide the current day of week. - -return **`int`** The value of day of week. - -1 for sunday and 7 for saturday - -```C++ -int getDayOfWeek(); -``` - - - - - -#### Provide the current day of week in String. - -return **`String`** The value of day of week. - -Returns sunday, monday, tuesday, wednesday, thurseday, friday and saturday. - -```C++ -String getDayOfWeekString(); -``` - - - - - - -#### Provide the current hour. - -return **`int`** The value of current hour (0 to 23). - -```C++ -int getHour(); -``` - - - - - - -#### Provide the current minute. - -return **`int`** The value of current minute (0 to 59). - -```C++ -int getMin(); -``` - - - - - - -#### Provide the current second. - -return **`int`** The value of current second (0 to 59). - -```C++ -int getSecond(); -``` - - - - - - - -#### Provide the total days of current year. - -return **`int`** The value of total days of current year. - -```C++ -int getNumberOfDayThisYear(); -``` - - - - - - -#### Provide the total days of from January 1, 1970 to specific date. - -param **`year`** The years from 1970. - -param **`mon`** The months from 1 to 12. - -param **`date`** The dates. - -return **`int`** The value of total days. - -```C++ -int getTotalDays(int year, int month, int day); -``` - - - - - -#### Provide the day of week from specific date. - -param **`year`** The years. - -param **`month`** The months from 1 to 12. - -param **`day`** The dates. - -return **`int`** The value of day of week. - -1 for sunday and 7 for saturday - -```C++ -int dayofWeek(int year, int month, int day); -``` - - - - - - -#### Provide the second of current hour. - -return **`int`** The value of current second. - -```C++ -int getCurrentSecond(); -``` - - - - - -#### Provide the current timestamp. - -return **`uint64_t`** The value of current timestamp. - -```C++ -uint64_t getCurrentTimestamp(); -``` - - - - - - -#### Provide the date and time from second counted from January 1, 1970. - -param **`sec`** The seconds from January 1, 1970 00.00. - -return **`tm`** The tm structured data. - -The returned structured data tm has the members e.g. - -tm_year (from 1900), tm_mon (from 0 to 11), tm_mday, tm_hour, tm_min and tm_sec. - -```C++ -struct tm getTimeFromSec(int secCount); -``` - - - - - - -#### Provide the current date time string that valid for Email - -return **`String`** The current date time string. - -```C++ -String getDateTimeString(); -``` - - - - - - - -## License - -The MIT License (MIT) - -Copyright (c) 2021 K. Suwatchai (Mobizt) - - -Permission is hereby granted, free of charge, to any person returning a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/lib/libesp32/lib_mail/src/SDK_Version_Common.h b/lib/libesp32/lib_mail/src/SDK_Version_Common.h deleted file mode 100644 index c0db7a62c..000000000 --- a/lib/libesp32/lib_mail/src/SDK_Version_Common.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _SDK_VERSION_COMMON_H -#define _SDK_VERSION_COMMON_H - -#if defined(ESP8266) - -#include - -//__GNUC__ -//__GNUC_MINOR__ -//__GNUC_PATCHLEVEL__ - -#ifdef __GNUC__ -#if __GNUC__ > 4 || __GNUC__ == 10 -#define ESP8266_CORE_SDK_V3_X_X -#endif -#endif - -#endif - -#endif \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/extras/ESPTimeHelper.cpp b/lib/libesp32/lib_mail/src/extras/ESPTimeHelper.cpp deleted file mode 100644 index b88b1c753..000000000 --- a/lib/libesp32/lib_mail/src/extras/ESPTimeHelper.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* - * ESP8266/ESP32 Internet Time Helper Arduino Library v 1.0.2 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person returning a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef ESPTimeHelper_CPP -#define ESPTimeHelper_CPP - -#include "ESPTimeHelper.h" - -ESPTimeHelper::ESPTimeHelper() -{ -} - -uint32_t ESPTimeHelper::getUnixTime() -{ - uint32_t utime = (msec_time_diff + millis()) / 1000; - return utime; -} - -int ESPTimeHelper::setTimestamp(time_t ts) -{ - struct timeval tm = {ts, 0};//sec, us - return settimeofday((const timeval *)&tm, 0); -} - -time_t ESPTimeHelper::getTimestamp(int year, int mon, int date, int hour, int mins, int sec) -{ - struct tm timeinfo; - timeinfo.tm_year = year - 1900; - timeinfo.tm_mon = mon - 1; - timeinfo.tm_mday = date; - timeinfo.tm_hour = hour; - timeinfo.tm_min = mins; - timeinfo.tm_sec = sec; - time_t ts = mktime(&timeinfo); - return ts; -} - -bool ESPTimeHelper::setClock(float gmtOffset, float daylightOffset) -{ - TZ = gmtOffset; - DST_MN = daylightOffset; - configTime((TZ)*3600, (DST_MN)*60, "pool.ntp.org", "time.nist.gov"); - - now = time(nullptr); - uint8_t attempts = 0; - while (now < 1577836800) - { - now = time(nullptr); - attempts++; - if (attempts > 200 || now > 1577836800) - break; - delay(100); - } - - uint64_t tmp = now; - tmp = tmp * 1000; - msec_time_diff = tmp - millis(); - -#if defined(ESP32) - getLocalTime(&timeinfo); -#elif defined(ESP8266) - gmtime_r(&now, &timeinfo); -#endif - - clockReady = now > 8 * 3600 * 2; - return clockReady; -} - -int ESPTimeHelper::getYear() -{ - setSysTime(); - return timeinfo.tm_year + 1900; -} -int ESPTimeHelper::getMonth() -{ - setSysTime(); - return timeinfo.tm_mon + 1; -} -int ESPTimeHelper::getDay() -{ - setSysTime(); - return timeinfo.tm_mday; -} - -int ESPTimeHelper::getDayOfWeek() -{ - setSysTime(); - return timeinfo.tm_wday; -} -String ESPTimeHelper::getDayOfWeekString() -{ - setSysTime(); - return dow[timeinfo.tm_wday]; -} - -int ESPTimeHelper::getHour() -{ - setSysTime(); - return timeinfo.tm_hour; -} - -int ESPTimeHelper::getMin() -{ - setSysTime(); - return timeinfo.tm_min; -} -int ESPTimeHelper::getSec() -{ - setSysTime(); - return timeinfo.tm_sec; -} -int ESPTimeHelper::getNumberOfDayThisYear() -{ - setSysTime(); - return timeinfo.tm_yday + 1; -} - -int ESPTimeHelper::totalDays(int y, int m, int d) -{ - static char daytab[2][13] = - { - {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; - int daystotal = d; - for (int year = 1; year <= y; year++) - { - int max_month = (year < y ? 12 : m - 1); - int leap = (year % 4 == 0); - if (year % 100 == 0 && year % 400 != 0) - leap = 0; - for (int month = 1; month <= max_month; month++) - { - daystotal += daytab[leap][month]; - } - } - return daystotal; -} -int ESPTimeHelper::getTotalDays(int year, int month, int day) -{ - return totalDays(year, month, day) - totalDays(1970, 1, 1); -} - -int ESPTimeHelper::dayofWeek(int year, int month, int day) /* 1 <= m <= 12, y > 1752 (in the U.K.) */ -{ - static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; - year -= month < 3; - return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7; -} - -int ESPTimeHelper::getCurrentSecond() -{ - return (timeinfo.tm_hour * 3600) + (timeinfo.tm_min * 60) + timeinfo.tm_sec; -} -uint64_t ESPTimeHelper::getCurrentTimestamp() -{ - return now; -} -struct tm ESPTimeHelper::getTimeFromSec(int seconds) -{ - struct tm timeinfo; - int _yrs = seconds / (365 * 24 * 3600); - seconds = seconds - _yrs * (365 * 24 * 3600); - timeinfo.tm_year = _yrs - 1900; - int _months = seconds / (30 * 24 * 3600); - seconds = seconds - _months * (30 * 24 * 3600); - timeinfo.tm_mon = _months - 1; - int _days = seconds / (24 * 3600); - seconds = seconds - _days * (24 * 3600); - timeinfo.tm_mday = _days; - int _hr = seconds / 3600; - seconds = seconds - _hr * 3600; - timeinfo.tm_hour = _hr; - int _min = seconds / 60; - seconds = seconds - _min * 60; - timeinfo.tm_min = _min; - timeinfo.tm_sec = seconds; - return timeinfo; -} - -char *ESPTimeHelper::intStr(int value) -{ - char *buf = new char[36]; - memset(buf, 0, 36); - itoa(value, buf, 10); - return buf; -} - -String ESPTimeHelper::getDateTimeString() -{ - setSysTime(); - std::string s; - - s = sdow[timeinfo.tm_wday]; - - s += ", "; - char *tmp = intStr(timeinfo.tm_mday); - s += tmp; - delete[] tmp; - - s += " "; - s += months[timeinfo.tm_mon]; - - s += " "; - tmp = intStr(timeinfo.tm_year + 1900); - s += tmp; - delete[] tmp; - - s += " "; - if (timeinfo.tm_hour < 10) - s += "0"; - tmp = intStr(timeinfo.tm_hour); - s += tmp; - delete[] tmp; - - s += ":"; - if (timeinfo.tm_min < 10) - s += "0"; - tmp = intStr(timeinfo.tm_min); - s += tmp; - delete[] tmp; - - s += ":"; - if (timeinfo.tm_sec < 10) - s += "0"; - tmp = intStr(timeinfo.tm_sec); - s += tmp; - delete[] tmp; - - int p = 1; - if (TZ < 0) - p = -1; - int tz = TZ; - float dif = (p * (TZ - tz)) * 60.0; - if (TZ < 0) - s += " -"; - else - s += " +"; - - if (tz < 10) - s += "0"; - tmp = intStr(tz); - s += tmp; - delete[] tmp; - - if (dif < 10) - s += "0"; - tmp = intStr((int)dif); - s += tmp; - delete[] tmp; - - return s.c_str(); -} - -void ESPTimeHelper::setSysTime() -{ -#if defined(ESP32) - getLocalTime(&timeinfo); -#elif defined(ESP8266) - now = time(nullptr); - localtime_r(&now, &timeinfo); -#endif -} - -#endif //ESPTimeHelper_CPP \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/extras/ESPTimeHelper.h b/lib/libesp32/lib_mail/src/extras/ESPTimeHelper.h deleted file mode 100644 index 2cc5fcddf..000000000 --- a/lib/libesp32/lib_mail/src/extras/ESPTimeHelper.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * ESP8266/ESP32 Internet Time Helper Arduino Library v 1.0.2 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person returning a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef ESPTimeHelper_H -#define ESPTimeHelper_H - -#include -#include -#if defined(ESP32) -#include -#elif defined(ESP8266) -#include -#include "SDK_Version_Common.h" -#endif - -class ESPTimeHelper -{ -public: - ESPTimeHelper(); - - /** Set the system time from the NTP server - * - * @param gmtOffset The GMT time offset in hour. - * @param daylightOffset The Daylight time offset in hour. - * @return boolean The status indicates the success of operation. - * - * @note This requires internet connection - */ - bool setClock(float gmtOffset, float daylightOffset); - - /** Set system time with provided timestamp - * - * @param ts timestamp in seconds from midnight Jan 1, 1970. - * @return error number, 0 for success. - */ - int setTimestamp(time_t ts); - - /** Provide the Unix time - * - * @return uint32_t The value of current Unix time. - */ - uint32_t getUnixTime(); - - /** Provide the timestamp from the year, month, date, hour, minute, - * and second provided. - * - * @param year The year. - * @param mon The month from 1 to 12. - * @param date The dates. - * @param hour The hours. - * @param mins The minutes. - * @param sec The seconds. - * @return time_t The value of timestamp. - */ - time_t getTimestamp(int year, int mon, int date, int hour, int mins, int sec); - - /** Provide the current year. - * - * @return int The value of current year. - */ - int getYear(); - - /** Provide the current month. - * - * @return int The value of current month. - */ - int getMonth(); - - /** Provide the current date. - * - * @return int The value of current date. - */ - int getDay(); - - /** Provide the current day of week. - * - * @return int The value of current day of week. - * - * @note 1 for sunday and 7 for saturday. - */ - int getDayOfWeek(); - - /** Provide the current day of week in String. - * - * @return String The value of day of week. - */ - String getDayOfWeekString(); - - /** Provide the current hour. - * - * @return int The value of current hour (0 to 23). - */ - int getHour(); - - /** Provide the current minute. - * - * @return int The value of current minute. - */ - int getMin(); - - /** Provide the current second. - * - * @return int The value of current second. - */ - int getSec(); - - /** Provide the total days of current year. - * - * @return int The value of total days of current year. - */ - int getNumberOfDayThisYear(); - - /** Provide the total days of from January 1, 1970 to specific date. - * - * @param year The year from 1970. - * @param mon The month from 1 to 12. - * @param day The dates. - * @return int The value of total days. - */ - int getTotalDays(int year, int month, int day); - - /** Provide the day of week from specific date. - * - * @param year The year from 1970. - * @param mon The month from 1 to 12. - * @param day The dates. - * @return int the value of day of week. - * @note 1 for sunday and 7 for saturday - */ - int dayofWeek(int year, int month, int day); - - /** Provide the second of current hour. - * - * @return int The value of current second. - */ - int getCurrentSecond(); - - /** Provide the current timestamp. - * - * @return uint64_t The value of current timestamp. - */ - uint64_t getCurrentTimestamp(); - - /** Provide the date and time from second counted from January 1, 1970. - * - * @param sec The seconds from January 1, 1970 00.00. - * @return tm The tm structured data. - * - * @note The returned structured data tm has the members e.g. - * tm_year (from 1900), tm_mon (from 0 to 11), tm_mday, tm_hour, - * tm_min and tm_sec. - */ - struct tm getTimeFromSec(int seconds); - - /** Provide the current date time string that valid for Email. - * - * @return String The current date time string. - */ - String getDateTimeString(); - - time_t now; - uint64_t msec_time_diff = 0; - struct tm timeinfo; - float TZ = 0.0; - uint8_t DST_MN = 0; - bool clockReady = false; - -private: - int totalDays(int y, int m, int d); - char *intStr(int value); - void setSysTime(); - const char *dow[7] = {"sunday", "monday", "tuesday", "wednesday", "thurseday", "friday", "saturday"}; - const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - const char *sdow[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; -}; - -#endif //ESPTimeHelper_H diff --git a/lib/libesp32/lib_mail/src/extras/MIMEInfo.h b/lib/libesp32/lib_mail/src/extras/MIMEInfo.h deleted file mode 100644 index 38269eb6b..000000000 --- a/lib/libesp32/lib_mail/src/extras/MIMEInfo.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef MIMEInfo_H -#define MIMEInfo_H -#include - -enum esp_mail_file_extension -{ - esp_mail_file_extension_html, - esp_mail_file_extension_htm, - esp_mail_file_extension_css, - esp_mail_file_extension_txt, - esp_mail_file_extension_js, - esp_mail_file_extension_json, - esp_mail_file_extension_png, - esp_mail_file_extension_gif, - esp_mail_file_extension_jpg, - esp_mail_file_extension_ico, - esp_mail_file_extension_svg, - esp_mail_file_extension_ttf, - esp_mail_file_extension_otf, - esp_mail_file_extension_woff, - esp_mail_file_extension_woff2, - esp_mail_file_extension_eot, - esp_mail_file_extension_sfnt, - esp_mail_file_extension_xml, - esp_mail_file_extension_pdf, - esp_mail_file_extension_zip, - esp_mail_file_extension_gz, - esp_mail_file_extension_appcache, - esp_mail_file_extension_none, - esp_mail_file_extension_maxType -}; - -struct esp_mail_mime_prop_t -{ - char endsWith[10]; - char mimeType[50]; -}; - -const struct esp_mail_mime_prop_t mimeinfo[esp_mail_file_extension_maxType] PROGMEM = - { - {".html", "text/html"}, - {".htm", "text/html"}, - {".css", "text/css"}, - {".txt", "text/plain"}, - {".js", "application/javascript"}, - {".json", "application/json"}, - {".png", "image/png"}, - {".gif", "image/gif"}, - {".jpg", "image/jpeg"}, - {".ico", "image/x-icon"}, - {".svg", "image/svg+xml"}, - {".ttf", "application/x-font-ttf"}, - {".otf", "application/x-font-opentype"}, - {".woff", "application/font-woff"}, - {".woff2", "application/font-woff2"}, - {".eot", "application/vnd.ms-fontobject"}, - {".sfnt", "application/font-sfnt"}, - {".xml", "text/xml"}, - {".pdf", "application/pdf"}, - {".zip", "application/zip"}, - {".gz", "application/x-gzip"}, - {".appcache", "text/cache-manifest"}, - {"", "application/octet-stream"}}; - -#endif diff --git a/lib/libesp32/lib_mail/src/extras/RFC2047.cpp b/lib/libesp32/lib_mail/src/extras/RFC2047.cpp deleted file mode 100644 index 8f5dc31e3..000000000 --- a/lib/libesp32/lib_mail/src/extras/RFC2047.cpp +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef RFC2047_CPP -#define RFC2047_CPP - -#include "RFC2047.h" - -RFC2047_Decoder::RFC2047_Decoder() {} -RFC2047_Decoder::~RFC2047_Decoder() {} - -void RFC2047_Decoder::rfc2047Decode(char *d, const char *s, size_t dlen) -{ - - const char *p, *q; - size_t n; - int found_encoded = 0; - - dlen--; /* save room for the terminal nul */ - - while (*s && dlen > 0) - { - if ((p = strstr (s, "=?")) == NULL || - (q = strchr (p + 2, '?')) == NULL || - (q = strchr (q + 1, '?')) == NULL || - (q = strstr (q + 1, "?=")) == NULL) - { - /* no encoded words */ - if (d != s) - strfcpy (d, s, dlen + 1); - return; - } - - if (p != s) - { - n = (size_t) (p - s); - /* ignore spaces between encoded words */ - if (!found_encoded || strspn (s, " \t\r\n") != n) - { - if (n > dlen) - n = dlen; - if (d != s) - memcpy (d, s, n); - d += n; - dlen -= n; - } - } - - rfc2047DecodeWord (d, p, dlen); - found_encoded = 1; - s = q + 2; - n = strlen (d); - dlen -= n; - d += n; - } - *d = 0; -} - -void RFC2047_Decoder::rfc2047DecodeWord(char *d, const char *s, size_t dlen) -{ - - char *p = safe_strdup (s); - char *pp = p; - char *pd = d; - size_t len = dlen; - int enc = 0, filter = 0, count = 0, c1, c2, c3, c4; - - while ((pp = strtok (pp, "?")) != NULL) - { - count++; - switch (count) - { - case 2: - if (strcasecmp (pp, Charset) != 0) - { - filter = 1; - } - break; - case 3: - if (toupper (*pp) == 'Q') - enc = ENCQUOTEDPRINTABLE; - else if (toupper (*pp) == 'B') - enc = ENCBASE64; - else - return; - break; - case 4: - if (enc == ENCQUOTEDPRINTABLE) - { - while (*pp && len > 0) - { - if (*pp == '_') - { - *pd++ = ' '; - len--; - } - else if (*pp == '=') - { - *pd++ = (hexval(pp[1]) << 4) | hexval(pp[2]); - len--; - pp += 2; - } - else - { - *pd++ = *pp; - len--; - } - pp++; - } - *pd = 0; - } - else if (enc == ENCBASE64) - { - while (*pp && len > 0) - { - c1 = base64val(pp[0]); - c2 = base64val(pp[1]); - *pd++ = (c1 << 2) | ((c2 >> 4) & 0x3); - if (--len == 0) break; - - if (pp[2] == '=') break; - - c3 = base64val(pp[2]); - *pd++ = ((c2 & 0xf) << 4) | ((c3 >> 2) & 0xf); - if (--len == 0) - break; - - if (pp[3] == '=') - break; - - c4 = base64val(pp[3]); - *pd++ = ((c3 & 0x3) << 6) | c4; - if (--len == 0) - break; - - pp += 4; - } - *pd = 0; - } - break; - } - pp = 0; - } - safe_free (&p); - if (filter) - { - - pd = d; - while (*pd) - { - if (!IsPrint (*pd)) - *pd = '?'; - pd++; - } - } - return; -} - -void *RFC2047_Decoder::safe_calloc(size_t nmemb, size_t size) -{ - void *p; - - if (!nmemb || !size) - return NULL; - if (!(p = calloc (nmemb, size))) - { - //out of memory - return NULL; - } - return p; -} - -void *RFC2047_Decoder::safe_malloc(unsigned int siz) -{ - void *p; - - if (siz == 0) - return 0; - if ((p = (void *) malloc (siz)) == 0) - { - //out of memory - return NULL; - } - return (p); -} - -void RFC2047_Decoder::safe_realloc(void **p, size_t siz) -{ - void *r; - - if (siz == 0) - { - if (*p) - { - free (*p); - *p = NULL; - } - return; - } - - if (*p) - r = (void *) realloc (*p, siz); - else - { - r = (void *) malloc (siz); - } - - if (!r) - { - //out of memory - return; - } - - *p = r; -} - -void RFC2047_Decoder::safe_free(void *ptr) -{ - void **p = (void **)ptr; - if (*p) - { - free (*p); - *p = 0; - } -} - -char *RFC2047_Decoder::safe_strdup(const char *s) -{ - char *p; - size_t l; - - if (!s || !*s) return 0; - l = strlen (s) + 1; - p = (char *)safe_malloc (l); - memcpy (p, s, l); - return (p); -} - - -#endif //RFC2047_CPP \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.cpp b/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.cpp deleted file mode 100644 index a1d386ea6..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Customized version of ESP32 HTTPClient Library. - * - * v 1.1.5 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * HTTPClient Arduino library for ESP32 - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the HTTPClient for Arduino. - * Port to ESP32 by Evandro Luis Copercini (2017), - * changed fingerprints to CA verification. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * -*/ - -#ifndef ESP_Mail_HTTPClient32_CPP -#define ESP_Mail_HTTPClient32_CPP - -#ifdef ESP32 - -#include "ESP_Mail_HTTPClient32.h" - -ESP_Mail_HTTPClient32::ESP_Mail_HTTPClient32() -{ -} - -ESP_Mail_HTTPClient32::~ESP_Mail_HTTPClient32() -{ - if (_wcs) - { - _wcs->stop(); - _wcs.reset(nullptr); - _wcs.release(); - } - std::string().swap(_host); - std::string().swap(_caCertFile); -} - -bool ESP_Mail_HTTPClient32::begin(const char *host, uint16_t port) -{ - _host = host; - _port = port; - return true; -} - -bool ESP_Mail_HTTPClient32::connected() -{ - if (_wcs) - { - if (_secured) - return _wcs->connected(); - else - return _wcs->_ns_connected(); - } - return false; -} - -bool ESP_Mail_HTTPClient32::send(const char *header) -{ - if (!connected()) - return false; - if (_secured) - return (_wcs->write(header, strlen(header)) == strlen(header)); - else - return (_wcs->_ns_write(header, strlen(header)) == strlen(header)); -} - -int ESP_Mail_HTTPClient32::send(const char *header, const char *payload) -{ - size_t size = strlen(payload); - if (strlen(header) > 0) - { - if (!connect(_secured)) - { - return ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED; - } - - if (!send(header)) - { - return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED; - } - } - - if (size > 0) - { - if (_secured) - { - if (_wcs->write(&payload[0], size) != size) - return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED; - } - else - { - if (_wcs->_ns_write(&payload[0], size) != size) - return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED; - } - } - - return 0; -} - -WiFiClient *ESP_Mail_HTTPClient32::stream(void) -{ - if (connected()) - return _wcs.get(); - return nullptr; -} -ESP_Mail_WCS32 *ESP_Mail_HTTPClient32::_stream(void) -{ - if (connected()) - return _wcs.get(); - return nullptr; -} - -size_t ESP_Mail_HTTPClient32::_ns_print(const char *buf) -{ - size_t size = strlen(buf); - return _wcs->_ns_write(&buf[0], size); -} - -size_t ESP_Mail_HTTPClient32::_ns_println(const char *buf) -{ - size_t size = strlen(buf); - size_t wr = _wcs->_ns_write((const char *)&buf[0], size); - std::string s = "\r\n"; - wr += _wcs->_ns_write(s.c_str(), s.length()); - return wr; -} - -bool ESP_Mail_HTTPClient32::connect(void) -{ - return connect(false); -} - -bool ESP_Mail_HTTPClient32::connect(bool secured) -{ - _secured = secured; - - if (connected()) - { - if (_secured) - { - while (_wcs->available() > 0) - _wcs->read(); - } - else - { - while (_wcs->_ns_available() > 0) - _wcs->_ns_read(); - } - return true; - } - - if (_debugCallback) - _wcs->setDebugCB(&_debugCallback); - _wcs->setSTARTTLS(!secured); - - if (!_wcs->connect(_host.c_str(), _port)) - return false; - return connected(); -} - -void ESP_Mail_HTTPClient32::setDebugCallback(DebugMsgCallback cb) -{ - _debugCallback = std::move(cb); -} - -void ESP_Mail_HTTPClient32::setCACert(const char *caCert) -{ - _wcs->setCACert(caCert); - if (caCert) - _certType = 1; - else - { - setInsecure(); - _certType = 0; - } - //_wcs->setNoDelay(true); -} - -void ESP_Mail_HTTPClient32::setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType) -{ - - if (strlen(caCertFile) > 0) - { - File f; - if (storageType == esp_mail_file_storage_type_flash) - { - ESP_MAIL_FLASH_FS.begin(); - if (ESP_MAIL_FLASH_FS.exists(caCertFile)) - f = ESP_MAIL_FLASH_FS.open(caCertFile, FILE_READ); - } - else if (storageType == esp_mail_file_storage_type_sd) - { - ESP_MAIL_SD_FS.begin(); - if (ESP_MAIL_SD_FS.exists(caCertFile)) - f = ESP_MAIL_SD_FS.open(caCertFile, FILE_READ); - } - - if (f) - { - size_t len = f.size(); - _wcs->loadCACert(f, len); - f.close(); - } - _certType = 2; - } - //_wcs->setNoDelay(true); -} - -void ESP_Mail_HTTPClient32::setInsecure() -{ - _wcs->setInsecure(); -} - -#endif //ESP32 - -#endif //ESP_Mail_HTTPClient32_CPP diff --git a/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.h b/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.h deleted file mode 100644 index 189e25ad1..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_HTTPClient32.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Customized version of ESP32 HTTPClient Library. - * - * v 1.1.5 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * HTTPClient Arduino library for ESP32 - * - * Copyright (c) 2015 Markus Sattler. All rights reserved. - * This file is part of the HTTPClient for Arduino. - * Port to ESP32 by Evandro Luis Copercini (2017), - * changed fingerprints to CA verification. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * -*/ - -#ifndef ESP_Mail_HTTPClient32_H -#define ESP_Mail_HTTPClient32_H - -#ifdef ESP32 - -#include -#include -#include -//#include -#include -#include "ESP_Mail_FS.h" -#include "ESP_Mail_WCS32.h" - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#define ESP_MAIL_FLASH_FS ESP_Mail_DEFAULT_FLASH_FS -#define ESP_MAIL_SD_FS ESP_Mail_DEFAULT_SD_FS - -#if __has_include() || __has_include() -#error WiFi UART bridge was not supported. -#endif - -#define ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED (-1) -#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED (-2) -#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3) -#define ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC 30 - -enum esp_mail_file_storage_type -{ - esp_mail_file_storage_type_none, - esp_mail_file_storage_type_flash, - esp_mail_file_storage_type_sd, - esp_mail_file_storage_type_univ -}; - -class ESP_Mail_HTTPClient32 -{ -public: - ESP_Mail_HTTPClient32(); - ~ESP_Mail_HTTPClient32(); - - /** - * Initialization of new http connection. - * \param host - Host name without protocols. - * \param port - Server's port. - * \return True as default. - * If no certificate string provided, use (const char*)NULL to CAcert param - */ - bool begin(const char *host, uint16_t port); - - /** - * Check the http connection status. - * \return True if connected. - */ - bool connected(); - - /** - * Establish http connection if header provided and send it, send payload if provided. - * \param header - The header string (constant chars array). - * \param payload - The payload string (constant chars array), optional. - * \return http status code, Return zero if new http connection and header and/or payload sent - * with no error or no header and payload provided. If obly payload provided, no new http connection was established. - */ - int send(const char *header, const char *payload); - - /** - * Send extra header without making new http connection (if send has been called) - * \param header - The header string (constant chars array). - * \return True if header sending success. - * Need to call send with header first. - */ - bool send(const char *header); - - /** - * Get the WiFi client pointer. - * \return WiFi client pointer. - */ - WiFiClient *stream(void); - - /** - * Set insecure mode - */ - void setInsecure(); - - ESP_Mail_WCS32 *_stream(void); - size_t _ns_print(const char *buf); - size_t _ns_println(const char *buf); - - int tcpTimeout = 40000; - bool connect(void); - bool connect(bool secured); - void setCACert(const char *caCert); - void setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType); - void setDebugCallback(DebugMsgCallback cb); - bool _secured = true; - - int _certType = -1; - std::string _caCertFile = ""; - esp_mail_file_storage_type _caCertFileStoreageType = esp_mail_file_storage_type::esp_mail_file_storage_type_none; - -protected: - DebugMsgCallback _debugCallback = NULL; - std::unique_ptr _wcs = std::unique_ptr(new ESP_Mail_WCS32()); - - std::string _host = ""; - uint16_t _port = 0; -}; - -#endif //ESP32 - -#endif //ESP_Mail_HTTPClient32_H diff --git a/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.cpp b/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.cpp deleted file mode 100644 index 72946d9e2..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* - *Customized WiFiClientSecure.cpp version 1.0.8 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - WiFiClientSecure.cpp - Client Secure class for ESP32 - Copyright (c) 2016 Hristo Gochkov All right reserved. - Additions Copyright (C) 2017 Evandro Luis Copercini. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef ESP_Mail_WCS32_CPP -#define ESP_Mail_WCS32_CPP - -#ifdef ESP32 - -#include "ESP_Mail_WCS32.h" -#include -#include -#include - -#undef connect -#undef write -#undef read - -ESP_Mail_WCS32::ESP_Mail_WCS32() -{ - _connected = false; - - sslclient = new esp_mail_ssl_client32::esp_mail_ssl_ctx32; - _ssl_client32.ssl_init(sslclient); - sslclient->socket = -1; - sslclient->handshake_timeout = 120000; - _use_insecure = false; - _CA_cert = NULL; - _cert = NULL; - _private_key = NULL; - _pskIdent = NULL; - _psKey = NULL; - next = NULL; -} - -ESP_Mail_WCS32::ESP_Mail_WCS32(int sock) -{ - _connected = false; - _timeout = 0; - - sslclient = new esp_mail_ssl_client32::esp_mail_ssl_ctx32; - _ssl_client32.ssl_init(sslclient); - sslclient->socket = sock; - sslclient->handshake_timeout = 120000; - - if (sock >= 0) - { - _connected = true; - } - - _CA_cert = NULL; - _cert = NULL; - _private_key = NULL; - _pskIdent = NULL; - _psKey = NULL; - next = NULL; -} - -ESP_Mail_WCS32::ESP_Mail_WCS32(bool secured) -{ - _connected = false; - - sslclient = new esp_mail_ssl_client32::esp_mail_ssl_ctx32; - _ssl_client32.ssl_init(sslclient); - sslclient->socket = -1; - sslclient->handshake_timeout = 120000; - _use_insecure = !secured; - _secured = secured; - _CA_cert = NULL; - _cert = NULL; - _private_key = NULL; - _pskIdent = NULL; - _psKey = NULL; - next = NULL; -} - -ESP_Mail_WCS32::~ESP_Mail_WCS32() -{ - stop(); - delete sslclient; -} - -ESP_Mail_WCS32 &ESP_Mail_WCS32::operator=(const ESP_Mail_WCS32 &other) -{ - stop(); - sslclient->socket = other.sslclient->socket; - _connected = other._connected; - return *this; -} - -void ESP_Mail_WCS32::stop() -{ - if (sslclient->socket >= 0) - { - close(sslclient->socket); - sslclient->socket = -1; - _connected = false; - _peek = -1; - } - _ssl_client32.stop_ssl_socket(sslclient, _CA_cert, _cert, _private_key); -} - -int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port) -{ - if (_pskIdent && _psKey) - return connect(ip, port, _pskIdent, _psKey); - return connect(ip, port, _CA_cert, _cert, _private_key); -} - -int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, int32_t timeout) -{ - _timeout = timeout; - return connect(ip, port); -} - -int ESP_Mail_WCS32::connect(const char *host, uint16_t port) -{ - if (_pskIdent && _psKey) - return connect(host, port, _pskIdent, _psKey); - return connect(host, port, _CA_cert, _cert, _private_key); -} - -int ESP_Mail_WCS32::connect(const char *host, uint16_t port, int32_t timeout) -{ - _timeout = timeout; - return connect(host, port); -} - -int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, const char *CA_cert, const char *cert, const char *private_key) -{ - return connect(ip.toString().c_str(), port, CA_cert, cert, private_key); -} - -int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *CA_cert, const char *cert, const char *private_key) -{ - _host = host; - _port = port; - _withCert = true; - - if (_timeout > 0) - { - sslclient->handshake_timeout = _timeout; - } - - int ret = _ssl_client32.start_socket(sslclient, host, port, _timeout, CA_cert, cert, private_key, NULL, NULL, _use_insecure); - - _lastError = ret; - if (ret < 0) - { - log_e("start_ssl_client: %d", ret); - stop(); - return 0; - } - - if (_secured) - { - ret = _ssl_client32.start_ssl_client(sslclient, host, port, _timeout, CA_cert, cert, private_key, NULL, NULL, _use_insecure); - _lastError = ret; - if (ret < 0) - { - log_e("start_ssl_client: %d", ret); - stop(); - return 0; - } - } - - _connected = true; - return 1; -} - -int ESP_Mail_WCS32::connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey) -{ - return connect(ip.toString().c_str(), port, pskIdent, psKey); -} - -int ESP_Mail_WCS32::connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey) -{ - _host = host; - _port = port; - _withCert = true; - - log_v("start_ssl_client with PSK"); - if (_timeout > 0) - { - sslclient->handshake_timeout = _timeout; - } - - int ret = _ssl_client32.start_socket(sslclient, host, port, _timeout, NULL, NULL, NULL, pskIdent, psKey, _use_insecure); - _lastError = ret; - if (ret < 0) - { - log_e("start_ssl_client: %d", ret); - stop(); - return 0; - } - - if (_secured) - { - ret = _ssl_client32.start_ssl_client(sslclient, host, port, _timeout, NULL, NULL, NULL, pskIdent, psKey, _use_insecure); - _lastError = ret; - if (ret < 0) - { - log_e("start_ssl_client: %d", ret); - stop(); - return 0; - } - } - _connected = true; - return 1; -} - -int ESP_Mail_WCS32::peek() -{ - if (_peek >= 0) - { - return _peek; - } - _peek = timedRead(); - return _peek; -} - -size_t ESP_Mail_WCS32::write(uint8_t data) -{ - return write(&data, 1); -} - -int ESP_Mail_WCS32::read() -{ - uint8_t data = -1; - int res = read(&data, 1); - if (res < 0) - { - return res; - } - return data; -} - -size_t ESP_Mail_WCS32::write(const uint8_t *buf, size_t size) -{ - if (!_connected) - { - return 0; - } - int res = _ssl_client32.send_ssl_data(sslclient, buf, size); - if (res < 0) - { - stop(); - res = 0; - } - return res; -} - -int ESP_Mail_WCS32::read(uint8_t *buf, size_t size) -{ - int peeked = 0; - int avail = available(); - if ((!buf && size) || avail <= 0) - { - return -1; - } - if (!size) - { - return 0; - } - if (_peek >= 0) - { - buf[0] = _peek; - _peek = -1; - size--; - avail--; - if (!size || !avail) - { - return 1; - } - buf++; - peeked = 1; - } - - int res = _ssl_client32.get_ssl_receive(sslclient, buf, size); - if (res < 0) - { - stop(); - return peeked ? peeked : res; - } - return res + peeked; -} - -int ESP_Mail_WCS32::available() -{ - int peeked = (_peek >= 0); - if (!_connected) - { - return peeked; - } - int res = _ssl_client32.data_to_read(sslclient); - if (res < 0) - { - stop(); - return peeked ? peeked : res; - } - return res + peeked; -} - -uint8_t ESP_Mail_WCS32::connected() -{ - uint8_t dummy = 0; - read(&dummy, 0); - - return _connected; -} - -void ESP_Mail_WCS32::setInsecure() -{ - _CA_cert = NULL; - _cert = NULL; - _private_key = NULL; - _pskIdent = NULL; - _psKey = NULL; - _use_insecure = true; -} - -void ESP_Mail_WCS32::setCACert(const char *rootCA) -{ - _CA_cert = rootCA; -} - -void ESP_Mail_WCS32::setCertificate(const char *client_ca) -{ - _cert = client_ca; -} - -void ESP_Mail_WCS32::setPrivateKey(const char *private_key) -{ - _private_key = private_key; -} - -void ESP_Mail_WCS32::setPreSharedKey(const char *pskIdent, const char *psKey) -{ - _pskIdent = pskIdent; - _psKey = psKey; -} - -bool ESP_Mail_WCS32::verify(const char *fp, const char *domain_name) -{ - if (!sslclient) - return false; - - return _ssl_client32.verify_ssl_fingerprint(sslclient, fp, domain_name); -} - -char *ESP_Mail_WCS32::_streamLoad(Stream &stream, size_t size) -{ - char *dest = (char *)malloc(size + 1); - if (!dest) - { - return nullptr; - } - if (size != stream.readBytes(dest, size)) - { - free(dest); - dest = nullptr; - return nullptr; - } - dest[size] = '\0'; - return dest; -} - -bool ESP_Mail_WCS32::loadCACert(Stream &stream, size_t size) -{ - char *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) - { - setCACert(dest); - ret = true; - } - return ret; -} - -bool ESP_Mail_WCS32::loadCertificate(Stream &stream, size_t size) -{ - char *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) - { - setCertificate(dest); - ret = true; - } - return ret; -} - -bool ESP_Mail_WCS32::loadPrivateKey(Stream &stream, size_t size) -{ - char *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) - { - setPrivateKey(dest); - ret = true; - } - return ret; -} - -int ESP_Mail_WCS32::lastError(char *buf, const size_t size) -{ - if (!_lastError) - { - return 0; - } - mbedtls_strerror(_lastError, buf, size); - return _lastError; -} - -void ESP_Mail_WCS32::setHandshakeTimeout(unsigned long handshake_timeout) -{ - sslclient->handshake_timeout = handshake_timeout * 1000; -} - -void ESP_Mail_WCS32::setSTARTTLS(bool enable) -{ - _secured = !enable; -} - -void ESP_Mail_WCS32::setDebugCB(DebugMsgCallback *cb) -{ - sslclient->_debugCallback = cb; -} - -int ESP_Mail_WCS32::_ns_available() -{ - if (sslclient->socket < 0) - return false; - - if (_rxBuf.length() == 0) - { - int bufLen = 1024; - char *tmp = new char[bufLen]; - memset(tmp, 0, bufLen); - int ret = _ssl_client32._ns_lwip_read(sslclient, tmp, bufLen); - if (ret > 0) - _rxBuf += tmp; - delete[] tmp; - } - - int result = _rxBuf.length(); - - if (!result) - { - optimistic_yield(100); - } - return result; -} - -size_t ESP_Mail_WCS32::_ns_write(const char *buf, size_t size) -{ - if (sslclient->socket < 0 || !size) - return 0; - return _ssl_client32._ns_lwip_write(sslclient, buf, size); -} - -size_t ESP_Mail_WCS32::_ns_read(char *buf, size_t size) -{ - if (_rxBuf.length() == 0) - return _ssl_client32._ns_lwip_read(sslclient, buf, size); - else - { - size_t sz = size; - if (sz > _rxBuf.length()) - sz = _rxBuf.length(); - strncpy(buf, _rxBuf.c_str(), sz); - _rxBuf.erase(0, sz); - return sz; - } -} - -int ESP_Mail_WCS32::_ns_read() -{ - int c = -1; - if (_rxBuf.length() == 0) - { - char *buf = new char[2]; - memset(buf, 0, 2); - int ret = _ssl_client32._ns_lwip_read(sslclient, buf, 1); - if (ret > 0) - c = buf[0]; - delete[] buf; - } - else - { - c = _rxBuf.c_str()[0]; - _rxBuf.erase(0, 1); - } - - return c; -} - -uint8_t ESP_Mail_WCS32::_ns_connected() -{ - return sslclient->socket >= 0; -} - -bool ESP_Mail_WCS32::_ns_connect_ssl() -{ - int ret = 0; - if (_withKey) - ret = _ssl_client32.start_ssl_client(sslclient, _host.c_str(), _port, _timeout, _CA_cert, _cert, _private_key, NULL, NULL, _use_insecure); - else if (_withCert) - ret = _ssl_client32.start_ssl_client(sslclient, _host.c_str(), _port, _timeout, NULL, NULL, NULL, _pskIdent, _psKey, _use_insecure); - - _lastError = ret; - if (ret < 0) - { - log_e("start_ssl_client: %d", ret); - stop(); - return 0; - } - - return 1; -} - -#endif //ESP32 - -#endif //ESP_Mail_WCS32_CPP \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.h b/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.h deleted file mode 100644 index 35be7527d..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp32/ESP_Mail_WCS32.h +++ /dev/null @@ -1,160 +0,0 @@ - -/* - *Customized WiFiClientSecure.h version 1.0.8 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* - WiFiClientSecure.h - Base class that provides Client SSL to ESP32 - Copyright (c) 2011 Adrian McEwen. All right reserved. - Additions Copyright (C) 2017 Evandro Luis Copercini. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef ESP_Mail_WCS32_H -#define ESP_Mail_WCS32_H - -#ifdef ESP32 - -#include "Arduino.h" -#include "IPAddress.h" -#include -#include "esp_mail_ssl_client32.h" - -typedef void (*DebugMsgCallback)(const char *msg); - -class ESP_Mail_WCS32 : public WiFiClient -{ - friend class ESP_Mail_HTTPClient32; - -protected: - esp_mail_ssl_client32::esp_mail_ssl_ctx32 *sslclient; - - int _lastError = 0; - int _peek = -1; - int _timeout = 0; - bool _use_insecure; - const char *_CA_cert; - const char *_cert; - const char *_private_key; - const char *_pskIdent; // identity for PSK cipher suites - const char *_psKey; // key in hex for PSK cipher suites - -public: - ESP_Mail_WCS32 *next; - ESP_Mail_WCS32(); - ESP_Mail_WCS32(int socket); - ESP_Mail_WCS32(bool secured); - ~ESP_Mail_WCS32(); - int connect(IPAddress ip, uint16_t port); - int connect(IPAddress ip, uint16_t port, int32_t timeout); - int connect(const char *host, uint16_t port); - int connect(const char *host, uint16_t port, int32_t timeout); - int connect(IPAddress ip, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); - int connect(const char *host, uint16_t port, const char *rootCABuff, const char *cli_cert, const char *cli_key); - int connect(IPAddress ip, uint16_t port, const char *pskIdent, const char *psKey); - int connect(const char *host, uint16_t port, const char *pskIdent, const char *psKey); - int peek(); - size_t write(uint8_t data); - size_t write(const uint8_t *buf, size_t size); - int available(); - int read(); - int read(uint8_t *buf, size_t size); - void flush() {} - void stop(); - uint8_t connected(); - int lastError(char *buf, const size_t size); - void setInsecure(); // Don't validate the chain, just accept whatever is given. VERY INSECURE! - void setPreSharedKey(const char *pskIdent, const char *psKey); // psKey in Hex - void setCACert(const char *rootCA); - void setCertificate(const char *client_ca); - void setPrivateKey(const char *private_key); - bool loadCACert(Stream &stream, size_t size); - bool loadCertificate(Stream &stream, size_t size); - bool loadPrivateKey(Stream &stream, size_t size); - bool verify(const char *fingerprint, const char *domain_name); - void setHandshakeTimeout(unsigned long handshake_timeout); - int setTimeout(uint32_t seconds) { return 0; } - void setSTARTTLS(bool enable); - void setDebugCB(DebugMsgCallback *cb); - int _ns_available(); - size_t _ns_write(const char *buf, size_t size); - size_t _ns_read(char *buf, size_t size); - int _ns_read(); - uint8_t _ns_connected(); - bool _ns_connect_ssl(); - - operator bool() - { - return connected(); - } - ESP_Mail_WCS32 &operator=(const ESP_Mail_WCS32 &other); - bool operator==(const bool value) - { - return bool() == value; - } - bool operator!=(const bool value) - { - return bool() != value; - } - bool operator==(const ESP_Mail_WCS32 &); - bool operator!=(const ESP_Mail_WCS32 &rhs) - { - return !this->operator==(rhs); - }; - - int socket() - { - return sslclient->socket = -1; - } - -private: - esp_mail_ssl_client32 _ssl_client32; - char *_streamLoad(Stream &stream, size_t size); - bool _secured = true; - bool _withCert = false; - bool _withKey = false; - std::string _host = ""; - std::string _rxBuf = ""; - int _port; - - //friend class WiFiServer; - using Print::write; -}; - -#endif //ESP32 - -#endif //ESP_Mail_WCS32_H diff --git a/lib/libesp32/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.cpp b/lib/libesp32/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.cpp deleted file mode 100644 index a96e2d6c8..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.cpp +++ /dev/null @@ -1,702 +0,0 @@ -/* - *Customized ssl_client.cpp to support STARTTLS protocol, version 1.0.8 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -/* Provide SSL/TLS functions to ESP32 with Arduino IDE -* -* Adapted from the ssl_client1 example of mbedtls. -* -* Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved, Apache 2.0 License. -* Additions Copyright (C) 2017 Evandro Luis Copercini, Apache 2.0 License. -*/ - -#ifndef ESP_MAIL_SSL_CLIENT32_CPP -#define ESP_MAIL_SSL_CLIENT32_CPP - -#ifdef ESP32 - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "esp_mail_ssl_client32.h" -#include - -#if !defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) && !defined(MBEDTLS_KEY_EXCHANGE_SOME_PSK_ENABLED) -#error "Please configure IDF framework to include mbedTLS -> Enable pre-shared-key ciphersuites and activate at least one cipher" -#endif - -const char *_esp_mail_pers32 = "esp_mail_esp32-tls"; - -static int _handle_error(int err, const char *file, int line) -{ - if (err == -30848) - { - return err; - } -#ifdef MBEDTLS_ERROR_C - char error_buf[100]; - mbedtls_strerror(err, error_buf, 100); - log_e("[%s():%d]: (%d) %s", file, line, err, error_buf); -#else - log_e("[%s():%d]: code %d", file, line, err); -#endif - return err; -} - -#define handle_error(e) _handle_error(e, __FUNCTION__, __LINE__) - -void esp_mail_ssl_client32::ssl_init(esp_mail_ssl_ctx32 *ssl_client) -{ - mbedtls_ssl_init(&ssl_client->ssl_ctx); - mbedtls_ssl_config_init(&ssl_client->ssl_conf); - mbedtls_ctr_drbg_init(&ssl_client->drbg_ctx); -} - -int esp_mail_ssl_client32::start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure) -{ - - if (rootCABuff == NULL && pskIdent == NULL && psKey == NULL && !insecure) - { - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_27); - return -1; - } - - int enable = 1; - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_2); - - log_v("Free internal heap before TLS %u", ESP.getFreeHeap()); - - log_v("Starting socket"); - ssl_client->socket = -1; - - ssl_client->socket = lwip_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (ssl_client->socket < 0) - { - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_3); - log_e("ERROR opening socket"); - return ssl_client->socket; - } - - IPAddress srv((uint32_t)0); - if (!WiFiGenericClass::hostByName(host, srv)) - { - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_4); - return -1; - } - - struct sockaddr_in serv_addr; - memset(&serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_addr.s_addr = srv; - serv_addr.sin_port = htons(port); - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_5); - - if (lwip_connect(ssl_client->socket, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == 0) - { - if (timeout <= 0) - { - timeout = 30000; // Milli seconds. - } - timeval so_timeout = {.tv_sec = timeout / 1000, .tv_usec = (timeout % 1000) * 1000}; - -#define ROE(x, msg) \ - { \ - if (((x) < 0)) \ - { \ - log_e("LWIP Socket config of " msg " failed."); \ - return -1; \ - } \ - } - ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_RCVTIMEO, &so_timeout, sizeof(so_timeout)), "SO_RCVTIMEO"); - ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_SNDTIMEO, &so_timeout, sizeof(so_timeout)), "SO_SNDTIMEO"); - - ROE(lwip_setsockopt(ssl_client->socket, IPPROTO_TCP, TCP_NODELAY, &enable, sizeof(enable)), "TCP_NODELAY"); - ROE(lwip_setsockopt(ssl_client->socket, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable)), "SO_KEEPALIVE"); - } - else - { - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_7); - log_e("Connect to Server failed!"); - return -1; - } - - fcntl(ssl_client->socket, F_SETFL, fcntl(ssl_client->socket, F_GETFL, 0) | O_NONBLOCK); - - return ssl_client->socket; -} - -int esp_mail_ssl_client32::start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure) -{ - - char buf[512]; - int ret, flags; - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_9); - - log_v("Seeding the random number generator"); - mbedtls_entropy_init(&ssl_client->entropy_ctx); - - ret = mbedtls_ctr_drbg_seed(&ssl_client->drbg_ctx, mbedtls_entropy_func, &ssl_client->entropy_ctx, (const unsigned char *)_esp_mail_pers32, strlen(_esp_mail_pers32)); - if (ret < 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - return handle_error(ret); - } - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_10); - - log_v("Setting up the SSL/TLS structure..."); - - if ((ret = mbedtls_ssl_config_defaults(&ssl_client->ssl_conf, - MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT)) != 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - return handle_error(ret); - } - - // MBEDTLS_SSL_VERIFY_REQUIRED if a CA certificate is defined on Arduino IDE and - // MBEDTLS_SSL_VERIFY_NONE if not. - - if (insecure) - { - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_28); - - mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); - log_i("WARNING: Skipping SSL Verification. INSECURE!"); - } - else if (rootCABuff != NULL) - { - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_11); - log_v("Loading CA cert"); - mbedtls_x509_crt_init(&ssl_client->ca_cert); - mbedtls_ssl_conf_authmode(&ssl_client->ssl_conf, MBEDTLS_SSL_VERIFY_REQUIRED); - ret = mbedtls_x509_crt_parse(&ssl_client->ca_cert, (const unsigned char *)rootCABuff, strlen(rootCABuff) + 1); - mbedtls_ssl_conf_ca_chain(&ssl_client->ssl_conf, &ssl_client->ca_cert, NULL); - //mbedtls_ssl_conf_verify(&ssl_client->ssl_ctx, my_verify, NULL ); - if (ret < 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - // free the ca_cert in the case parse failed, otherwise, the old ca_cert still in the heap memory, that lead to "out of memory" crash. - mbedtls_x509_crt_free(&ssl_client->ca_cert); - return handle_error(ret); - } - } - else if (pskIdent != NULL && psKey != NULL) - { - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_12); - log_v("Setting up PSK"); - // convert PSK from hex to binary - if ((strlen(psKey) & 1) != 0 || strlen(psKey) > 2 * MBEDTLS_PSK_MAX_LEN) - { - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_13); - log_e("pre-shared key not valid hex or too long"); - return -1; - } - - unsigned char psk[MBEDTLS_PSK_MAX_LEN]; - size_t psk_len = strlen(psKey) / 2; - for (int j = 0; j < strlen(psKey); j += 2) - { - char c = psKey[j]; - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'A' && c <= 'F') - c -= 'A' - 10; - else if (c >= 'a' && c <= 'f') - c -= 'a' - 10; - else - return -1; - psk[j / 2] = c << 4; - c = psKey[j + 1]; - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'A' && c <= 'F') - c -= 'A' - 10; - else if (c >= 'a' && c <= 'f') - c -= 'a' - 10; - else - return -1; - psk[j / 2] |= c; - } - // set mbedtls config - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_14); - - ret = mbedtls_ssl_conf_psk(&ssl_client->ssl_conf, psk, psk_len, - (const unsigned char *)pskIdent, strlen(pskIdent)); - if (ret != 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - - log_e("mbedtls_ssl_conf_psk returned %d", ret); - return handle_error(ret); - } - } - else - { - return -1; - } - - if (!insecure && cli_cert != NULL && cli_key != NULL) - { - - mbedtls_x509_crt_init(&ssl_client->client_cert); - mbedtls_pk_init(&ssl_client->client_key); - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_15); - - log_v("Loading CRT cert"); - - ret = mbedtls_x509_crt_parse(&ssl_client->client_cert, (const unsigned char *)cli_cert, strlen(cli_cert) + 1); - if (ret < 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - // free the client_cert in the case parse failed, otherwise, the old client_cert still in the heap memory, that lead to "out of memory" crash. - mbedtls_x509_crt_free(&ssl_client->client_cert); - return handle_error(ret); - } - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_16); - - log_v("Loading private key"); - ret = mbedtls_pk_parse_key(&ssl_client->client_key, (const unsigned char *)cli_key, strlen(cli_key) + 1, NULL, 0); - - if (ret != 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - return handle_error(ret); - } - - mbedtls_ssl_conf_own_cert(&ssl_client->ssl_conf, &ssl_client->client_cert, &ssl_client->client_key); - } - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_17); - - log_v("Setting hostname for TLS session..."); - - // Hostname set here should match CN in server certificate - if ((ret = mbedtls_ssl_set_hostname(&ssl_client->ssl_ctx, host)) != 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - return handle_error(ret); - } - - mbedtls_ssl_conf_rng(&ssl_client->ssl_conf, mbedtls_ctr_drbg_random, &ssl_client->drbg_ctx); - - if ((ret = mbedtls_ssl_setup(&ssl_client->ssl_ctx, &ssl_client->ssl_conf)) != 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - return handle_error(ret); - } - - mbedtls_ssl_set_bio(&ssl_client->ssl_ctx, &ssl_client->socket, mbedtls_net_send, mbedtls_net_recv, NULL); - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_18); - - log_v("Performing the SSL/TLS handshake..."); - unsigned long handshake_start_time = millis(); - while ((ret = mbedtls_ssl_handshake(&ssl_client->ssl_ctx)) != 0) - { - if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - return handle_error(ret); - } - if ((millis() - handshake_start_time) > ssl_client->handshake_timeout) - return -1; - vTaskDelay(2); //2 ticks - } - - if (cli_cert != NULL && cli_key != NULL) - { - log_d("Protocol is %s Ciphersuite is %s", mbedtls_ssl_get_version(&ssl_client->ssl_ctx), mbedtls_ssl_get_ciphersuite(&ssl_client->ssl_ctx)); - if ((ret = mbedtls_ssl_get_record_expansion(&ssl_client->ssl_ctx)) >= 0) - { - log_d("Record expansion is %d", ret); - } - else - { - log_w("Record expansion is unknown (compression)"); - } - } - - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_19); - - log_v("Verifying peer X.509 certificate..."); - - if ((flags = mbedtls_ssl_get_verify_result(&ssl_client->ssl_ctx)) != 0) - { - memset(buf, 0, sizeof(buf)); - mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags); - log_e("Failed to verify peer certificate! verification info: %s", buf); - stop_ssl_socket(ssl_client, rootCABuff, cli_cert, cli_key); //It's not safe continue. - return handle_error(ret); - } - else - { - log_v("Certificate verified."); - } - - if (rootCABuff != NULL) - { - mbedtls_x509_crt_free(&ssl_client->ca_cert); - } - - if (cli_cert != NULL) - { - mbedtls_x509_crt_free(&ssl_client->client_cert); - } - - if (cli_key != NULL) - { - mbedtls_pk_free(&ssl_client->client_key); - } - - log_v("Free internal heap after TLS %u", ESP.getFreeHeap()); - - return ssl_client->socket; -} - -void esp_mail_ssl_client32::stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key) -{ - if (ssl_client->_debugCallback) - ssl_client_debug_pgm_send_cb(ssl_client, esp_ssl_client_str_22); - - log_v("Cleaning SSL connection."); - - if (ssl_client->socket >= 0) - { - close(ssl_client->socket); - ssl_client->socket = -1; - } - - mbedtls_ssl_free(&ssl_client->ssl_ctx); - mbedtls_ssl_config_free(&ssl_client->ssl_conf); - mbedtls_ctr_drbg_free(&ssl_client->drbg_ctx); - mbedtls_entropy_free(&ssl_client->entropy_ctx); -} - -int esp_mail_ssl_client32::data_to_read(esp_mail_ssl_ctx32 *ssl_client) -{ - int ret, res; - ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, NULL, 0); - //log_e("RET: %i",ret); //for low level debug - res = mbedtls_ssl_get_bytes_avail(&ssl_client->ssl_ctx); - //log_e("RES: %i",res); //for low level debug - if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0) - { - if (ssl_client->_debugCallback) - ssl_client_send_mbedtls_error_cb(ssl_client, ret); - return handle_error(ret); - } - - return res; -} - -int esp_mail_ssl_client32::send_ssl_data(esp_mail_ssl_ctx32 *ssl_client, const uint8_t *data, size_t len) -{ - log_v("Writing HTTP request with %d bytes...", len); //for low level debug - int ret = -1; - - while ((ret = mbedtls_ssl_write(&ssl_client->ssl_ctx, data, len)) <= 0) - { - if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret < 0) - { - log_v("Handling error %d", ret); //for low level debug - return handle_error(ret); - } - //wait for space to become available - vTaskDelay(2); - } - - return ret; -} - -int esp_mail_ssl_client32::get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length) -{ - - //log_d( "Reading HTTP response..."); //for low level debug - int ret = -1; - - ret = mbedtls_ssl_read(&ssl_client->ssl_ctx, data, length); - - //log_v( "%d bytes read", ret); //for low level debug - return ret; -} - -bool esp_mail_ssl_client32::parseHexNibble(char pb, uint8_t *res) -{ - if (pb >= '0' && pb <= '9') - { - *res = (uint8_t)(pb - '0'); - return true; - } - else if (pb >= 'a' && pb <= 'f') - { - *res = (uint8_t)(pb - 'a' + 10); - return true; - } - else if (pb >= 'A' && pb <= 'F') - { - *res = (uint8_t)(pb - 'A' + 10); - return true; - } - return false; -} - -// Compare a name from certificate and domain name, return true if they match -bool esp_mail_ssl_client32::matchName(const std::string &name, const std::string &domainName) -{ - size_t wildcardPos = name.find('*'); - if (wildcardPos == std::string::npos) - { - // Not a wildcard, expect an exact match - return name == domainName; - } - - size_t firstDotPos = name.find('.'); - if (wildcardPos > firstDotPos) - { - // Wildcard is not part of leftmost component of domain name - // Do not attempt to match (rfc6125 6.4.3.1) - return false; - } - if (wildcardPos != 0 || firstDotPos != 1) - { - // Matching of wildcards such as baz*.example.com and b*z.example.com - // is optional. Maybe implement this in the future? - return false; - } - size_t domainNameFirstDotPos = domainName.find('.'); - if (domainNameFirstDotPos == std::string::npos) - { - return false; - } - return domainName.substr(domainNameFirstDotPos) == name.substr(firstDotPos); -} - -// Verifies certificate provided by the peer to match specified SHA256 fingerprint -bool esp_mail_ssl_client32::verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, const char *domain_name) -{ - // Convert hex string to byte array - uint8_t fingerprint_local[32]; - int len = strlen(fp); - int pos = 0; - for (size_t i = 0; i < sizeof(fingerprint_local); ++i) - { - while (pos < len && ((fp[pos] == ' ') || (fp[pos] == ':'))) - { - ++pos; - } - if (pos > len - 2) - { - log_d("pos:%d len:%d fingerprint too short", pos, len); - return false; - } - uint8_t high, low; - if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos + 1], &low)) - { - log_d("pos:%d len:%d invalid hex sequence: %c%c", pos, len, fp[pos], fp[pos + 1]); - return false; - } - pos += 2; - fingerprint_local[i] = low | (high << 4); - } - - // Get certificate provided by the peer - const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ssl_client->ssl_ctx); - - if (!crt) - { - log_d("could not fetch peer certificate"); - return false; - } - - // Calculate certificate's SHA256 fingerprint - uint8_t fingerprint_remote[32]; - mbedtls_sha256_context sha256_ctx; - mbedtls_sha256_init(&sha256_ctx); - mbedtls_sha256_starts(&sha256_ctx, false); - mbedtls_sha256_update(&sha256_ctx, crt->raw.p, crt->raw.len); - mbedtls_sha256_finish(&sha256_ctx, fingerprint_remote); - - // Check if fingerprints match - if (memcmp(fingerprint_local, fingerprint_remote, 32)) - { - log_d("fingerprint doesn't match"); - return false; - } - - // Additionally check if certificate has domain name if provided - if (domain_name) - return verify_ssl_dn(ssl_client, domain_name); - else - return true; -} - -// Checks if peer certificate has specified domain in CN or SANs -bool esp_mail_ssl_client32::verify_ssl_dn(esp_mail_ssl_ctx32 *ssl_client, const char *domain_name) -{ - log_d("domain name: '%s'", (domain_name) ? domain_name : "(null)"); - std::string domain_name_str(domain_name); - std::transform(domain_name_str.begin(), domain_name_str.end(), domain_name_str.begin(), ::tolower); - - // Get certificate provided by the peer - const mbedtls_x509_crt *crt = mbedtls_ssl_get_peer_cert(&ssl_client->ssl_ctx); - - // Check for domain name in SANs - const mbedtls_x509_sequence *san = &crt->subject_alt_names; - while (san != nullptr) - { - std::string san_str((const char *)san->buf.p, san->buf.len); - std::transform(san_str.begin(), san_str.end(), san_str.begin(), ::tolower); - - if (matchName(san_str, domain_name_str)) - return true; - - log_d("SAN '%s': no match", san_str.c_str()); - - // Fetch next SAN - san = san->next; - } - - // Check for domain name in CN - const mbedtls_asn1_named_data *common_name = &crt->subject; - while (common_name != nullptr) - { - // While iterating through DN objects, check for CN object - if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &common_name->oid)) - { - std::string common_name_str((const char *)common_name->val.p, common_name->val.len); - - if (matchName(common_name_str, domain_name_str)) - return true; - - log_d("CN '%s': not match", common_name_str.c_str()); - } - - // Fetch next DN object - common_name = common_name->next; - } - - return false; -} - -int esp_mail_ssl_client32::_ns_lwip_write(esp_mail_ssl_ctx32 *ssl_client, const char *buf, int bufLen) -{ - return lwip_write(ssl_client->socket, buf, bufLen); -} - -int esp_mail_ssl_client32::_ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen) -{ - fd_set readset; - fd_set writeset; - fd_set errset; - - struct timeval tv; - - FD_ZERO(&readset); - FD_SET(ssl_client->socket, &readset); - FD_ZERO(&writeset); - FD_SET(ssl_client->socket, &writeset); - - FD_ZERO(&errset); - FD_SET(ssl_client->socket, &errset); - - tv.tv_sec = 1; - tv.tv_usec = 0; - int ret = lwip_select(ssl_client->socket, &readset, &writeset, &errset, &tv); - - if (ret < 0) - return ret; - - return read(ssl_client->socket, buf, bufLen); -} - -void esp_mail_ssl_client32::ssl_client_send_mbedtls_error_cb(esp_mail_ssl_ctx32 *ssl_client, int errNo) -{ - char *buf = new char[512]; - char *error_buf = new char[100]; - memset(buf, 0, 512); - strcpy_P(buf, esp_ssl_client_str_1); - mbedtls_strerror(errNo, error_buf, 100); - strcat(buf, error_buf); - DebugMsgCallback cb = *ssl_client->_debugCallback; - cb(buf); - delete[] error_buf; - delete[] buf; -} - -void esp_mail_ssl_client32::ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info) -{ - size_t dbgInfoLen = strlen_P(info) + 10; - char *dbgInfo = new char[dbgInfoLen]; - memset(dbgInfo, 0, dbgInfoLen); - strcpy_P(dbgInfo, info); - DebugMsgCallback cb = *ssl_client->_debugCallback; - cb(dbgInfo); - delete[] dbgInfo; -} - -#endif //ESP32 - -#endif //ESP_MAIL_SSL_CLIENT32_CPP diff --git a/lib/libesp32/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.h b/lib/libesp32/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.h deleted file mode 100644 index b0704d13f..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp32/esp_mail_ssl_client32.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - *Customized ssl_client.h to support STARTTLS protocol, version 1.0.8 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -/* Provide SSL/TLS functions to ESP32 with Arduino IDE - * by Evandro Copercini - 2017 - Apache 2.0 License - */ - -#ifndef ESP_MAIL_SSL_CLIENT32_H -#define ESP_MAIL_SSL_CLIENT32_H - -#ifdef ESP32 -#include -#include "mbedtls/platform.h" -#include "mbedtls/net.h" -#include "mbedtls/debug.h" -#include "mbedtls/ssl.h" -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/error.h" - -static const char esp_ssl_client_str_1[] PROGMEM = "! E: "; -static const char esp_ssl_client_str_2[] PROGMEM = "> C: starting socket"; -static const char esp_ssl_client_str_3[] PROGMEM = "! E: opening socket"; -static const char esp_ssl_client_str_4[] PROGMEM = "! E: could not get ip from host"; -static const char esp_ssl_client_str_5[] PROGMEM = "> C: connecting to Server"; -static const char esp_ssl_client_str_6[] PROGMEM = "> C: server connected"; -static const char esp_ssl_client_str_7[] PROGMEM = "! E: connect to Server failed!"; -static const char esp_ssl_client_str_8[] PROGMEM = "< S: "; -static const char esp_ssl_client_str_9[] PROGMEM = "> C: seeding the random number generator"; -static const char esp_ssl_client_str_10[] PROGMEM = "> C: setting up the SSL/TLS structure"; -static const char esp_ssl_client_str_11[] PROGMEM = "> C: loading CA cert"; -static const char esp_ssl_client_str_12[] PROGMEM = "> C: setting up PSK"; -static const char esp_ssl_client_str_13[] PROGMEM = "! E: pre-shared key not valid hex or too long"; -static const char esp_ssl_client_str_14[] PROGMEM = "> C: set mbedtls config"; -static const char esp_ssl_client_str_15[] PROGMEM = "> C: loading CRT cert"; -static const char esp_ssl_client_str_16[] PROGMEM = "> C: loading private key"; -static const char esp_ssl_client_str_17[] PROGMEM = "> C: setting hostname for TLS session"; -static const char esp_ssl_client_str_18[] PROGMEM = "> C: performing the SSL/TLS handshake"; -static const char esp_ssl_client_str_19[] PROGMEM = "> C: verifying peer X.509 certificate"; -static const char esp_ssl_client_str_20[] PROGMEM = "! E: failed to verify peer certificate!"; -static const char esp_ssl_client_str_21[] PROGMEM = "> C: certificate verified"; -static const char esp_ssl_client_str_22[] PROGMEM = "> C: cleaning SSL connection"; -static const char esp_ssl_client_str_23[] PROGMEM = "! E: fingerprint too short"; -static const char esp_ssl_client_str_24[] PROGMEM = "! E: invalid hex sequence"; -static const char esp_ssl_client_str_25[] PROGMEM = "! E: could not fetch peer certificate"; -static const char esp_ssl_client_str_26[] PROGMEM = "! E: fingerprint doesn't match"; -static const char esp_ssl_client_str_27[] PROGMEM = "! E: root certificate, PSK identity or keys are required for secured connection"; -static const char esp_ssl_client_str_28[] PROGMEM = "! W: Skipping SSL Verification. INSECURE!"; - -class esp_mail_ssl_client32 -{ -public: - esp_mail_ssl_client32(){}; - - typedef void (*DebugMsgCallback)(const char *msg); - - typedef struct esp_mail_ssl_ctx32 - { - int socket; - mbedtls_ssl_context ssl_ctx; - mbedtls_ssl_config ssl_conf; - - mbedtls_ctr_drbg_context drbg_ctx; - mbedtls_entropy_context entropy_ctx; - - mbedtls_x509_crt ca_cert; - mbedtls_x509_crt client_cert; - mbedtls_pk_context client_key; - DebugMsgCallback *_debugCallback = NULL; - - unsigned long handshake_timeout; - } esp_mail_ssl_ctx32; - - void ssl_init(esp_mail_ssl_ctx32 *ssl_client); - - int start_socket(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure); - int start_ssl_client(esp_mail_ssl_ctx32 *ssl_client, const char *host, uint32_t port, int timeout, const char *rootCABuff, const char *cli_cert, const char *cli_key, const char *pskIdent, const char *psKey, bool insecure); - void stop_ssl_socket(esp_mail_ssl_ctx32 *ssl_client, const char *rootCABuff, const char *cli_cert, const char *cli_key); - - int data_to_read(esp_mail_ssl_ctx32 *ssl_client); - int send_ssl_data(esp_mail_ssl_ctx32 *ssl_client, const uint8_t *data, size_t len); - int get_ssl_receive(esp_mail_ssl_ctx32 *ssl_client, uint8_t *data, int length); - bool verify_ssl_fingerprint(esp_mail_ssl_ctx32 *ssl_client, const char *fp, const char *domain_name); - bool verify_ssl_dn(esp_mail_ssl_ctx32 *ssl_client, const char *domain_name); - - int _ns_lwip_write(esp_mail_ssl_ctx32 *ssl_client, const char *buf, int bufLen); - int _ns_lwip_read(esp_mail_ssl_ctx32 *ssl_client, char *buf, int bufLen); - void ssl_client_send_mbedtls_error_cb(esp_mail_ssl_ctx32 *ssl_client, int errNo); - void ssl_client_debug_pgm_send_cb(esp_mail_ssl_ctx32 *ssl_client, PGM_P info); - bool parseHexNibble(char pb, uint8_t *res); - bool matchName(const std::string &name, const std::string &domainName); -}; - -#endif //ESP32 - -#endif //ESP_MAIL_SSL_CLIENT32_H diff --git a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.h b/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.h deleted file mode 100644 index 4ee319736..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_BearSSLHelpers.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - Copy of BearSSLHelpers.h - - WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries - - Mostly compatible with Arduino WiFi shield library and standard - WiFiClient/ServerSecure (except for certificate handling). - - Copyright (c) 2018 Earle F. Philhower, III - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef ESP_Mail_BearSSLHelpers_H -#define ESP_Mail_BearSSLHelpers_H - -#ifdef ESP8266 - -#include -#include - -// Internal opaque structures, not needed by user applications -namespace ESP_Mail_brssl -{ - class public_key; - class private_key; -}; // namespace ESP_Mail_brssl - -namespace ESP_Mail -{ - - // Holds either a single public RSA or EC key for use when BearSSL wants a pubkey. - // Copies all associated data so no need to keep input PEM/DER keys. - // All inputs can be either in RAM or PROGMEM. - class PublicKey - { - public: - PublicKey(); - PublicKey(const char *pemKey); - PublicKey(const uint8_t *derKey, size_t derLen); - ~PublicKey(); - - bool parse(const char *pemKey); - bool parse(const uint8_t *derKey, size_t derLen); - - // Accessors for internal use, not needed by apps - bool isRSA() const; - bool isEC() const; - const br_rsa_public_key *getRSA() const; - const br_ec_public_key *getEC() const; - - // Disable the copy constructor, we're pointer based - PublicKey(const PublicKey &that) = delete; - - private: - ESP_Mail_brssl::public_key *_key; - }; - - // Holds either a single private RSA or EC key for use when BearSSL wants a secretkey. - // Copies all associated data so no need to keep input PEM/DER keys. - // All inputs can be either in RAM or PROGMEM. - class PrivateKey - { - public: - PrivateKey(); - PrivateKey(const char *pemKey); - PrivateKey(const uint8_t *derKey, size_t derLen); - ~PrivateKey(); - - bool parse(const char *pemKey); - bool parse(const uint8_t *derKey, size_t derLen); - - // Accessors for internal use, not needed by apps - bool isRSA() const; - bool isEC() const; - const br_rsa_private_key *getRSA() const; - const br_ec_private_key *getEC() const; - - // Disable the copy constructor, we're pointer based - PrivateKey(const PrivateKey &that) = delete; - - private: - ESP_Mail_brssl::private_key *_key; - }; - - // Holds one or more X.509 certificates and associated trust anchors for - // use whenever BearSSL needs a cert or TA. May want to have multiple - // certs for things like a series of trusted CAs (but check the CertStore class - // for a more memory efficient way). - // Copies all associated data so no need to keep input PEM/DER certs. - // All inputs can be either in RAM or PROGMEM. - class ESP_Mail_X509List - { - public: - ESP_Mail_X509List(); - ESP_Mail_X509List(const char *pemCert); - ESP_Mail_X509List(const uint8_t *derCert, size_t derLen); - ~ESP_Mail_X509List(); - - bool append(const char *pemCert); - bool append(const uint8_t *derCert, size_t derLen); - - // Accessors - size_t getCount() const - { - return _count; - } - const br_x509_certificate *getX509Certs() const - { - return _cert; - } - const br_x509_trust_anchor *getTrustAnchors() const - { - return _ta; - } - - // Disable the copy constructor, we're pointer based - ESP_Mail_X509List(const ESP_Mail_X509List &that) = delete; - - private: - size_t _count; - br_x509_certificate *_cert; - br_x509_trust_anchor *_ta; - }; - - // Opaque object which wraps the BearSSL SSL session to make repeated connections - // significantly faster. Completely optional. - class ESP_Mail_WCS; - - class Session - { - friend class ESP_Mail_WCS; - - public: - Session() { memset(&_session, 0, sizeof(_session)); } - - private: - br_ssl_session_parameters *getSession() { return &_session; } - // The actual BearSSL ession information - br_ssl_session_parameters _session; - }; - - // Updater SHA256 hash and signature verification - class HashSHA256 : public UpdaterHashClass - { - public: - virtual void begin() override; - virtual void add(const void *data, uint32_t len) override; - virtual void end() override; - virtual int len() override; - virtual const void *hash() override; - virtual const unsigned char *oid() override; - - private: - br_sha256_context _cc; - unsigned char _sha256[32]; - }; - - class SigningVerifier : public UpdaterVerifyClass - { - public: - virtual uint32_t length() override; - virtual bool verify(UpdaterHashClass *hash, const void *signature, uint32_t signatureLen) override; - - public: - SigningVerifier(PublicKey *pubKey) { _pubKey = pubKey; } - - private: - PublicKey *_pubKey; - }; - /* -// Stack thunked versions of calls -extern "C" { -extern unsigned char *thunk_br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len); -extern void thunk_br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len); -extern unsigned char *thunk_br_ssl_engine_recvrec_buf( const br_ssl_engine_context *cc, size_t *len); -extern void thunk_br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len); -extern unsigned char *thunk_br_ssl_engine_sendapp_buf( const br_ssl_engine_context *cc, size_t *len); -extern void thunk_br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len); -extern unsigned char *thunk_br_ssl_engine_sendrec_buf( const br_ssl_engine_context *cc, size_t *len); -extern void thunk_br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len); -}; -*/ - -}; // namespace ESP_Mail - -#endif /* ESP8266 */ - -#endif /* ESP_Mail_BearSSLHelpers_H */ diff --git a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.cpp b/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.cpp deleted file mode 100644 index f8efb1155..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_CertStoreBearSSL.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - Copy of CertStoreBearSSL.cpp - Library for Arduino ESP8266 - Copyright (c) 2018 Earle F. Philhower, III - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#ifndef ESP_Mail_CertStoreBearSSL_CPP -#define ESP_Mail_CertStoreBearSSL_CPP - -#ifdef ESP8266 - -#include "ESP_Mail_CertStoreBearSSL.h" -#include - - -#ifdef DEBUG_ESP_SSL -#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__) -#else -#define DEBUG_BSSL(...) -#endif - -namespace ESP_Mail { - -extern "C" { - // Callback for the x509 decoder - static void dn_append(void *ctx, const void *buf, size_t len) { - br_sha256_context *sha1 = (br_sha256_context*)ctx; - br_sha256_update(sha1, buf, len); - } -} - - -ESP_Mail_CertStore::~ESP_Mail_CertStore() { - free(_indexName); - free(_dataName); -} - -ESP_Mail_CertStore::ESP_Mail_CertInfo ESP_Mail_CertStore::_preprocessCert(uint32_t length, uint32_t offset, const void *raw) { - ESP_Mail_CertStore::ESP_Mail_CertInfo ci; - - // Clear the CertInfo - memset(&ci, 0, sizeof(ci)); - - // Process it using SHA256, same as the hashed_dn - br_x509_decoder_context *ctx = new br_x509_decoder_context; - br_sha256_context *sha256 = new br_sha256_context; - if (!ctx || !sha256) { - DEBUG_BSSL("CertStore::_preprocessCert: OOM\n"); - return ci; - } - - br_sha256_init(sha256); - br_x509_decoder_init(ctx, dn_append, sha256, nullptr, nullptr); - br_x509_decoder_push(ctx, (const void*)raw, length); - - // Copy result to structure - br_sha256_out(sha256, &ci.sha256); - ci.length = length; - ci.offset = offset; - - // Clean up allocated memory - delete sha256; - delete ctx; - - // Return result - return ci; -} - -// The certs.ar file is a UNIX ar format file, concatenating all the -// individual certificates into a single blob in a space-efficient way. -int ESP_Mail_CertStore::initCertStore(FS &fs, const char *indexFileName, const char *dataFileName) { - int count = 0; - uint32_t offset = 0; - - _fs = &fs; - - // In case initCertStore called multiple times, don't leak old filenames - free(_indexName); - free(_dataName); - - // No strdup_P, so manually do it - _indexName = (char *)malloc(strlen_P(indexFileName) + 1); - _dataName = (char *)malloc(strlen_P(dataFileName) + 1); - if (!_indexName || !_dataName) { - free(_indexName); - free(_dataName); - return 0; - } - memcpy_P(_indexName, indexFileName, strlen_P(indexFileName) + 1); - memcpy_P(_dataName, dataFileName, strlen_P(dataFileName) + 1); - - File index = _fs->open(_indexName, "w"); - if (!index) { - return 0; - } - - File data = _fs->open(_dataName, "r"); - if (!data) { - index.close(); - return 0; - } - - uint8_t magic[8]; - if (data.read(magic, sizeof(magic)) != sizeof(magic) || - memcmp(magic, "!\n", sizeof(magic)) ) { - data.close(); - index.close(); - return 0; - } - offset += sizeof(magic); - - while (true) { - uint8_t fileHeader[60]; - // 0..15 = filename in ASCII - // 48...57 = length in decimal ASCII - uint32_t length; - if (data.read(fileHeader, sizeof(fileHeader)) != sizeof(fileHeader)) { - break; - } - offset += sizeof(fileHeader); - fileHeader[58] = 0; - if (1 != sscanf((char *)(fileHeader + 48), "%d", &length) || !length) { - break; - } - - void *raw = malloc(length); - if (!raw) { - break; - } - if (data.read((uint8_t *)raw, length) != length) { - free(raw); - break; - } - - // If the filename starts with "//" then this is a rename file, skip it - if (fileHeader[0] != '/' || fileHeader[1] != '/') { - ESP_Mail_CertStore::ESP_Mail_CertInfo ci = _preprocessCert(length, offset, raw); - if (index.write((uint8_t *)&ci, sizeof(ci)) != (ssize_t)sizeof(ci)) { - free(raw); - break; - } - count++; - } - - offset += length; - free(raw); - if (offset & 1) { - uint8_t x; - data.read(&x, 1); - offset++; - } - } - data.close(); - index.close(); - return count; -} - -void ESP_Mail_CertStore::installCertStore(br_x509_minimal_context *ctx) { - br_x509_minimal_set_dynamic(ctx, (void*)this, findHashedTA, freeHashedTA); -} - -const br_x509_trust_anchor *ESP_Mail_CertStore::findHashedTA(void *ctx, void *hashed_dn, size_t len) { - ESP_Mail_CertStore *cs = static_cast(ctx); - ESP_Mail_CertStore::ESP_Mail_CertInfo ci; - - if (!cs || len != sizeof(ci.sha256) || !cs->_indexName || !cs->_dataName || !cs->_fs) { - return nullptr; - } - - File index = cs->_fs->open(cs->_indexName, "r"); - if (!index) { - return nullptr; - } - - while (index.read((uint8_t *)&ci, sizeof(ci)) == sizeof(ci)) { - if (!memcmp(ci.sha256, hashed_dn, sizeof(ci.sha256))) { - index.close(); - uint8_t *der = (uint8_t*)malloc(ci.length); - if (!der) { - return nullptr; - } - File data = cs->_fs->open(cs->_dataName, "r"); - if (!data) { - free(der); - return nullptr; - } - if (!data.seek(ci.offset, SeekSet)) { - data.close(); - free(der); - return nullptr; - } - if (data.read((uint8_t *)der, ci.length) != ci.length) { - free(der); - return nullptr; - } - data.close(); - cs->_x509 = new ESP_Mail_X509List(der, ci.length); - free(der); - if (!cs->_x509) { - DEBUG_BSSL("CertStore::findHashedTA: OOM\n"); - return nullptr; - } - - br_x509_trust_anchor *ta = (br_x509_trust_anchor*)cs->_x509->getTrustAnchors(); - memcpy(ta->dn.data, ci.sha256, sizeof(ci.sha256)); - ta->dn.len = sizeof(ci.sha256); - - return ta; - } - } - index.close(); - return nullptr; -} - -void ESP_Mail_CertStore::freeHashedTA(void *ctx, const br_x509_trust_anchor *ta) { - ESP_Mail_CertStore *cs = static_cast(ctx); - (void) ta; // Unused - delete cs->_x509; - cs->_x509 = nullptr; -} - -} - -#endif /* ESP8266 */ - -#endif /* ESP_Mail_CertStoreBearSSL_CPP */ \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.cpp b/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.cpp deleted file mode 100644 index b1fdbff5f..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * HTTP Client for ESP8266 wrapper v1.0.3 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person returning a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef ESP_Mail_HTTPClient_CPP -#define ESP_Mail_HTTPClient_CPP - -#ifdef ESP8266 - -#include "ESP_Mail_HTTPClient.h" - -ESP_Mail_HTTPClient::ESP_Mail_HTTPClient() -{ -} - -ESP_Mail_HTTPClient::~ESP_Mail_HTTPClient() -{ - if (_wcs) - { - _wcs->stop(); - _wcs.reset(nullptr); - _wcs.release(); - } - - std::string().swap(_host); - std::string().swap(_caCertFile); - _cacert.reset(new char); - _cacert = nullptr; -} - -bool ESP_Mail_HTTPClient::begin(const char *host, uint16_t port) -{ - if (strcmp(_host.c_str(), host) != 0) - mflnChecked = false; - - _host = host; - _port = port; - - //probe for fragmentation support at the specified size - if (!mflnChecked) - { - fragmentable = _wcs->probeMaxFragmentLength(_host.c_str(), _port, chunkSize); - if (fragmentable) - { - _bsslRxSize = chunkSize; - _bsslTxSize = chunkSize; - _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); - } - mflnChecked = true; - } - - if (!fragmentable) - _wcs->setBufferSizes(maxRXBufSize / rxBufDivider, maxTXBufSize / txBufDivider); - - return true; -} - -bool ESP_Mail_HTTPClient::connected() -{ - if (_wcs) - { - if (_secured) - return _wcs->connected(); - else - return _wcs->_ns_connected(); - } - - return false; -} - -bool ESP_Mail_HTTPClient::send(const char *header) -{ - if (!connected()) - return false; - if (_secured) - return (_wcs->write((uint8_t *)header, strlen(header)) == strlen(header)); - else - return (_wcs->_ns_write((uint8_t *)header, strlen(header)) == strlen(header)); -} - -int ESP_Mail_HTTPClient::send(const char *header, const char *payload) -{ - size_t size = strlen(payload); - if (strlen(header) > 0) - { - if (!connect(_secured)) - { - return ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED; - } - - if (!send(header)) - { - return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED; - } - } - - if (size > 0) - { - if (_secured) - { - if (_wcs->write((uint8_t *)&payload[0], size) != size) - return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED; - } - else - { - if (_wcs->_ns_write((uint8_t *)&payload[0], size) != size) - return ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED; - } - } - - return 0; -} - -WiFiClient *ESP_Mail_HTTPClient::stream(void) -{ - if (connected()) - return _wcs.get(); - return nullptr; -} - -ESP_Mail::ESP_Mail_WCS *ESP_Mail_HTTPClient::_stream(void) -{ - if (connected()) - return _wcs.get(); - return nullptr; -} - -size_t ESP_Mail_HTTPClient::_ns_print(const char *buf) -{ - size_t size = strlen(buf); - return _wcs->_ns_write((uint8_t *)&buf[0], size); -} - -size_t ESP_Mail_HTTPClient::_ns_println(const char *buf) -{ - size_t size = strlen(buf); - size_t wr = _wcs->_ns_write((uint8_t *)&buf[0], size); - std::string s = "\r\n"; - wr += _wcs->_ns_write((uint8_t *)s.c_str(), s.length()); - return wr; -} - -bool ESP_Mail_HTTPClient::connect(bool secured) -{ - _secured = secured; - - if (connected()) - { - if (_secured) - { - while (_wcs->available() > 0) - _wcs->read(); - } - else - { - while (_wcs->_ns_available() > 0) - _wcs->_ns_read(); - } - return true; - } - - _wcs->setStartTLS(!_secured); - if (!_wcs->connect(_host.c_str(), _port)) - return false; - - return connected(); -} - - -void ESP_Mail_HTTPClient::setCACert(const char *caCert) -{ - -#ifndef USING_AXTLS - _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); -#endif - - if (caCert) - { -#ifndef USING_AXTLS - _wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(caCert)); -#else - _wcs->setCACert_P(caCert, strlen_P(caCert)); -#endif - _certType = 1; - } - else - { -#ifndef USING_AXTLS - _wcs->setInsecure(); -#endif - _certType = 0; - } - - _wcs->setNoDelay(true); -} - -void ESP_Mail_HTTPClient::setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType, uint8_t sdPin) -{ - -#ifndef USING_AXTLS - _sdPin = sdPin; - _wcs->setBufferSizes(_bsslRxSize, _bsslTxSize); - - if (_clockReady && strlen(caCertFile) > 0) - { - - fs::File f; - if (storageType == esp_mail_file_storage_type_flash) - { - ESP_MAIL_FLASH_FS.begin(); - if (ESP_MAIL_FLASH_FS.exists(caCertFile)) - f = ESP_MAIL_FLASH_FS.open(caCertFile, "r"); - } - else if (storageType == esp_mail_file_storage_type_sd) - { - ESP_MAIL_SD_FS.begin(_sdPin); - if (ESP_MAIL_SD_FS.exists(caCertFile)) - f = ESP_MAIL_SD_FS.open(caCertFile, FILE_READ); - } - - if (f) - { - size_t len = f.size(); - uint8_t *der = new uint8_t[len]; - if (f.available()) - f.read(der, len); - f.close(); - _wcs->setTrustAnchors(new ESP_Mail::ESP_Mail_X509List(der, len)); - delete[] der; - } - _certType = 2; - } -#endif - - _wcs->setNoDelay(true); -} - -#endif /* ESP8266 */ - -#endif /* ESP_Mail_HTTPClient_CPP */ \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.h b/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.h deleted file mode 100644 index 883158a8d..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_HTTPClient.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * HTTP Client for ESP8266 wrapper v1.0.3 - * - * The MIT License (MIT) - * Copyright (c) 2021 K. Suwatchai (Mobizt) - * - * - * Permission is hereby granted, free of charge, to any person returning a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef ESP_Mail_HTTPClient_H -#define ESP_Mail_HTTPClient_H - -#ifdef ESP8266 - -//ARDUINO_ESP8266_GIT_VER -//2.6.2 0xbc204a9b -//2.6.1 0x482516e3 -//2.6.0 0x643ec203 -//2.5.2 0x8b899c12 -//2.5.1 0xac02aff5 -//2.5.0 0x951aeffa -//2.5.0-beta3 0x21db8fc9 -//2.5.0-beta2 0x0fd86a07 -//2.5.0-beta1 0x9c1e03a1 -//2.4.2 0xbb28d4a3 -//2.4.1 0x614f7c32 -//2.4.0 0x4ceabea9 -//2.4.0-rc2 0x0c897c37 -//2.4.0-rc1 0xf6d232f1 - -#include -#include -#include -#include - -#include "SDK_Version_Common.h" - -#ifndef ARDUINO_ESP8266_GIT_VER -#error Your ESP8266 Arduino Core SDK is outdated, please update. From Arduino IDE go to Boards Manager and search 'esp8266' then select the latest version. -#endif - -#include - -#if ARDUINO_ESP8266_GIT_VER != 0xf6d232f1 && ARDUINO_ESP8266_GIT_VER != 0x0c897c37 && ARDUINO_ESP8266_GIT_VER != 0x4ceabea9 && ARDUINO_ESP8266_GIT_VER != 0x614f7c32 && ARDUINO_ESP8266_GIT_VER != 0xbb28d4a3 -#include "ESP_Mail_WCS.h" -#include "ESP_Mail_BearSSLHelpers.h" -#define ESP_MAIL_SSL_CLIENT ESP_Mail::ESP_Mail_WCS -#else -#error Please update the ESP8266 Arduino Core SDK to latest version. -#endif - -#define FS_NO_GLOBALS -#include -#include -#include "ESP_Mail_FS.h" -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#define ESP_MAIL_FLASH_FS ESP_Mail_DEFAULT_FLASH_FS -#define ESP_MAIL_SD_FS ESP_Mail_DEFAULT_SD_FS - -#if __has_include() || __has_include() -#error WiFi UART bridge was not supported. -#endif - -#define ESP_MAIL_ERROR_HTTPC_ERROR_CONNECTION_REFUSED (-1) -#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_HEADER_FAILED (-2) -#define ESP_MAIL_ERROR_HTTPC_ERROR_SEND_PAYLOAD_FAILED (-3) -#define ESP_MAIL_DEFAULT_TCP_TIMEOUT_SEC 30 - -enum esp_mail_file_storage_type -{ - esp_mail_file_storage_type_none, - esp_mail_file_storage_type_flash, - esp_mail_file_storage_type_sd, - esp_mail_file_storage_type_univ -}; - -class ESP_Mail_HTTPClient -{ - -public: - ESP_Mail_HTTPClient(); - ~ESP_Mail_HTTPClient(); - - bool begin(const char *host, uint16_t port); - - bool connected(void); - - int send(const char *header, const char *payload); - - bool send(const char *header); - - WiFiClient *stream(void); - - ESP_Mail::ESP_Mail_WCS *_stream(void); - - size_t _ns_print(const char *buf); - - size_t _ns_println(const char *buf); - - void setCACert(const char *caCert); - void setCertFile(const char *caCertFile, esp_mail_file_storage_type storageType, uint8_t sdPin); - bool connect(bool secured); - - int _certType = -1; - std::string _caCertFile = ""; - esp_mail_file_storage_type _caCertFileStoreageType = esp_mail_file_storage_type::esp_mail_file_storage_type_none; - uint16_t tcpTimeout = 40000; - - uint8_t _sdPin = 15; - bool _clockReady = false; - uint16_t _bsslRxSize = 1024; - uint16_t _bsslTxSize = 1024; - bool fragmentable = false; - int chunkSize = 1024; - int maxRXBufSize = 16384; //SSL full supported 16 kB - int maxTXBufSize = 16384; - bool mflnChecked = false; - int rxBufDivider = maxRXBufSize / chunkSize; - int txBufDivider = maxRXBufSize / chunkSize; - ; - -private: - std::unique_ptr _wcs = std::unique_ptr(new ESP_MAIL_SSL_CLIENT()); - std::unique_ptr _cacert; - std::string _host = ""; - uint16_t _port = 0; - bool _secured = true; -}; - -#endif /* ESP8266 */ - -#endif /* ESP_Mail_HTTPClient_H */ \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.cpp b/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.cpp deleted file mode 100644 index d419a9249..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.cpp +++ /dev/null @@ -1,2139 +0,0 @@ -/* - Customized version of WiFiClientSecure.cpp v1.0.1 - - WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries - - Mostly compatible with Arduino WiFi shield library and standard - WiFiClient/ServerSecure (except for certificate handling). - - Copyright (c) 2018 Earle F. Philhower, III - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef ESP_Mail_WCS_CPP -#define ESP_Mail_WCS_CPP - -#ifdef ESP8266 - -#define LWIP_INTERNAL - -#include -#include -#include - -extern "C" -{ -#include -#include -} -#include -#include -#include -#include -#include "ESP_Mail_WCS.h" -#include -#include -#include -#include -#include -#include -#include -#ifdef ESP8266 - #include -#endif -#include - -#if !CORE_MOCK - -// The BearSSL thunks in use for now -#define br_ssl_engine_recvapp_ack thunk_br_ssl_engine_recvapp_ack -#define br_ssl_engine_recvapp_buf thunk_br_ssl_engine_recvapp_buf -#define br_ssl_engine_recvrec_ack thunk_br_ssl_engine_recvrec_ack -#define br_ssl_engine_recvrec_buf thunk_br_ssl_engine_recvrec_buf -#define br_ssl_engine_sendapp_ack thunk_br_ssl_engine_sendapp_ack -#define br_ssl_engine_sendapp_buf thunk_br_ssl_engine_sendapp_buf -#define br_ssl_engine_sendrec_ack thunk_br_ssl_engine_sendrec_ack -#define br_ssl_engine_sendrec_buf thunk_br_ssl_engine_sendrec_buf - -#endif - -#ifdef DEBUG_ESP_SSL -#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR("BSSL:" fmt), ##__VA_ARGS__) -#else -#define DEBUG_BSSL(...) -#endif - -namespace ESP_Mail -{ - - void ESP_Mail_WCS::_clear() - { - // TLS handshake may take more than the 5 second default timeout - _timeout = 15000; - - _sc = nullptr; - _sc_svr = nullptr; - _eng = nullptr; - _x509_minimal = nullptr; - _x509_insecure = nullptr; - _x509_knownkey = nullptr; - _iobuf_in = nullptr; - _iobuf_out = nullptr; - _now = 0; // You can override or ensure time() is correct w/configTime - _ta = nullptr; - setBufferSizes(16384, 512); // Minimum safe - _handshake_done = false; - _recvapp_buf = nullptr; - _recvapp_len = 0; - _oom_err = false; - _session = nullptr; - _cipher_list = nullptr; - _cipher_cnt = 0; - } - - void ESP_Mail_WCS::_clearAuthenticationSettings() - { - _use_insecure = false; - _use_fingerprint = false; - _use_self_signed = false; - _knownkey = nullptr; - _sk = nullptr; - _ta = nullptr; - _axtls_ta = nullptr; - _axtls_chain = nullptr; - _axtls_sk = nullptr; - } - - ESP_Mail_WCS::ESP_Mail_WCS() : WiFiClient() - { - _clear(); - _clearAuthenticationSettings(); - _certStore = nullptr; // Don't want to remove cert store on a clear, should be long lived - stack_thunk_add_ref(); - } - - ESP_Mail_WCS::ESP_Mail_WCS(const ESP_Mail_WCS &rhs) : WiFiClient(rhs) - { - *this = rhs; - stack_thunk_add_ref(); - } - - ESP_Mail_WCS::~ESP_Mail_WCS() - { - if (_client) - { - _client->unref(); - _client = nullptr; - } - _cipher_list = nullptr; // std::shared will free if last reference - _freeSSL(); - stack_thunk_del_ref(); - // Clean up any dangling axtls compat structures, if needed - _axtls_ta = nullptr; - _axtls_chain = nullptr; - _axtls_sk = nullptr; - } - - ESP_Mail_WCS::ESP_Mail_WCS(ClientContext *client, - const ESP_Mail_X509List *chain, const PrivateKey *sk, - int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta) - { - _clear(); - _clearAuthenticationSettings(); - stack_thunk_add_ref(); - _iobuf_in_size = iobuf_in_size; - _iobuf_out_size = iobuf_out_size; - _client = client; - _client->ref(); - if (!_connectSSLServerRSA(chain, sk, client_CA_ta)) - { - _client->unref(); - _client = nullptr; - _clear(); - } - } - - ESP_Mail_WCS::ESP_Mail_WCS(ClientContext *client, - const ESP_Mail_X509List *chain, - unsigned cert_issuer_key_type, const PrivateKey *sk, - int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta) - { - _clear(); - _clearAuthenticationSettings(); - stack_thunk_add_ref(); - _iobuf_in_size = iobuf_in_size; - _iobuf_out_size = iobuf_out_size; - _client = client; - _client->ref(); - if (!_connectSSLServerEC(chain, cert_issuer_key_type, sk, client_CA_ta)) - { - _client->unref(); - _client = nullptr; - _clear(); - } - } - - void ESP_Mail_WCS::setClientRSACert(const ESP_Mail_X509List *chain, const PrivateKey *sk) - { - _chain = chain; - _sk = sk; - } - - void ESP_Mail_WCS::setClientECCert(const ESP_Mail_X509List *chain, - const PrivateKey *sk, unsigned allowed_usages, unsigned cert_issuer_key_type) - { - _chain = chain; - _sk = sk; - _allowed_usages = allowed_usages; - _cert_issuer_key_type = cert_issuer_key_type; - } - - void ESP_Mail_WCS::setBufferSizes(int recv, int xmit) - { - // Following constants taken from bearssl/src/ssl/ssl_engine.c (not exported unfortunately) - const int MAX_OUT_OVERHEAD = 85; - const int MAX_IN_OVERHEAD = 325; - - // The data buffers must be between 512B and 16KB - recv = std::max(512, std::min(16384, recv)); - xmit = std::max(512, std::min(16384, xmit)); - - // Add in overhead for SSL protocol - recv += MAX_IN_OVERHEAD; - xmit += MAX_OUT_OVERHEAD; - _iobuf_in_size = recv; - _iobuf_out_size = xmit; - } - - bool ESP_Mail_WCS::stop(unsigned int maxWaitMs) - { - bool ret = WiFiClient::stop(maxWaitMs); // calls our virtual flush() - // Only if we've already connected, store session params and clear the connection options - if (_handshake_done) - { - if (_session) - { - br_ssl_engine_get_session_parameters(_eng, _session->getSession()); - } - } - _freeSSL(); - return ret; - } - - bool ESP_Mail_WCS::flush(unsigned int maxWaitMs) - { - (void)_run_until(BR_SSL_SENDAPP); - return WiFiClient::flush(maxWaitMs); - } - - int ESP_Mail_WCS::connect(IPAddress ip, uint16_t port) - { - if (!WiFiClient::connect(ip, port)) - { - return 0; - } - return _connectSSL(nullptr); - } - - int ESP_Mail_WCS::connect(const char *name, uint16_t port) - { - IPAddress remote_addr; - if (!WiFi.hostByName(name, remote_addr)) - { - DEBUG_BSSL("connect: Name loopup failure\n"); - return 0; - } - if (!WiFiClient::connect(remote_addr, port)) - { - DEBUG_BSSL("connect: Unable to connect TCP socket\n"); - return 0; - } - _host_name = name; - if (!_secured) - return true; - return _connectSSL(name); - } - - int ESP_Mail_WCS::connect(const String &host, uint16_t port) - { - return connect(host.c_str(), port); - } - - void ESP_Mail_WCS::_freeSSL() - { - // These are smart pointers and will free if refcnt==0 - _sc = nullptr; - _sc_svr = nullptr; - _x509_minimal = nullptr; - _x509_insecure = nullptr; - _x509_knownkey = nullptr; - _iobuf_in = nullptr; - _iobuf_out = nullptr; - // Reset non-allocated ptrs (pointing to bits potentially free'd above) - _recvapp_buf = nullptr; - _recvapp_len = 0; - // This connection is toast - _handshake_done = false; - _timeout = 15000; - } - - bool ESP_Mail_WCS::_clientConnected() - { - return (_client && _client->state() == ESTABLISHED); - } - - uint8_t ESP_Mail_WCS::connected() - { - if (available() || (_clientConnected() && _handshake_done && (br_ssl_engine_current_state(_eng) != BR_SSL_CLOSED))) - { - return true; - } - return false; - } - - size_t ESP_Mail_WCS::_write(const uint8_t *buf, size_t size, bool pmem) - { - size_t sent_bytes = 0; - - if (!connected() || !size || !_handshake_done) - { - return 0; - } - - do - { - // Ensure we yield if we need multiple fragments to avoid WDT - if (sent_bytes) - { - optimistic_yield(1000); - } - - // Get BearSSL to a state where we can send - if (_run_until(BR_SSL_SENDAPP) < 0) - { - break; - } - - if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) - { - size_t sendapp_len; - unsigned char *sendapp_buf = br_ssl_engine_sendapp_buf(_eng, &sendapp_len); - int to_send = size > sendapp_len ? sendapp_len : size; - if (pmem) - { - memcpy_P(sendapp_buf, buf, to_send); - } - else - { - memcpy(sendapp_buf, buf, to_send); - } - br_ssl_engine_sendapp_ack(_eng, to_send); - br_ssl_engine_flush(_eng, 0); - flush(); - buf += to_send; - sent_bytes += to_send; - size -= to_send; - } - else - { - break; - } - } while (size); - - return sent_bytes; - } - - size_t ESP_Mail_WCS::write(const uint8_t *buf, size_t size) - { - return _write(buf, size, false); - } - - size_t ESP_Mail_WCS::write_P(PGM_P buf, size_t size) - { - return _write((const uint8_t *)buf, size, true); - } - - // We have to manually read and send individual chunks. - size_t ESP_Mail_WCS::write(Stream &stream) - { - size_t totalSent = 0; - size_t countRead; - size_t countSent; - - if (!connected() || !_handshake_done) - { - DEBUG_BSSL("write: Connect/handshake not completed yet\n"); - return 0; - } - - do - { - uint8_t temp[256]; // Temporary chunk size same as ClientContext - countSent = 0; - countRead = stream.readBytes(temp, sizeof(temp)); - if (countRead) - { - countSent = _write((const uint8_t *)temp, countRead, true); - totalSent += countSent; - } - yield(); // Feed the WDT - } while ((countSent == countRead) && (countSent > 0)); - return totalSent; - } - - int ESP_Mail_WCS::read(uint8_t *buf, size_t size) - { - if (!ctx_present() || !_handshake_done) - { - return -1; - } - - int avail = available(); - bool conn = connected(); - if (!avail && conn) - { - return 0; // We're still connected, but nothing to read - } - if (!avail && !conn) - { - DEBUG_BSSL("read: Not connected, none left available\n"); - return -1; - } - - if (avail) - { - // Take data from the recvapp buffer - int to_copy = _recvapp_len < size ? _recvapp_len : size; - memcpy(buf, _recvapp_buf, to_copy); - br_ssl_engine_recvapp_ack(_eng, to_copy); - _recvapp_buf = nullptr; - _recvapp_len = 0; - return to_copy; - } - - if (!conn) - { - DEBUG_BSSL("read: Not connected\n"); - return -1; - } - return 0; // If we're connected, no error but no read. - } - - int ESP_Mail_WCS::read() - { - uint8_t c; - if (1 == read(&c, 1)) - { - return c; - } - DEBUG_BSSL("read: failed\n"); - return -1; - } - - int ESP_Mail_WCS::available() - { - if (_recvapp_buf) - { - return _recvapp_len; // Anything from last call? - } - _recvapp_buf = nullptr; - _recvapp_len = 0; - if (!ctx_present() || _run_until(BR_SSL_RECVAPP, false) < 0) - { - return 0; - } - int st = br_ssl_engine_current_state(_eng); - if (st == BR_SSL_CLOSED) - { - return 0; // Nothing leftover, SSL is closed - } - if (st & BR_SSL_RECVAPP) - { - _recvapp_buf = br_ssl_engine_recvapp_buf(_eng, &_recvapp_len); - return _recvapp_len; - } - - return 0; - } - - int ESP_Mail_WCS::peek() - { - if (!ctx_present() || !available()) - { - DEBUG_BSSL("peek: Not connected, none left available\n"); - return -1; - } - if (_recvapp_buf && _recvapp_len) - { - return _recvapp_buf[0]; - } - DEBUG_BSSL("peek: No data left\n"); - return -1; - } - - size_t ESP_Mail_WCS::peekBytes(uint8_t *buffer, size_t length) - { - size_t to_copy = 0; - if (!ctx_present()) - { - DEBUG_BSSL("peekBytes: Not connected\n"); - return 0; - } - - _startMillis = millis(); - while ((available() < (int)length) && ((millis() - _startMillis) < 5000)) - { - yield(); - } - - to_copy = _recvapp_len < length ? _recvapp_len : length; - memcpy(buffer, _recvapp_buf, to_copy); - return to_copy; - } - - /* --- Copied almost verbatim from BEARSSL SSL_IO.C --- - Run the engine, until the specified target state is achieved, or - an error occurs. The target state is SENDAPP, RECVAPP, or the - combination of both (the combination matches either). When a match is - achieved, this function returns 0. On error, it returns -1. -*/ - int ESP_Mail_WCS::_run_until(unsigned target, bool blocking) - { - if (!ctx_present()) - { - DEBUG_BSSL("_run_until: Not connected\n"); - return -1; - } - - esp8266::polledTimeout::oneShotMs loopTimeout(_timeout); - - for (int no_work = 0; blocking || no_work < 2;) - { - optimistic_yield(100); - - if (loopTimeout) - { - DEBUG_BSSL("_run_until: Timeout\n"); - return -1; - } - - int state; - state = br_ssl_engine_current_state(_eng); - if (state & BR_SSL_CLOSED) - { - return -1; - } - - if (!(_client->state() == ESTABLISHED) && !WiFiClient::available()) - { - return (state & target) ? 0 : -1; - } - - /* - If there is some record data to send, do it. This takes - precedence over everything else. - */ - if (state & BR_SSL_SENDREC) - { - unsigned char *buf; - size_t len; - int wlen; - size_t availForWrite; - - buf = br_ssl_engine_sendrec_buf(_eng, &len); - availForWrite = WiFiClient::availableForWrite(); - - if (!blocking && len > availForWrite) - { - /* - writes on WiFiClient will block if len > availableForWrite() - this is needed to prevent available() calls from blocking - on dropped connections - */ - len = availForWrite; - } - wlen = WiFiClient::write(buf, len); - if (wlen <= 0) - { - /* - If we received a close_notify and we - still send something, then we have our - own response close_notify to send, and - the peer is allowed by RFC 5246 not to - wait for it. - */ - return -1; - } - if (wlen > 0) - { - br_ssl_engine_sendrec_ack(_eng, wlen); - } - no_work = 0; - continue; - } - - /* - If we reached our target, then we are finished. - */ - if (state & target) - { - return 0; - } - - /* - If some application data must be read, and we did not - exit, then this means that we are trying to write data, - and that's not possible until the application data is - read. This may happen if using a shared in/out buffer, - and the underlying protocol is not strictly half-duplex. - This is unrecoverable here, so we report an error. - */ - if (state & BR_SSL_RECVAPP) - { - DEBUG_BSSL("_run_until: Fatal protocol state\n"); - return -1; - } - - /* - If we reached that point, then either we are trying - to read data and there is some, or the engine is stuck - until a new record is obtained. - */ - if (state & BR_SSL_RECVREC) - { - if (WiFiClient::available()) - { - unsigned char *buf; - size_t len; - int rlen; - - buf = br_ssl_engine_recvrec_buf(_eng, &len); - rlen = WiFiClient::read(buf, len); - if (rlen < 0) - { - return -1; - } - if (rlen > 0) - { - br_ssl_engine_recvrec_ack(_eng, rlen); - } - no_work = 0; - continue; - } - } - - /* - We can reach that point if the target RECVAPP, and - the state contains SENDAPP only. This may happen with - a shared in/out buffer. In that case, we must flush - the buffered data to "make room" for a new incoming - record. - */ - br_ssl_engine_flush(_eng, 0); - - no_work++; // We didn't actually advance here - } - // We only get here if we ran through the loop without getting anything done - return -1; - } - - bool ESP_Mail_WCS::_wait_for_handshake() - { - _handshake_done = false; - while (!_handshake_done && _clientConnected()) - { - int ret = _run_until(BR_SSL_SENDAPP); - if (ret < 0) - { - DEBUG_BSSL("_wait_for_handshake: failed\n"); - break; - } - if (br_ssl_engine_current_state(_eng) & BR_SSL_SENDAPP) - { - _handshake_done = true; - } - optimistic_yield(1000); - } - return _handshake_done; - } - - static uint8_t htoi(unsigned char c) - { - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'A' && c <= 'F') - return 10 + c - 'A'; - else if (c >= 'a' && c <= 'f') - return 10 + c - 'a'; - else - return 255; - } - - // Set a fingerprint by parsing an ASCII string - bool ESP_Mail_WCS::setFingerprint(const char *fpStr) - { - int idx = 0; - uint8_t c, d; - uint8_t fp[20]; - - while (idx < 20) - { - c = pgm_read_byte(fpStr++); - if (!c) - break; // String ended, done processing - d = pgm_read_byte(fpStr++); - if (!d) - { - DEBUG_BSSL("setFingerprint: FP too short\n"); - return false; // Only half of the last hex digit, error - } - c = htoi(c); - d = htoi(d); - if ((c > 15) || (d > 15)) - { - DEBUG_BSSL("setFingerprint: Invalid char\n"); - return false; // Error in one of the hex characters - } - fp[idx++] = (c << 4) | d; - - // Skip 0 or more spaces or colons - while (pgm_read_byte(fpStr) && (pgm_read_byte(fpStr) == ' ' || pgm_read_byte(fpStr) == ':')) - { - fpStr++; - } - } - if ((idx != 20) || pgm_read_byte(fpStr)) - { - DEBUG_BSSL("setFingerprint: Garbage at end of fp\n"); - return false; // Garbage at EOL or we didn't have enough hex digits - } - return setFingerprint(fp); - } - - extern "C" - { - - // BearSSL doesn't define a true insecure decoder, so we make one ourselves - // from the simple parser. It generates the issuer and subject hashes and - // the SHA1 fingerprint, only one (or none!) of which will be used to - // "verify" the certificate. - - // Private x509 decoder state - struct br_x509_insecure_context - { - const br_x509_class *vtable; - bool done_cert; - const uint8_t *match_fingerprint; - br_sha1_context sha1_cert; - bool allow_self_signed; - br_sha256_context sha256_subject; - br_sha256_context sha256_issuer; - br_x509_decoder_context ctx; - }; - - // Callback for the x509_minimal subject DN - static void insecure_subject_dn_append(void *ctx, const void *buf, size_t len) - { - br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; - br_sha256_update(&xc->sha256_subject, buf, len); - } - - // Callback for the x509_minimal issuer DN - static void insecure_issuer_dn_append(void *ctx, const void *buf, size_t len) - { - br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; - br_sha256_update(&xc->sha256_issuer, buf, len); - } - - // Callback on the first byte of any certificate - static void insecure_start_chain(const br_x509_class **ctx, const char *server_name) - { - br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; - br_x509_decoder_init(&xc->ctx, insecure_subject_dn_append, xc, insecure_issuer_dn_append, xc); - xc->done_cert = false; - br_sha1_init(&xc->sha1_cert); - br_sha256_init(&xc->sha256_subject); - br_sha256_init(&xc->sha256_issuer); - (void)server_name; - } - - // Callback for each certificate present in the chain (but only operates - // on the first one by design). - static void insecure_start_cert(const br_x509_class **ctx, uint32_t length) - { - (void)ctx; - (void)length; - } - - // Callback for each byte stream in the chain. Only process first cert. - static void insecure_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) - { - br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; - // Don't process anything but the first certificate in the chain - if (!xc->done_cert) - { - br_sha1_update(&xc->sha1_cert, buf, len); - br_x509_decoder_push(&xc->ctx, (const void *)buf, len); -#ifdef DEBUG_ESP_SSL - DEBUG_BSSL("CERT: "); - for (size_t i = 0; i < len; i++) - { - DEBUG_ESP_PORT.printf_P(PSTR("%02x "), buf[i] & 0xff); - } - DEBUG_ESP_PORT.printf_P(PSTR("\n")); -#endif - } - } - - // Callback on individual cert end. - static void insecure_end_cert(const br_x509_class **ctx) - { - br_x509_insecure_context *xc = (br_x509_insecure_context *)ctx; - xc->done_cert = true; - } - - // Callback when complete chain has been parsed. - // Return 0 on validation success, !0 on validation error - static unsigned insecure_end_chain(const br_x509_class **ctx) - { - const br_x509_insecure_context *xc = (const br_x509_insecure_context *)ctx; - if (!xc->done_cert) - { - DEBUG_BSSL("insecure_end_chain: No cert seen\n"); - return 1; // error - } - - // Handle SHA1 fingerprint matching - char res[20]; - br_sha1_out(&xc->sha1_cert, res); - if (xc->match_fingerprint && memcmp(res, xc->match_fingerprint, sizeof(res))) - { -#ifdef DEBUG_ESP_SSL - DEBUG_BSSL("insecure_end_chain: Received cert FP doesn't match\n"); - char buff[3 * sizeof(res) + 1]; // 3 chars per byte XX_, and null - buff[0] = 0; - for (size_t i = 0; i < sizeof(res); i++) - { - char hex[4]; // XX_\0 - snprintf(hex, sizeof(hex), "%02x ", xc->match_fingerprint[i] & 0xff); - strlcat(buff, hex, sizeof(buff)); - } - DEBUG_BSSL("insecure_end_chain: expected %s\n", buff); - buff[0] = 0; - for (size_t i = 0; i < sizeof(res); i++) - { - char hex[4]; // XX_\0 - snprintf(hex, sizeof(hex), "%02x ", res[i] & 0xff); - strlcat(buff, hex, sizeof(buff)); - } - DEBUG_BSSL("insecure_end_chain: received %s\n", buff); -#endif - return BR_ERR_X509_NOT_TRUSTED; - } - - // Handle self-signer certificate acceptance - char res_issuer[32]; - char res_subject[32]; - br_sha256_out(&xc->sha256_issuer, res_issuer); - br_sha256_out(&xc->sha256_subject, res_subject); - if (xc->allow_self_signed && memcmp(res_subject, res_issuer, sizeof(res_issuer))) - { - DEBUG_BSSL("insecure_end_chain: Didn't get self-signed cert\n"); - return BR_ERR_X509_NOT_TRUSTED; - } - - // Default (no validation at all) or no errors in prior checks = success. - return 0; - } - - // Return the public key from the validator (set by x509_minimal) - static const br_x509_pkey *insecure_get_pkey(const br_x509_class *const *ctx, unsigned *usages) - { - const br_x509_insecure_context *xc = (const br_x509_insecure_context *)ctx; - if (usages != NULL) - { - *usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN; // I said we were insecure! - } - return &xc->ctx.pkey; - } - - // Set up the x509 insecure data structures for BearSSL core to use. - void esp_mail_br_x509_insecure_init(br_x509_insecure_context *ctx, int _use_fingerprint, const uint8_t _fingerprint[20], int _allow_self_signed) - { - static const br_x509_class br_x509_insecure_vtable PROGMEM = { - sizeof(br_x509_insecure_context), - insecure_start_chain, - insecure_start_cert, - insecure_append, - insecure_end_cert, - insecure_end_chain, - insecure_get_pkey}; - - memset(ctx, 0, sizeof *ctx); - ctx->vtable = &br_x509_insecure_vtable; - ctx->done_cert = false; - ctx->match_fingerprint = _use_fingerprint ? _fingerprint : nullptr; - ctx->allow_self_signed = _allow_self_signed ? 1 : 0; - } - - // Some constants uses to init the server/client contexts - // Note that suites_P needs to be copied to RAM before use w/BearSSL! - // List copied verbatim from BearSSL/ssl_client_full.c - /* - * The "full" profile supports all implemented cipher suites. - * - * Rationale for suite order, from most important to least - * important rule: - * - * -- Don't use 3DES if AES or ChaCha20 is available. - * -- Try to have Forward Secrecy (ECDHE suite) if possible. - * -- When not using Forward Secrecy, ECDH key exchange is - * better than RSA key exchange (slightly more expensive on the - * client, but much cheaper on the server, and it implies smaller - * messages). - * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller code). - * -- GCM is better than CCM and CBC. CCM is better than CBC. - * -- CCM is preferable over CCM_8 (with CCM_8, forgeries may succeed - * with probability 2^(-64)). - * -- AES-128 is preferred over AES-256 (AES-128 is already - * strong enough, and AES-256 is 40% more expensive). - */ - static const uint16_t suites_P[] PROGMEM = { -#ifndef BEARSSL_SSL_BASIC - BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - BR_TLS_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_RSA_WITH_AES_256_GCM_SHA384, - BR_TLS_RSA_WITH_AES_128_CCM, - BR_TLS_RSA_WITH_AES_256_CCM, - BR_TLS_RSA_WITH_AES_128_CCM_8, - BR_TLS_RSA_WITH_AES_256_CCM_8, -#endif - BR_TLS_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_RSA_WITH_AES_256_CBC_SHA256, - BR_TLS_RSA_WITH_AES_128_CBC_SHA, - BR_TLS_RSA_WITH_AES_256_CBC_SHA, -#ifndef BEARSSL_SSL_BASIC - BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, - BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, - BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA -#endif - }; -#ifndef BEARSSL_SSL_BASIC - // Server w/EC has one set, not possible with basic SSL config - static const uint16_t suites_server_ec_P[] PROGMEM = { - BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, - BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, - BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, - BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, - BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, - BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, - BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}; -#endif - - static const uint16_t suites_server_rsa_P[] PROGMEM = { -#ifndef BEARSSL_SSL_BASIC - BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, - BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - BR_TLS_RSA_WITH_AES_128_GCM_SHA256, - BR_TLS_RSA_WITH_AES_256_GCM_SHA384, - BR_TLS_RSA_WITH_AES_128_CCM, - BR_TLS_RSA_WITH_AES_256_CCM, - BR_TLS_RSA_WITH_AES_128_CCM_8, - BR_TLS_RSA_WITH_AES_256_CCM_8, -#endif - BR_TLS_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_RSA_WITH_AES_256_CBC_SHA256, - BR_TLS_RSA_WITH_AES_128_CBC_SHA, - BR_TLS_RSA_WITH_AES_256_CBC_SHA, -#ifndef BEARSSL_SSL_BASIC - BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA -#endif - }; - - // For apps which want to use less secure but faster ciphers, only - static const uint16_t faster_suites_P[] PROGMEM = { - BR_TLS_RSA_WITH_AES_256_CBC_SHA256, - BR_TLS_RSA_WITH_AES_128_CBC_SHA256, - BR_TLS_RSA_WITH_AES_256_CBC_SHA, - BR_TLS_RSA_WITH_AES_128_CBC_SHA}; - - // Install hashes into the SSL engine - static void br_ssl_client_install_hashes(br_ssl_engine_context *eng) - { - br_ssl_engine_set_hash(eng, br_md5_ID, &br_md5_vtable); - br_ssl_engine_set_hash(eng, br_sha1_ID, &br_sha1_vtable); - br_ssl_engine_set_hash(eng, br_sha224_ID, &br_sha224_vtable); - br_ssl_engine_set_hash(eng, br_sha256_ID, &br_sha256_vtable); - br_ssl_engine_set_hash(eng, br_sha384_ID, &br_sha384_vtable); - br_ssl_engine_set_hash(eng, br_sha512_ID, &br_sha512_vtable); - } - - static void br_x509_minimal_install_hashes(br_x509_minimal_context *x509) - { - br_x509_minimal_set_hash(x509, br_md5_ID, &br_md5_vtable); - br_x509_minimal_set_hash(x509, br_sha1_ID, &br_sha1_vtable); - br_x509_minimal_set_hash(x509, br_sha224_ID, &br_sha224_vtable); - br_x509_minimal_set_hash(x509, br_sha256_ID, &br_sha256_vtable); - br_x509_minimal_set_hash(x509, br_sha384_ID, &br_sha384_vtable); - br_x509_minimal_set_hash(x509, br_sha512_ID, &br_sha512_vtable); - } - - // Default initializion for our SSL clients - static void br_ssl_client_base_init(br_ssl_client_context *cc, const uint16_t *cipher_list, int cipher_cnt) - { - uint16_t suites[cipher_cnt]; - memcpy_P(suites, cipher_list, cipher_cnt * sizeof(cipher_list[0])); - br_ssl_client_zero(cc); - br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION); // forbid SSL renegociation, as we free the Private Key after handshake - br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); - br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0])); - br_ssl_client_set_default_rsapub(cc); - br_ssl_engine_set_default_rsavrfy(&cc->eng); -#ifndef BEARSSL_SSL_BASIC - br_ssl_engine_set_default_ecdsa(&cc->eng); -#endif - br_ssl_client_install_hashes(&cc->eng); - br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); - br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); - br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); - br_ssl_engine_set_default_aes_cbc(&cc->eng); -#ifndef BEARSSL_SSL_BASIC - br_ssl_engine_set_default_aes_gcm(&cc->eng); - br_ssl_engine_set_default_aes_ccm(&cc->eng); - br_ssl_engine_set_default_des_cbc(&cc->eng); - br_ssl_engine_set_default_chapol(&cc->eng); -#endif - } - - // Default initializion for our SSL clients - static void br_ssl_server_base_init(br_ssl_server_context *cc, const uint16_t *cipher_list, int cipher_cnt) - { - uint16_t suites[cipher_cnt]; - memcpy_P(suites, cipher_list, cipher_cnt * sizeof(cipher_list[0])); - br_ssl_server_zero(cc); - br_ssl_engine_add_flags(&cc->eng, BR_OPT_NO_RENEGOTIATION); // forbid SSL renegociation, as we free the Private Key after handshake - br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12); - br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0])); -#ifndef BEARSSL_SSL_BASIC - br_ssl_engine_set_default_ec(&cc->eng); -#endif - - br_ssl_client_install_hashes(&cc->eng); - br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf); - br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf); - br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf); - br_ssl_engine_set_default_aes_cbc(&cc->eng); -#ifndef BEARSSL_SSL_BASIC - br_ssl_engine_set_default_aes_ccm(&cc->eng); - br_ssl_engine_set_default_aes_gcm(&cc->eng); - br_ssl_engine_set_default_des_cbc(&cc->eng); - br_ssl_engine_set_default_chapol(&cc->eng); -#endif - } - } - - // Set custom list of ciphers - bool ESP_Mail_WCS::setCiphers(const uint16_t *cipherAry, int cipherCount) - { - _cipher_list = nullptr; - _cipher_list = std::shared_ptr(new uint16_t[cipherCount], std::default_delete()); - if (!_cipher_list.get()) - { - DEBUG_BSSL("setCiphers: list empty\n"); - return false; - } - memcpy_P(_cipher_list.get(), cipherAry, cipherCount * sizeof(uint16_t)); - _cipher_cnt = cipherCount; - return true; - } - - bool ESP_Mail_WCS::setCiphersLessSecure() - { - return setCiphers(faster_suites_P, sizeof(faster_suites_P) / sizeof(faster_suites_P[0])); - } - - bool ESP_Mail_WCS::setCiphers(std::vector list) - { - return setCiphers(&list[0], list.size()); - } - - // Installs the appropriate X509 cert validation method for a client connection - bool ESP_Mail_WCS::_installClientX509Validator() - { - if (_use_insecure || _use_fingerprint || _use_self_signed) - { - // Use common insecure x509 authenticator - _x509_insecure = std::make_shared(); - if (!_x509_insecure) - { - DEBUG_BSSL("_installClientX509Validator: OOM for _x509_insecure\n"); - return false; - } - esp_mail_br_x509_insecure_init(_x509_insecure.get(), _use_fingerprint, _fingerprint, _use_self_signed); - br_ssl_engine_set_x509(_eng, &_x509_insecure->vtable); - } - else if (_knownkey) - { - // Simple, pre-known public key authenticator, ignores cert completely. - _x509_knownkey = std::make_shared(); - if (!_x509_knownkey) - { - DEBUG_BSSL("_installClientX509Validator: OOM for _x509_knownkey\n"); - return false; - } - if (_knownkey->isRSA()) - { - br_x509_knownkey_init_rsa(_x509_knownkey.get(), _knownkey->getRSA(), _knownkey_usages); - } - else if (_knownkey->isEC()) - { -#ifndef BEARSSL_SSL_BASIC - br_x509_knownkey_init_ec(_x509_knownkey.get(), _knownkey->getEC(), _knownkey_usages); -#else - (void)_knownkey; - (void)_knownkey_usages; - DEBUG_BSSL("_installClientX509Validator: Attempting to use EC keys in minimal cipher mode (no EC)\n"); - return false; -#endif - } - br_ssl_engine_set_x509(_eng, &_x509_knownkey->vtable); - } - else - { - // X509 minimal validator. Checks dates, cert chain for trusted CA, etc. - _x509_minimal = std::make_shared(); - if (!_x509_minimal) - { - DEBUG_BSSL("_installClientX509Validator: OOM for _x509_minimal\n"); - return false; - } - br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _ta ? _ta->getTrustAnchors() : nullptr, _ta ? _ta->getCount() : 0); - br_x509_minimal_set_rsa(_x509_minimal.get(), br_ssl_engine_get_rsavrfy(_eng)); -#ifndef BEARSSL_SSL_BASIC - br_x509_minimal_set_ecdsa(_x509_minimal.get(), br_ssl_engine_get_ec(_eng), br_ssl_engine_get_ecdsa(_eng)); -#endif - br_x509_minimal_install_hashes(_x509_minimal.get()); - if (_now) - { - // Magic constants convert to x509 times - br_x509_minimal_set_time(_x509_minimal.get(), ((uint32_t)_now) / 86400 + 719528, ((uint32_t)_now) % 86400); - } - if (_certStore) - { - _certStore->installCertStore(_x509_minimal.get()); - } - br_ssl_engine_set_x509(_eng, &_x509_minimal->vtable); - } - return true; - } - - // Called by connect() to do the actual SSL setup and handshake. - // Returns if the SSL handshake succeeded. - bool ESP_Mail_WCS::_connectSSL(const char *hostName) - { - DEBUG_BSSL("_connectSSL: start connection\n"); - _freeSSL(); - _oom_err = false; - -#ifdef DEBUG_ESP_SSL - // BearSSL will reject all connections unless an authentication option is set, warn in DEBUG builds - if (!_use_insecure && !_use_fingerprint && !_use_self_signed && !_knownkey && !_certStore && !_ta) - { - DEBUG_BSSL("Connection *will* fail, no authentication method is setup\n"); - } -#endif - - _sc = std::make_shared(); - _eng = &_sc->eng; // Allocation/deallocation taken care of by the _sc shared_ptr - _iobuf_in = std::shared_ptr(new unsigned char[_iobuf_in_size], std::default_delete()); - _iobuf_out = std::shared_ptr(new unsigned char[_iobuf_out_size], std::default_delete()); - - if (!_sc || !_iobuf_in || !_iobuf_out) - { - _freeSSL(); // Frees _sc, _iobuf* - _oom_err = true; - DEBUG_BSSL("_connectSSL: OOM error\n"); - return false; - } - - // If no cipher list yet set, use defaults - if (_cipher_list.get() == nullptr) - { - br_ssl_client_base_init(_sc.get(), suites_P, sizeof(suites_P) / sizeof(suites_P[0])); - } - else - { - br_ssl_client_base_init(_sc.get(), _cipher_list.get(), _cipher_cnt); - } - // Only failure possible in the installation is OOM - if (!_installClientX509Validator()) - { - _freeSSL(); - _oom_err = true; - DEBUG_BSSL("_connectSSL: Can't install x509 validator\n"); - return false; - } - br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size); - - // Apply any client certificates, if supplied. - if (_sk && _sk->isRSA()) - { - br_ssl_client_set_single_rsa(_sc.get(), _chain ? _chain->getX509Certs() : nullptr, _chain ? _chain->getCount() : 0, - _sk->getRSA(), br_rsa_pkcs1_sign_get_default()); - } - else if (_sk && _sk->isEC()) - { -#ifndef BEARSSL_SSL_BASIC - br_ssl_client_set_single_ec(_sc.get(), _chain ? _chain->getX509Certs() : nullptr, _chain ? _chain->getCount() : 0, - _sk->getEC(), _allowed_usages, - _cert_issuer_key_type, br_ec_get_default(), br_ecdsa_sign_asn1_get_default()); -#else - _freeSSL(); - DEBUG_BSSL("_connectSSL: Attempting to use EC cert in minimal cipher mode (no EC)\n"); - return false; -#endif - } - - // Restore session from the storage spot, if present - if (_session) - { - br_ssl_engine_set_session_parameters(_eng, _session->getSession()); - } - - if (!br_ssl_client_reset(_sc.get(), hostName, _session ? 1 : 0)) - { - _freeSSL(); - DEBUG_BSSL("_connectSSL: Can't reset client\n"); - return false; - } - - auto ret = _wait_for_handshake(); -#ifdef DEBUG_ESP_SSL - if (!ret) - { - char err[256]; - getLastSSLError(err, sizeof(err)); - DEBUG_BSSL("Couldn't connect. Error = '%s'\n", err); - } - else - { - DEBUG_BSSL("Connected!\n"); - } -#endif - - // Session is already validated here, there is no need to keep following - _x509_minimal = nullptr; - _x509_insecure = nullptr; - _x509_knownkey = nullptr; - - // reduce timeout after successful handshake to fail fast if server stop accepting our data for whathever reason - if (ret) - _timeout = 5000; - - return ret; - } - - // Slightly different X509 setup for servers who want to validate client - // certificates, so factor it out as it's used in RSA and EC servers. - bool ESP_Mail_WCS::_installServerX509Validator(const ESP_Mail_X509List *client_CA_ta) - { - if (client_CA_ta) - { - _ta = client_CA_ta; - // X509 minimal validator. Checks dates, cert chain for trusted CA, etc. - _x509_minimal = std::make_shared(); - if (!_x509_minimal) - { - _freeSSL(); - _oom_err = true; - DEBUG_BSSL("_installServerX509Validator: OOM for _x509_minimal\n"); - return false; - } - br_x509_minimal_init(_x509_minimal.get(), &br_sha256_vtable, _ta->getTrustAnchors(), _ta->getCount()); - br_ssl_engine_set_default_rsavrfy(_eng); -#ifndef BEARSSL_SSL_BASIC - br_ssl_engine_set_default_ecdsa(_eng); -#endif - br_x509_minimal_set_rsa(_x509_minimal.get(), br_ssl_engine_get_rsavrfy(_eng)); -#ifndef BEARSSL_SSL_BASIC - br_x509_minimal_set_ecdsa(_x509_minimal.get(), br_ssl_engine_get_ec(_eng), br_ssl_engine_get_ecdsa(_eng)); -#endif - br_x509_minimal_install_hashes(_x509_minimal.get()); - if (_now) - { - // Magic constants convert to x509 times - br_x509_minimal_set_time(_x509_minimal.get(), ((uint32_t)_now) / 86400 + 719528, ((uint32_t)_now) % 86400); - } - br_ssl_engine_set_x509(_eng, &_x509_minimal->vtable); - br_ssl_server_set_trust_anchor_names_alt(_sc_svr.get(), _ta->getTrustAnchors(), _ta->getCount()); - } - return true; - } - - // Called by WiFiServerBearSSL when an RSA cert/key is specified. - bool ESP_Mail_WCS::_connectSSLServerRSA(const ESP_Mail_X509List *chain, - const PrivateKey *sk, - const ESP_Mail_X509List *client_CA_ta) - { - _freeSSL(); - _oom_err = false; - _sc_svr = std::make_shared(); - _eng = &_sc_svr->eng; // Allocation/deallocation taken care of by the _sc shared_ptr - _iobuf_in = std::shared_ptr(new unsigned char[_iobuf_in_size], std::default_delete()); - _iobuf_out = std::shared_ptr(new unsigned char[_iobuf_out_size], std::default_delete()); - - if (!_sc_svr || !_iobuf_in || !_iobuf_out) - { - _freeSSL(); - _oom_err = true; - DEBUG_BSSL("_connectSSLServerRSA: OOM error\n"); - return false; - } - - br_ssl_server_base_init(_sc_svr.get(), suites_server_rsa_P, sizeof(suites_server_rsa_P) / sizeof(suites_server_rsa_P[0])); - br_ssl_server_set_single_rsa(_sc_svr.get(), chain ? chain->getX509Certs() : nullptr, chain ? chain->getCount() : 0, - sk ? sk->getRSA() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, - br_rsa_private_get_default(), br_rsa_pkcs1_sign_get_default()); - br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size); - if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) - { - DEBUG_BSSL("_connectSSLServerRSA: Can't install serverX509check\n"); - return false; - } - if (!br_ssl_server_reset(_sc_svr.get())) - { - _freeSSL(); - DEBUG_BSSL("_connectSSLServerRSA: Can't reset server ctx\n"); - return false; - } - - return _wait_for_handshake(); - } - - // Called by WiFiServerBearSSL when an elliptic curve cert/key is specified. - bool ESP_Mail_WCS::_connectSSLServerEC(const ESP_Mail_X509List *chain, - unsigned cert_issuer_key_type, const PrivateKey *sk, - const ESP_Mail_X509List *client_CA_ta) - { -#ifndef BEARSSL_SSL_BASIC - _freeSSL(); - _oom_err = false; - _sc_svr = std::make_shared(); - _eng = &_sc_svr->eng; // Allocation/deallocation taken care of by the _sc shared_ptr - _iobuf_in = std::shared_ptr(new unsigned char[_iobuf_in_size], std::default_delete()); - _iobuf_out = std::shared_ptr(new unsigned char[_iobuf_out_size], std::default_delete()); - - if (!_sc_svr || !_iobuf_in || !_iobuf_out) - { - _freeSSL(); - _oom_err = true; - DEBUG_BSSL("_connectSSLServerEC: OOM error\n"); - return false; - } - - br_ssl_server_base_init(_sc_svr.get(), suites_server_ec_P, sizeof(suites_server_ec_P) / sizeof(suites_server_ec_P[0])); - br_ssl_server_set_single_ec(_sc_svr.get(), chain ? chain->getX509Certs() : nullptr, chain ? chain->getCount() : 0, - sk ? sk->getEC() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, - cert_issuer_key_type, br_ssl_engine_get_ec(_eng), br_ecdsa_i15_sign_asn1); - br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size); - if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) - { - DEBUG_BSSL("_connectSSLServerEC: Can't install serverX509check\n"); - return false; - } - if (!br_ssl_server_reset(_sc_svr.get())) - { - _freeSSL(); - DEBUG_BSSL("_connectSSLServerEC: Can't reset server ctx\n"); - return false; - } - - return _wait_for_handshake(); -#else - (void)chain; - (void)cert_issuer_key_type; - (void)sk; - (void)client_CA_ta; - DEBUG_BSSL("_connectSSLServerEC: Attempting to use EC cert in minimal cipher mode (no EC)\n"); - return false; -#endif - } - - // Returns an error ID and possibly a string (if dest != null) of the last - // BearSSL reported error. - int ESP_Mail_WCS::getLastSSLError(char *dest, size_t len) - { - int err = 0; - const char *t = PSTR("OK"); - if (_sc || _sc_svr) - { - err = br_ssl_engine_last_error(_eng); - } - if (_oom_err) - { - err = -1000; - } - switch (err) - { - case -1000: - t = PSTR("Unable to allocate memory for SSL structures and buffers."); - break; - case BR_ERR_BAD_PARAM: - t = PSTR("Caller-provided parameter is incorrect."); - break; - case BR_ERR_BAD_STATE: - t = PSTR("Operation requested by the caller cannot be applied with the current context state (e.g. reading data while outgoing data is waiting to be sent)."); - break; - case BR_ERR_UNSUPPORTED_VERSION: - t = PSTR("Incoming protocol or record version is unsupported."); - break; - case BR_ERR_BAD_VERSION: - t = PSTR("Incoming record version does not match the expected version."); - break; - case BR_ERR_BAD_LENGTH: - t = PSTR("Incoming record length is invalid."); - break; - case BR_ERR_TOO_LARGE: - t = PSTR("Incoming record is too large to be processed, or buffer is too small for the handshake message to send."); - break; - case BR_ERR_BAD_MAC: - t = PSTR("Decryption found an invalid padding, or the record MAC is not correct."); - break; - case BR_ERR_NO_RANDOM: - t = PSTR("No initial entropy was provided, and none can be obtained from the OS."); - break; - case BR_ERR_UNKNOWN_TYPE: - t = PSTR("Incoming record type is unknown."); - break; - case BR_ERR_UNEXPECTED: - t = PSTR("Incoming record or message has wrong type with regards to the current engine state."); - break; - case BR_ERR_BAD_CCS: - t = PSTR("ChangeCipherSpec message from the peer has invalid contents."); - break; - case BR_ERR_BAD_ALERT: - t = PSTR("Alert message from the peer has invalid contents (odd length)."); - break; - case BR_ERR_BAD_HANDSHAKE: - t = PSTR("Incoming handshake message decoding failed."); - break; - case BR_ERR_OVERSIZED_ID: - t = PSTR("ServerHello contains a session ID which is larger than 32 bytes."); - break; - case BR_ERR_BAD_CIPHER_SUITE: - t = PSTR("Server wants to use a cipher suite that we did not claim to support. This is also reported if we tried to advertise a cipher suite that we do not support."); - break; - case BR_ERR_BAD_COMPRESSION: - t = PSTR("Server wants to use a compression that we did not claim to support."); - break; - case BR_ERR_BAD_FRAGLEN: - t = PSTR("Server's max fragment length does not match client's."); - break; - case BR_ERR_BAD_SECRENEG: - t = PSTR("Secure renegotiation failed."); - break; - case BR_ERR_EXTRA_EXTENSION: - t = PSTR("Server sent an extension type that we did not announce, or used the same extension type several times in a single ServerHello."); - break; - case BR_ERR_BAD_SNI: - t = PSTR("Invalid Server Name Indication contents (when used by the server, this extension shall be empty)."); - break; - case BR_ERR_BAD_HELLO_DONE: - t = PSTR("Invalid ServerHelloDone from the server (length is not 0)."); - break; - case BR_ERR_LIMIT_EXCEEDED: - t = PSTR("Internal limit exceeded (e.g. server's public key is too large)."); - break; - case BR_ERR_BAD_FINISHED: - t = PSTR("Finished message from peer does not match the expected value."); - break; - case BR_ERR_RESUME_MISMATCH: - t = PSTR("Session resumption attempt with distinct version or cipher suite."); - break; - case BR_ERR_INVALID_ALGORITHM: - t = PSTR("Unsupported or invalid algorithm (ECDHE curve, signature algorithm, hash function)."); - break; - case BR_ERR_BAD_SIGNATURE: - t = PSTR("Invalid signature in ServerKeyExchange or CertificateVerify message."); - break; - case BR_ERR_WRONG_KEY_USAGE: - t = PSTR("Peer's public key does not have the proper type or is not allowed for the requested operation."); - break; - case BR_ERR_NO_CLIENT_AUTH: - t = PSTR("Client did not send a certificate upon request, or the client certificate could not be validated."); - break; - case BR_ERR_IO: - t = PSTR("I/O error or premature close on transport stream."); - break; - case BR_ERR_X509_INVALID_VALUE: - t = PSTR("Invalid value in an ASN.1 structure."); - break; - case BR_ERR_X509_TRUNCATED: - t = PSTR("Truncated certificate or other ASN.1 object."); - break; - case BR_ERR_X509_EMPTY_CHAIN: - t = PSTR("Empty certificate chain (no certificate at all)."); - break; - case BR_ERR_X509_INNER_TRUNC: - t = PSTR("Decoding error: inner element extends beyond outer element size."); - break; - case BR_ERR_X509_BAD_TAG_CLASS: - t = PSTR("Decoding error: unsupported tag class (application or private)."); - break; - case BR_ERR_X509_BAD_TAG_VALUE: - t = PSTR("Decoding error: unsupported tag value."); - break; - case BR_ERR_X509_INDEFINITE_LENGTH: - t = PSTR("Decoding error: indefinite length."); - break; - case BR_ERR_X509_EXTRA_ELEMENT: - t = PSTR("Decoding error: extraneous element."); - break; - case BR_ERR_X509_UNEXPECTED: - t = PSTR("Decoding error: unexpected element."); - break; - case BR_ERR_X509_NOT_CONSTRUCTED: - t = PSTR("Decoding error: expected constructed element, but is primitive."); - break; - case BR_ERR_X509_NOT_PRIMITIVE: - t = PSTR("Decoding error: expected primitive element, but is constructed."); - break; - case BR_ERR_X509_PARTIAL_BYTE: - t = PSTR("Decoding error: BIT STRING length is not multiple of 8."); - break; - case BR_ERR_X509_BAD_BOOLEAN: - t = PSTR("Decoding error: BOOLEAN value has invalid length."); - break; - case BR_ERR_X509_OVERFLOW: - t = PSTR("Decoding error: value is off-limits."); - break; - case BR_ERR_X509_BAD_DN: - t = PSTR("Invalid distinguished name."); - break; - case BR_ERR_X509_BAD_TIME: - t = PSTR("Invalid date/time representation."); - break; - case BR_ERR_X509_UNSUPPORTED: - t = PSTR("Certificate contains unsupported features that cannot be ignored."); - break; - case BR_ERR_X509_LIMIT_EXCEEDED: - t = PSTR("Key or signature size exceeds internal limits."); - break; - case BR_ERR_X509_WRONG_KEY_TYPE: - t = PSTR("Key type does not match that which was expected."); - break; - case BR_ERR_X509_BAD_SIGNATURE: - t = PSTR("Signature is invalid."); - break; - case BR_ERR_X509_TIME_UNKNOWN: - t = PSTR("Validation time is unknown."); - break; - case BR_ERR_X509_EXPIRED: - t = PSTR("Certificate is expired or not yet valid."); - break; - case BR_ERR_X509_DN_MISMATCH: - t = PSTR("Issuer/Subject DN mismatch in the chain."); - break; - case BR_ERR_X509_BAD_SERVER_NAME: - t = PSTR("Expected server name was not found in the chain."); - break; - case BR_ERR_X509_CRITICAL_EXTENSION: - t = PSTR("Unknown critical extension in certificate."); - break; - case BR_ERR_X509_NOT_CA: - t = PSTR("Not a CA, or path length constraint violation."); - break; - case BR_ERR_X509_FORBIDDEN_KEY_USAGE: - t = PSTR("Key Usage extension prohibits intended usage."); - break; - case BR_ERR_X509_WEAK_PUBLIC_KEY: - t = PSTR("Public key found in certificate is too small."); - break; - case BR_ERR_X509_NOT_TRUSTED: - t = PSTR("Chain could not be linked to a trust anchor."); - break; - default: - t = PSTR("Unknown error code."); - break; - } - if (dest) - { - strncpy_P(dest, t, len); - dest[len - 1] = 0; - } - return err; - } - - bool ESP_Mail_WCS::probeMaxFragmentLength(const char *name, uint16_t port, uint16_t len) - { - IPAddress remote_addr; - if (!WiFi.hostByName(name, remote_addr)) - { - DEBUG_BSSL("probeMaxFragmentLength: Can't resolve host\n"); - return false; - } - return ESP_Mail_WCS::probeMaxFragmentLength(remote_addr, port, len); - } - - bool ESP_Mail_WCS::probeMaxFragmentLength(const String &host, uint16_t port, uint16_t len) - { - return ESP_Mail_WCS::probeMaxFragmentLength(host.c_str(), port, len); - } - - // Helper function which aborts a TLS handshake by sending TLS - // ClientAbort and ClientClose messages. - static bool _SendAbort(WiFiClient &probe, bool supportsLen) - { - // If we're still connected, send the appropriate notice that - // we're aborting the handshake per RFCs. - static const uint8_t clientAbort_P[] PROGMEM = { - 0x15 /*alert*/, 0x03, 0x03 /*TLS 1.2*/, 0x00, 0x02, - 1, 90 /* warning: user_cancelled */ - }; - static const uint8_t clientClose_P[] PROGMEM = { - 0x15 /*alert*/, 0x03, 0x03 /*TLS 1.2*/, 0x00, 0x02, - 1, 0 /* warning: close_notify */ - }; - if (probe.connected()) - { - uint8_t msg[sizeof(clientAbort_P)]; - memcpy_P(msg, clientAbort_P, sizeof(clientAbort_P)); - probe.write(msg, sizeof(clientAbort_P)); - memcpy_P(msg, clientClose_P, sizeof(clientClose_P)); - probe.write(msg, sizeof(clientClose_P)); - } - return supportsLen; - } - - // Checks for support of Maximum Frame Length Negotiation at the given - // blocksize. Note that, per spec, only 512, 1024, 2048, and 4096 are - // supported. Many servers today do not support this negotiation. - - // TODO - Allow for fragmentation...but not very critical as the ServerHello - // we use comes to < 80 bytes which has no reason to ever be fragmented. - // TODO - Check the type of returned extensions and that the MFL is the exact - // same one we sent. Not critical as only horribly broken servers would - // return changed or add their own extensions. - bool ESP_Mail_WCS::probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len) - { - // Hardcoded TLS 1.2 packets used throughout - static const uint8_t clientHelloHead_P[] PROGMEM = { - 0x16, 0x03, 0x03, 0x00, 0, // TLS header, change last 2 bytes to len - 0x01, 0x00, 0x00, 0, // Last 3 bytes == length - 0x03, 0x03, // Proto version TLS 1.2 - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // Random (gmtime + rand[28]) - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x00, // Session ID - }; - // Followed by our cipher-suite, generated on-the-fly - // 0x00, 0x02, // cipher suite len - // 0xc0, 0x13, // BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - static const uint8_t clientHelloTail_P[] PROGMEM = { - 0x01, 0x00, // No compression - 0x00, 26 + 14 + 6 + 5, // Extension length - 0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x04, 0x03, 0x03, 0x03, 0x05, 0x03, - 0x06, 0x03, 0x02, 0x03, 0x04, 0x01, 0x03, 0x01, 0x05, 0x01, 0x06, - 0x01, 0x02, 0x01, // Supported signature algorithms - 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19, - 0x00, 0x1d, // Supported groups - 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, // Supported EC formats - 0x00, 0x01, // Max Frag Len - 0x00, 0x01, // len of MaxFragLen - }; - // Followed by a 1-byte MFLN size requesst - // 0x04 // 2^12 = 4K - uint8_t mfl; - - switch (len) - { - case 512: - mfl = 1; - break; - case 1024: - mfl = 2; - break; - case 2048: - mfl = 3; - break; - case 4096: - mfl = 4; - break; - default: - return false; // Invalid size - } - int ttlLen = sizeof(clientHelloHead_P) + (2 + sizeof(suites_P)) + (sizeof(clientHelloTail_P) + 1); - uint8_t *clientHello = new uint8_t[ttlLen]; - if (!clientHello) - { - DEBUG_BSSL("probeMaxFragmentLength: OOM\n"); - return false; - } - memcpy_P(clientHello, clientHelloHead_P, sizeof(clientHelloHead_P)); - clientHello[sizeof(clientHelloHead_P) + 0] = sizeof(suites_P) >> 8; // MSB byte len - clientHello[sizeof(clientHelloHead_P) + 1] = sizeof(suites_P) & 0xff; // LSB byte len - for (size_t i = 0; i < sizeof(suites_P) / sizeof(suites_P[0]); i++) - { - uint16_t flip = pgm_read_word(&suites_P[i]); - // Swap to network byte order - flip = ((flip >> 8) & 0xff) | ((flip & 0xff) << 8); - memcpy(clientHello + sizeof(clientHelloHead_P) + 2 + 2 * i, &flip, 2); - } - memcpy_P(clientHello + sizeof(clientHelloHead_P) + 2 + sizeof(suites_P), clientHelloTail_P, sizeof(clientHelloTail_P)); - clientHello[sizeof(clientHelloHead_P) + 2 + sizeof(suites_P) + sizeof(clientHelloTail_P)] = mfl; - - // Fix up TLS fragment length - clientHello[3] = (ttlLen - 5) >> 8; - clientHello[4] = (ttlLen - 5) & 0xff; - // Fix up ClientHello message length - clientHello[7] = (ttlLen - 5 - 4) >> 8; - clientHello[8] = (ttlLen - 5 - 4) & 0xff; - - WiFiClient probe; - probe.connect(ip, port); - if (!probe.connected()) - { - delete[] clientHello; - DEBUG_BSSL("probeMaxFragmentLength: Can't connect\n"); - return false; - } - - int ret = probe.write(clientHello, ttlLen); - delete[] clientHello; // We're done w/the hello message - if (!probe.connected() || (ret != ttlLen)) - { - DEBUG_BSSL("probeMaxFragmentLength: Protocol error\n"); - return false; - } - - bool supportsLen = false; - uint8_t fragResp[5]; - int fragLen; - uint8_t hand[4]; - int handLen; - uint8_t protoVer[2]; - uint8_t rand[32]; - uint8_t sessionLen; - uint8_t cipher[2]; - uint8_t comp; - uint8_t extBytes[2]; - uint16_t extLen; - - ret = probe.readBytes(fragResp, 5); - if (!probe.connected() || (ret != 5) || (fragResp[0] != 0x16) || (fragResp[1] != 0x03) || (fragResp[2] != 0x03)) - { - // Short read, not a HANDSHAKE or not TLS 1.2, so it's not supported - return _SendAbort(probe, supportsLen); - } - fragLen = (fragResp[3] << 8) | fragResp[4]; - if (fragLen < 4 + 2 + 32 + 1 + 2 + 1) - { - // Too short to have an extension - return _SendAbort(probe, supportsLen); - } - - ret = probe.readBytes(hand, 4); - fragLen -= ret; - if ((ret != 4) || (hand[0] != 2)) - { - // Short read or not server_hello - return _SendAbort(probe, supportsLen); - } - handLen = (hand[1] << 16) | (hand[2] << 8) | hand[3]; - if (handLen != fragLen) - { - // Got some weird mismatch, this is invalid - return _SendAbort(probe, supportsLen); - } - - ret = probe.readBytes(protoVer, 2); - handLen -= ret; - if ((ret != 2) || (protoVer[0] != 0x03) || (protoVer[1] != 0x03)) - { - // Short read or not tls 1.2, so can't do MFLN - return _SendAbort(probe, supportsLen); - } - - ret = probe.readBytes(rand, 32); - handLen -= ret; - if (ret != 32) - { - // short read of random data - return _SendAbort(probe, supportsLen); - } - - ret = probe.readBytes(&sessionLen, 1); - handLen -= ret; - if ((ret != 1) || (sessionLen > 32)) - { - // short read of session len or invalid size - return _SendAbort(probe, supportsLen); - } - if (sessionLen) - { - ret = probe.readBytes(rand, sessionLen); - handLen -= ret; - if (ret != sessionLen) - { - // short session id read - return _SendAbort(probe, supportsLen); - } - } - - ret = probe.readBytes(cipher, 2); - handLen -= ret; - if (ret != 2) - { - // Short read...we don't check the cipher here - return _SendAbort(probe, supportsLen); - } - - ret = probe.readBytes(&comp, 1); - handLen -= ret; - if ((ret != 1) || comp != 0) - { - // short read or invalid compression - return _SendAbort(probe, supportsLen); - } - - ret = probe.readBytes(extBytes, 2); - handLen -= ret; - extLen = extBytes[1] | (extBytes[0] << 8); - if ((extLen == 0) || (ret != 2)) - { - return _SendAbort(probe, supportsLen); - } - - while (handLen > 0) - { - // Parse each extension and look for MFLN - uint8_t typeBytes[2]; - ret = probe.readBytes(typeBytes, 2); - handLen -= 2; - if ((ret != 2) || (handLen <= 0)) - { - return _SendAbort(probe, supportsLen); - } - uint8_t lenBytes[2]; - ret = probe.readBytes(lenBytes, 2); - handLen -= 2; - uint16_t extLen = lenBytes[1] | (lenBytes[0] << 8); - if ((ret != 2) || (handLen <= 0) || (extLen > 32) || (extLen > handLen)) - { - return _SendAbort(probe, supportsLen); - } - if ((typeBytes[0] == 0x00) && (typeBytes[1] == 0x01)) - { // MFLN extension! - // If present and 1-byte in length, it's supported - return _SendAbort(probe, extLen == 1 ? true : false); - } - // Skip the extension, move to next one - uint8_t junk[32]; - ret = probe.readBytes(junk, extLen); - handLen -= extLen; - if (ret != extLen) - { - return _SendAbort(probe, supportsLen); - } - } - return _SendAbort(probe, supportsLen); - } - - // AXTLS compatibility interfaces - bool ESP_Mail_WCS::setCACert(const uint8_t *pk, size_t size) - { - _axtls_ta = nullptr; - _axtls_ta = std::shared_ptr(new ESP_Mail_X509List(pk, size)); - _ta = _axtls_ta.get(); - return _ta ? true : false; - } - - bool ESP_Mail_WCS::setCertificate(const uint8_t *pk, size_t size) - { - _axtls_chain = nullptr; - _axtls_chain = std::shared_ptr(new ESP_Mail_X509List(pk, size)); - _chain = _axtls_chain.get(); - return _chain ? true : false; - } - - bool ESP_Mail_WCS::setPrivateKey(const uint8_t *pk, size_t size) - { - _axtls_sk = nullptr; - _axtls_sk = std::shared_ptr(new PrivateKey(pk, size)); - _sk = _axtls_sk.get(); - return _sk ? true : false; - } - - uint8_t *ESP_Mail_WCS::_streamLoad(Stream &stream, size_t size) - { - uint8_t *dest = (uint8_t *)malloc(size); - if (!dest) - { - return nullptr; - } - if (size != stream.readBytes(dest, size)) - { - free(dest); - return nullptr; - } - return dest; - } - - bool ESP_Mail_WCS::loadCACert(Stream &stream, size_t size) - { - uint8_t *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - ret = setCACert(dest, size); -#pragma GCC diagnostic pop - } - free(dest); - return ret; - } - - bool ESP_Mail_WCS::loadCertificate(Stream &stream, size_t size) - { - uint8_t *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - ret = setCertificate(dest, size); -#pragma GCC diagnostic pop - } - free(dest); - return ret; - } - - bool ESP_Mail_WCS::loadPrivateKey(Stream &stream, size_t size) - { - uint8_t *dest = _streamLoad(stream, size); - bool ret = false; - if (dest) - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - ret = setPrivateKey(dest, size); -#pragma GCC diagnostic pop - } - free(dest); - return ret; - } - - void ESP_Mail_WCS::setStartTLS(bool enable) - { - _secured = !enable; - } - - size_t ESP_Mail_WCS::_ns_write(uint8_t b) - { - return write(&b, 1); - } - - size_t ESP_Mail_WCS::_ns_write(const uint8_t *buf, size_t size) - { - if (!_client || !size) - { - return 0; - } - _client->setTimeout(_timeout); -#if defined(ESP8266_CORE_SDK_V3_X_X) - return _client->write((const char *)buf, size); -#else - return _client->write(buf, size); -#endif - } - - size_t ESP_Mail_WCS::_ns_write(Stream &stream, size_t unused) - { - (void)unused; - return WiFiClient::write(stream); - } - - size_t ESP_Mail_WCS::_ns_write(Stream &stream) - { - if (!_client || !stream.available()) - { - return 0; - } - _client->setTimeout(_timeout); -#if defined(ESP8266_CORE_SDK_V3_X_X) - size_t dl = stream.available(); - uint8_t buf[dl]; - stream.readBytes(buf, dl); - return _client->write((const char *)buf, dl); -#else - return _client->write(stream); -#endif - } - - size_t ESP_Mail_WCS::_ns_write_P(PGM_P buf, size_t size) - { - - if (!_client || !size) - { - return 0; - } - _client->setTimeout(_timeout); - -#if defined(ESP8266_CORE_SDK_V3_X_X) - char dest[size]; - memcpy_P((void *)dest, (PGM_VOID_P)buf, size); - return _client->write((const char *)dest, size); -#else - return _client->write_P(buf, size); -#endif - } - - int ESP_Mail_WCS::_ns_available() - { - if (!_client) - return false; - - int result = _client->getSize(); - - if (!result) - { - optimistic_yield(100); - } - return result; - } - - int ESP_Mail_WCS::_ns_read() - { - if (!_ns_available()) - return -1; - - return _client->read(); - } - - int ESP_Mail_WCS::_ns_read(uint8_t *buf, size_t size) - { - return (int)_client->read(reinterpret_cast(buf), size); - } - - int ESP_Mail_WCS::_ns_peek() - { - if (!_ns_available()) - return -1; - - return _client->peek(); - } - - size_t ESP_Mail_WCS::_ns_peekBytes(uint8_t *buffer, size_t length) - { - size_t count = 0; - - if (!_client) - { - return 0; - } - - _startMillis = millis(); - while ((_ns_available() < (int)length) && ((millis() - _startMillis) < _timeout)) - { - yield(); - } - - if (_ns_available() < (int)length) - { - count = _ns_available(); - } - else - { - count = length; - } - - return _client->peekBytes((char *)buffer, count); - } - - uint8_t ESP_Mail_WCS::_ns_connected() - { - if (!_client || _client->state() == CLOSED) - return 0; - - return _client->state() == ESTABLISHED || _ns_available(); - } - - bool ESP_Mail_WCS::_ns_connect_ssl() - { - return _connectSSL(_host_name.c_str()); - } -}; // namespace ESP_Mail - -#endif /* ESP8266 */ - -#endif /* ESP_Mail_WCS_CPP */ \ No newline at end of file diff --git a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.h b/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.h deleted file mode 100644 index aef48cc5e..000000000 --- a/lib/libesp32/lib_mail/src/wcs/esp8266/ESP_Mail_WCS.h +++ /dev/null @@ -1,306 +0,0 @@ -/* - Customized version of WiFiClientSecure.h v1.0.1 - - WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries - - Mostly compatible with Arduino WiFi shield library and standard - WiFiClient/ServerSecure (except for certificate handling). - - Copyright (c) 2018 Earle F. Philhower, III - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef ESP_Mail_WCS_H -#define ESP_Mail_WCS_H - -#ifdef ESP8266 - -#include -#include -#include -#include "ESP_Mail_BearSSLHelpers.h" -#include "ESP_Mail_CertStoreBearSSL.h" -#include "SDK_Version_Common.h" - -namespace ESP_Mail { - -//#define DEBUG_ESP_SSL -//#define DEBUG_ESP_PORT Serial - - struct br_x509_insecure_context; - - class ESP_Mail_WCS : public WiFiClient - { - public: - ESP_Mail_WCS(); - ESP_Mail_WCS(const ESP_Mail_WCS &rhs); - ~ESP_Mail_WCS() override; - - ESP_Mail_WCS& operator=(const ESP_Mail_WCS&) = default; // The shared-ptrs handle themselves automatically - - int connect(IPAddress ip, uint16_t port) override; - int connect(const String& host, uint16_t port) override; - int connect(const char* name, uint16_t port) override; - - uint8_t connected() override; - size_t write(const uint8_t *buf, size_t size) override; - size_t write_P(PGM_P buf, size_t size) override; - size_t write(const char *buf) { - return write((const uint8_t*)buf, strlen(buf)); - } - size_t write_P(const char *buf) { - return write_P((PGM_P)buf, strlen_P(buf)); - } - size_t write(Stream& stream); // Note this is not virtual - int read(uint8_t *buf, size_t size) override; - int available() override; - int read() override; - int peek() override; - size_t peekBytes(uint8_t *buffer, size_t length) override; - bool flush(unsigned int maxWaitMs); - bool stop(unsigned int maxWaitMs); - void flush() override { (void)flush(0); } - void stop() override { (void)stop(0); } - - // Allow sessions to be saved/restored automatically to a memory area - void setSession(Session *session) { _session = session; } - - // Don't validate the chain, just accept whatever is given. VERY INSECURE! - void setInsecure() { - _clearAuthenticationSettings(); - _use_insecure = true; - } - // Assume a given public key, don't validate or use cert info at all - void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) { - _clearAuthenticationSettings(); - _knownkey = pk; - _knownkey_usages = usages; - } - // Only check SHA1 fingerprint of certificate - bool setFingerprint(const uint8_t fingerprint[20]) { - _clearAuthenticationSettings(); - _use_fingerprint = true; - memcpy_P(_fingerprint, fingerprint, 20); - return true; - } - bool setFingerprint(const char *fpStr); - // Accept any certificate that's self-signed - void allowSelfSignedCerts() { - _clearAuthenticationSettings(); - _use_self_signed = true; - } - // Install certificates of trusted CAs or specific site - void setTrustAnchors(const ESP_Mail_X509List *ta) { - _clearAuthenticationSettings(); - _ta = ta; - } - // In cases when NTP is not used, app must set a time manually to check cert validity - void setX509Time(time_t now) { - _now = now; - } - // Install a client certificate for this connection, in case the server requires it (i.e. MQTT) - void setClientRSACert(const ESP_Mail_X509List *cert, const PrivateKey *sk); - void setClientECCert(const ESP_Mail_X509List *cert, const PrivateKey *sk, - unsigned allowed_usages, unsigned cert_issuer_key_type); - - // Sets the requested buffer size for transmit and receive - void setBufferSizes(int recv, int xmit); - - // Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection) - int getMFLNStatus() { - return connected() && br_ssl_engine_get_mfln_negotiated(_eng); - } - - // Return an error code and possibly a text string in a passed-in buffer with last SSL failure - int getLastSSLError(char *dest = NULL, size_t len = 0); - - // Attach a preconfigured certificate store - void setCertStore(ESP_Mail_CertStore *certStore) { - _certStore = certStore; - } - - // Select specific ciphers (i.e. optimize for speed over security) - // These may be in PROGMEM or RAM, either will run properly - bool setCiphers(const uint16_t *cipherAry, int cipherCount); - bool setCiphers(std::vector list); - bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC - - // Check for Maximum Fragment Length support for given len before connection (possibly insecure) - static bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len); - static bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len); - static bool probeMaxFragmentLength(const String& host, uint16_t port, uint16_t len); - - void setStartTLS(bool enable); - size_t _ns_write(uint8_t b); - size_t _ns_write(const uint8_t *buf, size_t size); - size_t _ns_write(Stream &stream, size_t unused); - size_t _ns_write(Stream &stream); - size_t _ns_write_P(PGM_P buf, size_t size); - int _ns_available(); - int _ns_read(); - int _ns_read(uint8_t *buf, size_t size); - int _ns_peek(); - size_t _ns_peekBytes(uint8_t *buffer, size_t length); - uint8_t _ns_connected(); - bool _ns_connect_ssl(); - - //////////////////////////////////////////////////// - // AxTLS API deprecated warnings to help upgrading - - bool setCACert(const uint8_t* pk, size_t size) ; - bool setCertificate(const uint8_t* pk, size_t size) ; - bool setPrivateKey(const uint8_t* pk, size_t size) ; - - bool loadCACert(Stream& stream, size_t size) ; - bool loadCertificate(Stream& stream, size_t size) ; - bool loadPrivateKey(Stream& stream, size_t size) ; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - - bool setCACert_P(PGM_VOID_P pk, size_t size) { - return setCACert((const uint8_t *)pk, size); - } - - bool setCertificate_P(PGM_VOID_P pk, size_t size) { - return setCertificate((const uint8_t *)pk, size); - } - - bool setPrivateKey_P(PGM_VOID_P pk, size_t size) { - return setPrivateKey((const uint8_t *)pk, size); - } - -#pragma GCC diagnostic pop - - template - bool loadCertificate(TFile& file) { - return loadCertificate(file, file.size()); - } - - template - bool loadPrivateKey(TFile& file) { - return loadPrivateKey(file, file.size()); - } - - template - bool loadCACert(TFile& file) { - return loadCACert(file, file.size()); - } - - bool verify(const char* fingerprint, const char* domain_name) { - (void)fingerprint; - (void)domain_name; - return connected(); - } - - bool verifyCertChain(const char* domain_name) { - (void)domain_name; - return connected(); - } - - // AxTLS API deprecated section end - ///////////////////////////////////// - - protected: - bool _connectSSL(const char *hostName); // Do initial SSL handshake - - private: - void _clear(); - void _clearAuthenticationSettings(); - // Only one of the following two should ever be != nullptr! - std::shared_ptr _sc; - std::shared_ptr _sc_svr; - inline bool ctx_present() { - return (_sc != nullptr) || (_sc_svr != nullptr); - } - br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts - std::shared_ptr _x509_minimal; - std::shared_ptr _x509_insecure; - std::shared_ptr _x509_knownkey; - std::shared_ptr _iobuf_in; - std::shared_ptr _iobuf_out; - time_t _now; - const ESP_Mail_X509List *_ta; - ESP_Mail_CertStore *_certStore; - int _iobuf_in_size; - int _iobuf_out_size; - bool _handshake_done; - bool _oom_err; - - bool _secured; - std::string _host_name; - - // AXTLS compatibility shim elements: - // AXTLS managed memory for certs and keys, while BearSSL assumes - // the app manages these. Use this local storage for holding the - // BearSSL created objects in a shared form. - std::shared_ptr _axtls_ta; - std::shared_ptr _axtls_chain; - std::shared_ptr _axtls_sk; - - // Optional storage space pointer for session parameters - // Will be used on connect and updated on close - Session *_session; - - bool _use_insecure; - bool _use_fingerprint; - uint8_t _fingerprint[20]; - bool _use_self_signed; - const PublicKey *_knownkey; - unsigned _knownkey_usages; - - // Custom cipher list pointer or NULL if default - std::shared_ptr _cipher_list; - uint8_t _cipher_cnt; - - unsigned char *_recvapp_buf; - size_t _recvapp_len; - - bool _clientConnected(); // Is the underlying socket alive? - void _freeSSL(); - int _run_until(unsigned target, bool blocking = true); - size_t _write(const uint8_t *buf, size_t size, bool pmem); - bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting - - // Optional client certificate - const ESP_Mail_X509List *_chain; - const PrivateKey *_sk; - unsigned _allowed_usages; - unsigned _cert_issuer_key_type; - - // Methods for handling server.available() call which returns a client connection. - friend class WiFiServerSecure; // Server needs to access these constructors - ESP_Mail_WCS(ClientContext *client, const ESP_Mail_X509List *chain, unsigned cert_issuer_key_type, - const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta); - ESP_Mail_WCS(ClientContext* client, const ESP_Mail_X509List *chain, const PrivateKey *sk, - int iobuf_in_size, int iobuf_out_size, const ESP_Mail_X509List *client_CA_ta); - - // RSA keyed server - bool _connectSSLServerRSA(const ESP_Mail_X509List *chain, const PrivateKey *sk, const ESP_Mail_X509List *client_CA_ta); - // EC keyed server - bool _connectSSLServerEC(const ESP_Mail_X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk, - const ESP_Mail_X509List *client_CA_ta); - - // X.509 validators differ from server to client - bool _installClientX509Validator(); // Set up X509 validator for a client conn. - bool _installServerX509Validator(const ESP_Mail_X509List *client_CA_ta); // Setup X509 client cert validation, if supplied - - uint8_t *_streamLoad(Stream& stream, size_t size); - }; -}; - -#endif /* ESP8266 */ - -#endif /* ESP_Mail_WCS_H */ diff --git a/lib/libesp32/rtsp/CRtspSession.cpp b/lib/libesp32/rtsp/CRtspSession.cpp index 7462e8f89..79e210d1e 100755 --- a/lib/libesp32/rtsp/CRtspSession.cpp +++ b/lib/libesp32/rtsp/CRtspSession.cpp @@ -5,7 +5,7 @@ CRtspSession::CRtspSession(SOCKET aRtspClient, CStreamer * aStreamer) : m_RtspClient(aRtspClient),m_Streamer(aStreamer) { - printf("Creating RTSP session\n"); +// printf("Creating RTSP session\n"); Init(); m_RtspSessionID = getRandom(); // create a session ID @@ -95,11 +95,11 @@ bool CRtspSession::ParseRtspRequest(char const * aRequest, unsigned aRequestSize } CmdName[i] = '\0'; if (!parseSucceeded) { - printf("failed to parse RTSP\n"); +// printf("failed to parse RTSP\n"); return false; } - printf("RTSP received %s\n", CmdName); +// printf("RTSP received %s\n", CmdName); // find out the command type if (strstr(CmdName,"OPTIONS") != nullptr) m_RtspCmdType = RTSP_OPTIONS; else @@ -400,7 +400,7 @@ bool CRtspSession::handleRequests(uint32_t readTimeoutMs) return true; } else if(res == 0) { - printf("client closed socket, exiting\n"); +// printf("client closed socket, exiting\n"); m_stopped = true; return true; } diff --git a/lib/libesp32/rtsp/CStreamer.cpp b/lib/libesp32/rtsp/CStreamer.cpp index af4519ec7..a9f638de9 100755 --- a/lib/libesp32/rtsp/CStreamer.cpp +++ b/lib/libesp32/rtsp/CStreamer.cpp @@ -6,7 +6,7 @@ CStreamer::CStreamer(SOCKET aClient, u_short width, u_short height) : m_Client(aClient) { - printf("Creating TSP streamer\n"); +// printf("Creating TSP streamer\n"); m_RtpServerPort = 0; m_RtcpServerPort = 0; m_RtpClientPort = 0; @@ -228,7 +228,7 @@ bool findJPEGheader(BufPtr *start, uint32_t *len, uint8_t marker) { while(bytes - *start < *len) { uint8_t framing = *bytes++; // better be 0xff if(framing != 0xff) { - printf("malformed jpeg, framing=%x\n", framing); +// printf("malformed jpeg, framing=%x\n", framing); return false; } uint8_t typecode = *bytes++; @@ -263,13 +263,13 @@ bool findJPEGheader(BufPtr *start, uint32_t *len, uint8_t marker) { break; } default: - printf("unexpected jpeg typecode 0x%x\n", typecode); +// printf("unexpected jpeg typecode 0x%x\n", typecode); break; } } } - printf("failed to find jpeg marker 0x%x", marker); +// printf("failed to find jpeg marker 0x%x", marker); return false; } @@ -309,7 +309,7 @@ bool decodeJPEGfile(BufPtr *start, uint32_t *len, BufPtr *qtable0, BufPtr *qtabl BufPtr quantstart = *start; uint32_t quantlen = *len; if(!findJPEGheader(&quantstart, &quantlen, 0xdb)) { - printf("error can't find quant table 0\n"); +// printf("error can't find quant table 0\n"); } else { // printf("found quant table %x\n", quantstart[2]); @@ -317,7 +317,7 @@ bool decodeJPEGfile(BufPtr *start, uint32_t *len, BufPtr *qtable0, BufPtr *qtabl *qtable0 = quantstart + 3; // 3 bytes of header skipped nextJpegBlock(&quantstart); if(!findJPEGheader(&quantstart, &quantlen, 0xdb)) { - printf("error can't find quant table 1\n"); +// printf("error can't find quant table 1\n"); } else { // printf("found quant table %x\n", quantstart[2]); diff --git a/lib/libesp32/rtsp/OV2640.cpp b/lib/libesp32/rtsp/OV2640.cpp index 9c1908b99..f8abe39f9 100755 --- a/lib/libesp32/rtsp/OV2640.cpp +++ b/lib/libesp32/rtsp/OV2640.cpp @@ -184,7 +184,7 @@ esp_err_t OV2640::init(camera_config_t config) esp_err_t err = esp_camera_init(&_cam_config); if (err != ESP_OK) { - printf("Camera probe failed with error 0x%x", err); +// printf("Camera probe failed with error 0x%x", err); return err; } // ESP_ERROR_CHECK(gpio_install_isr_service(0)); diff --git a/lib/libesp32/rtsp/OV2640Streamer.cpp b/lib/libesp32/rtsp/OV2640Streamer.cpp index 679594f48..43e92b647 100755 --- a/lib/libesp32/rtsp/OV2640Streamer.cpp +++ b/lib/libesp32/rtsp/OV2640Streamer.cpp @@ -6,7 +6,7 @@ OV2640Streamer::OV2640Streamer(SOCKET aClient, OV2640 &cam) : CStreamer(aClient, cam.getWidth(), cam.getHeight()), m_cam(cam) { - Serial.printf("Created streamer width=%d, height=%d\n", cam.getWidth(), cam.getHeight()); +// Serial.printf("Created streamer width=%d, height=%d\n", cam.getWidth(), cam.getHeight()); } void OV2640Streamer::streamImage(uint32_t curMsec) @@ -15,5 +15,5 @@ void OV2640Streamer::streamImage(uint32_t curMsec) BufPtr bytes = m_cam.getfb(); streamFrame(bytes, m_cam.getSize(), curMsec); - Serial.printf("get frame: %d\n",m_cam.getSize()); +// Serial.printf("get frame: %d\n",m_cam.getSize()); } diff --git a/lib/libesp32/rtsp/platglue-esp32.h b/lib/libesp32/rtsp/platglue-esp32.h index 8646904c9..0d921bb80 100755 --- a/lib/libesp32/rtsp/platglue-esp32.h +++ b/lib/libesp32/rtsp/platglue-esp32.h @@ -22,7 +22,7 @@ typedef uint16_t IPPORT; // on linux use network byte order #define NULLSOCKET NULL inline void closesocket(SOCKET s) { - printf("closing TCP socket\n"); +// printf("closing TCP socket\n"); if(s) { s->stop(); @@ -38,7 +38,7 @@ inline void socketpeeraddr(SOCKET s, IPADDRESS *addr, IPPORT *port) { } inline void udpsocketclose(UDPSOCKET s) { - printf("closing UDP socket\n"); +// printf("closing UDP socket\n"); if(s) { s->stop(); delete s; @@ -50,7 +50,7 @@ inline UDPSOCKET udpsocketcreate(unsigned short portNum) UDPSOCKET s = new WiFiUDP(); if(!s->begin(portNum)) { - printf("Can't bind port %d\n", portNum); +// printf("Can't bind port %d\n", portNum); delete s; return NULL; } @@ -69,8 +69,9 @@ inline ssize_t udpsocketsend(UDPSOCKET sockfd, const void *buf, size_t len, { sockfd->beginPacket(destaddr, destport); sockfd->write((const uint8_t *) buf, len); - if(!sockfd->endPacket()) - printf("error sending udp packet\n"); + if(!sockfd->endPacket()) { +// printf("error sending udp packet\n"); + } return len; } @@ -83,7 +84,7 @@ inline ssize_t udpsocketsend(UDPSOCKET sockfd, const void *buf, size_t len, inline int socketread(SOCKET sock, char *buf, size_t buflen, int timeoutmsec) { if(!sock->connected()) { - printf("client has closed the socket\n"); +// printf("client has closed the socket\n"); return 0; } diff --git a/lib/libesp32/rtsp/platglue-posix.h b/lib/libesp32/rtsp/platglue-posix.h index 046258ef5..fd442731c 100755 --- a/lib/libesp32/rtsp/platglue-posix.h +++ b/lib/libesp32/rtsp/platglue-posix.h @@ -28,7 +28,7 @@ inline void socketpeeraddr(SOCKET s, IPADDRESS *addr, IPPORT *port) { sockaddr_in r; socklen_t len = sizeof(r); if(getpeername(s,(struct sockaddr*)&r,&len) < 0) { - printf("getpeername failed\n"); +// printf("getpeername failed\n"); *addr = 0; *port = 0; } @@ -54,7 +54,7 @@ inline UDPSOCKET udpsocketcreate(unsigned short portNum) int s = socket(AF_INET, SOCK_DGRAM, 0); addr.sin_port = htons(portNum); if (bind(s,(sockaddr*)&addr,sizeof(addr)) != 0) { - printf("Error, can't bind\n"); +// printf("Error, can't bind\n"); close(s); s = 0; } diff --git a/lib/libesp32_audio/es7210/src/es7210.cpp b/lib/libesp32_audio/es7210/src/es7210.cpp index 65b2c0cb7..e84834e13 100644 --- a/lib/libesp32_audio/es7210/src/es7210.cpp +++ b/lib/libesp32_audio/es7210/src/es7210.cpp @@ -27,6 +27,7 @@ #include #include #include "esp_log.h" +#include "rom/ets_sys.h" #include "es7210.h" diff --git a/lib/libesp32_audio/es7243e/src/es7243e.cpp b/lib/libesp32_audio/es7243e/src/es7243e.cpp index 6ea7824fb..124f3d4db 100644 --- a/lib/libesp32_audio/es7243e/src/es7243e.cpp +++ b/lib/libesp32_audio/es7243e/src/es7243e.cpp @@ -27,7 +27,8 @@ #include #include "string.h" #include "esp_log.h" -#include "es7243e.h" + #include "rom/ets_sys.h" + #include "es7243e.h" static const char *TAG = "DRV7243E"; diff --git a/lib/libesp32_audio/es8156/src/es8156.cpp b/lib/libesp32_audio/es8156/src/es8156.cpp index 1de1ed716..30c237c10 100644 --- a/lib/libesp32_audio/es8156/src/es8156.cpp +++ b/lib/libesp32_audio/es8156/src/es8156.cpp @@ -28,6 +28,7 @@ #include #include "string.h" #include "esp_log.h" +#include "rom/ets_sys.h" #include "es8156.h" /* diff --git a/lib/libesp32_audio/es8311/src/es8311.cpp b/lib/libesp32_audio/es8311/src/es8311.cpp index 6cdc41f75..06518d82c 100644 --- a/lib/libesp32_audio/es8311/src/es8311.cpp +++ b/lib/libesp32_audio/es8311/src/es8311.cpp @@ -27,6 +27,7 @@ #include #include #include "esp_log.h" +#include "rom/ets_sys.h" #include "es8311.h" diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3bitstream.cpp b/lib/libesp32_audio/mp3_shine_esp32/src/l3bitstream.cpp index 9952e04c7..2450036a5 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/l3bitstream.cpp +++ b/lib/libesp32_audio/mp3_shine_esp32/src/l3bitstream.cpp @@ -34,7 +34,7 @@ void shine_format_bitstream(shine_global_config *config) { for ( gr = 0; gr < config->mpeg.granules_per_frame; gr++ ) { int *pi = &config->l3_enc[ch][gr][0]; - int32_t *pr = &config->mdct_freq[ch][gr][0]; + int *pr = &config->mdct_freq[ch][gr][0]; for ( i = 0; i < GRANULE_SIZE; i++ ) { if ( (pr[i] < 0) && (pi[i] > 0) ) diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp b/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp index 0dd25df90..a42bf10e2 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp +++ b/lib/libesp32_audio/mp3_shine_esp32/src/l3loop.cpp @@ -31,7 +31,7 @@ static void calc_xmin( gr_info *cod_info, shine_psy_xmin_t *l3_xmin, int gr, int static int quantize(int ix[GRANULE_SIZE], int stepsize, shine_global_config *config); -int32_t sqrt_int(int32_t r) { +int sqrt_int(int r) { float x; float rr = r; float y = rr*0.5; @@ -40,7 +40,7 @@ int32_t sqrt_int(int32_t r) { x = (1.5f*x) - (x*x)*(x*y); if(r>101123) x = (1.5f*x) - (x*x)*(x*y); - int32_t is = (int32_t)(x*rr + 0.5f); + int is = (int)(x*rr + 0.5f); return is + ((r - is*is)>>31); } @@ -382,7 +382,7 @@ void shine_loop_initialise(shine_global_config *config) { * In quantize, the long multiply does not shift it's result left one * bit to compensate. */ - config->l3loop->steptabi[i] = (int32_t)((config->l3loop->steptab[i]*2) + 0.5); + config->l3loop->steptabi[i] = (int)((config->l3loop->steptab[i]*2) + 0.5); } /* quantize: vector conversion, three quarter power table. @@ -401,7 +401,7 @@ void shine_loop_initialise(shine_global_config *config) { int quantize(int ix[GRANULE_SIZE], int stepsize, shine_global_config *config ) { int i, max, ln; - int32_t scalei; + int scalei; float scale, dbl; scalei = config->l3loop->steptabi[stepsize+127]; /* 2**(-stepsize/4) */ @@ -444,8 +444,8 @@ int quantize(int ix[GRANULE_SIZE], int stepsize, shine_global_config *config ) * Function: Calculate the maximum of ix from 0 to 575 */ static inline int ix_max( int ix[GRANULE_SIZE], unsigned int begin, unsigned int end ) { - register int i; - register int max = 0; + int i; + int max = 0; for(i=begin;imdct.cos_l[m][k] = (int32_t)(sin(PI36*(k+0.5)) + config->mdct.cos_l[m][k] = (int)(sin(PI36*(k+0.5)) * cos((PI/72)*(2*k+19)*(2*m+1)) * 0x7fffffff); } @@ -50,17 +50,17 @@ void shine_mdct_sub(shine_global_config *config, int stride) { /* note. we wish to access the array 'config->mdct_freq[2][2][576]' as * [2][2][32][18]. (32*18=576), */ - int32_t (*mdct_enc)[18]; + int (*mdct_enc)[18]; int ch,gr,band,j,k; - int32_t mdct_in[36]; + int mdct_in[36]; for(ch=config->wave.channels; ch--; ) { for(gr=0; grmpeg.granules_per_frame; gr++) { /* set up pointer to the part of config->mdct_freq we're using */ - mdct_enc = (int32_t (*)[18]) config->mdct_freq[ch][gr]; + mdct_enc = (int (*)[18]) config->mdct_freq[ch][gr]; /* polyphase filtering */ for(k=0; k<18; k+=2) @@ -91,7 +91,7 @@ void shine_mdct_sub(shine_global_config *config, int stride) { for(k=18; k--; ) { - int32_t vm; + int vm; #ifdef __BORLANDC__ uint32_t vm_lo; #else diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp b/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp index 683dd2cf1..717ae5fbe 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp +++ b/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.cpp @@ -28,7 +28,7 @@ void shine_subband_initialise(shine_global_config *config) { else modf(filter-0.5, &filter); /* scale and convert to fixed point before storing */ - config->subband.fl[i][j] = (int32_t)(filter * (0x7fffffff * 1e-9)); + config->subband.fl[i][j] = (int)(filter * (0x7fffffff * 1e-9)); } } @@ -46,20 +46,20 @@ void shine_subband_initialise(shine_global_config *config) { * picking out values from the windowed samples, and then multiplying * them by the filter matrix, producing 32 subband samples. */ -void shine_window_filter_subband(int16_t **buffer, int32_t s[SBLIMIT], int ch, shine_global_config *config, int stride) { - int32_t y[64]; +void shine_window_filter_subband(int16_t **buffer, int s[SBLIMIT], int ch, shine_global_config *config, int stride) { + int y[64]; int i,j; int16_t *ptr = *buffer; /* replace 32 oldest samples with 32 new samples */ for (i=32;i--;) { - config->subband.x[ch][i+config->subband.off[ch]] = ((int32_t)*ptr) << 16; + config->subband.x[ch][i+config->subband.off[ch]] = ((int)*ptr) << 16; ptr += stride; } *buffer = ptr; for (i=64; i--; ) { - int32_t s_value; + int s_value; #ifdef __BORLANDC__ uint32_t s_value_lo; #else @@ -81,7 +81,7 @@ void shine_window_filter_subband(int16_t **buffer, int32_t s[SBLIMIT], int ch, s config->subband.off[ch] = (config->subband.off[ch] + 480) & (HAN_SIZE-1); /* offset is modulo (HAN_SIZE)*/ for (i=SBLIMIT; i--; ) { - int32_t s_value; + int s_value; #ifdef __BORLANDC__ uint32_t s_value_lo; #else diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.h b/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.h index 9bfe861ee..631ac42a2 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.h +++ b/lib/libesp32_audio/mp3_shine_esp32/src/l3subband.h @@ -4,6 +4,6 @@ #include void shine_subband_initialise( shine_global_config *config ); -void shine_window_filter_subband(int16_t **buffer, int32_t s[SBLIMIT], int k, shine_global_config *config, int stride); +void shine_window_filter_subband(int16_t **buffer, int s[SBLIMIT], int k, shine_global_config *config, int stride); #endif diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/layer3.cpp b/lib/libesp32_audio/mp3_shine_esp32/src/layer3.cpp index 80d7b0626..16fd65d37 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/layer3.cpp +++ b/lib/libesp32_audio/mp3_shine_esp32/src/layer3.cpp @@ -106,12 +106,12 @@ shine_global_config *shine_initialise(shine_config_t *pub_config) { for (x = 0; x < MAX_CHANNELS; x++) { for (y = 0; y < MAX_GRANULES; y++) { // 2 * 2 * 576 each - config->l3_enc[x][y] = (int*)heap_caps_malloc_prefer(sizeof(int32_t)*GRANULE_SIZE, MALLOC_CAP_32BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //Significant performance hit in IRAM + config->l3_enc[x][y] = (int*)heap_caps_malloc_prefer(4*GRANULE_SIZE, MALLOC_CAP_32BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //Significant performance hit in IRAM if (!config->l3_enc[x][y]) { // error should never occur because of spiram size //config->l3_enc[x][y] = (int*)heap_caps_malloc(sizeof(int32_t)*GRANULE_SIZE,MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); } - config->mdct_freq[x][y] = (int*)heap_caps_malloc_prefer(sizeof(int32_t)*GRANULE_SIZE, MALLOC_CAP_32BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //OK 1% + config->mdct_freq[x][y] = (int*)heap_caps_malloc_prefer(4*GRANULE_SIZE, MALLOC_CAP_32BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //OK 1% if (!config->mdct_freq[x][y]) { // error //config->mdct_freq[x][y] = (int*)heap_caps_malloc(sizeof(int32_t)*GRANULE_SIZE, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); @@ -123,15 +123,15 @@ shine_global_config *shine_initialise(shine_config_t *pub_config) { #endif config->l3loop = (l3loop_t*)heap_caps_malloc(sizeof(l3loop_t), MALLOC_CAP_SPIRAM); #ifdef SHINE_DEBUG - printf("xrsq & xrabs each: %d\n", sizeof(int32_t)*GRANULE_SIZE); + printf("xrsq & xrabs each: %d\n", sizeof(int)*GRANULE_SIZE); #endif - config->l3loop->xrsq = (int*)heap_caps_malloc_prefer(sizeof(int32_t)*GRANULE_SIZE, MALLOC_CAP_32BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //OK 0.5% + config->l3loop->xrsq = (int*)heap_caps_malloc_prefer(4*GRANULE_SIZE, MALLOC_CAP_32BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //OK 0.5% if (!config->l3loop->xrsq) { // error //config->l3loop->xrsq = (int*)heap_caps_malloc(sizeof(int32_t)*GRANULE_SIZE, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //OK 0.5% } - config->l3loop->xrabs = (int*)heap_caps_malloc_prefer(sizeof(int32_t)*GRANULE_SIZE, MALLOC_CAP_32BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //OK 0.5% + config->l3loop->xrabs = (int*)heap_caps_malloc_prefer(4*GRANULE_SIZE, MALLOC_CAP_32BIT, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //OK 0.5% if (!config->l3loop->xrabs) { //config->l3loop->xrabs = (int*)heap_caps_malloc(sizeof(int32_t)*GRANULE_SIZE, MALLOC_CAP_SPIRAM|MALLOC_CAP_32BIT); //OK 0.5% } @@ -226,7 +226,8 @@ Counters 2664123380 : 2664123448 : 2666717886 : 2668665908 : 2668859025 static unsigned char *shine_encode_buffer_internal(shine_global_config *config, int *written, int stride) { - counter[0] = xthal_get_ccount(); + counter[0] = portGET_RUN_TIME_COUNTER_VALUE(); // TASMOTA more portable solution + // counter[0] = xthal_get_ccount(); if(config->mpeg.frac_slots_per_frame) { config->mpeg.padding = (config->mpeg.slot_lag <= (config->mpeg.frac_slots_per_frame - 1.0)); config->mpeg.slot_lag += (config->mpeg.padding - config->mpeg.frac_slots_per_frame); @@ -234,18 +235,22 @@ static unsigned char *shine_encode_buffer_internal(shine_global_config *config, config->mpeg.bits_per_frame = 8*(config->mpeg.whole_slots_per_frame + config->mpeg.padding); config->mean_bits = (config->mpeg.bits_per_frame - config->sideinfo_len)/config->mpeg.granules_per_frame; - counter[1] = xthal_get_ccount(); + counter[1] = portGET_RUN_TIME_COUNTER_VALUE(); // TASMOTA more portable solution + // counter[1] = xthal_get_ccount(); /* apply mdct to the polyphase output */ // put on core 1 shine_mdct_sub(config, stride); - counter[2] = xthal_get_ccount(); + counter[2] = portGET_RUN_TIME_COUNTER_VALUE(); // TASMOTA more portable solution + // counter[2] = xthal_get_ccount(); /* bit and noise allocation */ //put on core 0 shine_iteration_loop(config); - counter[3] = xthal_get_ccount(); + counter[3] = portGET_RUN_TIME_COUNTER_VALUE(); // TASMOTA more portable solution + // counter[3] = xthal_get_ccount(); /* write the frame to the bitstream */ shine_format_bitstream(config); - counter[4] = xthal_get_ccount(); + counter[4] = portGET_RUN_TIME_COUNTER_VALUE(); // TASMOTA more portable solution + // counter[4] = xthal_get_ccount(); /* Return data. */ *written = config->bs.data_position; config->bs.data_position = 0; diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_mips_gcc.h b/lib/libesp32_audio/mp3_shine_esp32/src/mult_mips_gcc.h index 092ed844e..43ca1aa8c 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/mult_mips_gcc.h +++ b/lib/libesp32_audio/mp3_shine_esp32/src/mult_mips_gcc.h @@ -2,7 +2,7 @@ #define mul(a,b) \ ({ \ - register int32_t res; \ + register int res; \ __asm__ __volatile__("mult %0, %1" : : "r" (a), "r" (b)); \ __asm__ __volatile__("mfhi %0" : "=r" (res)); \ res; \ @@ -19,14 +19,14 @@ #define mulz(hi,lo) \ do { \ - register int32_t t; \ + register int t; \ __asm__ __volatile__("mfhi %0" : "=r" (t)); \ (hi) = t; \ } while (0) #define cmuls(dre, dim, are, aim, bre, bim) \ do { \ - register int32_t t1, t2, tre; \ + register int t1, t2, tre; \ __asm__ __volatile__("mult %0, %1" : : "r" (are), "r" (bre)); \ __asm__ __volatile__("msub %0, %1" : : "r" (aim), "r" (bim)); \ __asm__ __volatile__("mfhi %0; mflo %1" : "=r" (t1), "=r" (t2)); \ diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h b/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h index e1143f830..01862f153 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h +++ b/lib/libesp32_audio/mp3_shine_esp32/src/mult_noarch_gcc.h @@ -1,119 +1,35 @@ #include #ifndef asm_mul -//#define /// mul(a,b) (int32_t) ( ( ((int64_t) a) * ((int64_t) b) ) >>32 ) - -#define asm_mul(x,y) \ -({ \ - register int32_t result; \ - asm ("mulsh %0, %2, %1" : "=r" (result) : "r" (x), "r" (y)); \ - result ;\ -}) - +#define asm_mul(a,b) (int) ( ( ((int64_t) a) * ((int64_t) b) ) >>32 ) #endif #ifndef asm_muls //Not sure about this -#define asm_muls(x,y) \ -({ \ - register int32_t result; \ - asm ( \ - "mulsh %0, %2, %1\n\t" \ - "add %0, %0, %0" \ - : "=r" (result) : "r" (x), "r" (y)); \ - result ;\ -}) - - - -//#define muls(a,b) (int32_t) ( ( ((int64_t) a) * ((int64_t) b) ) >>31 ) +#define asm_muls(a,b) (int) ( ( ((int64_t) a) * ((int64_t) b) ) >>31 ) #endif #ifndef asm_mulr //no rounding shortcut -#define asm_mulr(x,y) \ -({ \ - register int32_t result; \ - asm ("mulsh %0, %2, %1" : "=r" (result) : "r" (x), "r" (y)); \ - result ;\ -}) - -//#define mulr(a,b) (int32_t) ( ( ( ((int64_t) a) * ((int64_t) b)) + 0x80000000LL ) >>32 ) +#define asm_mulr(a,b) (int) ( ( ( ((int64_t) a) * ((int64_t) b)) + 0x80000000LL ) >>32 ) #endif #ifndef asm_mulsr //no rounding shortcut -#define asm_mulsr(x,y) \ -({ \ - register int32_t result; \ - asm ( \ - "mulsh %0, %2, %1\n\t" \ - "add %0, %0, %0" \ - : "=r" (result) : "r" (x), "r" (y)); \ - result ;\ -}) - -//#define mulsr(a,b) (int32_t) ( ( ( ((int64_t) a) * ((int64_t) b)) + 0x40000000LL ) >>31 ) +#define asm_mulsr(a,b) (int) ( ( ( ((int64_t) a) * ((int64_t) b)) + 0x40000000LL ) >>31 ) #endif #ifndef asm_mul0 #define asm_mul0(hi,lo,a,b) ((hi) = asm_mul((a), (b))) -// This didn't seem to help either -#define asm_muladd(hi, lo, x, y) \ - ({ \ - asm ( \ - "mulsh a7, %2, %1\n\t" \ - "add %0, %0, a7\n\t" \ - : "+r" (hi) : "r" (x), "r" (y) \ - : "a7");\ -}) - - -//#define asm_muladd(hi,lo,a,b) ((hi) += mul((a), (b))) - #define asm_mulsub(hi, lo, x, y) \ - ({ \ - asm ( \ - "mulsh a8, %2, %1\n\t" \ - "sub %0, %0, a8\n\t" \ - : "+r" (hi) : "r" (x), "r" (y) \ - : "a8");\ -}) -//#define mulsub(hi,lo,a,b) ((hi) -= mul((a), (b))) +#define asm_muladd(hi,lo,a,b) ((hi) += asm_mul((a), (b))) +#define mulsub(hi,lo,a,b) ((hi) -= asm_mul((a), (b))) #define asm_mulz(hi,lo) #endif #ifndef asm_cmuls -/* - #define cmuls(dre, dim, are, aim, bre, bim) \ -do { \ - register int32_t tre, tim; \ - asm ( \ - "mull %0, %2, %4\n\t" \ //mulsh - "mulsh r3, %2, %4\n\t" \ //mulsh - "mull r4, %3, %5\n\t" \ //mulsh - "mulsh r5, %3, %5\n\t" \ //mulsh - "add %0, %0, %0\n\t" \ shl - - "smull r3, %0, %2, %4\n\t" \ //mulsh - "smlal r3, %0, %3, %5\n\t" \ //mulsh + add - "movs r3, r3, lsl #1\n\t" \ //add r to r - "adc %0, %0, %0\n\t" \. //add with carry - "smull r3, %1, %2, %6\n\t" \ - "smlal r3, %1, %4, %3\n\t" \ - "movs r3, r3, lsl #1\n\t" \ - "adc %1, %1, %1\n\t" \ - : "=&r" (tre), "=&r" (tim) \ - : "r" (are), "r" (aim), "r" (bre), "r" (-(bim)), "r" (bim) \ - : "r3", "cc" \ - ); \ - dre = tre; \ - dim = tim; \ -} while (0)*/ - - #define asm_cmuls(dre, dim, are, aim, bre, bim) \ do { \ - int32_t tre; \ - (tre) = (int32_t) (((int64_t) (are) * (int64_t) (bre) - (int64_t) (aim) * (int64_t) (bim)) >> 31); \ - (dim) = (int32_t) (((int64_t) (are) * (int64_t) (bim) + (int64_t) (aim) * (int64_t) (bre)) >> 31); \ + int tre; \ + (tre) = (int) (((int64_t) (are) * (int64_t) (bre) - (int64_t) (aim) * (int64_t) (bim)) >> 31); \ + (dim) = (int) (((int64_t) (are) * (int64_t) (bim) + (int64_t) (aim) * (int64_t) (bre)) >> 31); \ (dre) = tre; \ } while (0) #endif diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_sarm_gcc.h b/lib/libesp32_audio/mp3_shine_esp32/src/mult_sarm_gcc.h index d229effd8..4f7bb9ca3 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/mult_sarm_gcc.h +++ b/lib/libesp32_audio/mp3_shine_esp32/src/mult_sarm_gcc.h @@ -4,14 +4,14 @@ #if __ARM_ARCH >= 6 #define mul(x,y) \ ({ \ - register int32_t result; \ + register int result; \ asm ("smmul %0, %2, %1" : "=r" (result) : "r" (x), "r" (y)); \ result ;\ }) #else #define mul(x,y) \ ({ \ - register int32_t result; \ + register int result; \ asm ("smull r3, %0, %2, %1" : "=r" (result) : "r" (x), "r" (y) : "r3"); \ result ; \ }) @@ -20,7 +20,7 @@ /* Fractional multiply with single bit left shift. */ #define muls(x,y) \ ({ \ - register int32_t result; \ + register int result; \ asm ( \ "smull r3, %0, %2, %1\n\t" \ "movs r3, r3, lsl #1\n\t" \ @@ -34,7 +34,7 @@ #if __ARM_ARCH >= 6 #define mulr(x,y) \ ({ \ - register int32_t result; \ + register int result; \ asm ( \ "smmulr %0, %2, %1" : "=r" (result) : "r" (x), "r" (y) \ ); \ @@ -43,7 +43,7 @@ #else #define mulr(x,y) \ ({ \ - register int32_t result; \ + register int result; \ asm ( \ "smull r3, %0, %2, %1\n\t" \ "adds r3, r3, #0x80000000\n\t" \ @@ -56,7 +56,7 @@ #define mulsr(x,y) \ ({ \ - register int32_t result; \ + register int result; \ asm ( \ "smull r3, %0, %1, %2\n\t" \ "movs r3, r3, lsl #1\n\t" \ @@ -81,7 +81,7 @@ #define cmuls(dre, dim, are, aim, bre, bim) \ do { \ - register int32_t tre, tim; \ + register int tre, tim; \ asm ( \ "smull r3, %0, %2, %4\n\t" \ "smlal r3, %0, %3, %5\n\t" \ diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/mult_xtensa_gcc.h b/lib/libesp32_audio/mp3_shine_esp32/src/mult_xtensa_gcc.h new file mode 100644 index 000000000..ef12af3e9 --- /dev/null +++ b/lib/libesp32_audio/mp3_shine_esp32/src/mult_xtensa_gcc.h @@ -0,0 +1,119 @@ +#include + +#ifndef asm_mul +//#define /// mul(a,b) (int) ( ( ((int64_t) a) * ((int64_t) b) ) >>32 ) + +#define asm_mul(x,y) \ +({ \ + int result; \ + asm ("mulsh %0, %2, %1" : "=r" (result) : "r" (x), "r" (y)); \ + result ;\ +}) + +#endif + +#ifndef asm_muls //Not sure about this +#define asm_muls(x,y) \ +({ \ + register int result; \ + asm ( \ + "mulsh %0, %2, %1\n\t" \ + "add %0, %0, %0" \ + : "=r" (result) : "r" (x), "r" (y)); \ + result ;\ +}) + + + +//#define muls(a,b) (int) ( ( ((int64_t) a) * ((int64_t) b) ) >>31 ) +#endif + +#ifndef asm_mulr //no rounding shortcut +#define asm_mulr(x,y) \ +({ \ + int result; \ + asm ("mulsh %0, %2, %1" : "=r" (result) : "r" (x), "r" (y)); \ + result ;\ +}) + +//#define mulr(a,b) (int) ( ( ( ((int64_t) a) * ((int64_t) b)) + 0x80000000LL ) >>32 ) +#endif + +#ifndef asm_mulsr //no rounding shortcut +#define asm_mulsr(x,y) \ +({ \ + int result; \ + asm ( \ + "mulsh %0, %2, %1\n\t" \ + "add %0, %0, %0" \ + : "=r" (result) : "r" (x), "r" (y)); \ + result ;\ +}) + +//#define mulsr(a,b) (int) ( ( ( ((int64_t) a) * ((int64_t) b)) + 0x40000000LL ) >>31 ) +#endif + +#ifndef asm_mul0 +#define asm_mul0(hi,lo,a,b) ((hi) = asm_mul((a), (b))) + +// This didn't seem to help either +#define asm_muladd(hi, lo, x, y) \ + ({ \ + asm ( \ + "mulsh a7, %2, %1\n\t" \ + "add %0, %0, a7\n\t" \ + : "+r" (hi) : "r" (x), "r" (y) \ + : "a7");\ +}) + + +//#define asm_muladd(hi,lo,a,b) ((hi) += mul((a), (b))) + #define asm_mulsub(hi, lo, x, y) \ + ({ \ + asm ( \ + "mulsh a8, %2, %1\n\t" \ + "sub %0, %0, a8\n\t" \ + : "+r" (hi) : "r" (x), "r" (y) \ + : "a8");\ +}) +//#define mulsub(hi,lo,a,b) ((hi) -= mul((a), (b))) +#define asm_mulz(hi,lo) +#endif + +#ifndef asm_cmuls +/* + #define cmuls(dre, dim, are, aim, bre, bim) \ +do { \ + register int tre, tim; \ + asm ( \ + "mull %0, %2, %4\n\t" \ //mulsh + "mulsh r3, %2, %4\n\t" \ //mulsh + "mull r4, %3, %5\n\t" \ //mulsh + "mulsh r5, %3, %5\n\t" \ //mulsh + "add %0, %0, %0\n\t" \ shl + + "smull r3, %0, %2, %4\n\t" \ //mulsh + "smlal r3, %0, %3, %5\n\t" \ //mulsh + add + "movs r3, r3, lsl #1\n\t" \ //add r to r + "adc %0, %0, %0\n\t" \. //add with carry + "smull r3, %1, %2, %6\n\t" \ + "smlal r3, %1, %4, %3\n\t" \ + "movs r3, r3, lsl #1\n\t" \ + "adc %1, %1, %1\n\t" \ + : "=&r" (tre), "=&r" (tim) \ + : "r" (are), "r" (aim), "r" (bre), "r" (-(bim)), "r" (bim) \ + : "r3", "cc" \ + ); \ + dre = tre; \ + dim = tim; \ +} while (0)*/ + + +#define asm_cmuls(dre, dim, are, aim, bre, bim) \ +do { \ + int tre; \ + (tre) = (int) (((int64_t) (are) * (int64_t) (bre) - (int64_t) (aim) * (int64_t) (bim)) >> 31); \ + (dim) = (int) (((int64_t) (are) * (int64_t) (bim) + (int64_t) (aim) * (int64_t) (bre)) >> 31); \ + (dre) = tre; \ +} while (0) +#endif diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/tables.cpp b/lib/libesp32_audio/mp3_shine_esp32/src/tables.cpp index ff7e37492..40cdd9d99 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/tables.cpp +++ b/lib/libesp32_audio/mp3_shine_esp32/src/tables.cpp @@ -66,11 +66,11 @@ const int shine_scale_fact_band_index[9][23] = /* note. 0.035781 is shine_enwindow maximum value */ /* scale and convert to fixed point before storing */ -#define SHINE_EW(x) (int32_t)((double)(x) * 0x7fffffff) +#define SHINE_EW(x) (int)((double)(x) * 0x7fffffff) #define SHINE_EW2(a,b) SHINE_EW(a), SHINE_EW(b) #define SHINE_EW10(a,b,c,d,e,f,g,h,i,j) SHINE_EW2(a,b), SHINE_EW2(c,d), SHINE_EW2(e,f), SHINE_EW2(g,h), SHINE_EW2(i,j) -const int32_t shine_enwindow[] = { +const int shine_enwindow[] = { SHINE_EW10( 0.000000, -0.000000, -0.000000, -0.000000, -0.000000, -0.000000, -0.000000, -0.000001, -0.000001, -0.000001), SHINE_EW10( -0.000001, -0.000001, -0.000001, -0.000002, -0.000002, -0.000002, -0.000002, -0.000003, -0.000003, -0.000003), SHINE_EW10( -0.000004, -0.000004, -0.000005, -0.000005, -0.000006, -0.000007, -0.000008, -0.000008, -0.000009, -0.000010), diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/tables.h b/lib/libesp32_audio/mp3_shine_esp32/src/tables.h index 5c94228cb..1fbde4bd4 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/tables.h +++ b/lib/libesp32_audio/mp3_shine_esp32/src/tables.h @@ -10,7 +10,7 @@ extern const int samplerates[9]; extern const int bitrates[16][4]; extern const int shine_scale_fact_band_index[9][23]; -extern const int32_t shine_enwindow[]; +extern const int shine_enwindow[]; #endif diff --git a/lib/libesp32_audio/mp3_shine_esp32/src/types.h b/lib/libesp32_audio/mp3_shine_esp32/src/types.h index 69827481c..1b768a70e 100755 --- a/lib/libesp32_audio/mp3_shine_esp32/src/types.h +++ b/lib/libesp32_audio/mp3_shine_esp32/src/types.h @@ -17,6 +17,8 @@ #include "mult_mips_gcc.h" #elif defined(__arm__) && !defined(__thumb__) #include "mult_sarm_gcc.h" +#elif defined(__XTENSA__) +#include "mult_xtensa_gcc.h" #endif /* Include and define generic instructions, @@ -85,27 +87,27 @@ typedef struct { } priv_shine_mpeg_t; typedef struct { - int32_t *xr; /* magnitudes of the spectral values */ - int32_t *xrsq; /* xr squared */ - int32_t *xrabs; /* xr absolute */ - int32_t xrmax; /* maximum of xrabs array */ - int32_t en_tot[MAX_GRANULES]; /* gr */ - int32_t en[MAX_GRANULES][21]; - int32_t xm[MAX_GRANULES][21]; - int32_t xrmaxl[MAX_GRANULES]; + int *xr; /* magnitudes of the spectral values */ + int *xrsq; /* xr squared */ + int *xrabs; /* xr absolute */ + int xrmax; /* maximum of xrabs array */ + int en_tot[MAX_GRANULES]; /* gr */ + int en[MAX_GRANULES][21]; + int xm[MAX_GRANULES][21]; + int xrmaxl[MAX_GRANULES]; double steptab[128]; /* 2**(-x/4) for x = -127..0 */ - int32_t steptabi[128]; /* 2**(-x/4) for x = -127..0 */ + int steptabi[128]; /* 2**(-x/4) for x = -127..0 */ int16_t int2idx[10000]; /* x**(3/4) for x = 0..9999 */ } l3loop_t; typedef struct { - int32_t cos_l[18][36]; + int cos_l[18][36]; } mdct_t; typedef struct { int off[MAX_CHANNELS]; - int32_t fl[SBLIMIT][64]; - int32_t x[MAX_CHANNELS][HAN_SIZE]; + int fl[SBLIMIT][64]; + int x[MAX_CHANNELS][HAN_SIZE]; } subband_t; /* Side information */ @@ -150,8 +152,8 @@ typedef struct { } shine_psy_xmin_t; typedef struct { - int32_t l[MAX_GRANULES][MAX_CHANNELS][22]; /* [cb] */ - int32_t s[MAX_GRANULES][MAX_CHANNELS][13][3]; /* [window][cb] */ + int l[MAX_GRANULES][MAX_CHANNELS][22]; /* [cb] */ + int s[MAX_GRANULES][MAX_CHANNELS][13][3]; /* [window][cb] */ } shine_scalefac_t; @@ -167,8 +169,8 @@ typedef struct shine_global_flags { int16_t *buffer[MAX_CHANNELS]; double pe[MAX_CHANNELS][MAX_GRANULES]; int *l3_enc[MAX_CHANNELS][MAX_GRANULES]; //4% reduction in performance IRAM - int32_t l3_sb_sample[MAX_CHANNELS][MAX_GRANULES+1][18][SBLIMIT]; - int32_t *mdct_freq[MAX_CHANNELS][MAX_GRANULES]; //1% reduction in perormance IRAM + int l3_sb_sample[MAX_CHANNELS][MAX_GRANULES+1][18][SBLIMIT]; + int *mdct_freq[MAX_CHANNELS][MAX_GRANULES]; //1% reduction in perormance IRAM int ResvSize; int ResvMax; l3loop_t *l3loop; diff --git a/lib/libesp32_div/ESP32-HomeKit/.gitattributes b/lib/libesp32_div/ESP32-HomeKit/.gitattributes deleted file mode 100644 index dfe077042..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/lib/libesp32_div/ESP32-HomeKit/.gitignore b/lib/libesp32_div/ESP32-HomeKit/.gitignore deleted file mode 100644 index 259148fa1..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app diff --git a/lib/libesp32_div/ESP32-HomeKit/README.md b/lib/libesp32_div/ESP32-HomeKit/README.md deleted file mode 100644 index 923bd4a11..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Arduino-HomeKit-ESP -Arduino library version of espressif's official [esp-homekit-sdk](https://github.com/espressif/esp-homekit-sdk). - -Currently, only for ESP32 with hardware acceleration. ESP32-S2, ESP32-C3 and future IDF based chips are all on the way. - -Tested on my ESP32 board, works fine. - -The performance is awesome!!! - -The serial log is [here](https://raw.github.com/Mixiaoxiao/Arduino-HomeKit-ESP/master/extras/SerialLog.txt) - -## Setup code - -``111-11-111`` - -## Manual Installation - -Refer to the official guide: [Manual installation](https://www.arduino.cc/en/guide/libraries#toc5) -Note: this library will not publish the release version for Arduino IDE. - - -#### Manual Installation for Windows - -1. Click on _"Clone or Download"_ button, then click _"[Download ZIP](https://github.com/Mixiaoxiao/Arduino-HomeKit-ESP/archive/master.zip)"_ on the page. -1. Extract the contents of the downloaded zip file. -1. Rename the extracted folder to _"Arduino-HomeKit-ESP"_. -1. Move this folder to your libraries directory. (under windows: `C:\Users\\Documents\Arduino\libraries\`) -1. Restart your Arduino IDE. -1. Check out the examples. - - diff --git a/lib/libesp32_div/ESP32-HomeKit/SerialLog.txt b/lib/libesp32_div/ESP32-HomeKit/SerialLog.txt deleted file mode 100644 index 04a3862c7..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/SerialLog.txt +++ /dev/null @@ -1,43 +0,0 @@ -Boot OK -WiFi connecting... -............... -WiFi connected, IP: 192.168.6.134 -[ 1657] Keystore initialised -[ 1662] Accessory is not Paired with any controller -[ 1664] Database initialised. Accessory Device ID: 90:60:09:AB:F0:1D -[ 1664] HAP Initialization succeeded. Version : 4.0 -[ 1670] MFi auth not supported. Falling back to HAP_MFI_AUTH_NONE -[ 1675] Setup ID: ES32 -[ 1681] HAP Main Loop Started -[ 1684] mDNS initialised -[ 1684] Registering HomeKit web handlers -[ 1687] Announcing _hap._tcp mDNS service -[ 10032] ######## Starting Pair Setup ######## -[ 10032] Pair Setup M1 Received -[ 12073] Pair Setup M2 Successful -[ 12501] Pair Setup M3 Received -[ 14540] Using pair-setup without MFi. -[ 14540] Pair Setup M4 Successful -[ 14929] Pair Setup M5 Received -[ 15023] Pair Setup Successful for CF87DA6B-7078-44BB-AC04-27B6F2B26D37 -[ 15027] Updated state number to 11 -[ 15028] Cleaning Pair Setup Context -[ 15032] Re-announcing _hap._tcp mDNS service -[ 16205] ######## Starting Pair Verify ######## -[ 16205] Pair Verify M1 Received -[ 16327] Pair Verify M2 Successful -[ 16385] Pair Verify M3 Received -[ 16444] HomeKit Session active -[ 16445] Pair Verify Successful for CF87DA6B-7078-44BB-AC04-27B6F2B26D37 -[ 16781] Events Enabled for aid=1 iid=12 -[ 16781] Events Enabled for aid=1 iid=13 -[ 17080] Events Enabled for aid=1 iid=12 -[ 17080] Events Enabled for aid=1 iid=13 -[ 22311] ######## Starting Pair Verify ######## -[ 22311] Pair Verify M1 Received -[ 22435] Pair Verify M2 Successful -[ 22470] Pair Verify M3 Received -[ 22528] HomeKit Session active -[ 22528] Pair Verify Successful for CF87DA6B-7078-44BB-AC04-27B6F2B26D37 -[ 25069] Value Changed -[ 26605] Value Changed \ No newline at end of file diff --git a/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/HomeKit_IDF.ino b/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/HomeKit_IDF.ino deleted file mode 100644 index d0b7b6743..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/HomeKit_IDF.ino +++ /dev/null @@ -1,20 +0,0 @@ -#include "Arduino.h" -#include "wifi_info.h" -#include "hap.h" - -extern "C" void homekit_main(); - -void setup() { - Serial.begin(115200); - Serial.println("Boot OK"); - wifi_connect(); - // Useful apis: (see hap.h) - // hap_reset_to_factory(); - // hap_reset_homekit_data(); - // hap_reset_pairings(); - homekit_main(); - vTaskDelete(NULL); -} - -void loop() { -} diff --git a/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/homekit_main.c b/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/homekit_main.c deleted file mode 100644 index b9a14ce2c..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/homekit_main.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2018 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -/* HomeKit Smart Outlet Example -*/ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -//#include -//#include - -static const char *TAG = "HAP outlet"; - -#define SMART_OUTLET_TASK_PRIORITY 1 -#define SMART_OUTLET_TASK_STACKSIZE 4 * 1024 -#define SMART_OUTLET_TASK_NAME "hap_outlet" - -//#define OUTLET_IN_USE_GPIO GPIO_NUM_0 -#define OUTLET_IN_USE_GPIO -1 - -#define ESP_INTR_FLAG_DEFAULT 0 - -static xQueueHandle s_esp_evt_queue = NULL; -/** - * @brief the recover outlet in use gpio interrupt function - */ -static void IRAM_ATTR outlet_in_use_isr(void* arg) -{ - uint32_t gpio_num = (uint32_t) arg; - xQueueSendFromISR(s_esp_evt_queue, &gpio_num, NULL); -} - -/** - * Enable a GPIO Pin for Outlet in Use Detection - */ -static void outlet_in_use_key_init(uint32_t key_gpio_pin) -{ - gpio_config_t io_conf; - /* Interrupt for both the edges */ - io_conf.intr_type = GPIO_INTR_ANYEDGE; - /* Bit mask of the pins */ - io_conf.pin_bit_mask = 1 << key_gpio_pin; - /* Set as input mode */ - io_conf.mode = GPIO_MODE_INPUT; - /* Enable internal pull-up */ - io_conf.pull_up_en = 1; - /* Disable internal pull-down */ - io_conf.pull_down_en = 0; - /* Set the GPIO configuration */ - gpio_config(&io_conf); - - /* Install gpio isr service */ - gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); - /* Hook isr handler for specified gpio pin */ - gpio_isr_handler_add(key_gpio_pin, outlet_in_use_isr, (void*)key_gpio_pin); -} - -/** - * Initialize the Smart Outlet Hardware.Here, we just enebale the Outlet-In-Use detection. - */ -void smart_outlet_hardware_init(gpio_num_t gpio_num) -{ - s_esp_evt_queue = xQueueCreate(2, sizeof(uint32_t)); - if (s_esp_evt_queue != NULL) { - outlet_in_use_key_init(gpio_num); - } -} - -/* Mandatory identify routine for the accessory. - * In a real accessory, something like LED blink should be implemented - * got visual identification - */ -static int outlet_identify(hap_acc_t *ha) -{ - ESP_LOGI(TAG, "Accessory identified"); - return HAP_SUCCESS; -} - -/* A dummy callback for handling a write on the "On" characteristic of Outlet. - * In an actual accessory, this should control the hardware - */ -static int outlet_write(hap_write_data_t write_data[], int count, - void *serv_priv, void *write_priv) -{ - int i, ret = HAP_SUCCESS; - hap_write_data_t *write; - for (i = 0; i < count; i++) { - write = &write_data[i]; - if (!strcmp(hap_char_get_type_uuid(write->hc), HAP_CHAR_UUID_ON)) { - //ESP_LOGI(TAG, "Received Write. Outlet %s", write->val.b ? "On" : "Off"); - ESP_LOG_LEVEL(ESP_LOG_INFO, TAG, "Received Write. Outlet %s", write->val.b ? "On" : "Off"); - /* TODO: Control Actual Hardware */ - hap_char_update_val(write->hc, &(write->val)); - *(write->status) = HAP_STATUS_SUCCESS; - } else { - *(write->status) = HAP_STATUS_RES_ABSENT; - } - } - return ret; -} - -/*The main thread for handling the Smart Outlet Accessory */ -static void smart_outlet_thread_entry(void *p) -{ - hap_acc_t *accessory; - hap_serv_t *service; - - /* Initialize the HAP core */ - hap_init(HAP_TRANSPORT_WIFI); - - /* Initialise the mandatory parameters for Accessory which will be added as - * the mandatory services internally - */ - hap_acc_cfg_t cfg = { - .name = "Esp-Smart-Outlet", - .manufacturer = "Espressif", - .model = "EspSmartOutlet01", - .serial_num = "001122334455", - .fw_rev = "0.9.0", - .hw_rev = NULL, - .pv = "1.1.0", - .identify_routine = outlet_identify, - .cid = HAP_CID_OUTLET, - }; - /* Create accessory object */ - accessory = hap_acc_create(&cfg); - - /* Add a dummy Product Data */ - uint8_t product_data[] = {'E','S','P','3','2','H','A','P'}; - hap_acc_add_product_data(accessory, product_data, sizeof(product_data)); - - /* Create the Outlet Service. Include the "name" since this is a user visible service */ - service = hap_serv_outlet_create(false, false); - hap_serv_add_char(service, hap_char_name_create("My Smart Outlet")); - - /* Get pointer to the outlet in use characteristic which we need to monitor for state changes */ - hap_char_t *outlet_in_use = hap_serv_get_char_by_uuid(service, HAP_CHAR_UUID_OUTLET_IN_USE); - - /* Set the write callback for the service */ - hap_serv_set_write_cb(service, outlet_write); - - /* Add the Outlet Service to the Accessory Object */ - hap_acc_add_serv(accessory, service); - - /* Add the Accessory to the HomeKit Database */ - hap_add_accessory(accessory); - - /* Initialize the appliance specific hardware. This enables out-in-use detection */ - smart_outlet_hardware_init(OUTLET_IN_USE_GPIO); - - /* For production accessories, the setup code shouldn't be programmed on to - * the device. Instead, the setup info, derived from the setup code must - * be used. Use the factory_nvs_gen utility to generate this data and then - * flash it into the factory NVS partition. - * - * By default, the setup ID and setup info will be read from the factory_nvs - * Flash partition and so, is not required to set here explicitly. - * - * However, for testing purpose, this can be overridden by using hap_set_setup_code() - * and hap_set_setup_id() APIs, as has been done here. - */ - hap_set_setup_code("111-11-111"); - hap_set_setup_id("ES32"); -#ifdef CONFIG_EXAMPLE_USE_HARDCODED_SETUP_CODE - /* Unique Setup code of the format xxx-xx-xxx. Default: 111-22-333 */ - hap_set_setup_code(CONFIG_EXAMPLE_SETUP_CODE); - /* Unique four character Setup Id. Default: ES32 */ - hap_set_setup_id(CONFIG_EXAMPLE_SETUP_ID); -#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING - app_hap_setup_payload(CONFIG_EXAMPLE_SETUP_CODE, CONFIG_EXAMPLE_SETUP_ID, true, cfg.cid); -#else - app_hap_setup_payload(CONFIG_EXAMPLE_SETUP_CODE, CONFIG_EXAMPLE_SETUP_ID, false, cfg.cid); -#endif -#endif - - /* Enable Hardware MFi authentication (applicable only for MFi variant of SDK) */ - hap_enable_mfi_auth(HAP_MFI_AUTH_HW); - - /* Initialize Wi-Fi */ - //app_wifi_init(); - - /* After all the initializations are done, start the HAP core */ - hap_start(); - /* Start Wi-Fi */ - //app_wifi_start(portMAX_DELAY); - - uint32_t io_num = OUTLET_IN_USE_GPIO; - hap_val_t appliance_value = { - .b = true, - }; - /* Listen for Outlet-In-Use state change events. Other read/write functionality will be handled - * by the HAP Core. - * When the Outlet in Use GPIO goes low, it means Outlet is not in use. - * When the Outlet in Use GPIO goes high, it means Outlet is in use. - * Applications can define own logic as per their hardware. - */ - while (1) { - if (xQueueReceive(s_esp_evt_queue, &io_num, portMAX_DELAY) == pdFALSE) { - ESP_LOGI(TAG, "Outlet-In-Use trigger FAIL"); - } else { - appliance_value.b = gpio_get_level(io_num); - /* If any state change is detected, update the Outlet In Use characteristic value */ - hap_char_update_val(outlet_in_use, &appliance_value); - ESP_LOGI(TAG, "Outlet-In-Use triggered [%d]", appliance_value.b); - } - } -} - -void homekit_main() -{ - /* Create the application thread */ - xTaskCreate(smart_outlet_thread_entry, SMART_OUTLET_TASK_NAME, SMART_OUTLET_TASK_STACKSIZE, - NULL, SMART_OUTLET_TASK_PRIORITY, NULL); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/wifi_info.h b/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/wifi_info.h deleted file mode 100644 index 39e2c5320..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/examples/HomeKit_IDF/wifi_info.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * wifi_info.h - * - * Created on: 2020-05-15 - * Author: Mixiaoxiao (Wang Bin) - */ - -#ifndef WIFI_INFO_H_ -#define WIFI_INFO_H_ - -#if defined(ESP8266) -#include -#elif defined(ESP32) -#include -#endif - -const char *ssid = "your-ssid"; -const char *password = "your-password"; - -void wifi_connect() { - WiFi.persistent(false); - WiFi.mode(WIFI_STA); - WiFi.setAutoReconnect(true); - WiFi.begin(ssid, password); - Serial.println("WiFi connecting..."); - while (!WiFi.isConnected()) { - delay(100); - Serial.print("."); - } - Serial.print("\n"); - Serial.printf("WiFi connected, IP: %s\n", WiFi.localIP().toString().c_str()); -} - -#endif /* WIFI_INFO_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/library.json b/lib/libesp32_div/ESP32-HomeKit/library.json deleted file mode 100644 index 83cb22489..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/library.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name":"ESP32-HomeKit", - "version": "1.0.0", - "description":"Apple HomeKit for ESP32", - "keywords":"HomeKit", - "repository": { - "type": "git", - "url": "" - }, - "frameworks": "arduino", - "platforms": "espressif32" -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/_esp_hap_config.h b/lib/libesp32_div/ESP32-HomeKit/src/_esp_hap_config.h deleted file mode 100755 index ea5421b62..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/_esp_hap_config.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * _esp_hap_config.h - * - * Created on: 2020-11-23 - * Author: Mixiaoxiao - */ - -#ifndef ESP_HAP_CONFIG_H_ -#define ESP_HAP_CONFIG_H_ - -#define HAP_SDK_VER "4.0" -#define MFI_VER HAP_SDK_VER - -#define CONFIG_HAP_HTTP_STACK_SIZE 12288 -#define CONFIG_HAP_HTTP_SERVER_PORT 5556 // 80 for normal webserver -#define CONFIG_HAP_HTTP_CONTROL_PORT 32859 -#define CONFIG_HAP_HTTP_MAX_OPEN_SOCKETS 5 // 6 -#define CONFIG_HAP_HTTP_MAX_URI_HANDLERS 16 - -#endif /* ESP_HAP_CONFIG_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/base36.h b/lib/libesp32_div/ESP32-HomeKit/src/base36.h deleted file mode 100644 index 332e38794..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/base36.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Base36 PostgreSQL input/output function for bigint - * - * Author: Dimitri Fontaine - * - * Taken from https://github.com/dimitri/base36/blob/master/base36.c - */ - -#include -#include - -#define BASE36_LENGTH 13 - -typedef long long int base36; - -static int base36_digits[36] = - {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', - 'U', 'V', 'W', 'X', 'Y', 'Z' - }; - -static base36 base36_powers[BASE36_LENGTH] = - { -1ULL, - 36ULL, - 1296ULL, - 46656ULL, - 1679616ULL, - 60466176ULL, - 2176782336ULL, - 78364164096ULL, - 2821109907456ULL, - 101559956668416ULL, - 3656158440062976ULL, - 131621703842267136ULL, - 4738381338321616896ULL - }; - -static inline -char *base36_to_str(base36 c) -{ - int i, d, p = 0; - base36 m = c; - bool discard = true; - char *str = calloc((BASE36_LENGTH + 1), sizeof(char)); - - for(i=BASE36_LENGTH-1; i>=0; i--) - { - d = m / base36_powers[i]; - m = m - base36_powers[i] * d; - - discard = discard && (d == 0 && i >0); - - if( !discard ) - str[p++] = base36_digits[d]; - } - - return str; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/byte_convert.c b/lib/libesp32_div/ESP32-HomeKit/src/byte_convert.c deleted file mode 100644 index 57decd165..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/byte_convert.c +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include -#include - -/* Functions to convert Little Endian byte stream to - * uint16, uint32 and uint64 - */ -uint16_t get_u16_le(const void *val_ptr) -{ - const uint8_t *p = (const uint8_t *)val_ptr; - uint16_t val; - - val = (uint16_t)p[0]; - val |= (uint16_t)p[1] << 8; - - return val; -} - -uint32_t get_u32_le(const void *val_ptr) -{ - const uint8_t *p = (const uint8_t *)val_ptr; - uint32_t val; - - val = (uint32_t)p[0]; - val |= (uint32_t)p[1] << 8; - val |= (uint32_t)p[2] << 16; - val |= (uint32_t)p[3] << 24; - - return val; -} - -uint64_t get_u64_le(const void *val_ptr) -{ - const uint8_t *p = (const uint8_t *)val_ptr; - uint64_t val; - - val = (uint64_t)p[0]; - val |= (uint64_t)p[1] << 8; - val |= (uint64_t)p[2] << 16; - val |= (uint64_t)p[3] << 24; - val |= (uint64_t)p[4] << 32; - val |= (uint64_t)p[5] << 40; - val |= (uint64_t)p[6] << 48; - val |= (uint64_t)p[7] << 56; - - return val; -} - -/* Functions to convert Big Endian byte stream to - * uint16, uint32 and uint64 - */ -uint16_t get_u16_be(const void *val_ptr) -{ - const uint8_t *p = (const uint8_t *)val_ptr; - uint16_t val; - - val = (uint16_t)p[0] << 8; - val |= (uint16_t)p[1]; - - return val; -} - -uint32_t get_u32_be(const void *val_ptr) -{ - const uint8_t *p = (const uint8_t *)val_ptr; - uint32_t val; - - val = (uint32_t)p[0] << 24; - val |= (uint32_t)p[1] << 16; - val |= (uint32_t)p[2] << 8; - val |= (uint32_t)p[3]; - - return val; -} - -uint64_t get_u64_be(const void *val_ptr) -{ - const uint8_t *p = (const uint8_t *)val_ptr; - uint64_t val; - - val = (uint64_t)p[0] << 56; - val |= (uint64_t)p[1] << 48; - val |= (uint64_t)p[2] << 40; - val |= (uint64_t)p[3] << 32; - val |= (uint64_t)p[4] << 24; - val |= (uint64_t)p[5] << 16; - val |= (uint64_t)p[6] << 8; - val |= (uint64_t)p[7]; - - return val; -} - -/* Functions to convert uint16, uint32 and uint64 - * to Little Endian - */ -void put_u16_le(void *val_ptr, const uint16_t val) -{ - uint8_t *p = (uint8_t *)val_ptr; - - p[0] = (uint8_t)val & 0xff; - p[1] = (uint8_t)(val >> 8) & 0xff; -} - -void put_u32_le(void *val_ptr, const uint32_t val) -{ - uint8_t *p = (uint8_t *)val_ptr; - - p[0] = (uint8_t)val & 0xff; - p[1] = (uint8_t)(val >> 8) & 0xff; - p[2] = (uint8_t)(val >> 16) & 0xff; - p[3] = (uint8_t)(val >> 24) & 0xff; -} - -void put_u64_le(void *val_ptr, const uint64_t val) -{ - uint8_t *p = (uint8_t *)val_ptr; - - p[0] = (uint8_t)val & 0xff; - p[1] = (uint8_t)(val >> 8) & 0xff; - p[2] = (uint8_t)(val >> 16) & 0xff; - p[3] = (uint8_t)(val >> 24) & 0xff; - p[4] = (uint8_t)(val >> 32) & 0xff; - p[5] = (uint8_t)(val >> 40) & 0xff; - p[6] = (uint8_t)(val >> 48) & 0xff; - p[7] = (uint8_t)(val >> 56) & 0xff; -} - -/* Functions to convert uint16, uint32 and uint64 - * to Big Endian - */ -void put_u16_be(void *val_ptr, const uint16_t val) -{ - uint8_t *p = (uint8_t *)val_ptr; - - p[0] = (uint8_t)(val >> 8) & 0xff; - p[1] = (uint8_t)val & 0xff; -} - -void put_u32_be(void *val_ptr, const uint32_t val) -{ - uint8_t *p = (uint8_t *)val_ptr; - - p[0] = (uint8_t)((val >> 24) & 0xff); - p[1] = (uint8_t)((val >> 16) & 0xff); - p[2] = (uint8_t)((val >> 8) & 0xff); - p[3] = (uint8_t)(val & 0xff); -} - -void put_u64_be(void *val_ptr, const uint64_t val) -{ - uint8_t *p = (uint8_t *)val_ptr; - - p[0] = (uint8_t)(val >> 56) & 0xff; - p[1] = (uint8_t)(val >> 48) & 0xff; - p[2] = (uint8_t)(val >> 40) & 0xff; - p[3] = (uint8_t)(val >> 32) & 0xff; - p[4] = (uint8_t)(val >> 24) & 0xff; - p[5] = (uint8_t)(val >> 16) & 0xff; - p[6] = (uint8_t)(val >> 8) & 0xff; - p[7] = (uint8_t)val & 0xff; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/byte_convert.h b/lib/libesp32_div/ESP32-HomeKit/src/byte_convert.h deleted file mode 100644 index 0c91ed8d2..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/byte_convert.h +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -/** - * \file byte_convert.h - * \brief Conversion between integers and byte streams - * - * This module offers APIs to convert 16bit, 32bit and 64 bit unsigned integers - * into Little/Big Endian byte streams - */ -#ifndef _BYTE_CONVERT_H -#define _BYTE_CONVERT_H - -#include - -/** Little Endian to uint16 Conversion - * Get a uint16 integer from a little Endian byte stream - * - * \param[in] val_ptr Pointer to the 2 byte stream - * - * \return The converted uint16 integer - */ -uint16_t get_u16_le(const void *val_ptr); - -/** Little Endian to uint32 Conversion - * Get a uint32 integer from a little Endian byte stream - * - * \param[in] val_ptr Pointer to the 4 byte stream - * - * \return The converted uint32 integer - */ -uint32_t get_u32_le(const void *val_ptr); - -/** Little Endian to uint64 Conversion - * Get a uint64 integer from a little Endian byte stream - * - * \param[in] val_ptr Pointer to the 8 byte stream - * - * \return The converted uint32 integer - */ -uint64_t get_u64_le(const void *val_ptr); - -/** Big Endian to uint16 Conversion - * Get a uint16 integer from a Big Endian byte stream - * - * \param[in] val_ptr Pointer to the 2 byte stream - * - * \return The converted uint16 integer - */ -uint16_t get_u16_be(const void *val_ptr); - -/** Big Endian to uint32 Conversion - * Get a uint32 integer from a Big Endian byte stream - * - * \param[in] val_ptr Pointer to the 4 byte stream - * - * \return The converted uint32 integer - */ -uint32_t get_u32_be(const void *val_ptr); - -/** Big Endian to uint64 Conversion - * Get a uint64 integer from a Big Endian byte stream - * - * \param[in] val_ptr Pointer to the 8 byte stream - * - * \return The converted uint16 integer - */ -uint64_t get_u64_be(const void *val_ptr); - -/** Uint16 to Little Endian Conversion - * - * Put a uint16 integer into a Little Endian byte stream - * - * \param[out] Pointer to a 2 byte stream that will be filled with the value - * - * \param[in] The uint16 integer - */ -void put_u16_le(void *val_ptr, const uint16_t val); - -/** Uint32 to Little Endian Conversion - * - * Put a uint32 integer into a Little Endian byte stream - * - * \param[out] Pointer to a 4 byte stream that will be filled with the value - * - * \param[in] The uint32 integer - */ -void put_u32_le(void *val_ptr, const uint32_t val); - -/** Uint64 to Little Endian Conversion - * - * Put a uint64 integer into a Little Endian byte stream - * - * \param[out] Pointer to a 8 byte stream that will be filled with the value - * - * \param[in] The uint64 integer - */ -void put_u64_le(void *val_ptr, const uint64_t val); - -/** Uint16 to Big Endian Conversion - * - * Put a uint16 integer into a Big Endian byte stream - * - * \param[out] Pointer to a 2 byte stream that will be filled with the value - * - * \param[in] The uint16 integer - */ -void put_u16_be(void *val_ptr, const uint16_t val); - -/** Uint32 to Big Endian Conversion - * - * Put a uint32 integer into a Big Endian byte stream - * - * \param[out] Pointer to a 4 byte stream that will be filled with the value - * - * \param[in] The uint32 integer - */ -void put_u32_be(void *val_ptr, const uint32_t val); - -/** Uint64 to Big Endian Conversion - * - * Put a uint64 integer into a Big Endian byte stream - * - * \param[out] Pointer to a 8 byte stream that will be filled with the value - * - * \param[in] The uint64 integer - */ -void put_u64_be(void *val_ptr, const uint64_t val); -#endif /* _BYTE_CONVERT_H */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_acc.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_acc.c deleted file mode 100644 index b42314afc..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_acc.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Primary Accessory Pointer */ -static __hap_acc_t *primary_acc; - -/*****************************************************************************************************/ - -hap_acc_t *hap_get_first_acc() -{ - return (hap_acc_t *)primary_acc; -} - -hap_acc_t *hap_acc_get_next(hap_acc_t *ha) -{ - if (!ha) - return NULL; - - __hap_acc_t *_ha = (__hap_acc_t *)ha; - return (hap_acc_t *)_ha->next; -} -/* Service write callback to handle "Identify" */ -static int hap_acc_info_write(hap_write_data_t write_data[], int count, - void *serv_priv, void *write_priv) -{ - int i; - __hap_char_t *_hc; - for (i = 0; i < count; i++) { - _hc = (__hap_char_t *)write_data[i].hc; - if (!strcmp(_hc->type_uuid, HAP_CHAR_UUID_IDENTIFY)) { - __hap_acc_t *_ha = (__hap_acc_t *)serv_priv; - if (_ha) { - _ha->identify_routine((hap_acc_t *)_ha); - *(write_data->status) = HAP_STATUS_SUCCESS; - continue; - } - } - *(write_data->status) = HAP_STATUS_VAL_INVALID; - } - return HAP_SUCCESS; -} - -/** - * @brief HAP create an accessory - */ -hap_acc_t *hap_acc_create(hap_acc_cfg_t *acc_cfg) -{ - static bool first = true; - int ret = 0; - __hap_acc_t *_ha = hap_platform_memory_calloc(1, sizeof(__hap_acc_t)); - if (!_ha) { - return NULL; - } - - _ha->identify_routine = acc_cfg->identify_routine; - _ha->next_iid = 1; - - /* Add the Accessory Information Service internally */ - hap_serv_t *hs = hap_serv_create("3E"); - if (!hs) { - goto acc_create_fail; - } - ret = hap_serv_add_char(hs, hap_char_bool_create(HAP_CHAR_UUID_IDENTIFY, HAP_CHAR_PERM_PW, false)); - ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_MANUFACTURER, HAP_CHAR_PERM_PR, acc_cfg->manufacturer)); - ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_MODEL, HAP_CHAR_PERM_PR, acc_cfg->model)); - ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_NAME, HAP_CHAR_PERM_PR, acc_cfg->name)); - ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_SERIAL_NUMBER, HAP_CHAR_PERM_PR, acc_cfg->serial_num)); - ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_FIRMWARE_REVISION, HAP_CHAR_PERM_PR, acc_cfg->fw_rev)); - if (acc_cfg->hw_rev) { - ret |= hap_serv_add_char(hs, hap_char_string_create(HAP_CHAR_UUID_HARDWARE_REVISION, HAP_CHAR_PERM_PR, acc_cfg->hw_rev)); - } - - if (ret) { - goto acc_create_fail; - } - - hap_serv_set_write_cb(hs, hap_acc_info_write); - hap_serv_set_priv(hs,(void *)_ha); - hap_acc_add_serv((hap_acc_t *)_ha, hs); - - if (first) { - /* Add the Procol Information Service Internally */ - hs = hap_serv_create("A2"); - if (!hs) { - goto acc_create_fail; - } - ret = hap_serv_add_char(hs, hap_char_string_create("37", HAP_CHAR_PERM_PR, "1.1.0")); - - if (ret) { - goto acc_create_fail; - } - hap_acc_add_serv((hap_acc_t *)_ha, hs); - hap_priv.cid = acc_cfg->cid; - first = false; - } - - return (hap_acc_t *)_ha; - -acc_create_fail: - hap_acc_delete((hap_acc_t *)_ha); - return NULL; -} - -int hap_acc_add_accessory_flags(hap_acc_t *ha, uint32_t flags) -{ - if (!ha) { - return HAP_FAIL; - } - hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION); - if (!hs) { - return HAP_FAIL; - } - return hap_serv_add_char(hs, hap_char_accessory_flags_create(flags)); - -} - -int hap_acc_update_accessory_flags(hap_acc_t *ha, uint32_t flags) -{ - if (!ha) { - return HAP_FAIL; - } - hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION); - if (!hs) { - return HAP_FAIL; - } - hap_char_t *hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_ACCESSORY_FLAGS); - if (!hc) { - return HAP_FAIL; - } - hap_val_t val = { - .u = flags, - }; - return hap_char_update_val(hc, &val); -} - -int hap_acc_add_product_data(hap_acc_t *ha, uint8_t *product_data, size_t data_size) -{ - if (!ha) { - return HAP_FAIL; - } - hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION); - if (!hs) { - return HAP_FAIL; - } - if (data_size != 8) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Product data size is not 8"); - } - uint8_t *buf = calloc(1, data_size); - if (!buf) { - return HAP_FAIL; - } - memcpy(buf, product_data, data_size); - hap_data_val_t data_val = { - .buf = buf, - .buflen = data_size - }; - return hap_serv_add_char(hs, hap_char_product_data_create(&data_val)); -} - -const hap_val_t *hap_get_product_data() -{ - hap_char_t *acc_info = hap_acc_get_serv_by_uuid(hap_get_first_acc(), HAP_SERV_UUID_ACCESSORY_INFORMATION); - if (acc_info) { - hap_char_t *product_data = hap_serv_get_char_by_uuid(acc_info, HAP_CHAR_UUID_PRODUCT_DATA); - if (product_data) { - return hap_char_get_val(product_data); - } - } - return NULL; -} -/** - * @brief check if accessory's AID matches the target AID - */ -bool hap_check_aid(__hap_acc_t *accessory, int32_t aid) -{ - return accessory->aid == aid ? true : false; -} - -hap_serv_t *hap_acc_get_first_serv(hap_acc_t *ha) -{ - return ((__hap_acc_t *)ha)->servs; -} -/** - * @brief get target service by it's type description string - */ -hap_serv_t *hap_acc_get_serv_by_iid(hap_acc_t *ha, int32_t iid) -{ - if (!ha) - return NULL; - - hap_serv_t *hs; - for (hs = hap_acc_get_first_serv(ha); hs; hs = hap_serv_get_next(hs)) { - if (((__hap_serv_t *)hs)->iid == iid) - return hs; - } - return NULL; -} - -hap_serv_t *hap_acc_get_serv_by_uuid(hap_acc_t *ha, const char *uuid) -{ - if (!ha) - return NULL; - - hap_serv_t *hs; - for (hs = hap_acc_get_first_serv(ha); hs; hs = hap_serv_get_next(hs)) { - if (!strcmp(((__hap_serv_t *)hs)->type_uuid, uuid)) - return hs; - } - return NULL; -} - -/** - * @brief get target characteristics by it's IID - */ -hap_char_t *hap_acc_get_char_by_iid(hap_acc_t *ha, int32_t iid) -{ - if (!ha) - return NULL; - hap_serv_t *hs; - hap_char_t *hc; - for (hs = hap_acc_get_first_serv(ha); hs; hs = hap_serv_get_next(hs)) { - hc = hap_serv_get_char_by_iid(hs, iid); - if (hc) - return hc; - } - return NULL; -} - -int hap_acc_get_info(hap_acc_cfg_t *acc_cfg) -{ - ESP_MFI_ASSERT(acc_cfg); - hap_acc_t *ha = hap_get_first_acc(); - - ESP_MFI_ASSERT(ha); - - hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION); - - hap_char_t *hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_NAME); - acc_cfg->name = ((__hap_char_t *)hc)->val.s; - - hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_MODEL); - acc_cfg->model = ((__hap_char_t *)hc)->val.s; - - hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_MANUFACTURER); - acc_cfg->manufacturer = ((__hap_char_t *)hc)->val.s; - - hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_SERIAL_NUMBER); - acc_cfg->serial_num = ((__hap_char_t *)hc)->val.s; - - hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_FIRMWARE_REVISION); - acc_cfg->fw_rev = ((__hap_char_t *)hc)->val.s; - - hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_HARDWARE_REVISION); - if (hc) { - acc_cfg->hw_rev = ((__hap_char_t *)hc)->val.s; - } else { - acc_cfg->hw_rev = NULL; - } - - hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_PROTOCOL_INFORMATION); - - hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_VERSION); - acc_cfg->pv = ((__hap_char_t *)hc)->val.s; - - return 0; -} - -/** - * @brief add a characteristics to a service - */ -int hap_acc_add_serv(hap_acc_t *ha, hap_serv_t *hs) -{ - ESP_MFI_ASSERT(ha); - ESP_MFI_ASSERT(hs); - __hap_acc_t *_ha = (__hap_acc_t *)ha; - __hap_serv_t *_hs = (__hap_serv_t *)hs; - - if (_hs->parent) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Service already added"); - return HAP_FAIL; - } - - /* If the accessory has no services, add this as the first */ - if (!_ha->servs) { - _ha->servs = hs; - } else { - /* Else loop through the services to get to the last one, - * and add this at the end - */ - __hap_serv_t *temp = (__hap_serv_t *)_ha->servs; - while (temp->next_serv) - temp = (__hap_serv_t *)temp->next_serv; - temp->next_serv = hs; - } - _hs->iid = _ha->next_iid++; - __hap_char_t *_hc = (__hap_char_t *)_hs->chars; - while(_hc) { - _hc->iid = _ha->next_iid++; - _hc = (__hap_char_t *)_hc->next_char; - } - _hs->parent = ha; - return 0; -} - -static void hap_add_acc_to_list(__hap_acc_t *primary, __hap_acc_t *new) -{ - __hap_acc_t *cur = primary; - while (cur->next) { - cur = cur->next; - } - cur->next = new; -} - -static void hap_remove_acc_from_list(__hap_acc_t *primary, __hap_acc_t *old) -{ - __hap_acc_t *cur = primary; - while (cur->next != old) { - cur = cur->next; - } - cur->next = cur->next->next; -} - -#define HAP_BRIDGE_KEYSTORE "hap_bridge" - -int hap_get_unique_aid(const char *id) -{ - if (!id) { - return -1; - } - int aid = 0; - size_t aid_size = sizeof(aid); - if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, id, (uint8_t *)&aid, &aid_size) != HAP_SUCCESS) { - aid = hap_get_next_aid(); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Assigning aid = %d for Bridged accessory %s", aid, id); - hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, id, (uint8_t *)&aid, sizeof(aid)); - } else { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Using aid = %d for Bridged accessory %s", aid, id); - } - return aid; -} - -/** - * @brief HAP add accessory to HAP kernel - */ -void hap_add_accessory(hap_acc_t *ha) -{ - if (!ha) { - return; - } - if (primary_acc) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Primary Accessory already added. Use hap_add_bridged_accessory() instead"); - return; - } - __hap_acc_t *_ha = (__hap_acc_t *)ha; - _ha->aid = 1; - primary_acc = _ha; - if (hap_priv.cfg.unique_param >= UNIQUE_NAME) { - char name[74]; - uint8_t eth_mac[6]; - esp_wifi_get_mac(WIFI_IF_STA, eth_mac); - hap_serv_t *hs = hap_acc_get_serv_by_uuid(ha, HAP_SERV_UUID_ACCESSORY_INFORMATION); - hap_char_t *hc = hap_serv_get_char_by_uuid(hs, HAP_CHAR_UUID_NAME); - snprintf(name, sizeof(name), "%s-%02X%02X%02X", ((__hap_char_t *)hc)->val.s, - eth_mac[3], eth_mac[4], eth_mac[5]); - hap_platform_memory_free(((__hap_char_t *)hc)->val.s); - ((__hap_char_t *)hc)->val.s = strdup(name); - } - hap_acc_get_info(&hap_priv.primary_acc); -} - -void hap_add_bridged_accessory(hap_acc_t *ha, int aid) -{ - if (!ha) { - return; - } - __hap_acc_t *_ha = (__hap_acc_t *)ha; - if (aid) { - _ha->aid = aid; - } else { - _ha->aid = hap_get_next_aid(); - } - - hap_add_acc_to_list(primary_acc, _ha); - if (!hap_priv.cfg.disable_config_num_update) { - hap_update_config_number(); - } -} - -void hap_remove_bridged_accessory(hap_acc_t *ha) -{ - if ((__hap_acc_t *)ha == primary_acc) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Cannot remove primary accessory"); - } else { - if (ha) { - hap_remove_acc_from_list(primary_acc, (__hap_acc_t *)ha); - if (!hap_priv.cfg.disable_config_num_update) { - hap_update_config_number(); - } - } - - } -} -/** - * @brief HAP delete target accessory - */ -void hap_acc_delete(hap_acc_t *ha) -{ - /* Returning success even if pointer is NULL, because it means - * that the accessory is absent and as good as deleted - */ - if (!ha) - return; - __hap_acc_t *_ha = (__hap_acc_t *)ha; - __hap_serv_t *_hs = (__hap_serv_t *)_ha->servs; - while (_hs) { - _ha->servs = _hs->next_serv; - hap_serv_delete((hap_serv_t *)_hs); - _hs = (__hap_serv_t *)_ha->servs; - } - hap_platform_memory_free(_ha); -} - -/** - * @brief HAP get target accessory AID - */ -uint32_t hap_acc_get_aid(hap_acc_t *ha) -{ - ESP_MFI_ASSERT(ha); - __hap_acc_t *_ha = (__hap_acc_t *)ha; - - return _ha->aid; -} - -/** - * @brief delete all accessories - */ -void hap_delete_all_accessories(void) -{ - __hap_acc_t *next, *ha = primary_acc; - while (ha) { - next = ha->next; - hap_acc_delete((hap_acc_t *)ha); - ha = next; - } -} -/** - * @brief get target accessory by AID - */ -hap_acc_t *hap_acc_get_by_aid(int32_t aid) -{ - hap_acc_t *ha; - for (ha = hap_get_first_acc(); ha; ha = hap_acc_get_next(ha)) { - if (((__hap_acc_t *)ha)->aid == aid) { - return ha; - } - } - return NULL; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_acc.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_acc.h deleted file mode 100644 index 2783f9c3c..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_acc.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _HAP_ACC_H_ -#define _HAP_ACC_H_ - -#include -#include - -#ifdef __cplusplus -extern "C"{ -#endif - -typedef struct esp_mfi_accessory { - struct esp_mfi_accessory *next; - uint32_t aid; /* accessory AID */ - hap_serv_t *servs; /* service list */ - bool power_off; - uint32_t next_iid; - hap_identify_routine_t identify_routine; -} __hap_acc_t; -hap_char_t *hap_acc_get_char_by_iid(hap_acc_t *ha, int32_t iid); -hap_acc_t *hap_acc_get_by_aid(int32_t aid); -int hap_acc_get_info(hap_acc_cfg_t *acc_cfg); -const hap_val_t *hap_get_product_data(); -#ifdef __cplusplus -} -#endif - -#endif /* _HAP_ACC_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_bct.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_bct.c deleted file mode 100644 index ff9083a59..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_bct.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static char *new_name; - -void hap_bct_change_name(const char *name) -{ - if (new_name) { - hap_platform_memory_free(new_name); - } - new_name = strdup(name); - hap_send_event(HAP_INTERNAL_EVENT_BCT_CHANGE_NAME); -} - -void hap_bct_hot_plug() -{ - hap_send_event(HAP_INTERNAL_EVENT_BCT_HOT_PLUG); -} - -void hap_handle_bct_change_name() -{ - if (!new_name) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No BCT name specified"); - return; - } else { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Changing BCT Name to %s", new_name); - } - if (hap_mdns_serv_name_change(&hap_priv.hap_mdns_handle, new_name) != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to change BCT name"); - } - hap_platform_memory_free(new_name); - new_name = NULL; -} - -void hap_handle_hot_plug() -{ - esp_wifi_stop(); - vTaskDelay((10 * 1000) / portTICK_PERIOD_MS); /* Wait for 10 seconds */ - esp_wifi_start(); - esp_wifi_connect(); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_bct_priv.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_bct_priv.h deleted file mode 100644 index 70df56ce9..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_bct_priv.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_BCT_PRIV_H_ -#define _HAP_BCT_PRIV_H_ -void hap_handle_bct_change_name(); -void hap_handle_hot_plug(); -#endif /* _HAP_BCT_PRIV_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.c deleted file mode 100644 index 6b31814af..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include -#include "esp_mfi_debug.h" - -#include -#include -#include -#include -#include - -static QueueHandle_t hap_event_queue; - -/** - * @brief get characteristics's value - */ -hap_val_t *esp_mfi_characteristics_get_value(__hap_char_t *_hc) -{ - return &_hc->val; -} - -/** - * @brief check if characteristics has the specific permission - */ -bool hap_char_has_permission(__hap_char_t *_hc, uint16_t permission) -{ - return _hc->permission & permission ? true : false; -} - -/** - * @brief compute the mod of a and b: a % b - */ -static double esp_mfi_fmod(double a, double b) -{ - if (a < 1e-06 || b < 1e-06) - return 0; - - while (!((long long)a) || !((long long)b)) { - a *= 10.0; - b *= 10.0; - } - - return fmod(a, b); -} - -int hap_event_queue_init() -{ - hap_event_queue = xQueueCreate( hap_priv.cfg.max_event_notif_chars, - sizeof(hap_char_t *) ); - if (hap_event_queue) { - return HAP_SUCCESS; - } else { - return HAP_FAIL; - } -} - -hap_char_t * hap_get_pending_notif_char() -{ - hap_char_t *hc; - if (xQueueReceive(hap_event_queue, &hc, 0) != pdTRUE) { - return NULL; - } - return hc; -} - -static int hap_queue_event(hap_char_t *hc) -{ - int ret; - if (!hap_event_queue) { - return HAP_FAIL; - } - if (xPortInIsrContext() == pdTRUE) { - ret = xQueueSendFromISR(hap_event_queue, &hc, NULL); - } else { - ret = xQueueSend(hap_event_queue, &hc, 0); - } - if (ret == pdTRUE) { - hap_send_event(HAP_INTERNAL_EVENT_TRIGGER_NOTIF); - return HAP_SUCCESS; - } - return HAP_FAIL; -} - - -/** - * @brief check if characteristics value is at the range - */ -int hap_char_check_val_constraints(__hap_char_t *_hc, hap_val_t *val) -{ - if (!_hc->constraint_flags) - return HAP_SUCCESS; - - if (_hc->format == HAP_CHAR_FORMAT_INT) { - int value = val->i; - int remainder; - - if (value > _hc->max.i - || value < _hc->min.i) - return HAP_FAIL; - - if (!_hc->step.i) - return HAP_SUCCESS; - - remainder = (value - _hc->min.i) % _hc->step.i; - if (remainder) - return HAP_FAIL; - } else if (_hc->format == HAP_CHAR_FORMAT_FLOAT) { - float value = val->f; - - if (value > _hc->max.f - || value < _hc->min.f) - return HAP_FAIL; -# if 0 - /* Check for step value for floats has a high chance of failure, - * because of precision issues. Hence, better to skip it. - */ - double remainder; - if (_hc->step.f == 0.0) - return HAP_SUCCESS; - - remainder = esp_mfi_fmod(value - _hc->min.f, _hc->step.f); - if (remainder != 0.0) - return HAP_FAIL; -#endif - } else if (_hc->format == HAP_CHAR_FORMAT_UINT8 - || _hc->format == HAP_CHAR_FORMAT_UINT16 - || _hc->format == HAP_CHAR_FORMAT_UINT32) { - uint32_t value = val->u; - uint32_t remainder; - - - if (value > _hc->max.u - || value < _hc->min.u) - return HAP_FAIL; - - if (!_hc->step.u) - return HAP_SUCCESS; - - remainder = (value - _hc->min.u) % _hc->step.u; - if (remainder) - return HAP_FAIL; - } else if (_hc->format == HAP_CHAR_FORMAT_UINT64) { - /* TODO: Add support. Currently, there is no particular 64-bit characteristic */ - } - - return HAP_SUCCESS; -} - -/** - * @brief user update characteristics value, preparing for notification - */ -int hap_char_update_val(hap_char_t *hc, hap_val_t *val) -{ - if (!hc || !val) { - return HAP_FAIL; - } - __hap_char_t *_hc = (__hap_char_t *)hc; - _hc->update_called = true; - if (hap_char_check_val_constraints(_hc, val) != HAP_SUCCESS) - return HAP_FAIL; - /* Boolean to track if the value has changed. - * This will be later used to decide if an event notification - * is required or not. If the new and old values are same, - * there is no need of a notification - */ - bool value_changed = false; - - switch (_hc->format) { - case HAP_CHAR_FORMAT_BOOL: - if (_hc->val.b != val->b) { - _hc->val.b = val->b; - value_changed = true; - } - break; - case HAP_CHAR_FORMAT_INT: - case HAP_CHAR_FORMAT_UINT8: - case HAP_CHAR_FORMAT_UINT16: - case HAP_CHAR_FORMAT_UINT32: - if (_hc->val.i != val->i) { - _hc->val.i = val->i; - value_changed = true; - } - break; - case HAP_CHAR_FORMAT_FLOAT: - if (_hc->val.f != val->f) { - _hc->val.f = val->f; - value_changed = true; - } - break; - case HAP_CHAR_FORMAT_STRING: - /* Not checking all combinations to find if value has changed, - * since generally we do not expect dynamic string values - * - * Eg. - * Both (old and new) values being NULL - * Old value NULL, New non-NULL - * Old value non-NULL, new NULL - */ - if (_hc->val.s && val->s && !strcmp(_hc->val.s, val->s)) - value_changed = false; - else - value_changed = true; - - if (_hc->val.s) { - hap_platform_memory_free(_hc->val.s); - _hc->val.s = NULL; - } - - if (val->s) { - _hc->val.s = strdup(val->s); - if (!_hc->val.s) - return HAP_FAIL; - } - break; - case HAP_CHAR_FORMAT_DATA: - case HAP_CHAR_FORMAT_TLV8: { - _hc->val.d.buf = val->d.buf; - _hc->val.d.buflen = val->d.buflen; - value_changed = true; - } - break; - default: - break; - } - if (value_changed || (_hc->permission & HAP_CHAR_PERM_SPECIAL_READ)) { - ESP_MFI_DEBUG_INTR(ESP_MFI_DEBUG_INFO, "Value Changed"); - hap_queue_event(hc); - } else { - /* If there is no value change, reset the owner flag here itself, as no notification - * is being sent anyways. In the absence of this, if there is a GET /characteristics - * followed by some value change from hardware, the owner_ctrl stays assigned to a - * stale value, and so the controller misses a notification. - */ - _hc->owner_ctrl = 0; - } - return HAP_SUCCESS; -} - -const hap_val_t *hap_char_get_val(hap_char_t *hc) -{ - if (!hc) - return NULL; - return &((__hap_char_t *)hc)->val; -} - -/** - * @brief Get the minimum value of characteristic - */ -const hap_val_t *hap_char_get_min_val(hap_char_t *hc) -{ - if (hc) { - if(((__hap_char_t *)hc)->constraint_flags & HAP_CHAR_MIN_FLAG) { - return &((__hap_char_t *)hc)->min; - } - } - return NULL; -} - -/** - * @brief Get the maximum value of characteristic - */ -const hap_val_t *hap_char_get_max_val(hap_char_t *hc) -{ - if (hc) { - if(((__hap_char_t *)hc)->constraint_flags & HAP_CHAR_MAX_FLAG || ((__hap_char_t *)hc)->constraint_flags & HAP_CHAR_MAXLEN_FLAG) { - return &((__hap_char_t *)hc)->max; - } - } - return NULL; -} - -/** - * @brief Get the step value of characteristic - */ -const hap_val_t *hap_char_get_step_val(hap_char_t *hc) -{ - if (hc) { - if (((__hap_char_t *)hc)->constraint_flags & HAP_CHAR_STEP_FLAG) { - return &((__hap_char_t *)hc)->step; - } - } - return NULL; -} - -/** - * @brief HAP create a characteristics - */ -static hap_char_t *hap_char_create(const char *type_uuid, uint32_t permission, hap_char_format_t format, hap_val_t val) -{ - __hap_char_t *new_ch; - - ESP_MFI_ASSERT(type_uuid); - - if (HAP_CHAR_FORMAT_STRING == format && val.s) { - if (strlen(val.s) > HAP_CHAR_STRING_MAX_LEN) - return NULL; - } - - new_ch = hap_platform_memory_calloc(1, sizeof(__hap_char_t)); - if (!new_ch) { - return NULL; - } - - new_ch->val = val; - new_ch->type_uuid = type_uuid; - new_ch->format = format; - new_ch->permission = permission; - - return (hap_char_t *) new_ch; -} - -hap_char_t *hap_char_bool_create(const char *type_uuid, uint16_t perms, bool b) -{ - hap_val_t val = {.b = b}; - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_BOOL, val); -} -hap_char_t *hap_char_uint8_create(const char *type_uuid, uint16_t perms, uint8_t u8) -{ - hap_val_t val = {.u = u8}; - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT8, val); -} -hap_char_t *hap_char_uint16_create(const char *type_uuid, uint16_t perms, uint16_t u16) -{ - hap_val_t val = {.u = u16}; - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT16, val); -} -hap_char_t *hap_char_uint32_create(const char *type_uuid, uint16_t perms, uint32_t u32) -{ - hap_val_t val = {.u = u32}; - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT32, val); -} -hap_char_t *hap_char_uint64_create(const char *type_uuid, uint16_t perms, uint64_t u64) -{ - hap_val_t val = {.i64 = u64}; - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_UINT64, val); -} -hap_char_t *hap_char_int_create(const char *type_uuid, uint16_t perms, int i32) -{ - hap_val_t val = {.i = i32}; - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_INT, val); -} -hap_char_t *hap_char_float_create(const char *type_uuid, uint16_t perms, float f) -{ - hap_val_t val = {.f = f}; - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_FLOAT, val); -} -hap_char_t *hap_char_string_create(const char *type_uuid, uint16_t perms, const char *s) -{ - hap_val_t val; - if (s) - val.s = strdup(s); - else - val.s = NULL; - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_STRING, val); -} - -hap_char_t *hap_char_data_create(const char *type_uuid, uint16_t perms, hap_data_val_t *d) -{ - hap_val_t val = {0}; - if (d) { - val.d = *d; - } - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_DATA, val); -} - -hap_char_t *hap_char_tlv8_create(const char *type_uuid, uint16_t perms, hap_tlv8_val_t *t) -{ - hap_val_t val = {0}; - if (t) { - val.t = *t; - } - return hap_char_create(type_uuid, perms, HAP_CHAR_FORMAT_TLV8, val); -} - -/** - * @brief HAP get target characteristics IID - */ -uint32_t hap_char_get_iid(hap_char_t *hc) -{ - ESP_MFI_ASSERT(hc); - __hap_char_t *tmp = (__hap_char_t *)hc; - - return tmp->iid; -} - -/** - * @brief HAP get target characteristics type UUID - */ -const char * hap_char_get_type_uuid(hap_char_t *hc) -{ - ESP_MFI_ASSERT(hc); - __hap_char_t *tmp = (__hap_char_t *)hc; - - return tmp->type_uuid; -} - -uint16_t hap_char_get_perm(hap_char_t *hc) -{ - if (!hc) - return 0; - - __hap_char_t *tmp = (__hap_char_t *)hc; - return tmp->permission; -} - -hap_char_format_t hap_char_get_format(hap_char_t *hc) -{ - if (!hc) - return 0; - - __hap_char_t *tmp = (__hap_char_t *)hc; - return tmp->format; -} - -/** - * @brief HAP delete target characteristics - */ -void hap_char_delete(hap_char_t *hc) -{ - ESP_MFI_ASSERT(hc); - __hap_char_t *_hc = (__hap_char_t *)hc; - if (_hc->format == HAP_CHAR_FORMAT_STRING) { - if (_hc->val.s) { - hap_platform_memory_free(_hc->val.s); - } - } - if (_hc->valid_vals) { - hap_platform_memory_free(_hc->valid_vals); - } - if (_hc->valid_vals_range) { - hap_platform_memory_free(_hc->valid_vals_range); - } - hap_platform_memory_free(_hc); -} - -/** - * @brief HAP configure the characteristics's value description - */ -void hap_char_int_set_constraints(hap_char_t *hc, int min, int max, int step) -{ - ESP_MFI_ASSERT(hc); - __hap_char_t *tmp = (__hap_char_t *)hc; - tmp->min.i = min; - tmp->max.i = max; - tmp->step.i = step; - if (step) { - tmp->constraint_flags |= (HAP_CHAR_MIN_FLAG | HAP_CHAR_MAX_FLAG | HAP_CHAR_STEP_FLAG); - } else { - tmp->constraint_flags |= (HAP_CHAR_MIN_FLAG | HAP_CHAR_MAX_FLAG); - } -} -void hap_char_float_set_constraints(hap_char_t *hc, float min, float max, float step) -{ - ESP_MFI_ASSERT(hc); - __hap_char_t *tmp = (__hap_char_t *)hc; - tmp->min.f = min; - tmp->max.f = max; - tmp->step.f = step; - if (step) { - tmp->constraint_flags |= (HAP_CHAR_MIN_FLAG | HAP_CHAR_MAX_FLAG | HAP_CHAR_STEP_FLAG); - } else { - tmp->constraint_flags |= (HAP_CHAR_MIN_FLAG | HAP_CHAR_MAX_FLAG); - } -} - -void hap_char_string_set_maxlen(hap_char_t *hc, int maxlen) -{ - ESP_MFI_ASSERT(hc); - __hap_char_t *tmp = (__hap_char_t *)hc; - if (maxlen > HAP_CHAR_STRING_MAX_LEN) { - maxlen = HAP_CHAR_STRING_MAX_LEN; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_WARN, "Characteristic string length larger than maximum value(%d), falling back to the maximum value.", HAP_CHAR_STRING_MAX_LEN); - } - tmp->max.i = maxlen; - tmp->constraint_flags |= HAP_CHAR_MAXLEN_FLAG; -} - -void hap_char_add_description(hap_char_t *hc, const char *description) -{ - ESP_MFI_ASSERT(hc); - __hap_char_t *tmp = (__hap_char_t *)hc; - tmp->description = (char *)description; -} -void hap_char_add_unit(hap_char_t *hc, const char *unit) -{ - ESP_MFI_ASSERT(hc); - __hap_char_t *tmp = (__hap_char_t *)hc; - tmp->unit = (char *)unit; -} -hap_char_t *hap_char_get_next(hap_char_t *hc) -{ - return ((__hap_char_t *)hc)->next_char; -} - -hap_serv_t *hap_char_get_parent(hap_char_t *hc) -{ - return ((__hap_char_t *)hc)->parent; - -} - -#define set_bit(val, index) ((val) |= (1 << index)) -#define reset_bit(val, index) ((val) &= ~(1 << index)) -void hap_char_manage_notification(hap_char_t *hc, int index, bool ev) -{ - __hap_char_t *_hc = (__hap_char_t *)hc; - if (ev) - set_bit(_hc->ev_ctrls, index); - else - reset_bit(_hc->ev_ctrls, index); -} - -bool hap_char_is_ctrl_subscribed(hap_char_t *hc, int index) -{ - __hap_char_t *_hc = (__hap_char_t *)hc; - return (_hc->ev_ctrls & (1 << index)) ? true : false; -} - -void hap_char_set_owner_ctrl(hap_char_t *hc, int index) -{ - __hap_char_t *_hc = (__hap_char_t *)hc; - _hc->owner_ctrl = 0; - set_bit(_hc->owner_ctrl, index); -} - -bool hap_char_is_ctrl_owner(hap_char_t *hc, int index) -{ - __hap_char_t *_hc = (__hap_char_t *)hc; - return (_hc->owner_ctrl & (1 << index)) ? true : false; -} - -void hap_char_set_iid(hap_char_t *hc, int32_t iid) -{ - if (hc) { - ((__hap_char_t *)hc)->iid = iid; - } -} - -void hap_disable_all_char_notif(int index) -{ - /* Just loop through all characteristic objects and reset the - * bit indicating event notifications. This is the simplest way - */ - hap_acc_t *ha; - hap_serv_t *hs; - hap_char_t *hc; - for (ha = hap_get_first_acc(); ha; ha = hap_acc_get_next(ha)) { - for (hs = hap_acc_get_first_serv(ha); hs; hs = hap_serv_get_next(hs)) { - for (hc = hap_serv_get_first_char(hs); hc; hc = hap_char_get_next(hc)) { - reset_bit(((__hap_char_t *)hc)->ev_ctrls, index); - } - } - } -} - -void hap_char_add_valid_vals(hap_char_t *hc, const uint8_t *valid_vals, size_t valid_val_cnt) -{ - if (!hc) - return; - __hap_char_t *_hc = (__hap_char_t *)hc; - _hc->valid_vals = hap_platform_memory_malloc(valid_val_cnt); - if (_hc->valid_vals) { - memcpy(_hc->valid_vals, valid_vals, valid_val_cnt); - _hc->valid_vals_cnt = valid_val_cnt; - } -} - -void hap_char_add_valid_vals_range(hap_char_t *hc, uint8_t start_val, uint8_t end_val) -{ - if (!hc) - return; - __hap_char_t *_hc = (__hap_char_t *)hc; - _hc->valid_vals_range = hap_platform_memory_malloc(sizeof(uint8_t)); - if (_hc->valid_vals_range) { - _hc->valid_vals_range[0] = start_val; - _hc->valid_vals_range[1] = end_val; - } -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.h deleted file mode 100644 index d24fcf8b6..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_char.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _HAP_CHAR_H_ -#define _HAP_CHAR_H_ - -#include -#include -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif -#define HAP_CHAR_MIN_FLAG (1 << 0) -#define HAP_CHAR_MAX_FLAG (1 << 1) -#define HAP_CHAR_STEP_FLAG (1 << 2) -#define HAP_CHAR_MAXLEN_FLAG (1 << 3) -#define HAP_CHAR_MAXDATALEN_FLAG (1 << 4) - -/** - * @brief characteristics object information - */ -typedef struct { - uint32_t iid; /* Characteristic instance ID */ - const char *type_uuid; /* Apple's characteristic UUID */ - uint16_t permission; /* Characteristic permission */ - hap_char_format_t format; /* data type of the value */ - hap_val_t val; - bool ev; /* check if characteristics supports event */ - char *description; /* characteristics's description */ - char *unit; - - /* Characteristics's father subsystem */ - hap_serv_t *parent; - - uint8_t constraint_flags; - - hap_val_t max; /* maximum value, maxlen, max data len*/ - hap_val_t min; /* minimum value */ - hap_val_t step; /* step value */ - - hap_char_t *next_char; - /* Bitmap to indicate which controllers have enabled notifications - */ - uint16_t ev_ctrls; - - /* Bitmap indicating the last controller that modified the value. - * No notification should be sent to the owner - */ - uint16_t owner_ctrl; - - /* Pointer to a valid values range. It will be a 2 byte array, if set from application */ - uint8_t *valid_vals_range; - /* Since a list of valid values can have any length, using a pointer here, - * which will be allocated if valid values are set for a characteristic - */ - uint8_t *valid_vals; - size_t valid_vals_cnt; - bool update_called; -} __hap_char_t; - -void hap_char_manage_notification(hap_char_t *hc, int index, bool ev); -bool hap_char_is_ctrl_subscribed(hap_char_t *hc, int index); -void hap_char_set_owner_ctrl(hap_char_t *hc, int index); -bool hap_char_is_ctrl_owner(hap_char_t *hc, int index); -void hap_disable_all_char_notif(int index); -int hap_char_check_val_constraints(__hap_char_t *_hc, hap_val_t *val); -int hap_event_queue_init(); -hap_char_t * hap_get_pending_notif_char(); -#ifdef __cplusplus -} -#endif - -#endif /* _HAP_CHAR_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_controllers.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_controllers.c deleted file mode 100644 index 4b2b16eb2..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_controllers.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include - -#include -#include -#include -#include - -#define HAP_KEYSTORE_NAMESPACE_CTRL "hap_ctrl" - -int hap_controllers_init() -{ - memset(hap_priv.controllers, 0, sizeof(hap_priv.controllers)); - char index_str[4]; - uint8_t i; - size_t info_size; - bool acc_paired = false; - for (i = 0; i < HAP_MAX_CONTROLLERS; i++) { - snprintf(index_str, sizeof(index_str), "%d", i); - info_size = sizeof(hap_ctrl_info_t); - if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_CTRL, index_str, - (uint8_t *)&hap_priv.controllers[i].info, &info_size) == HAP_SUCCESS) { - if (info_size == sizeof(hap_ctrl_info_t)) { - hap_priv.controllers[i].index = i; - hap_priv.controllers[i].valid = true; - acc_paired = true; - } - } - } - if (acc_paired) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Accessory is Paired with atleast one controller"); - } else { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Accessory is not Paired with any controller"); - } - return HAP_SUCCESS; -} - -hap_ctrl_data_t *hap_controller_get_empty_loc() -{ - int i; - for (i = 0; i < HAP_MAX_CONTROLLERS; i++) { - if (!hap_priv.controllers[i].valid) { - hap_priv.controllers[i].index = i; - return &hap_priv.controllers[i]; - } - } - return NULL; -} - -int hap_get_paired_controller_count() -{ - int i, cnt = 0; - for (i = 0; i < HAP_MAX_CONTROLLERS; i++) { - if (hap_priv.controllers[i].valid) { - cnt++; - } - } - return cnt; -} - -bool is_accessory_paired() -{ - int i; - for (i = 0; i < HAP_MAX_CONTROLLERS; i++) { - if (hap_priv.controllers[i].valid) - return true; - } - return false; -} - -bool is_admin_paired() -{ - int i; - for (i = 0; i < HAP_MAX_CONTROLLERS; i++) { - if (hap_priv.controllers[i].valid && hap_priv.controllers[i].info.perms) - return true; - } - return false; -} - -int hap_controller_save(hap_ctrl_data_t *ctrl_data) -{ - ctrl_data->valid = true; - char index_str[4]; - snprintf(index_str, sizeof(index_str), "%d", ctrl_data->index); - int ret = hap_keystore_set(HAP_KEYSTORE_NAMESPACE_CTRL, index_str, - (const uint8_t *)&ctrl_data->info, (size_t)sizeof(hap_ctrl_info_t)); - - if (ret != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to store controller %d", ctrl_data->index); - return HAP_FAIL; - } - hap_report_event(HAP_EVENT_CTRL_PAIRED, ctrl_data->info.id, sizeof(ctrl_data->info.id)); - return HAP_SUCCESS; -} - -void hap_controller_remove(hap_ctrl_data_t *ctrl_data) -{ - if (!ctrl_data) - return; - char index_str[4]; - snprintf(index_str, sizeof(index_str), "%d", ctrl_data->index); - char id[HAP_CTRL_ID_LEN]; - strncpy(id, ctrl_data->info.id, sizeof(id)); - hap_keystore_delete(HAP_KEYSTORE_NAMESPACE_CTRL, index_str); - memset(ctrl_data, 0, sizeof(hap_ctrl_data_t)); - hap_report_event(HAP_EVENT_CTRL_UNPAIRED, id, sizeof(id)); -} - -hap_ctrl_data_t *hap_get_controller(char *ctrl_id) -{ - int i; - for (i = 0; i < HAP_MAX_CONTROLLERS; i++) { - if (hap_priv.controllers[i].valid - && (!strcmp(hap_priv.controllers[i].info.id, ctrl_id))) - return &hap_priv.controllers[i]; - } - return NULL; -} - -void hap_erase_controller_info() -{ - hap_keystore_delete_namespace(HAP_KEYSTORE_NAMESPACE_CTRL); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_controllers.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_controllers.h deleted file mode 100644 index 1a341ddeb..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_controllers.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_CONTROLLERS_H_ -#define _HAP_CONTROLLERS_H_ - -#include -#include - -#define HAP_MAX_CONTROLLERS 16 -#define HAP_CTRL_ID_LEN 64 -#define ED_KEY_LEN 32 - - -typedef struct { - char id[HAP_CTRL_ID_LEN]; - uint8_t ltpk[ED_KEY_LEN]; - uint8_t perms; -} __attribute__((packed)) hap_ctrl_info_t; - -typedef struct { - hap_ctrl_info_t info; - /* If "valid" is false, it means that the entry is invalid, - * irrespective of the values of other members, and can be - * used to store new controller info - */ - bool valid; - /* Index is used just for better managing the keystore data */ - uint8_t index; -} hap_ctrl_data_t; - -int hap_controllers_init(); -bool is_accessory_paired(); -bool is_admin_paired(); -hap_ctrl_data_t *hap_controller_get_empty_loc(); -int hap_controller_save(hap_ctrl_data_t *ctrl_data); -void hap_controller_remove(hap_ctrl_data_t *ctrl_data); -hap_ctrl_data_t *hap_get_controller(char *ctrl_id); -void hap_erase_controller_info(); - -#endif /* _HAP_CONTROLLERS_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_database.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_database.c deleted file mode 100644 index dec7e80f8..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_database.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define HAP_KEY_ACC_ID "acc_id" -#define HAP_KEY_LTSKA "ltska" -#define HAP_KEY_LTPKA "ltpka" -#define HAP_KEY_CONFIG_NUM "config_num" -#define HAP_KEY_FW_REV "fw_rev" -#define HAP_KEY_CUR_AID "cur_aid" -#define HAP_KEY_STATE_NUM "state_num" - -#define HAP_KEY_SETUP_ID "setup_id" -#define HAP_KEY_SETUP_SALT "setup_salt" -#define HAP_KEY_SETUP_VERIFIER "setup_verifier" - -#define HAP_LOOP_STACK (4 * 1024) -#define HAP_MAIN_THREAD_PRIORITY 7 -#define HAP_MAX_NOTIF_CHARS 8 -#define HAP_SOCK_RECV_TIMEOUT 10 -#define HAP_SOCK_SEND_TIMEOUT 10 - -hap_priv_t hap_priv = { - .cfg = { - .task_stack_size = HAP_LOOP_STACK, - .task_priority = HAP_MAIN_THREAD_PRIORITY, - .max_event_notif_chars = HAP_MAX_NOTIF_CHARS, - .unique_param = UNIQUE_SSID, - .recv_timeout = HAP_SOCK_RECV_TIMEOUT, - .send_timeout = HAP_SOCK_SEND_TIMEOUT, - .sw_token_max_len = HAP_SW_TOKEN_MAX_LEN, - } -}; - -static void hap_save_config_number() -{ - - hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_CONFIG_NUM, - (uint8_t *)&hap_priv.config_num, sizeof(hap_priv.config_num)); -} - -static void hap_get_config_number() -{ - size_t config_num_len = sizeof(hap_priv.config_num); - if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_CONFIG_NUM, - (uint8_t *)&hap_priv.config_num, &config_num_len) != HAP_SUCCESS) { - hap_priv.config_num = 1; - hap_save_config_number(); - } - if (hap_priv.config_num > 65535) { - hap_priv.config_num = 1; - hap_save_config_number(); - } -} - -void hap_increment_and_save_config_num() -{ - hap_priv.config_num++; - if (hap_priv.config_num > 65535) { - hap_priv.config_num = 1; - } - hap_save_config_number(); -} - - -static void hap_save_state_number() -{ - hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_STATE_NUM, - (uint8_t *)&hap_priv.state_num, sizeof(hap_priv.state_num)); -} - -void hap_increment_and_save_state_num() -{ - if (is_accessory_paired()) { - hap_priv.state_num++; - /* If value becomes 0 after incrementing, it means that it has wrapped around. - * So, reset to 1 - */ - if (hap_priv.state_num == 0) { - hap_priv.state_num = 1; - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Updated state number to %d", hap_priv.state_num); - hap_save_state_number(); - } -} - -static void hap_init_state_number() -{ - size_t state_num_len = sizeof(hap_priv.state_num); - if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_STATE_NUM, - (uint8_t *)&hap_priv.state_num, &state_num_len) != HAP_SUCCESS) { - /* If state number is not found, initialise with 1 and store. - */ - hap_priv.state_num = 1; - hap_save_state_number(); - } else { - hap_increment_and_save_state_num(); - } -} - -static void hap_save_cur_aid() -{ - hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_CUR_AID, - (uint8_t *)&hap_priv.cur_aid, sizeof(hap_priv.cur_aid)); -} - -static void hap_get_cur_aid() -{ - size_t aid_len = sizeof(hap_priv.cur_aid); - if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_CUR_AID, - (uint8_t *)&hap_priv.cur_aid, &aid_len) != HAP_SUCCESS) { - /* AID = 1 is reserved for Primary Accessory. So, we set the initial - * value to 1, so that the bridged accessories get assigned aid from - * 2 onwards - */ - hap_priv.cur_aid = 1; - hap_save_cur_aid(); - } -} - -static int hap_get_setup_id() -{ - /* Read setup id from NVS, only if it is not already set from the accessory code */ - if (!strlen(hap_priv.setup_id)) { - size_t setup_id_len = sizeof(hap_priv.setup_id); - if (hap_factory_keystore_get(HAP_FACTORY_NAMESPACE_HAP_SETUP, HAP_KEY_SETUP_ID, - (uint8_t *)hap_priv.setup_id, &setup_id_len) != HAP_SUCCESS) { - return HAP_FAIL; - } - } - return HAP_SUCCESS; -} - -static int hap_get_setup_info() -{ - /* If the setup code has been set directly, no need to check for setup info */ - if (hap_priv.setup_code) { - return HAP_SUCCESS; - } - /* If the setup info has been set externally, directly from the accessory code, - * no need to check in the NVS - */ - if (!hap_priv.setup_info) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Getting setup info from factory NVS"); - hap_priv.setup_info = hap_platform_memory_calloc(1, sizeof(hap_setup_info_t)); - if (!hap_priv.setup_info) - return HAP_FAIL; - size_t salt_len = sizeof(hap_priv.setup_info->salt); - size_t verifier_len = sizeof(hap_priv.setup_info->verifier); - int ret = hap_factory_keystore_get(HAP_FACTORY_NAMESPACE_HAP_SETUP, HAP_KEY_SETUP_SALT, - hap_priv.setup_info->salt, &salt_len); - ret |= hap_factory_keystore_get(HAP_FACTORY_NAMESPACE_HAP_SETUP, HAP_KEY_SETUP_VERIFIER, - hap_priv.setup_info->verifier, &verifier_len); - if (ret != HAP_SUCCESS) { - hap_platform_memory_free(hap_priv.setup_info); - hap_priv.setup_info = NULL; - return HAP_FAIL; - } - } - return HAP_SUCCESS; -} - -static void hap_check_fw_version() -{ - char fw_rev[64] = {0}; - size_t fw_rev_len = sizeof(fw_rev); - /* Check if the firmware revision is stored in NVS */ - if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_FW_REV, - (uint8_t *)fw_rev, &fw_rev_len) == HAP_SUCCESS) { - /* If the firmware revision is found, compare with the current revision. - * If it is the same, no need to do anything. So, just return - */ - if (strncmp(fw_rev, hap_priv.primary_acc.fw_rev, sizeof(fw_rev)) == 0) { - return; - } else { - /* If there is a version mismatch, it means that the firmware was upgraded. - * Update config number in that case - */ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "FW Update detected. Incrementing config number"); - hap_increment_and_save_config_num(); - } - } - /* Save the new firmare revision to NVS */ - hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_FW_REV, - (uint8_t *)hap_priv.primary_acc.fw_rev, - strlen(hap_priv.primary_acc.fw_rev)); -} - -int hap_acc_setup_init() -{ - if (hap_get_setup_id() != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Setup ID absent"); - return HAP_FAIL; - } else { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Setup ID: %s", hap_priv.setup_id); - } - - if (hap_get_setup_info() != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Setup Info absent"); - return HAP_FAIL; - } - - uint8_t digest[MFI_SHA512_SIZE] = {0}; - esp_mfi_sha_ctx_t ctx = 0; - ctx = esp_mfi_sha512_new(); - if (!ctx) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Out of Memory"); - return HAP_FAIL; - } - /* Compute setup hash by taking a SHA512 hash of the setup id and device id */ - esp_mfi_sha512_init(ctx); - esp_mfi_sha512_update(ctx, (const uint8_t *)hap_priv.setup_id, strlen(hap_priv.setup_id)); - esp_mfi_sha512_update(ctx, (const uint8_t *)hap_priv.acc_id, strlen(hap_priv.acc_id)); - esp_mfi_sha512_final(ctx, digest); - /* Copy only the first 4 bytes as the setup hash */ - memcpy(hap_priv.setup_hash, digest, SETUP_HASH_LEN); - esp_mfi_sha512_free(ctx); - - int hash_size = sizeof(hap_priv.setup_hash_str); - esp_mfi_base64_encode((const char *)hap_priv.setup_hash, SETUP_HASH_LEN, - hap_priv.setup_hash_str, hash_size, &hash_size); - - hap_check_fw_version(); - - return HAP_SUCCESS; -} - -int hap_database_init(void) -{ - uint8_t id[6]; - size_t val_size = sizeof(id); - if (hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_ACC_ID, id, &val_size) == HAP_SUCCESS) { - val_size = sizeof(hap_priv.ltska); - hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_LTSKA, hap_priv.ltska, &val_size); - val_size = sizeof(hap_priv.ltpka); - hap_keystore_get(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_LTPKA, hap_priv.ltpka, &val_size); - } else { - /* If the accessory ID is not found in keystore, create and store a new random ID */ - esp_mfi_get_random(id, sizeof(id)); - hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_ACC_ID, id, sizeof(id)); - /* Also create a new ED25519 key pair */ - esp_mfi_get_random(hap_priv.ltska, sizeof(hap_priv.ltska)); - crypto_sign_ed25519_keypair(hap_priv.ltpka, hap_priv.ltska); - hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_LTSKA, hap_priv.ltska, sizeof(hap_priv.ltska)); - hap_keystore_set(HAP_KEYSTORE_NAMESPACE_HAPMAIN, HAP_KEY_LTPKA, hap_priv.ltpka, sizeof(hap_priv.ltpka)); - } - - memcpy(hap_priv.raw_acc_id, id, sizeof(hap_priv.raw_acc_id)); - snprintf(hap_priv.acc_id, sizeof(hap_priv.acc_id), "%02X:%02X:%02X:%02X:%02X:%02X", - id[0], id[1], id[2], id[3], id[4], id[5]); - - hap_controllers_init(); - hap_get_config_number(); - hap_get_cur_aid(); - hap_init_state_number(); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Database initialised. Accessory Device ID: %s", hap_priv.acc_id); - return HAP_SUCCESS; -} - -char *hap_get_acc_id() -{ - return hap_priv.acc_id; -} - -int hap_get_next_aid(char *id) -{ - hap_priv.cur_aid++; - hap_save_cur_aid(); - return hap_priv.cur_aid; -} - -void hap_erase_accessory_info() -{ - hap_keystore_delete_namespace(HAP_KEYSTORE_NAMESPACE_HAPMAIN); -} - -void hap_configure_unique_param(hap_unique_param_t param) -{ - hap_priv.cfg.unique_param = param; -} - -int hap_get_config(hap_cfg_t *cfg) -{ - if (!cfg) { - return HAP_FAIL; - } - *cfg = hap_priv.cfg; - return HAP_SUCCESS; -} - -int hap_set_config(const hap_cfg_t *cfg) -{ - if (!cfg) { - return HAP_FAIL; - } - hap_priv.cfg = *cfg; - return HAP_SUCCESS; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_database.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_database.h deleted file mode 100644 index 22da74c8e..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_database.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_DATABASE_H_ -#define _HAP_DATABASE_H_ - -#include -#include -#include -#include -#include -#include - -#define HAP_KEYSTORE_NAMESPACE_HAPMAIN "hap_main" -#define HAP_FACTORY_NAMESPACE_HAP_SETUP "hap_setup" - -#define HAP_MAX_SESSIONS 8 -#define SETUP_ID_LEN 4 -#define SETUP_HASH_LEN 4 - -#define HAP_ACC_ID_LEN 18 /* AA:BB:CC:XX:YY:ZZ\0 */ -#define ED_KEY_LEN 32 -#define HAP_SW_TOKEN_MAX_LEN 1200 - - -typedef struct { - hap_acc_cfg_t primary_acc; - uint32_t config_num; - uint32_t cur_aid; - uint8_t raw_acc_id[6]; - char acc_id[HAP_ACC_ID_LEN]; - char setup_id[SETUP_ID_LEN + 1]; - uint8_t setup_hash[SETUP_HASH_LEN]; - char setup_hash_str[SETUP_HASH_LEN * 2 + 1]; - uint8_t ltska[ED_KEY_LEN]; - uint8_t ltpka[ED_KEY_LEN]; - hap_cid_t cid; - hap_ctrl_data_t controllers[HAP_MAX_CONTROLLERS]; - hap_secure_session_t *sessions[HAP_MAX_SESSIONS]; - uint8_t pair_attempts; - hap_mdns_handle_t wac_mdns_handle; - hap_mdns_handle_t hap_mdns_handle; - hap_setup_info_t *setup_info; - char *setup_code; - char *ssid; - char *password; - hap_software_token_info_t *token_info; - uint8_t features; - hap_event_handler_t hap_event_handler; - char *softap_ssid; - void (*ext_nw_prov_start)(void *data, const char *name); - void (*ext_nw_prov_stop)(void *data); - void *ext_nw_prov_data; - hap_cfg_t cfg; - hap_transport_t transport; - uint32_t pairing_flags; - httpd_handle_t server; - uint8_t *product_data; - uint16_t state_num; - bool disconnected_event_sent; - hap_mfi_auth_type_t auth_type; -} hap_priv_t; - -extern hap_priv_t hap_priv; -int hap_database_init(void); -char *hap_get_acc_id(); -int hap_get_next_aid(); -int hap_acc_setup_init(); -void hap_erase_accessory_info(); -void hap_increment_and_save_config_num(); -void hap_increment_and_save_state_num(); -#endif /* _HAP_DATABASE_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.c deleted file mode 100644 index 357db53d7..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.c +++ /dev/null @@ -1,1630 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include //??? - -#ifdef ESP_MFI_DEBUG_ENABLE -#define ESP_MFI_DEBUG_PLAIN(fmt, ...) \ - if (http_debug) { \ - printf("\e[1;35m" fmt "\e[0m", ##__VA_ARGS__); \ - } -#else /* ESP_MFI_DEBUG_ENABLE */ -#define ESP_MFI_DEBUG_PLAIN(fmt, ...) -#endif /* ESP_MFI_DEBUG_ENABLE */ - -static bool http_debug; - -int hap_http_session_not_authorized(httpd_req_t *req) -{ - char buf[50]; - httpd_resp_set_status(req, "470 Connection Authorization Required"); - httpd_resp_set_type(req, "application/hap+json"); - snprintf(buf, sizeof(buf),"{\"status\":-70401}"); - httpd_resp_send(req, buf, strlen(buf)); - return HAP_SUCCESS; - -} - -int hap_httpd_get_data(httpd_req_t *req, char *buffer, int len) -{ - int read_len = 0; - while (read_len < len) { - int tmp_len = httpd_req_recv(req, buffer + read_len, len - read_len); - if (tmp_len <= 0) { - return read_len; - } - read_len += tmp_len; - } - return read_len; -} - -static int hap_http_pair_setup_handler(httpd_req_t *req) -{ - uint8_t buf[1200]; - int ret, ret1, outlen; - void *ctx = (hap_secure_session_t *)hap_platform_httpd_get_sess_ctx(req); - int fd = httpd_req_to_sockfd(req); - ESP_MFI_DEBUG_PLAIN("Socket fd: %d; HTTP Request %s %s\n", httpd_req_to_sockfd(req), hap_platform_httpd_get_req_method(req), hap_platform_httpd_get_req_uri(req)); - if (!ctx) { - if (hap_pair_setup_context_init(fd, &ctx, buf, sizeof(buf), &outlen) == HAP_SUCCESS) { - hap_platform_httpd_set_sess_ctx(req, ctx, hap_pair_setup_ctx_clean, true); - } else { - httpd_resp_set_type(req, "application/pairing+tlv8"); - httpd_resp_send(req, (char *)buf, outlen); - return HAP_SUCCESS; - } - } - int data_len = httpd_req_recv(req, (char *)buf, sizeof(buf)); - ret = hap_pair_setup_process(&ctx, buf, data_len, sizeof(buf), &outlen); - httpd_resp_set_type(req, "application/pairing+tlv8"); - ret1 = httpd_resp_send(req, (char *)buf, outlen); - if (ret != HAP_SUCCESS) { - hap_pair_setup_ctx_clean(ctx); - ctx = NULL; - } else { - /* A pair verify function is called here, because for Software Token Authentication, - * secure session keys are generated at the step M4 of Pair Setup, and there onwards, - * the behavior is like a pair verified session. - */ - if (hap_pair_verify_get_state(ctx) == STATE_VERIFIED) { - /* Saving socket fd since it will later be required for - * event notifications. - */ - ((hap_secure_session_t *)ctx)->conn_identifier = fd; - hap_platform_httpd_set_sess_ctx(req, ctx, hap_free_session, true); - httpd_sess_set_send_override(hap_priv.server, fd, hap_httpd_send); - httpd_sess_set_recv_override(hap_priv.server, fd, hap_httpd_recv); - } - } - /* Context will be NULL, either if there was an error and a cleanup was required, - * or if the pair_setup_process cleared it after successful pairing. - * For both the cases, we will set the sess_ctx and free_ctx to NULL - */ - if (!ctx) { - hap_platform_httpd_set_sess_ctx(req, NULL, NULL, true); - } - return ret1; -} -static struct httpd_uri hap_pair_setup = { - .uri = "/pair-setup", - .method = HTTP_POST, - .handler = hap_http_pair_setup_handler, -}; - -static int hap_http_pair_verify_handler(httpd_req_t *req) -{ - uint8_t buf[512]; - int ret, outlen; - void *ctx = hap_platform_httpd_get_sess_ctx(req); - ESP_MFI_DEBUG_PLAIN("Socket fd: %d; HTTP Request %s %s\n", httpd_req_to_sockfd(req), hap_platform_httpd_get_req_method(req), hap_platform_httpd_get_req_uri(req)); - if (!ctx) { - if (hap_pair_verify_context_init(&ctx, buf, sizeof(buf), &outlen) == HAP_SUCCESS) { - hap_platform_httpd_set_sess_ctx(req, ctx, NULL, true); - } - } - int data_len = httpd_req_recv(req, (char *)buf, sizeof(buf)); - ret = hap_pair_verify_process(&ctx, buf, data_len, sizeof(buf), &outlen); - httpd_resp_set_type(req, "application/pairing+tlv8"); - int ret1 = httpd_resp_send(req, (char *)buf, outlen); - if (ret == HAP_SUCCESS) { - if (hap_pair_verify_get_state(ctx) == STATE_VERIFIED) { - /* Saving socket fd since it will later be required for - * event notifications. - */ - int fd = httpd_req_to_sockfd(req); - ((hap_secure_session_t *)ctx)->conn_identifier = fd; - - struct timeval timeout; - timeout.tv_sec = hap_priv.cfg.recv_timeout; - timeout.tv_usec = 0; - if (setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, - sizeof(timeout)) < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "setsockopt on pair verified socket failed for SO_RCVTIMEO"); - } - - timeout.tv_sec = hap_priv.cfg.send_timeout; - timeout.tv_usec = 0; - if (setsockopt (fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, - sizeof(timeout)) < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "setsockopt on pair verified socket failed for SO_SNDTIMEO"); - } - - - // ---- - const int s = fd; - const int yes = 1; /* enable sending keepalive probes for socket */ - setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)); - - const int idle = 15; /* 180 sec idle before start sending probes */ - setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)); - - const int interval = 5; /* 30 sec between probes */ - setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, &interval, sizeof(interval)); - - const int maxpkt = 3; /* Drop connection after 4 probes without response */ - setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, &maxpkt, sizeof(maxpkt)); - // ---- - - hap_platform_httpd_set_sess_ctx(req, ctx, hap_free_session, true); - httpd_sess_set_send_override(hap_priv.server, fd, hap_httpd_send); - httpd_sess_set_recv_override(hap_priv.server, fd, hap_httpd_recv); - - - hap_secure_session_t* session = (hap_secure_session_t *)ctx; - int socket = session->conn_identifier; - - //struct sockaddr_storage addr; - struct sockaddr_in6 addr; - socklen_t len = sizeof addr; - getpeername(fd, (struct sockaddr*)&addr, &len); - /* - struct sockaddr_in *sockaddr = (struct sockaddr_in *)&addr; - in_addr_t a = sockaddr->sin_addr.s_addr; - union { - uint8_t ui8[4]; - uint32_t ui32; - }ip; - ip.ui32 = (uint32_t)a; - */ - //uint16_t port = ntohs(sockaddr->sin6_port); - uint16_t port = addr.sin6_port; - printf("---- STATE_VERIFIED ----\n"); - //printf("ip32: %u\n", a); - //printf("fd: %d, %u.%u.%u.%u:%u \n", socket, - //ip.ui8[0], ip.ui8[1], ip.ui8[2], ip.ui8[3], port); - //https://github.com/espressif/esp-idf/issues/4863 - printf("fd: %d, remote: %s:%u\n", fd, inet_ntoa(addr.sin6_addr.un.u32_addr[3]), port); - printf("ctrl: %s\n", session->ctrl->info.id); - - printf("------------------------\n"); - } - } - return ret1; -} - -static struct httpd_uri hap_pair_verify = { - .uri = "/pair-verify", - .method = HTTP_POST, - .handler = hap_http_pair_verify_handler, -}; - -static int hap_add_char_val_json(hap_char_format_t format, const char *key, - hap_val_t *val, json_gen_str_t *jptr) -{ - switch (format) { - case HAP_CHAR_FORMAT_BOOL : { - json_gen_obj_set_bool(jptr, key, val->b); - break; - } - case HAP_CHAR_FORMAT_UINT8: - case HAP_CHAR_FORMAT_UINT16: - case HAP_CHAR_FORMAT_UINT32: - case HAP_CHAR_FORMAT_INT: { - json_gen_obj_set_int(jptr, key, val->i); - break; - } - case HAP_CHAR_FORMAT_FLOAT : { - json_gen_obj_set_float(jptr, key, val->f); - break; - } - case HAP_CHAR_FORMAT_STRING : { - if (val->s) { - json_gen_obj_set_string(jptr, key, val->s); - } else { - json_gen_obj_set_null(jptr, key); - } - break; - } - case HAP_CHAR_FORMAT_DATA: - case HAP_CHAR_FORMAT_TLV8: { - if (val->d.buf) { - json_gen_obj_start_long_string(jptr, key, NULL); - uint8_t *buf = val->d.buf; - uint32_t buflen = val->d.buflen; - char tmp[100]; - while (buflen) { - int tmp_len = sizeof(tmp); - if (buflen > 60) { - esp_mfi_base64_encode((char *)buf, 60, tmp, tmp_len, &tmp_len); - buflen -= 60; - buf += 60; - } else { - esp_mfi_base64_encode((char *)buf, buflen, tmp, tmp_len, &tmp_len); - buflen -= buflen; - } - tmp[tmp_len] = 0; - json_gen_add_to_long_string(jptr, tmp); - } - json_gen_end_long_string(jptr); - } else { - json_gen_obj_set_null(jptr, key); - } - break; - } - default : - break; - } - return HAP_SUCCESS; -} - -static int hap_add_char_format_json(__hap_char_t *hc, json_gen_str_t *jptr) -{ - switch (hc->format) { - case HAP_CHAR_FORMAT_UINT8: - return json_gen_obj_set_string(jptr, "format", "uint8"); - case HAP_CHAR_FORMAT_UINT16: - return json_gen_obj_set_string(jptr, "format", "uint16"); - case HAP_CHAR_FORMAT_UINT32: - return json_gen_obj_set_string(jptr, "format", "uint32"); - case HAP_CHAR_FORMAT_INT: - return json_gen_obj_set_string(jptr, "format", "int"); - case HAP_CHAR_FORMAT_BOOL: - return json_gen_obj_set_string(jptr, "format", "bool"); - case HAP_CHAR_FORMAT_STRING: - return json_gen_obj_set_string(jptr, "format", "string"); - case HAP_CHAR_FORMAT_FLOAT: - return json_gen_obj_set_string(jptr, "format", "float"); - case HAP_CHAR_FORMAT_DATA: - return json_gen_obj_set_string(jptr, "format", "data"); - case HAP_CHAR_FORMAT_TLV8: - return json_gen_obj_set_string(jptr, "format", "tlv8"); - default: - break; - } - return HAP_SUCCESS; -} - -static int hap_add_char_type(__hap_char_t *hc, json_gen_str_t *jptr) -{ - return json_gen_obj_set_string(jptr, "type", (char *)hc->type_uuid); -} - -static int hap_add_char_meta(__hap_char_t *hc, json_gen_str_t *jptr) -{ - hap_add_char_format_json(hc, jptr); - - if (hc->constraint_flags & HAP_CHAR_MIN_FLAG) - hap_add_char_val_json(hc->format, "minValue", &hc->min, jptr); - if (hc->constraint_flags & HAP_CHAR_MAX_FLAG) - hap_add_char_val_json(hc->format, "maxValue", &hc->max, jptr); - if (hc->constraint_flags & HAP_CHAR_STEP_FLAG) - hap_add_char_val_json(hc->format, "minStep", &hc->step, jptr); - - /* maxLen and maxDataLen are constraints for "string" and "data" format - * of characteristics, respectively. However, the constraints themselves - * are integers. So, we pass the format as HAP_CHAR_FORMAT_INT - */ - if (hc->constraint_flags & HAP_CHAR_MAXLEN_FLAG) - hap_add_char_val_json(HAP_CHAR_FORMAT_INT, "maxLen", &hc->max, jptr); - if (hc->constraint_flags & HAP_CHAR_MAXDATALEN_FLAG) - hap_add_char_val_json(HAP_CHAR_FORMAT_INT, "maxDataLen", &hc->max, jptr); - - if (hc->description) - json_gen_obj_set_string(jptr, "description", hc->description); - if (hc->unit) - json_gen_obj_set_string(jptr, "unit", hc->unit); - - return HAP_SUCCESS; -} - -static int hap_add_char_perms(__hap_char_t *hc, json_gen_str_t *jptr) -{ - json_gen_push_array(jptr, "perms"); - if (hc->permission & HAP_CHAR_PERM_PR) - json_gen_arr_set_string(jptr, "pr"); - if (hc->permission & HAP_CHAR_PERM_PW) - json_gen_arr_set_string(jptr, "pw"); - if (hc->permission & HAP_CHAR_PERM_EV) - json_gen_arr_set_string(jptr, "ev"); - if (hc->permission & HAP_CHAR_PERM_AA) - json_gen_arr_set_string(jptr, "aa"); - if (hc->permission & HAP_CHAR_PERM_TW) - json_gen_arr_set_string(jptr, "tw"); - if (hc->permission & HAP_CHAR_PERM_HD) - json_gen_arr_set_string(jptr, "hd"); - json_gen_pop_array(jptr); - return HAP_SUCCESS; -} - -static int hap_add_char_ev(__hap_char_t *hc, json_gen_str_t *jptr, uint8_t session_index) -{ - if (hap_char_is_ctrl_subscribed((hap_char_t *)hc, session_index)) { - return json_gen_obj_set_bool(jptr, "ev", true); - } else { - return json_gen_obj_set_bool(jptr, "ev", false); - } -} - -static int hap_add_char_valid_vals(__hap_char_t *hc, json_gen_str_t *jptr) -{ - if (hc->valid_vals) { - json_gen_push_array(jptr, "valid-values"); - int i; - for (i = 0; i < hc->valid_vals_cnt; i++) { - json_gen_arr_set_int(jptr, hc->valid_vals[i]); - } - json_gen_pop_array(jptr); - } - if (hc->valid_vals_range) { - json_gen_push_array(jptr, "valid-values-range"); - json_gen_arr_set_int(jptr, hc->valid_vals_range[0]); - json_gen_arr_set_int(jptr, hc->valid_vals_range[1]); - json_gen_pop_array(jptr); - } - return HAP_SUCCESS; -} - -static int hap_prepare_char_db(__hap_char_t *hc, json_gen_str_t *jptr, int session_index) -{ - json_gen_start_object(jptr); - - json_gen_obj_set_int(jptr, "iid", hc->iid); - - /* If the Update API has not been called from the service read routine, - * reset the owner controller value. - * Else, the controller will miss the next notification. - */ - if (!hc->update_called) { - hc->owner_ctrl = 0; - } - hc->update_called = false; - - if (hc->permission & HAP_CHAR_PERM_PR) { - if (hc->permission & HAP_CHAR_PERM_SPECIAL_READ) { - json_gen_obj_set_null(jptr, "value"); - } else { - hap_add_char_val_json(hc->format, "value", &hc->val, jptr); - } - } - hap_add_char_type(hc, jptr); - hap_add_char_perms(hc, jptr); - hap_add_char_ev(hc, jptr, session_index); - hap_add_char_meta(hc, jptr); - hap_add_char_valid_vals(hc, jptr); - - json_gen_end_object(jptr); - - return HAP_SUCCESS; -} - -static int hap_prepare_serv_db(__hap_serv_t *hs, json_gen_str_t *jptr, int session_index) -{ - json_gen_start_object(jptr); - json_gen_obj_set_int(jptr, "iid", hs->iid); - json_gen_obj_set_string(jptr, "type", hs->type_uuid); - if (hs->hidden) - json_gen_obj_set_bool(jptr, "hidden", "true"); - if (hs->primary) - json_gen_obj_set_bool(jptr, "primary", "true"); - if (hs->linked_servs) { - hap_linked_serv_t *linked = hs->linked_servs; - json_gen_push_array(jptr, "linked"); - while (linked) { - json_gen_arr_set_int(jptr, ((__hap_serv_t *)linked->hs)->iid); - linked = linked->next; - } - json_gen_pop_array(jptr); - } - - json_gen_push_array(jptr, "characteristics"); - int char_cnt = 0; - hap_char_t *hc; - for (hc = hap_serv_get_first_char((hap_serv_t *)hs); hc; hc = hap_char_get_next(hc)) { - if (((__hap_char_t *)hc)->permission & HAP_CHAR_PERM_PR) { - char_cnt++; - } - } - if (char_cnt) { - hap_read_data_t *read_arr = hap_platform_memory_calloc(char_cnt, sizeof(hap_read_data_t)); - if (!read_arr) { - return HAP_FAIL; - } - - hap_status_t *status_codes = hap_platform_memory_calloc(char_cnt, sizeof(hap_status_t)); - if (!status_codes) { - hap_platform_memory_free(read_arr); - return HAP_FAIL; - } - - /* Create an array of characteristics to read, and then read them in one go */ - char_cnt = 0; - for (hc = hap_serv_get_first_char((hap_serv_t *)hs); hc; hc = hap_char_get_next(hc)) { - if (((__hap_char_t *)hc)->permission & HAP_CHAR_PERM_PR) { - hap_char_set_owner_ctrl(hc, session_index); - ((__hap_char_t *)hc)->update_called = false; - read_arr[char_cnt].hc = hc; - status_codes[char_cnt] = HAP_STATUS_SUCCESS; - read_arr[char_cnt].status = &status_codes[char_cnt]; - char_cnt++; - } - } - - hs->bulk_read(&read_arr[0], char_cnt, hs->priv, NULL); - hap_platform_memory_free(read_arr); - hap_platform_memory_free(status_codes); - } - for (hc = hap_serv_get_first_char((hap_serv_t *)hs); hc; hc = hap_char_get_next(hc)) { - hap_prepare_char_db((__hap_char_t *)hc, jptr, session_index); - } - - json_gen_pop_array(jptr); - json_gen_end_object(jptr); - return HAP_SUCCESS; -} - -static int hap_prepare_acc_db(__hap_acc_t *ha, json_gen_str_t *jptr, int session_index) -{ - json_gen_start_object(jptr); - json_gen_obj_set_int(jptr, "aid", ha->aid); - json_gen_push_array(jptr, "services"); - hap_serv_t *hs; - for (hs = hap_acc_get_first_serv((hap_acc_t *)ha); hs; hs = hap_serv_get_next(hs)) { - hap_prepare_serv_db((__hap_serv_t *)hs, jptr, session_index); - } - json_gen_pop_array(jptr); - json_gen_end_object(jptr); - return HAP_SUCCESS; -} - -static int hap_prepare_json_database(char *buf, int bufsize, json_gen_flush_cb_t flush_cb, httpd_req_t *req) -{ - if (!req) { - return HAP_FAIL; - } - hap_secure_session_t *session = (hap_secure_session_t *)hap_platform_httpd_get_sess_ctx(req); - if (!session) { - return HAP_FAIL; - } - json_gen_str_t jstr; - json_gen_str_start(&jstr, buf, bufsize, flush_cb, req); - json_gen_start_object(&jstr); - json_gen_push_array(&jstr, "accessories"); - hap_acc_t *ha; - for (ha = hap_get_first_acc(); ha; ha = hap_acc_get_next(ha)) { - hap_prepare_acc_db((__hap_acc_t *)ha, &jstr, hap_get_ctrl_session_index(session)); - } - json_gen_pop_array(&jstr); - json_gen_end_object(&jstr); - json_gen_str_end(&jstr); - return HAP_SUCCESS; -} - -static void hap_http_json_flush_chunk(char *data, void *priv) -{ - ESP_MFI_DEBUG_PLAIN("%s", data); - httpd_resp_send_chunk((httpd_req_t *)priv, data, strlen(data)); -} - -static int hap_http_get_accessories(httpd_req_t *req) -{ - char buf[1000]; - ESP_MFI_DEBUG_PLAIN("Socket fd: %d; HTTP Request %s %s\n", httpd_req_to_sockfd(req), hap_platform_httpd_get_req_method(req), hap_platform_httpd_get_req_uri(req)); - hap_secure_session_t *session = (hap_secure_session_t *)hap_platform_httpd_get_sess_ctx(req); - if (!hap_is_req_secure(session)) { - return hap_http_session_not_authorized(req); - } - httpd_resp_set_type(req, "application/hap+json"); - ESP_MFI_DEBUG_PLAIN("Generating HTTP Response\n"); - /* Using chunked encoding since the response can be large, especially for bridges */ - hap_prepare_json_database(buf, sizeof(buf), hap_http_json_flush_chunk, req); - /* This indicates the last chunk */ - httpd_resp_send_chunk(req, NULL, 0); - ESP_MFI_DEBUG_PLAIN("\n"); - - hap_report_event(HAP_EVENT_GET_ACC_COMPLETED, NULL, 0); - return HAP_SUCCESS; -} -static struct httpd_uri hap_accessories = { - .uri = "/accessories", - .method = HTTP_GET, - .handler = hap_http_get_accessories, -}; - -static void hap_set_char_report_status(bool *include_status, json_gen_str_t *jstr, - int aid, int iid, int status) -{ - if (!*include_status) { - json_gen_start_object(jstr); - json_gen_push_array(jstr, "characteristics"); - *include_status = true; - } - json_gen_start_object(jstr); - json_gen_obj_set_int(jstr, "aid", aid); - json_gen_obj_set_int(jstr, "iid", iid); - json_gen_obj_set_int(jstr, "status", status); - json_gen_end_object(jstr); -} - -static int hap_http_handle_set_char(jparse_ctx_t *jctx, char *outbuf, int buf_size, - httpd_req_t *req) -{ - int cnt = 0, char_cnt = 0, i; - bool include_status = false; - uint64_t pid; - bool valid_tw = false; - bool req_tw = false; - hap_secure_session_t *session = (hap_secure_session_t *)hap_platform_httpd_get_sess_ctx(req); - if (!session) - return HAP_FAIL; - - int64_t cur_time = esp_timer_get_time() / 1000; - int64_t prepare_time = session->prepare_time; - if (prepare_time) { - /* If prepare time is non zero, it means that a prepare was received - * before this request, and so this write needs to be timed write - */ - req_tw = true; - /* Reset prepare_time to 0, since a prepare is valid only for the immediate - * following write - */ - session->prepare_time = 0; - } - if (json_obj_get_int64(jctx, "pid", (int64_t *)&pid) == OS_SUCCESS) { - /* If the pid value is present, this must be a timed write. - * However, if there was no preceding prepare, the check below will - * fail (as ttl will be 0) and appropriate error will be reported subsequently - */ - req_tw = true; - if ((pid == session->pid) && ((cur_time - prepare_time) <= session->ttl)) { - valid_tw = true; - } - } - /* Resetting the values so that the session is ready for next prepare or write */ - session->pid = 0; - session->ttl = 0; - - json_obj_get_array(jctx, "characteristics", &cnt); - if (cnt <= 0) - return HAP_FAIL; - - hap_write_data_t *write_arr = hap_platform_memory_calloc(cnt, sizeof(hap_write_data_t)); - hap_status_t *status_arr = hap_platform_memory_calloc(cnt, sizeof(hap_status_t)); - if (!write_arr || !status_arr) - goto set_char_end; - - json_gen_str_t jstr; - json_gen_str_start(&jstr, outbuf, buf_size, hap_http_json_flush_chunk, req); - /* Dummy get, so that the loop can start by leaving the previous - * object and getting newer one - */ - json_arr_get_object(jctx, 0); - /* Loop through all characteristic objects {aid,iid,value}, handle - * errors if any, and if there are no errors, put the characteristic - * pointer and value in an array (with char_cnt) - */ - for (i = 0; i < cnt; i++) { - /* Leave the previous object and get a newer one from the array */ - json_arr_leave_object(jctx); - int aid = 0, iid = 0; - json_arr_get_object(jctx, i); - json_obj_get_int(jctx, "aid", &aid); - json_obj_get_int(jctx, "iid", &iid); - hap_acc_t *ha = hap_acc_get_by_aid(aid); - __hap_char_t *hc = (__hap_char_t *)hap_acc_get_char_by_iid(ha, iid); - if (!ha || !hc) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_RES_ABSENT); - continue; - } - - /* If the previous request was a prepare, but the current - * one was not a valid timed write, report error. - */ - if (req_tw == true && valid_tw == false) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_VAL_INVALID); - continue; - } - - /* For characteristic that require a Mandatory Timed Write, return - * error if this write is not a valid timed write - */ - if (hc->permission & HAP_CHAR_PERM_TW) { - if (valid_tw == false) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_VAL_INVALID); - continue; - } - } - - /* Check if this write is just to enable/disable event notifications. - * This is valid even for read-only characteristics that support event - * notifications (like sensor readings), so we do not check the HAP_CHAR_PERM_PW - * here. - */ - bool ev; - if (json_obj_get_bool(jctx, "ev", &ev) == HAP_SUCCESS) { - if (hc->permission & HAP_CHAR_PERM_EV) { - int index = hap_get_ctrl_session_index(session); - hap_char_manage_notification((hap_char_t *)hc, index, ev); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Events %s for aid=%d iid=%d", - ev ? "Enabled" : "Disabled", aid, iid); - } else { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_NO_NOTIF); - } - continue; - } - - /* Check if the characteristic has write permission */ - if (!(hc->permission & HAP_CHAR_PERM_PW)) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_WR_ON_RDONLY); - continue; - } - - /* Check if the characteristic needs Authorization Data. - * Actual authData value will be read later. - */ - if (hc->permission & HAP_CHAR_PERM_AA) { - int tmp_len; - if (json_obj_get_strlen(jctx, "authData", &tmp_len) != HAP_SUCCESS) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_INSUFFICIENT_AUTH); - continue; - } - } - /* If there is no write routine registered, there is no point of having - * this write request. Return an error. - */ - if (!((__hap_serv_t *)(hap_char_get_parent((hap_char_t *)hc)))->write_cb) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_VAL_INVALID); - continue; - } - - hap_auth_data_t auth_data = { - .data = NULL, - .len = 0, - }; - hap_val_t val; - int json_ret = HAP_FAIL; - switch (hc->format) { - case HAP_CHAR_FORMAT_BOOL: - json_ret = json_obj_get_bool(jctx, "value", &val.b); - break; - case HAP_CHAR_FORMAT_UINT8: - case HAP_CHAR_FORMAT_UINT16: - case HAP_CHAR_FORMAT_UINT32: - case HAP_CHAR_FORMAT_INT: - json_ret = json_obj_get_int(jctx, "value", &val.i); - break; - case HAP_CHAR_FORMAT_FLOAT: - json_ret = json_obj_get_float(jctx, "value", &val.f); - break; - case HAP_CHAR_FORMAT_STRING: { - int str_len = 0; - json_ret = json_obj_get_strlen(jctx, "value", &str_len); - if (json_ret == HAP_SUCCESS) { - /* Increment string length, for NULL termination byte */ - str_len++; - val.s = hap_platform_memory_calloc(str_len, 1); - if (!val.s) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_OO_RES); - continue; - } - json_obj_get_string(jctx, "value", val.s, str_len); - } - break; - } - case HAP_CHAR_FORMAT_DATA: - case HAP_CHAR_FORMAT_TLV8: { - int str_len = 0; - json_ret = json_obj_get_strlen(jctx, "value", &str_len); - if (json_ret == HAP_SUCCESS) { - val.d.buf = hap_platform_memory_calloc(1, str_len + 1); - if (!val.d.buf) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_OO_RES); - continue; - } - val.d.buflen = str_len + 1; - json_obj_get_string(jctx, "value", (char *)val.d.buf, val.d.buflen); - if (esp_mfi_base64_decode((const char *)val.d.buf, strlen((char *)val.d.buf), - (char *)val.d.buf, val.d.buflen, (int *)&val.d.buflen) != 0) { - hap_platform_memory_free(val.d.buf); - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_VAL_INVALID); - continue; - } - } - break; - } - default: - json_ret = HAP_FAIL; - } - if (json_ret != HAP_SUCCESS) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_VAL_INVALID); - continue; - } - - /* Check if the value is within constraints */ - if (hap_char_check_val_constraints(hc, &val) != HAP_SUCCESS) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_VAL_INVALID); - continue; - } - - if (json_obj_get_strlen(jctx, "authData", &auth_data.len) == HAP_SUCCESS) { - auth_data.data = hap_platform_memory_calloc(1, auth_data.len + 1); - json_obj_get_string(jctx, "authData", (char *)auth_data.data, auth_data.len + 1); - esp_mfi_base64_decode((const char *)auth_data.data, auth_data.len, (char *)auth_data.data, auth_data.len + 1, &auth_data.len); - } - bool remote = false; - json_obj_get_bool(jctx, "remote", &remote); - - int index = hap_get_ctrl_session_index(session); - hap_char_set_owner_ctrl((hap_char_t *)hc, index); - /* No errors in the object data itself. Save the characteristic - * pointer and value, to be used later - */ - write_arr[char_cnt].hc = (hap_char_t *)hc; - write_arr[char_cnt].val = val; - write_arr[char_cnt].auth_data = auth_data; - write_arr[char_cnt].remote = remote; - write_arr[char_cnt].status = &status_arr[char_cnt]; - char_cnt++; - } - if (!char_cnt) - goto set_char_end; - - /* The logic here is to loop through all the saved characteristic - * pointers, and invoke a single write callback for all consecutive - * characteristics of the same service. - * The write callback will be invoked if the service changes or - * if the last characteristic in the array is reached - */ - int hs_index = 0; - bool write_err = false; - __hap_serv_t *hs = (__hap_serv_t *)hap_char_get_parent(write_arr[0].hc); - /* The counter here will go till char_cnt instead of char_cnt - 1. - * When i == char_cnt, it will mean that all elements in the array - * have been looped through. - * So, last iteration will invoke the write callback for the last - * set of characteritics. - */ - for (i = 0; i <= char_cnt; i++) { - if ((i < char_cnt) && ((hap_serv_t *)hs == hap_char_get_parent(write_arr[i].hc))) - continue; - else { - /* Passing the pointers to the first elements of the array - * for a given service (indicated by hs_index). - * Number of elements of the array are indicated by - * i - hs_index - */ - if (hs->write_cb(&write_arr[hs_index], i - hs_index, - hs->priv, hap_platform_httpd_get_sess_ctx(req)) != HAP_SUCCESS) - write_err = true; - if (i < char_cnt) { - hs = (__hap_serv_t *)hap_char_get_parent(write_arr[i].hc); - hs_index = i; - } - } - } - if (write_err || include_status) { - for (i = 0; i < char_cnt; i++) { - /* TODO: The code to get aid looks complex. Simplify */ - hap_set_char_report_status(&include_status, &jstr, - ((__hap_acc_t *)hap_serv_get_parent(hap_char_get_parent(write_arr[i].hc)))->aid, - ((__hap_char_t *)(write_arr[i].hc))->iid, *write_arr[i].status); - } - } - - int ret = HAP_SUCCESS; -set_char_end: - if (include_status) { - json_gen_pop_array(&jstr); - json_gen_end_object(&jstr); - json_gen_str_end(&jstr); - ret = HAP_FAIL; - } - - if (write_arr) { - for (i = 0; i < char_cnt; i++) { - if (((__hap_char_t *)write_arr[i].hc)->format == HAP_CHAR_FORMAT_STRING) { - if (write_arr[i].val.s) { - hap_platform_memory_free(write_arr[i].val.s); - } - } else if ((((__hap_char_t *)write_arr[i].hc)->format == HAP_CHAR_FORMAT_DATA) || - (((__hap_char_t *)write_arr[i].hc)->format == HAP_CHAR_FORMAT_TLV8)) { - hap_platform_memory_free(write_arr[i].val.d.buf); - } - if (write_arr[i].auth_data.data) { - hap_platform_memory_free(write_arr[i].auth_data.data); - } - } - } - if (write_arr) - hap_platform_memory_free(write_arr); - if (status_arr) - hap_platform_memory_free(status_arr); - return ret; -} - -static int hap_http_put_characteristics(httpd_req_t *req) -{ - char stack_inbuf[512] = {0}; - char outbuf[512] = {0}; - char *heap_inbuf = NULL; - char *inbuf = stack_inbuf; - - ESP_MFI_DEBUG_PLAIN("Socket fd: %d; HTTP Request %s %s\n", httpd_req_to_sockfd(req), hap_platform_httpd_get_req_method(req), hap_platform_httpd_get_req_uri(req)); - hap_secure_session_t *session = (hap_secure_session_t *)hap_platform_httpd_get_sess_ctx(req); - if (!hap_is_req_secure(session)) { - return hap_http_session_not_authorized(req); - } - - /* If received content is larger than the buffer on stack, allocate one from heap. - * This will mostly be required only in case of bridges, wherein there could be a request to - * control all/many accessories at once. - */ - int content_len = hap_platform_httpd_get_content_len(req); - if (content_len > sizeof(stack_inbuf)) { - heap_inbuf = hap_platform_memory_calloc(content_len + 1, 1); /* Allocating an extra byte for NULL termination */ - if (!heap_inbuf) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to read HTTPD Data"); - httpd_resp_set_status(req, HTTPD_500); - return httpd_resp_send(req, NULL, 0); - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Allocated buffer of size %d for the large PUT", - content_len + 1) - inbuf = heap_inbuf; - } - int data_len = hap_httpd_get_data(req, inbuf, content_len); - if (data_len < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to read HTTPD Data"); - httpd_resp_set_status(req, HTTPD_500); - if (heap_inbuf) { - hap_platform_memory_free(heap_inbuf); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Freed allocated buffer for PUT"); - } - return httpd_resp_send(req, NULL, 0); - } - ESP_MFI_DEBUG_PLAIN("Data Received: %s\n", inbuf); - jparse_ctx_t jctx; - if (json_parse_start(&jctx, inbuf, data_len) != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to parse HTTPD JSON Data"); - httpd_resp_set_status(req, HTTPD_500); - if (heap_inbuf) { - hap_platform_memory_free(heap_inbuf); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Freed allocated buffer for PUT"); - } - return httpd_resp_send(req, NULL, 0); - } - - httpd_resp_set_type(req, "application/hap+json"); - /* Setting response type to indicate error. - * This will be actually sent out only if there is some error - * to be reported while handling the characteristic writes. - * Else, the response type will be set to 204 - */ - httpd_resp_set_status(req, HTTPD_207); - if (hap_http_handle_set_char(&jctx, outbuf, sizeof(outbuf), req) == HAP_SUCCESS) - { - snprintf(outbuf, sizeof(outbuf), "HTTP/1.1 %s\r\n\r\n", HTTPD_204); - httpd_send(req, outbuf, strlen(outbuf)); - } else { - /* If a failure was encountered, it would mean that a response has been generated, - * which will be chunk encoded. So, sending the last chunk here and also printing - * a new line to end the prints of the error string. - */ - httpd_resp_send_chunk(req, NULL, 0); - ESP_MFI_DEBUG_PLAIN("\n"); - } - json_parse_end(&jctx); - - if (heap_inbuf) { - hap_platform_memory_free(heap_inbuf); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Freed allocated buffer for PUT"); - } - - hap_report_event(HAP_EVENT_SET_CHAR_COMPLETED, NULL, 0); - return HAP_SUCCESS; -} - -static bool hap_get_bool_url_param(const char *query_str, const char *key) -{ - char val[6]; /* Max string will be "false" */ - if (httpd_query_key_value(query_str, key, val, sizeof(val)) == HAP_SUCCESS) { - if (!strcmp(val, "true") || !strcmp(val, "1")) - return true; - } - return false; -} - -static int hap_http_get_characteristics(httpd_req_t *req) -{ - char outbuf[512]; - char stack_val_buf[512] = {0}; - char *heap_val_buf = NULL; - char *val = stack_val_buf; - - ESP_MFI_DEBUG_PLAIN("Socket fd: %d; HTTP Request %s %s\n", httpd_req_to_sockfd(req), hap_platform_httpd_get_req_method(req), hap_platform_httpd_get_req_uri(req)); - - hap_secure_session_t *session = (hap_secure_session_t *)hap_platform_httpd_get_sess_ctx(req); - if (!hap_is_req_secure(session)) { - return hap_http_session_not_authorized(req); - } - const char *uri = hap_platform_httpd_get_req_uri(req); - /* Allocate on heap, if URI is longer */ - if (strlen(uri) > sizeof(stack_val_buf)) { - heap_val_buf = hap_platform_memory_calloc(strlen(uri) + 1, 1); /* Allocating an extra byte for NULL termination */ - if (!heap_val_buf) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to read URL"); - httpd_resp_set_status(req, HTTPD_500); - return httpd_resp_send(req, NULL, 0); - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Allocated buffer of size %d for the large GET", - strlen(uri) + 1) - val = heap_val_buf; - } - size_t url_query_str_len = httpd_req_get_url_query_len(req); - char * url_query_str = hap_platform_memory_calloc(1, url_query_str_len + 1); - if (!url_query_str) { - httpd_resp_set_status(req, HTTPD_400); - httpd_resp_set_type(req, "application/hap+json"); - snprintf(outbuf, sizeof(outbuf),"{\"status\":-70409}"); - httpd_resp_send(req, outbuf, strlen(outbuf)); - goto get_char_return; - } - httpd_req_get_url_query_str(req, url_query_str, url_query_str_len + 1); - /* Check for all the optional URL query paramaters */ - bool meta = hap_get_bool_url_param(url_query_str, "meta"); - bool perms = hap_get_bool_url_param(url_query_str, "perms"); - bool type = hap_get_bool_url_param(url_query_str, "type"); - bool ev = hap_get_bool_url_param(url_query_str, "ev"); - - /* Check for the mandatory "id" URL query parameter. - * If not found, return success - */ - if (httpd_query_key_value(url_query_str, "id", val, strlen(uri) + 1) != HAP_SUCCESS) { - httpd_resp_set_status(req, HTTPD_400); - httpd_resp_set_type(req, "application/hap+json"); - snprintf(outbuf, sizeof(outbuf),"{\"status\":-70409}"); - httpd_resp_send(req, outbuf, strlen(outbuf)); - goto get_char_return; - } - - /* Get the total count of characteristics in the request. This will be - * required to decide the size of the characteristic pointers' array - */ - int char_cnt = 0; - char *val_ptr = val; - /* We do not do any error checking here and just assume that the id - * tag has a characteristic list which is a comma separated list - * of . elements - */ - char *p = strsep(&val_ptr, ","); - while (p) { - char_cnt++; - p = strsep(&val_ptr, ","); - } - - /* Normally, it would have been fine to just go on parsing the - * characteristics in the URL, fetch their values and prepare - * the response. However, if there is error for any characteristic - * a "status" field needs to be added for all characteristics. - * - * So, it is better to maintain a list of characteristics pointers, - * read all the values, and only then create the response - */ - hap_read_data_t *read_arr = hap_platform_memory_calloc(char_cnt, sizeof(hap_read_data_t)); - if (!read_arr) { - httpd_resp_set_status(req, HTTPD_500); - httpd_resp_set_type(req, "application/hap+json"); - snprintf(outbuf, sizeof(outbuf),"{\"status\":-70407}"); - httpd_resp_send(req, outbuf, strlen(outbuf)); - goto get_char_return; - } - hap_status_t *status_codes = hap_platform_memory_calloc(char_cnt, sizeof(hap_status_t)); - if (!status_codes) { - hap_platform_memory_free(read_arr); - httpd_resp_set_status(req, HTTPD_500); - httpd_resp_set_type(req, "application/hap+json"); - snprintf(outbuf, sizeof(outbuf),"{\"status\":-70407}"); - httpd_resp_send(req, outbuf, strlen(outbuf)); - goto get_char_return; - } - - ESP_MFI_DEBUG_PLAIN("Generating HTTP Response\n"); - /* Generate the JSON response */ - bool include_status = 0; - httpd_resp_set_status(req, HTTPD_207); - httpd_resp_set_type(req, "application/hap+json"); - json_gen_str_t jstr; - json_gen_str_start(&jstr, outbuf, sizeof(outbuf), hap_http_json_flush_chunk, req); - - /* Get the ids once again. Not checking for success since that - * would be redundant - */ - httpd_query_key_value(url_query_str, "id", val, strlen(uri) + 1); - char_cnt = 0; - int aid, iid; - val_ptr = val; - /* Parse the AIDs and IIDs in the "id" field and fetch the - * characteristic pointer for each - */ - p = strsep(&val_ptr, "."); - while (p) { - aid = atoi(p); - p = strsep(&val_ptr, ","); - iid = atoi(p); - p = strsep(&val_ptr, "."); - hap_char_t *hc = hap_acc_get_char_by_iid(hap_acc_get_by_aid(aid), iid); - if (!hc) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_RES_ABSENT); - continue; - } - if (!(((__hap_char_t *)hc)->permission & HAP_CHAR_PERM_PR)) { - hap_set_char_report_status(&include_status, &jstr, - aid, iid, HAP_STATUS_RD_ON_WRONLY); - continue; - } - hap_char_set_owner_ctrl(hc, hap_get_ctrl_session_index(session)); - ((__hap_char_t *)hc)->update_called = false; - /* Add the characteristic to the read array */ - read_arr[char_cnt].hc = hc; - status_codes[char_cnt] = HAP_STATUS_SUCCESS; - read_arr[char_cnt].status = &status_codes[char_cnt]; - char_cnt++; - } - - if (!char_cnt) { - goto get_char_end; - } - - - int hs_index = 0; - bool read_err = false; - __hap_serv_t *hs = (__hap_serv_t *)hap_char_get_parent(read_arr[0].hc); - /* Read all the values first, before preparing the response, so that it - * would be known in advance, if any read error is encountered - */ - int i; - /* The counter here will go till char_cnt instead of char_cnt - 1. - * When i == char_cnt, it will mean that all elements in the array - * have been looped through. - * So, last iteration will invoke the read callback for the last - * set of characteritics. - */ - for (i = 0; i <= char_cnt; i++) { - if ((i < char_cnt) && ((hap_serv_t *)hs == hap_char_get_parent(read_arr[i].hc))) - continue; - else { - /* Passing the pointers to the first elements of the array - * for a given service (indicated by hs_index). - * Number of elements of the array are indicated by - * i - hs_index - */ - if (hs->bulk_read(&read_arr[hs_index], i - hs_index, hs->priv, hap_platform_httpd_get_sess_ctx(req)) != HAP_SUCCESS) - read_err = true; - if (i < char_cnt) { - hs = (__hap_serv_t *)hap_char_get_parent(read_arr[i].hc); - hs_index = i; - } - } - } - if (!include_status) { - if (!read_err) { - /* If "include_status" is false, it means there - * were no errors. - * So, set response type to 200 OK - */ - httpd_resp_set_status(req, HTTPD_200); - } - json_gen_start_object(&jstr); - json_gen_push_array(&jstr, "characteristics"); - } - /* Loop through the characteristics and include their data - */ - for (i = 0; i < char_cnt; i++) { - __hap_char_t *hc = (__hap_char_t *)read_arr[i].hc; - /* If the Update API has not been called from the service read routine, - * reset the owner controller value. - * Else, the controller will miss the next notification. - */ - if (!hc->update_called) { - hc->owner_ctrl = 0; - } - hc->update_called = false; - - json_gen_start_object(&jstr); - __hap_acc_t *ha = (__hap_acc_t *)hap_serv_get_parent(hc->parent); - json_gen_obj_set_int(&jstr, "aid", ha->aid); - json_gen_obj_set_int(&jstr, "iid", hc->iid); - - if (hc->permission & HAP_CHAR_PERM_SPECIAL_READ) { - json_gen_obj_set_null(&jstr, "value"); - } else { - /* Include "value" only if status is SUCCESS */ - if (*read_arr[i].status == HAP_STATUS_SUCCESS) { - hap_add_char_val_json(hc->format, "value", &hc->val, &jstr); - } - } - /* Include status only if it was already included because of - * some parsing errors, or if an error was encountered while - * actually reading the characteristics. - */ - if (include_status || read_err) { - json_gen_obj_set_int(&jstr, "status", *read_arr[i].status); - } - if (type) - hap_add_char_type(hc, &jstr); - if (perms) - hap_add_char_perms(hc, &jstr); - if (ev) { - hap_add_char_ev(hc, &jstr, hap_get_ctrl_session_index(session)); - } - if (meta) - hap_add_char_meta(hc, &jstr); - json_gen_end_object(&jstr); - } -get_char_end: - json_gen_pop_array(&jstr); - json_gen_end_object(&jstr); - json_gen_str_end(&jstr); - - hap_platform_memory_free(read_arr); - hap_platform_memory_free(status_codes); - - /* This indicates the last chunk */ - httpd_resp_send_chunk(req, NULL, 0); - ESP_MFI_DEBUG_PLAIN("\n"); -get_char_return: - if (heap_val_buf) { - hap_platform_memory_free(heap_val_buf); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Freed allocated buffer for GET"); - } - - if (url_query_str) { - hap_platform_memory_free(url_query_str); - } - - hap_report_event(HAP_EVENT_GET_CHAR_COMPLETED, NULL, 0); - return HAP_SUCCESS; -} -static struct httpd_uri hap_characteristics_get = { - .uri = "/characteristics", - .method = HTTP_GET, - .handler = hap_http_get_characteristics, -}; -static struct httpd_uri hap_characteristics_put = { - .uri = "/characteristics", - .method = HTTP_PUT, - .handler = hap_http_put_characteristics, -}; - -static int hap_http_pairings_handler(httpd_req_t *req) -{ - uint8_t buf[2048]; /* Large buffer to accommodate 16 pairings list */ - void *ctx = hap_platform_httpd_get_sess_ctx(req); - ESP_MFI_DEBUG_PLAIN("Socket fd: %d; HTTP Request %s %s\n", httpd_req_to_sockfd(req), hap_platform_httpd_get_req_method(req), hap_platform_httpd_get_req_uri(req)); - int data_len = httpd_req_recv(req, (char *)buf, sizeof(buf)); - int outlen; - hap_secure_session_t *session = (hap_secure_session_t *)ctx; - if (!hap_is_req_secure(session)) { - /* Only setting the HTTP status here. Actual error TLV will be added - * by the hap_pairings_process() call - */ - httpd_resp_set_status(req, "470 Connection Authorization Required"); - } - hap_pairings_process(ctx, buf, data_len, sizeof(buf), &outlen); - httpd_resp_set_type(req, "application/pairing+tlv8"); - return httpd_resp_send(req, (char *)buf, outlen); -} -static struct httpd_uri hap_pairings = { - .uri = "/pairings", - .method = HTTP_POST, - .handler = hap_http_pairings_handler, -}; - -static int hap_http_post_identify(httpd_req_t *req) -{ - char buf[100]; - ESP_MFI_DEBUG_PLAIN("Socket fd: %d\nHTTP Request %s %s\n", httpd_req_to_sockfd(req), hap_platform_httpd_get_req_method(req), hap_platform_httpd_get_req_uri(req)); - if (is_accessory_paired()) { - httpd_resp_set_status(req, HTTPD_400); - httpd_resp_set_type(req, "application/hap+json"); - snprintf(buf, sizeof(buf),"{\"status\":-70401}"); - httpd_resp_send(req, buf, strlen(buf)); - } else { - hap_acc_t *ha = hap_get_first_acc(); - __hap_acc_t *_ha = (__hap_acc_t *)ha; - _ha->identify_routine(ha); - snprintf(buf, sizeof(buf), "HTTP/1.1 %s\r\n\r\n", HTTPD_204); - httpd_send(req, buf, strlen(buf)); - } - return HAP_SUCCESS; -} - -static struct httpd_uri hap_identify = { - .uri = "/identify", - .method = HTTP_POST, - .handler = hap_http_post_identify, -}; - -static int hap_http_put_prepare(httpd_req_t *req) -{ - char buf[512] = {0}; - - ESP_MFI_DEBUG_PLAIN("Socket fd: %d; HTTP Request %s %s\n", httpd_req_to_sockfd(req), hap_platform_httpd_get_req_method(req), hap_platform_httpd_get_req_uri(req)); - hap_secure_session_t *session = (hap_secure_session_t *)hap_platform_httpd_get_sess_ctx(req); - if (!hap_is_req_secure(session)) { - return hap_http_session_not_authorized(req); - } - int data_len = httpd_req_recv(req, (char *)buf, sizeof(buf)); - if (data_len < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to read HTTPD Data"); - httpd_resp_set_status(req, HTTPD_500); - return httpd_resp_send(req, NULL, 0); - } - ESP_MFI_DEBUG_PLAIN("Data Received: %s\n", buf); - jparse_ctx_t jctx; - if (json_parse_start(&jctx, buf, data_len) != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to parse HTTPD JSON Data"); - httpd_resp_set_status(req, HTTPD_500); - return httpd_resp_send(req, NULL, 0); - } - - httpd_resp_set_type(req, "application/hap+json"); - uint64_t pid; - int64_t ttl; - if ((json_obj_get_int64(&jctx, "pid", (int64_t *)&pid) != OS_SUCCESS) || - (json_obj_get_int64(&jctx, "ttl", &ttl) != OS_SUCCESS)) { - snprintf(buf, sizeof(buf),"{\"status\":-70410}"); - } else { - session->pid = pid; - session->ttl = ttl; - session->prepare_time = esp_timer_get_time() / 1000; /* Set current time in msec */ - snprintf(buf, sizeof(buf),"{\"status\":0}"); - } - json_parse_end(&jctx); - httpd_resp_send(req, buf, strlen(buf)); - return HAP_SUCCESS; -} - -static struct httpd_uri hap_prepare = { - .uri = "/prepare", - .method = HTTP_PUT, - .handler = hap_http_put_prepare, -}; - -static void hap_send_notification(void *arg) -{ - int num_char = hap_priv.cfg.max_event_notif_chars; - hap_char_t *hc; - hap_char_t **char_arr = hap_platform_memory_calloc(num_char, sizeof(hap_char_t *)); - - if (!char_arr) { - return; - } - - int i, num_notif_chars; - for (i = 0; i < num_char; i++) { - hc = hap_get_pending_notif_char(); - if (hc) { - char_arr[i] = hc; - } else { - break; - } - } - /* If no characteristic notifications are pending, free char_arr and exit */ - if (i == 0) { - hap_platform_memory_free(char_arr); - return; - } - num_notif_chars = i; - hap_secure_session_t *session; - /* Flag to indicate if any controller was connected */ - bool ctrl_connected = false; - char buf[250]; - for (i = 0; i < HAP_MAX_SESSIONS; i++) { - session = hap_priv.sessions[i]; - if (!session) - continue; - ctrl_connected = true; - int fd = session->conn_identifier; -#define HTTPD_HDR_STR "EVENT/1.0 200 OK\r\n" \ - "Content-Type: application/hap+json\r\n" \ - "Content-Length: %d\r\n" - char notif_json[1024]; - json_gen_str_t jstr; - json_gen_str_start(&jstr, notif_json, sizeof(notif_json), NULL, NULL); - json_gen_start_object(&jstr); - json_gen_push_array(&jstr, "characteristics"); - - int j; - bool notif_to_send = false; - for (j = 0; j < num_notif_chars; j++) { - hc = char_arr[j]; - __hap_char_t *_hc = ( __hap_char_t *)hc; - /* If the controller is the owner, dont send notification to it */ - if (hap_char_is_ctrl_owner(hc, i)) { - /* Since there can be only one owner, which we are anyways skipping, - * we can reset owner value to 0 - */ - _hc->owner_ctrl = 0; - continue; - } - if (!hap_char_is_ctrl_subscribed(hc, i)) - continue; - - json_gen_start_object(&jstr); - hap_acc_t *ha = hap_serv_get_parent(hap_char_get_parent(hc)); - int aid = ((__hap_acc_t *)ha)->aid; - json_gen_obj_set_int(&jstr, "aid", aid); - json_gen_obj_set_int(&jstr, "iid", _hc->iid); - hap_add_char_val_json(_hc->format, "value", &_hc->val, &jstr); - json_gen_end_object(&jstr); - notif_to_send = true; - } - if (!notif_to_send) { - /* No notification required for this controller. Just continue */ - continue; - } - - json_gen_pop_array(&jstr); - json_gen_end_object(&jstr); - json_gen_str_end(&jstr); - - snprintf(buf, sizeof(buf), HTTPD_HDR_STR, - strlen(notif_json)); - hap_httpd_send(hap_priv.server, fd, buf, strlen(buf), 0); - /* Space for sending additional headers based on set_header */ - hap_httpd_send(hap_priv.server, fd, "\r\n", strlen("\r\n"), 0); - hap_httpd_send(hap_priv.server, fd, notif_json, strlen(notif_json), 0); - httpd_sess_update_lru_counter(hap_priv.server, fd); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Notification Sent"); - ESP_MFI_DEBUG_PLAIN("Socket fd: %d; Event message: %s\n", fd, notif_json); - } - /* If no controller was connected and no disconnected event was sent, - * reannaounce mDNS. That will increment state number as required - * by HAP Spec R15. - */ - if (!ctrl_connected && !hap_priv.disconnected_event_sent) { - hap_mdns_announce(false); - hap_priv.disconnected_event_sent = true; - } - hap_platform_memory_free(char_arr); -} - -void hap_http_debug_enable() -{ - http_debug = true; -} - -void hap_http_debug_disable() -{ - http_debug = false; -} - -void hap_http_send_notif() -{ - httpd_queue_work(hap_priv.server, hap_send_notification, NULL); -} - -static bool hap_http_registered; -int hap_register_http_handlers() -{ - if (!hap_http_registered) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Registering HomeKit web handlers"); - httpd_register_uri_handler(hap_priv.server, &hap_pair_setup); - httpd_register_uri_handler(hap_priv.server, &hap_pair_verify); - httpd_register_uri_handler(hap_priv.server, &hap_pairings); - httpd_register_uri_handler(hap_priv.server, &hap_accessories); - httpd_register_uri_handler(hap_priv.server, &hap_characteristics_get); - httpd_register_uri_handler(hap_priv.server, &hap_characteristics_put); - httpd_register_uri_handler(hap_priv.server, &hap_identify); - httpd_register_uri_handler(hap_priv.server, &hap_prepare); - if (hap_priv.features & HAP_FF_SW_TOKEN_AUTH) { - hap_register_secure_message_handler(hap_priv.server); - } - } - hap_http_registered = true; - return HAP_SUCCESS; -} - -int hap_unregister_http_handlers() -{ - if (hap_http_registered) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Unegistering HomeKit web handlers"); - httpd_unregister_uri_handler(hap_priv.server, "/pair-setup", HTTP_POST); - httpd_unregister_uri_handler(hap_priv.server, "/pair-verify", HTTP_POST); - httpd_unregister_uri_handler(hap_priv.server, "/pairings", HTTP_POST); - httpd_unregister_uri_handler(hap_priv.server, "/accessories", HTTP_GET); - httpd_unregister_uri_handler(hap_priv.server, "/characteristics", HTTP_GET); - httpd_unregister_uri_handler(hap_priv.server, "/characteristics", HTTP_PUT); - httpd_unregister_uri_handler(hap_priv.server, "/identify", HTTP_POST); - httpd_unregister_uri_handler(hap_priv.server, "/prepare", HTTP_PUT); - if (hap_priv.features & HAP_FF_SW_TOKEN_AUTH) { - hap_unregister_secure_message_handler(hap_priv.server); - } - } - hap_http_registered = false; - return HAP_SUCCESS; -} - -int hap_httpd_start(void) -{ - if (hap_platform_httpd_start(&hap_priv.server) == ESP_OK) { - return HAP_SUCCESS; - } - return HAP_FAIL; -} - -httpd_handle_t * hap_httpd_get_handle() -{ - return &hap_priv.server; -} -static bool first_announce_done; - -int hap_mdns_deannounce(void) -{ - int ret = HAP_SUCCESS; - if (first_announce_done) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Deannouncing _hap._tcp mDNS service"); - ret = hap_mdns_serv_stop(&hap_priv.hap_mdns_handle); - if (ret == HAP_SUCCESS) { - /* Wait for some time for the packets to go out on network */ - vTaskDelay(2000 / hap_platform_os_get_msec_per_tick()); - first_announce_done = false; - } - } - return ret; -} - -int hap_mdns_announce(bool first) -{ - /* If the API is called with the "first" argument as true, Force announce the service, - * rather than just sending a re-announce packet - */ - if (first) { - first_announce_done = false; - } - static char config_num[6]; /* Max value can be 65535 */ - static char state_num[6]; /* Max value can be 65535 */ - static char ff[4]; - static char sf[4]; - static char ci[4]; - - mdns_txt_item_t txt[9]; - int i = 0; - - snprintf(config_num, sizeof(config_num), "%d", hap_priv.config_num); - txt[i].key = "c#"; - txt[i++].value = config_num; - - - uint8_t features = 0; - /* Either hardware authentication, or software authentication - * can be enabled at a time. - */ - if (hap_priv.features & HAP_FF_HARDWARE_AUTH) { - features |= HAP_FF_HARDWARE_AUTH; - } else if (hap_priv.features & HAP_FF_SW_TOKEN_AUTH) { - features |= HAP_FF_SW_TOKEN_AUTH; - } - snprintf(ff, sizeof(ff), "%d", features); - txt[i].key = "ff"; - txt[i++].value = ff; - - txt[i].key = "id"; - txt[i++].value = hap_priv.acc_id; - - txt[i].key = "md"; - txt[i++].value = hap_priv.primary_acc.model; - - txt[i].key = "pv"; - txt[i++].value = "1.1"; /* As per HAP Spec R10 */ - - if (first_announce_done) { - /* If first announcement was already done, this is a republish. - * Update the state number, since HAP Spec R15 requires that any Bonjour republish - * should update state number. - */ - if (is_accessory_paired()) { - hap_increment_and_save_state_num(); - } - } - snprintf(state_num, sizeof(state_num), "%u", hap_priv.state_num); - txt[i].key = "s#"; - txt[i++].value = state_num; - - uint8_t status_flags = is_accessory_paired() ? 0 : HAP_SF_ACC_UNPAIRED; - if (!hap_is_network_configured()) - status_flags |= HAP_SF_ACC_UNCONFIGURED; - snprintf(sf, sizeof(sf), "%d", status_flags); - txt[i].key = "sf"; - txt[i++].value = sf; - - snprintf(ci, sizeof(ci), "%d", hap_priv.cid); - txt[i].key = "ci"; - txt[i++].value = ci; - - txt[i].key = "sh"; - txt[i++].value = hap_priv.setup_hash_str; - - int ret; - /* If first announce is not done, the service will be added instead of just updating. - * Else, first add the service, instead of just updating. - */ - if (!first_announce_done) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Announcing _hap._tcp mDNS service"); - ret = hap_mdns_serv_start(&hap_priv.hap_mdns_handle, - hap_priv.primary_acc.name, "_hap", "_tcp", hap_platform_httpd_get_port(), txt, i); - first_announce_done = true; - } else { - /* Else, just update TXT records. Not add new service.*/ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Re-announcing _hap._tcp mDNS service"); - ret = hap_mdns_serv_update_txt(&hap_priv.hap_mdns_handle, txt, i); - } - if (ret != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to announce _hap mDNS service"); - return HAP_FAIL; - } - return HAP_SUCCESS; -} - -int hap_ip_services_start() -{ - static bool hap_ip_services_started; - if (hap_ip_services_started) { - return HAP_SUCCESS; - } - hap_register_http_handlers(); - if (hap_mdns_announce(false) != HAP_SUCCESS) { - hap_unregister_http_handlers(); - return HAP_FAIL; - } - hap_ip_services_started = true; - return HAP_SUCCESS; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.h deleted file mode 100644 index fa65bfa10..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_ip_services.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_IP_SERVICES_H_ -#define _HAP_IP_SERVICES_H_ -#include -#include -int hap_http_session_not_authorized(httpd_req_t *req); -int hap_httpd_get_data(httpd_req_t *req, char *buffer, int len); -int hap_httpd_start(); -int hap_ip_services_start(); -int hap_mdns_announce(bool first); -int hap_mdns_deannounce(); -void hap_http_send_notif(); -#endif /* _HAP_IP_SERVICES_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_keystore.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_keystore.c deleted file mode 100644 index 43a72021b..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_keystore.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include - -static bool keystore_init_done; -static char *hap_platform_nvs_partition; -static char *hap_platform_factory_nvs_partition; - -int hap_keystore_init() -{ - if (keystore_init_done) { - return HAP_SUCCESS; - } - - - - hap_platform_nvs_partition = hap_platform_keystore_get_nvs_partition_name(); - - // hap_platfrom_keystore_erase_partition(hap_platform_nvs_partition); - - int err = hap_platform_keystore_init_partition(hap_platform_nvs_partition, false); - if (err != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Error (%d) NVS init failed", err); - return HAP_FAIL; - } - /* Not cheking the return value, as this partition may be absent */ - hap_platform_factory_nvs_partition = hap_platform_keystore_get_factory_nvs_partition_name(); - hap_platform_keystore_init_partition(hap_platform_factory_nvs_partition, true); - - keystore_init_done = true; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Keystore initialised"); - return HAP_SUCCESS; -} - -int __hap_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size) -{ - if (!keystore_init_done) { - return HAP_FAIL; - } - - int err = hap_platform_keystore_get(part_name, name_space, key, val, val_size); - if (err != 0) { - return HAP_FAIL; - } - return HAP_SUCCESS; -} -int hap_keystore_get(const char *name_space, const char *key, uint8_t *val, size_t *val_size) -{ - - return __hap_keystore_get(hap_platform_nvs_partition, name_space, key, val, val_size); -} -int hap_factory_keystore_get(const char *name_space, const char *key, uint8_t *val, size_t *val_size) -{ - return __hap_keystore_get(hap_platform_factory_nvs_partition, name_space, key, val, val_size); -} - -int __hap_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len) - -{ - if (!keystore_init_done) { - return HAP_FAIL; - } - - int err = hap_platform_keystore_set(part_name, name_space, key, val, val_len); - if (err != 0) { - return HAP_FAIL; - } - return HAP_SUCCESS; -} - -int hap_keystore_set(const char *name_space, const char *key, const uint8_t *val, const size_t val_len) -{ - return __hap_keystore_set(hap_platform_nvs_partition, name_space, key, val, val_len); -} - -int hap_factory_keystore_set(const char *name_space, const char *key, const uint8_t *val, const size_t val_len) -{ - return __hap_keystore_set(hap_platform_factory_nvs_partition, name_space, key, val, val_len); -} - -int hap_keystore_delete(const char *name_space, const char *key) -{ - if (!keystore_init_done) { - return HAP_FAIL; - } - - int err = hap_platform_keystore_delete(hap_platform_nvs_partition, name_space, key); - if (err != 0) { - return HAP_FAIL; - } - return HAP_SUCCESS; -} - -int hap_keystore_delete_namespace(const char *name_space) -{ - if (!keystore_init_done) { - return HAP_FAIL; - } - - int err = hap_platform_keystore_delete_namespace(hap_platform_nvs_partition, name_space); - if (err != 0) { - return HAP_FAIL; - } - return HAP_SUCCESS; -} - -void hap_keystore_erase_all_data() -{ - hap_platfrom_keystore_erase_partition(hap_platform_nvs_partition); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_keystore.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_keystore.h deleted file mode 100644 index 26587e867..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_keystore.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_KEYSTORE_H_ -#define _HAP_KEYSTORE_H_ -#include -int hap_keystore_init(); -int hap_keystore_get(const char *name_space, const char *key, uint8_t *val, size_t *val_size); -int hap_keystore_set(const char *name_space, const char *key, const uint8_t *val, const size_t val_len); -int hap_keystore_delete(const char *name_space, const char *key); -int hap_keystore_delete_namespace(const char *name_space); -int hap_factory_keystore_set(const char *name_space, const char *key, const uint8_t *val, const size_t val_len); -void hap_keystore_erase_all_data(); -#endif /* _HAP_KEYSTORE_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.c deleted file mode 100644 index 2ed94b216..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include <_esp_hap_config.h> -#include -#include - -static QueueHandle_t xQueue; -ESP_EVENT_DEFINE_BASE(HAP_EVENT); -// static TaskHandle_t hap_loop_handle; - -const char * hap_get_version(void) -{ - return MFI_VER; -} -static void hap_nw_configured_sm(hap_internal_event_t event, hap_state_t *state) -{ - switch (event) { - case HAP_INTERNAL_EVENT_ACC_PAIRED: - hap_mdns_announce(false); - break; - case HAP_INTERNAL_EVENT_ACC_UNPAIRED: - hap_mdns_announce(false); - break; - case HAP_INTERNAL_EVENT_CONFIG_NUM_UPDATED: - hap_increment_and_save_config_num(); - hap_mdns_announce(false); - break; - case HAP_INTERNAL_EVENT_BCT_CHANGE_NAME: - /* Waiting for sometime to allow the response to reach the host */ - vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); - hap_handle_bct_change_name(); - break; - case HAP_INTERNAL_EVENT_BCT_HOT_PLUG: - /* Waiting for sometime to allow the response to reach the host */ - vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); - hap_handle_hot_plug(); - break; - default: - break; - } -} - -static void hap_common_sm(hap_internal_event_t event) -{ - const char *reboot_reason = HAP_REBOOT_REASON_UNKNOWN; - switch (event) { - case HAP_INTERNAL_EVENT_RESET_PAIRINGS: - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting all Pairing Information"); - /* Wait for some time before erasing the information, so that the callee - * gets some time for any additional operations - */ - vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); - hap_close_all_sessions(); - hap_mdns_deannounce(); - hap_erase_controller_info(); - hap_erase_accessory_info(); - reboot_reason = HAP_REBOOT_REASON_RESET_PAIRINGS; - break; - case HAP_INTERNAL_EVENT_RESET_TO_FACTORY: - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting to Factory Defaults"); - /* Wait for some time before erasing the information, so that the callee - * gets some time for any additional operations - */ - vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); - hap_close_all_sessions(); - hap_mdns_deannounce(); - hap_keystore_erase_all_data(); - reboot_reason = HAP_REBOOT_REASON_RESET_TO_FACTORY; - break; - case HAP_INTERNAL_EVENT_RESET_HOMEKIT_DATA: - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting all HomeKit Data"); - /* Wait for some time before erasing the information, so that the callee - * gets some time for any additional operations - */ - vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); - hap_close_all_sessions(); - hap_mdns_deannounce(); - hap_erase_controller_info(); - hap_erase_network_info(); - hap_erase_accessory_info(); - reboot_reason = HAP_REBOOT_REASON_RESET_HOMEKIT_DATA; - break; - case HAP_INTERNAL_EVENT_REBOOT: - vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); - /* Wait for some time and then close all the active sessions - */ - hap_close_all_sessions(); - hap_mdns_deannounce(); - reboot_reason = HAP_REBOOT_REASON_REBOOT_ACC; - break; - case HAP_INTERNAL_EVENT_RESET_NETWORK: - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Resetting Network Credentials"); - /* Wait for some time, close all the active sessions and then - * erase network info. - */ - vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); - hap_close_all_sessions(); - hap_mdns_deannounce(); - hap_erase_network_info(); - reboot_reason = HAP_REBOOT_REASON_RESET_NETWORK; - break; - case HAP_INTERNAL_EVENT_TRIGGER_NOTIF: -/* TODO: Avoid direct http function. Notification could be even for iCloud or BLE. - */ - hap_http_send_notif(); - return; - default: - return; - } - - /* Wait for some time after peeforming the operations and then reboot */ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Rebooting..."); - hap_report_event(HAP_EVENT_ACC_REBOOTING, (void*)reboot_reason, strlen(reboot_reason) + 1); - vTaskDelay(1000 / hap_platform_os_get_msec_per_tick()); - esp_restart(); -} - -static void hap_loop_task(void *param) -{ - hap_state_t cur_state = HAP_STATE_NONE; - xQueue = xQueueCreate( 10, sizeof(hap_event_ctx_t) ); - hap_event_ctx_t hap_event; - bool loop_continue = true; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HAP Main Loop Started"); - while (loop_continue) { - if (xQueueReceive(xQueue, &hap_event, portMAX_DELAY) != pdTRUE) { - continue; - } - if (hap_event.event == HAP_INTERNAL_EVENT_LOOP_STOP) { - loop_continue = false; - continue; - } - hap_common_sm(hap_event.event); - hap_nw_configured_sm(hap_event.event, &cur_state); - } - vQueueDelete(xQueue); - xQueue = NULL; - vTaskDelete(NULL); -} - -static bool loop_started; -int hap_loop_start() -{ - if (!loop_started) { - loop_started = true; - xTaskCreate(hap_loop_task, "hap-loop", hap_priv.cfg.task_stack_size, NULL, - hap_priv.cfg.task_priority, NULL); - } - return HAP_SUCCESS; -} - -bool is_hap_loop_started() -{ - return loop_started; -} -int hap_send_event(hap_internal_event_t event) -{ - if (!is_hap_loop_started()) { - return HAP_FAIL; - } - if (!xQueue) { - return HAP_FAIL; - } - hap_event_ctx_t hap_event = { - .event = event, - }; - BaseType_t ret; - if (xPortInIsrContext() == pdTRUE) { - ret = xQueueSendFromISR(xQueue, &hap_event, NULL); - } else { - ret = xQueueSend(xQueue, &hap_event, 0); - } - if (ret == pdTRUE) { - return HAP_SUCCESS; - } - return HAP_FAIL; -} - -int hap_update_config_number() -{ - return hap_send_event(HAP_INTERNAL_EVENT_CONFIG_NUM_UPDATED); -} - -int hap_loop_stop() -{ - return hap_send_event(HAP_INTERNAL_EVENT_LOOP_STOP); -} - -#if 0 -static void hap_network_event_handler(void* arg, esp_event_base_t event_base, - int event_id, void* event_data) -{ - if (((event_base == WIFI_EVENT) && (event_id == WIFI_EVENT_STA_CONNECTED)) || - ((event_base == ETH_EVENT) && (event_id == ETHERNET_EVENT_CONNECTED))){ - hap_send_event(HAP_INTERNAL_EVENT_NETWORK_CONNECTED); - } -} -#endif -int hap_init(hap_transport_t method) -{ - int ret = HAP_SUCCESS; - if (!(method & (HAP_TRANSPORT_WIFI | HAP_TRANSPORT_ETHERNET))) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid Transport"); - return HAP_FAIL; - } - - hap_priv.transport = method; - - ret = hap_keystore_init(); - if (ret != 0 ) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP Key Store Init failed"); - return ret; - } - - ret = hap_database_init(); - if (ret != 0 ) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP Database Init failed"); - return ret; - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HAP Initialization succeeded. Version : %s", hap_get_version()); - - return ret; -} - -int hap_deinit(void) -{ - int ret = HAP_SUCCESS; - //todo - return ret; -} - -int hap_reset_to_factory() -{ - return hap_send_event(HAP_INTERNAL_EVENT_RESET_TO_FACTORY); -} - -int hap_reset_homekit_data() -{ - return hap_send_event(HAP_INTERNAL_EVENT_RESET_HOMEKIT_DATA); -} - -int hap_reset_pairings() -{ - return hap_send_event(HAP_INTERNAL_EVENT_RESET_PAIRINGS); -} - -int hap_reboot_accessory() -{ - return hap_send_event(HAP_INTERNAL_EVENT_REBOOT); -} - -int hap_reset_network() -{ - return hap_send_event(HAP_INTERNAL_EVENT_RESET_NETWORK); -} - -int hap_start(void) -{ - int ret = 0; -#ifdef CONFIG_HAP_MFI_ENABLE - if (hap_priv.auth_type == HAP_MFI_AUTH_HW) { - ret = hap_enable_hw_auth(); - } else if (hap_priv.auth_type == HAP_MFI_AUTH_SW) { - ret = hap_enable_sw_auth(); - } -#endif /* CONFIG_HAP_MFI_ENABLE */ - if (ret != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to enable MFi %s authentication", - hap_priv.auth_type == HAP_MFI_AUTH_HW ? "HW" : "SW"); - return HAP_FAIL; - } - - if (!hap_get_first_acc()) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to start HAP. Please add an Accessory before hap_start()"); - return HAP_FAIL; - } - - ret = hap_acc_setup_init(); - if (ret != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Accessory Setup init failed"); - return ret; - } - - ret = hap_httpd_start(); - if (ret != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HTTPD START Failed [%d]", ret); - return ret; - } - - ret = hap_event_queue_init(); - if (ret != HAP_SUCCESS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Queue Initialisation for Event Notifications Failed"); - return ret; - } - - ret = hap_loop_start(); - if (ret != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP Loop Failed: [%d]", ret); - return ret; - } - ret = hap_mdns_init(); - if (ret != 0 ) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP mDNS Init failed"); - return ret; - } - - ret = hap_ip_services_start(); - if (ret != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "HAP IP Services Start Failed [%d]", ret); - return ret; - } - return HAP_SUCCESS; -} - -int hap_stop(void) -{ - int ret = HAP_SUCCESS; - hap_mdns_deannounce(); - hap_mdns_deinit(); - httpd_handle_t _handle = hap_platform_httpd_get_handle(); - if(_handle != NULL) hap_platform_httpd_stop(_handle); - ret = hap_loop_stop(); - return ret; -} - -void hap_report_event(hap_event_t event, void *data, size_t data_size) -{ - if (hap_priv.hap_event_handler) { - hap_priv.hap_event_handler(event, data); - } - esp_event_post(HAP_EVENT, event, data, data_size, portMAX_DELAY); -} - -void hap_register_event_handler(hap_event_handler_t handler) -{ - hap_priv.hap_event_handler = handler; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.h deleted file mode 100644 index 508c856ef..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_main.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _HAP_MAIN_LOOP_H_ -#define _HAP_MAIN_LOOP_H_ -#include -#include - -#define HAP_FF_HARDWARE_AUTH 0x01 -#define HAP_FF_SW_TOKEN_AUTH 0x02 - - -#define HAP_SF_ACC_UNPAIRED 0x01 -#define HAP_SF_ACC_UNCONFIGURED 0x02 -#define HAP_SF_PROBLEM_DETECTED 0x04 - -typedef enum { - HAP_INTERNAL_EVENT_LOOP_STOP = 1, - HAP_INTERNAL_EVENT_ACC_PAIRED, - HAP_INTERNAL_EVENT_ACC_UNPAIRED, - HAP_INTERNAL_EVENT_CONFIG_NUM_UPDATED, - HAP_INTERNAL_EVENT_BCT_CHANGE_NAME, - HAP_INTERNAL_EVENT_BCT_HOT_PLUG, - HAP_INTERNAL_EVENT_RESET_PAIRINGS, - HAP_INTERNAL_EVENT_RESET_TO_FACTORY, - HAP_INTERNAL_EVENT_REBOOT, - HAP_INTERNAL_EVENT_RESET_NETWORK, - HAP_INTERNAL_EVENT_TRIGGER_NOTIF, - HAP_INTERNAL_EVENT_RESET_HOMEKIT_DATA, -} hap_internal_event_t; - -typedef struct { - hap_internal_event_t event; -} hap_event_ctx_t; - -typedef enum { - HAP_STATE_NONE = 0, - HAP_STATE_NW_UNCONFIGURED, - HAP_STATE_NW_CONFIGURED, -} hap_state_t; - -int hap_loop_start(); -int hap_loop_stop(); -int hap_send_event(hap_internal_event_t event); -int hap_update_config_number(); -bool is_hap_loop_started(); -void hap_report_event(hap_event_t event, void *data, size_t data_size); -int hap_enable_hw_auth(void); -int hap_enable_sw_auth(void); - -#endif /* _HAP_MAIN_LOOP_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_mdns.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_mdns.c deleted file mode 100644 index 2ccda5686..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_mdns.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include - -static bool mdns_init_done; - -int hap_mdns_serv_start(hap_mdns_handle_t *handle, const char *name, const char *type, - const char *protocol, int port, mdns_txt_item_t *txt_records, size_t num_txt) -{ - strcpy(handle->type, type); - strcpy(handle->proto, protocol); - if (mdns_service_add(name, type, protocol, port, txt_records, num_txt) != 0) { - return HAP_FAIL; - } - return HAP_SUCCESS; -} - -int hap_mdns_serv_update_txt(hap_mdns_handle_t *handle, mdns_txt_item_t *txt_records, size_t num_txt) -{ - if (mdns_service_txt_set(handle->type, handle->proto, txt_records, num_txt) != 0) { - return HAP_FAIL; - } - return HAP_SUCCESS; -} - -int hap_mdns_serv_name_change(hap_mdns_handle_t *handle, const char * instance_name) -{ - if (mdns_service_instance_name_set(handle->type, handle->proto, instance_name) == ESP_OK) { - return HAP_SUCCESS; - } - return HAP_FAIL; -} - -int hap_mdns_serv_stop(hap_mdns_handle_t *handle) -{ - if (mdns_service_remove(handle->type, handle->proto) == ESP_OK) { - return HAP_SUCCESS; - } - return HAP_FAIL; -} - -int hap_mdns_init() -{ - int ret = HAP_SUCCESS; - if (!mdns_init_done) { - ret = mdns_init(); - if (ret == ESP_OK) { - mdns_hostname_set("MyHost"); - mdns_init_done = true; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "mDNS initialised"); - return HAP_SUCCESS; - } - } - return HAP_FAIL; -} - -int hap_mdns_deinit() -{ - mdns_free(); - mdns_init_done = false; - return HAP_SUCCESS; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_mdns.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_mdns.h deleted file mode 100644 index c206161ee..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_mdns.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_MDNS_H_ -#define _HAP_MDNS_H_ - -#include -#include - -typedef struct { - char type[32]; - char proto[32]; -} hap_mdns_handle_t; - -int hap_mdns_serv_start(hap_mdns_handle_t *handle, const char *name, const char *type, - const char *protocol, int port, mdns_txt_item_t *txt_records, size_t num_txt); -int hap_mdns_serv_update_txt(hap_mdns_handle_t *handle, mdns_txt_item_t *txt_records, size_t num_txt); -int hap_mdns_serv_name_change(hap_mdns_handle_t *handle, const char * instance_name); -int hap_mdns_serv_stop(hap_mdns_handle_t *handle); -int hap_mdns_init(); -int hap_mdns_deinit(); - -#endif /* _HAP_MDNS_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_network_io.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_network_io.c deleted file mode 100644 index 2342773aa..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_network_io.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#define HAP_MAX_NW_FRAME_SIZE 1024 /* As per HAP Specifications */ -#define AUTH_TAG_LEN 16 -typedef struct { - uint8_t pkt_size[2]; - uint8_t data[HAP_MAX_NW_FRAME_SIZE]; - /* The Poly auth tag buffer will get used only if the data length is - * greater than HAP_MAX_NW_FRAME_SIZE - 16. - * Else, the auth tag would be included in the data buffer itself - */ - uint8_t poly_auth_tag[AUTH_TAG_LEN]; -} hap_encrypt_frame_t; - -typedef struct { - uint16_t pkt_size; - uint16_t bytes_read; - uint8_t data[HAP_MAX_NW_FRAME_SIZE + AUTH_TAG_LEN]; - hap_secure_session_t *session; -} hap_decrypt_frame_t; - -typedef int (*hap_decrypt_read_fn_t) (uint8_t *buf, int buf_size, void *context); -static int min(int val1, int val2) -{ - if (val1 < val2) - return val1; - return val2; -} -static int hap_httpd_raw_recv(uint8_t *buf, int buf_size, void *context) -{ - int sock = *((int *)context); - return recv(sock, buf, buf_size, 0); -} - -/* Frame format as per HAP Specifications: - * <2: AAD for Little Endian length of encrypted data (n) in bytes> - * - * <16: authTag according to AEAD algorithm> - */ -int hap_encrypt_data(hap_encrypt_frame_t *frame, hap_secure_session_t *session, - uint8_t *buf, int buflen) -{ - if (!session) - return HAP_FAIL; - put_u16_le(frame->pkt_size, buflen); - /* Encrypt the received data as per Chacha20-Poly1305 AEAD algorithm. - * The authTag will be appended at the end of data. Hence, pointer given as - * frame->data + nlen - */ - unsigned long long mlen = 16; - uint8_t newnonce[12]; - memset(newnonce, 0, sizeof newnonce); - memcpy(newnonce+4, session->encrypt_nonce, 8); - crypto_aead_chacha20poly1305_ietf_encrypt_detached(frame->data, frame->data + buflen, &mlen, - buf, buflen, frame->pkt_size, 2, NULL, newnonce, session->encrypt_key); - - /* Increment nonce after every frame */ - uint64_t int_nonce = get_u64_le(session->encrypt_nonce); - int_nonce++; - put_u64_le(session->encrypt_nonce, int_nonce); - return 2 + buflen + 16; /* Total length of the encrypted data */ -} - -#include -void hap_close_ctrl_sessions_fix(hap_secure_session_t *session) -{ - if (!session) - return; - int i; - printf("---- hap_close_ctrl_sessions_fix begin -----\n"); - for (i = 0; i < HAP_MAX_SESSIONS; i++) { - if (!hap_priv.sessions[i]) - continue; - if (hap_priv.sessions[i] == session) { - hap_report_event(HAP_EVENT_CTRL_DISCONNECTED, (session->ctrl->info.id), - sizeof((session->ctrl->info.id))); - /* TODO: Use some generic function and not a direct HTTPD function - */ - printf("---- trigger_close fd: %d\n", hap_priv.sessions[i]->conn_identifier); - httpd_sess_trigger_close(hap_priv.server, hap_priv.sessions[i]->conn_identifier); - } - } - printf("---- hap_close_ctrl_sessions_fix end ----\n"); -} - -int hap_decrypt_error(hap_secure_session_t *session) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Decryption error/Connection lost. Marking session as invalid"); - if (session) { - session->state = STATE_INVALID; - //hap_close_ctrl_sessions(session->ctrl); - hap_close_ctrl_sessions_fix(session); - } - return HAP_FAIL; -} - -int hap_decrypt_data(hap_decrypt_frame_t *frame, hap_secure_session_t *session, - void *buf, int buf_size, hap_decrypt_read_fn_t read_fn, void *context) -{ - if (!frame || !session) - return -1; - if (frame->session != session) { - memset(frame, 0, sizeof(hap_decrypt_frame_t)); - frame->session = session; - } - if ((frame->pkt_size - frame->bytes_read) == 0) { - int len = read_fn(frame->data, 2, context); - if (len == 0) { //nothing received, but we should NOT consider this is a 'decrypt_error' - return 0; - } - if (len < 2) { - //len is -1 or 1 - //len = -1: socket disconnected - //len = 1: try receiving 2 bytes timeout (SO_RCVTIMEO is set in esp_hap_ip_services.c) - printf("---- error 1 ----, len: %d\n", len); - //Decryption error/Connection lost on ESP32 with multiple Apple devices running Home - //https://github.com/espressif/esp-homekit-sdk/issues/14 - //---- error 1 ----, len: 0 - return hap_decrypt_error(session); - } - - frame->pkt_size = get_u16_le(frame->data); - frame->bytes_read = 0; - uint16_t bytes_to_read = frame->pkt_size + AUTH_TAG_LEN; /* +AUTH_TAG_LEN as the receivedd packet will also have the auth Tag */ - while (bytes_to_read) { - int num_bytes = read_fn(&frame->data[frame->bytes_read], - bytes_to_read, context); - if (num_bytes <= 0) { - printf("---- error 2 ----\n"); - return hap_decrypt_error(session); - } - bytes_to_read -= num_bytes; - frame->bytes_read += num_bytes; - } - frame->bytes_read -= AUTH_TAG_LEN; /* -AUTH_TAG_LEN to get only the data length */ - uint8_t aad[2]; - int ret; - put_u16_le(aad, frame->pkt_size); /* Packet size is the AAD for AEAD */ - uint8_t newnonce[12]; - memset(newnonce, 0, sizeof newnonce); - memcpy(newnonce+4, session->decrypt_nonce, 8); - ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached(frame->data, NULL, frame->data, frame->pkt_size, - &frame->data[frame->bytes_read], aad, 2, newnonce, session->decrypt_key); - if (ret != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "AEAD decryption failure"); - printf("---- error 3 ----\n"); - return hap_decrypt_error(session); - } - frame->bytes_read = 0; - /* Increment nonce after every frame */ - int64_t int_nonce = get_u64_le(session->decrypt_nonce); - int_nonce++; - put_u64_le(session->decrypt_nonce, int_nonce); - } - int bytes = min(frame->pkt_size - frame->bytes_read, buf_size); - memcpy(buf, &frame->data[frame->bytes_read], bytes); - frame->bytes_read += bytes; - return bytes; -} - -int hap_httpd_send(httpd_handle_t hd, int sockfd, const char *buf, unsigned buf_len, int flags) -{ - hap_secure_session_t *session = httpd_sess_get_ctx(hap_priv.server, sockfd); - if (session && (session->state == STATE_VERIFIED)) { - uint8_t *buf_ptr = (uint8_t *)buf; - int tmp_buf_len = buf_len; - while (tmp_buf_len) { - hap_encrypt_frame_t encrypt_frame; - memset(&encrypt_frame, 0, sizeof(encrypt_frame)); - int len = min(tmp_buf_len, HAP_MAX_NW_FRAME_SIZE); - int send_len = hap_encrypt_data(&encrypt_frame, session, buf_ptr, len); - if (send(sockfd, (uint8_t *)&encrypt_frame, send_len, flags) <= 0) - return HAP_FAIL; - tmp_buf_len -= len; - buf_ptr += len; - } - /* Return the total length at the end since this API expects so - */ - return buf_len; - } - return send(sockfd, buf, buf_len, flags); -} - -int hap_httpd_recv(httpd_handle_t hd, int sockfd, char *buf, unsigned buf_len, int flags) -{ - static hap_decrypt_frame_t decrypt_frame; - hap_secure_session_t *session = httpd_sess_get_ctx(hap_priv.server, sockfd); - if (session) { - if (session->state == STATE_VERIFIED) { - return hap_decrypt_data(&decrypt_frame, session, buf, buf_len, - hap_httpd_raw_recv, &sockfd); - } else { - /* If the session state is invalid, we return an error. - * The errno is set here explicitly, so that even if the higher layers - * query for it, they do not get a stale value. - * EACCES means permission denied, which indeed is the case here. - */ - errno = EACCES; - return HAP_FAIL; - } - } - return recv(sockfd, buf, buf_len, sockfd); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_network_io.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_network_io.h deleted file mode 100644 index 7c8b3ef03..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_network_io.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_NETWORK_IO_H_ -#define _HAP_NETWORK_IO_H_ -#include -#include -int hap_httpd_send(httpd_handle_t hd, int sockfd, const char *buf, unsigned buf_len, int flags); -int hap_httpd_recv(httpd_handle_t hd, int sockfd, char *buf, unsigned buf_len, int flags); - -#endif /* _HAP_NETWORK_IO_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_common.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_common.c deleted file mode 100644 index 9a003ab6c..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_common.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include - -void hap_tlv_data_init(hap_tlv_data_t *tlv_data, uint8_t *buf, int buf_size) -{ - tlv_data->bufptr = buf; - tlv_data->bufsize = buf_size; - tlv_data->curlen = 0; -} - -int get_tlv_length(uint8_t *buf, int buflen, uint8_t type) -{ - if (!buf ) - return -1; - int curlen = 0; - int val_len = 0; - bool found = false; - while (buflen > 0) { - if (buf[curlen] == type) { - uint8_t len = buf[curlen + 1]; - if ((buflen - len) < 2) - return -1; - val_len += len; - if (len < 255) - return val_len; - else - found = true; - - } else if (found) - return val_len; - - /* buf[curlen +1] will give the Length */ - buflen -= (2 + buf[curlen + 1]); - curlen += (2 + buf[curlen + 1]); - } - return -1; -} -int get_value_from_tlv(uint8_t *buf, int buflen, uint8_t type, void *val, int val_size) -{ - if (!buf || !val) - return -1; - int curlen = 0; - int val_len = 0; - bool found = false; - while (buflen > 0) { - if (buf[curlen] == type) { - uint8_t len = buf[curlen + 1]; - if ((val_size < len) || ((buflen - len) < 2)) - return -1; - memcpy(val + val_len, &buf[curlen + 2], len); - val_len += len; - val_size -= len; - if (len < 255) - return val_len; - else - found = true; - - } else if (found) - return val_len; - - /* buf[curlen +1] will give the Length */ - buflen -= (2 + buf[curlen + 1]); - curlen += (2 + buf[curlen + 1]); - } - return -1; -} - -int add_tlv(hap_tlv_data_t *tlv_data, uint8_t type, int len, void *val) -{ - if(!tlv_data->bufptr || ((len + 2) > (tlv_data->bufsize - tlv_data->curlen))) - return -1; - uint8_t *buf_ptr = (uint8_t *)val; - int orig_len = tlv_data->curlen; - do { - tlv_data->bufptr[tlv_data->curlen++] = type; - int tmp_len; - if (len > 255) - tmp_len = 255; - else - tmp_len = len; - tlv_data->bufptr[tlv_data->curlen++] = tmp_len; - memcpy(&tlv_data->bufptr[tlv_data->curlen], buf_ptr, tmp_len); - tlv_data->curlen += tmp_len; - buf_ptr += tmp_len; - len -= tmp_len; - } while (len); - return tlv_data->curlen - orig_len; -} -void hap_prepare_error_tlv(uint8_t state, uint8_t error, void *buf, int bufsize, int *outlen) -{ - hap_tlv_data_t tlv_data; - tlv_data.bufptr = buf; - tlv_data.bufsize = bufsize; - tlv_data.curlen = 0; - /* Not doing any error handling because the size required for "state" and "error" will - * be too small to cause any error, and we anyways dont have any specific action to - * do in case if error in add_tlv() - */ - add_tlv(&tlv_data, kTLVType_State, sizeof(state), &state); - add_tlv(&tlv_data, kTLVType_Error, sizeof(error), &error); - *outlen = tlv_data.curlen; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_common.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_common.h deleted file mode 100644 index a795d583a..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_common.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_PAIR_COMMON_H_ -#define _HAP_PAIR_COMMON_H_ - -#include -#include -#define ENCRYPT_KEY_LEN 32 -#define POLY_AUTHTAG_LEN 16 -#define CURVE_KEY_LEN 32 -#define ED_SIGN_LEN 64 -#define NONCE_LEN 8 - -#define STATE_M0 0 -#define STATE_M1 1 -#define STATE_M2 2 -#define STATE_M3 3 -#define STATE_M4 4 -#define STATE_M5 5 -#define STATE_M6 6 -#define STATE_VERIFIED 0x55 -#define STATE_INVALID 0xaa - -typedef enum { - HAP_METHOD_RESERVED = 0, - HAP_METHOD_PAIR_SETUP = 1, - HAP_METHOD_PAIR_VERIFY = 2, - HAP_METHOD_ADD_PAIRING = 3, - HAP_METHOD_REMOVE_PAIRING = 4, - HAP_METHOD_LIST_PAIRINGS = 5, -} hap_pairing_methods_t; - - -typedef enum { - kTLVError_Unknown = 0x01, - kTLVError_Authentication = 0x02, - kTLVError_Backoff = 0x03, - kTLVError_MaxPeers = 0x04, - kTLVError_MaxTries = 0x05, - kTLVError_Unavailable = 0x06, - kTLVError_Busy = 0x07, -} hap_tlv_error_t; - -typedef enum { - kTLVType_Method = 0x00, - kTLVType_Identifier = 0x01, - kTLVType_Salt = 0x02, - kTLVType_PublicKey = 0x03, - kTLVType_Proof = 0x04, - kTLVType_EncryptedData = 0x05, - kTLVType_State = 0x06, - kTLVType_Error = 0x07, - kTLVType_RetryDelay = 0x08, - kTLVType_Certificate = 0x09, - kTLVType_Signature = 0x0a, - kTLVType_Permissions = 0x0b, - kTLVType_FragmentedData = 0x0c, - kTLVType_FragmentLast = 0x0d, - kTLVType_Flags = 0x13, - kTLVType_OwnershipProofToken = 0x1A, - kTLVType_ProductData = 0x1C, - kTLVType_Separator = 0xff, -} hap_tlv_type_t; - -typedef struct { - uint8_t *bufptr; - int bufsize; - int curlen; -} hap_tlv_data_t; - -typedef struct { - uint8_t state; - uint8_t encrypt_key[ENCRYPT_KEY_LEN]; - uint8_t decrypt_key[ENCRYPT_KEY_LEN]; - uint8_t encrypt_nonce[NONCE_LEN]; - uint8_t decrypt_nonce[NONCE_LEN]; - hap_ctrl_data_t *ctrl; - uint64_t pid; - int64_t ttl; - int64_t prepare_time; - /* TODO: As of now, this identifier will be the socket - * number, since only http is supported. - * Need to make this generic later. - */ - int conn_identifier; -} hap_secure_session_t; - -void hap_tlv_data_init(hap_tlv_data_t *tlv_data, uint8_t *buf, int buf_size); -int get_value_from_tlv(uint8_t *buf, int buf_len, uint8_t type, void *val, int val_size); -int get_tlv_length(uint8_t *buf, int buflen, uint8_t type); -int add_tlv(hap_tlv_data_t *tlv_data, uint8_t type, int len, void *val); -void hap_prepare_error_tlv(uint8_t state, uint8_t error, void *buf, int buf_size, int *out_len); -#endif /* _HAP_PAIR_COMMON_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_setup.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_setup.c deleted file mode 100644 index 995158d35..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_setup.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* Maximum attempts allowed for Pair Setup, as per HAP Specifications */ -#define HAP_PAIR_SETUP_MAX_ATTEMPTS 100 - -#define PAIR_SETUP_ENCRYPT_SALT "Pair-Setup-Encrypt-Salt" -#define PAIR_SETUP_ENCRYPT_INFO "Pair-Setup-Encrypt-Info" -#define PAIR_SETUP_CTRL_SIGN_SALT "Pair-Setup-Controller-Sign-Salt" -#define PAIR_SETUP_CTRL_SIGN_INFO "Pair-Setup-Controller-Sign-Info" -#define PAIR_SETUP_ACC_SIGN_SALT "Pair-Setup-Accessory-Sign-Salt" -#define PAIR_SETUP_ACC_SIGN_INFO "Pair-Setup-Accessory-Sign-Info" - -#define PS_CTX_INIT 1 -#define PS_CTX_DEINIT 2 - -/* Timeout if pair setup not completed in 1 minute (60sec)*/ -#define HAP_SETUP_TIMEOUT_IN_TICKS ((40 * 1000) / hap_platform_os_get_msec_per_tick()) - -static int hap_pair_setup_process_srp_start(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen, - int bufsize, int *outlen) -{ - /* Pair setup is not allowed if the accessory is already paired */ - if (is_accessory_paired()) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Accessory is already paired. " - "Please use \"Add Pairing\" to add more controllers"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unavailable, buf, bufsize, outlen); - return HAP_FAIL; - } - - /* Pair Setup is not allowed if the failed attempts have exceeded the - * maximum allowed attempts. - */ - if (hap_priv.pair_attempts >= HAP_PAIR_SETUP_MAX_ATTEMPTS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Too many attempts. Aborting"); - hap_prepare_error_tlv(STATE_M2, kTLVError_MaxTries, buf, bufsize, outlen); - return HAP_FAIL; - } - - ps_ctx->ctrl = hap_controller_get_empty_loc(); - if (!ps_ctx->ctrl) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No empty controller slot. Aborting"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - - uint8_t state; - if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || - (get_value_from_tlv(buf, inlen, kTLVType_Method, - &ps_ctx->method, sizeof(ps_ctx->method)) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - if (state != STATE_M1) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M1 Received"); - - int flags_len; - if ((flags_len = get_value_from_tlv(buf, inlen, kTLVType_Flags, &ps_ctx->pairing_flags, sizeof(ps_ctx->pairing_flags))) > 0) { - ps_ctx->pairing_flags_len = flags_len; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Got pairing flags %x", ps_ctx->pairing_flags); - - /* If the Split pairing flag is not set, it is an error */ - if (!(ps_ctx->pairing_flags & PAIR_FLAG_SPLIT)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Pairing Flags received, but the Split flag is not set"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - - /* If either the current or the previous request didn't have transient flag set, return authentication error */ - if (!((ps_ctx->pairing_flags | hap_priv.pairing_flags) & PAIR_FLAG_TRANSIENT)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Split pairing received before preceding Transient Pairing"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Authentication, buf, bufsize, outlen); - return HAP_FAIL; - } - } - hap_priv.pairing_flags = ps_ctx->pairing_flags; - - int len_B = 0; - char *bytes_B; - - /* Create SRP Salt and Verifier for the provided pairing PIN */ - mu_srp_init(&ps_ctx->srp_hd, MU_NG_3072); - - /* If a setup code is explicitly set, use it */ - if (hap_priv.setup_code) { - ps_ctx->len_s = 16; - mu_srp_srv_pubkey(&ps_ctx->srp_hd, "Pair-Setup", (const char*)hap_priv.setup_code, strlen(hap_priv.setup_code), - ps_ctx->len_s, &bytes_B, &len_B, &ps_ctx->bytes_s); - } else { - /* Else, use the salt and verifier for SRP. This should be the default production case - */ - if (mu_srp_set_salt_verifier(&ps_ctx->srp_hd, (char *)hap_priv.setup_info->salt, sizeof(hap_priv.setup_info->salt), - (char *)hap_priv.setup_info->verifier, sizeof(hap_priv.setup_info->verifier)) < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP-6a Salt-Verifier Init Failed"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - ps_ctx->bytes_s = (char *)hap_priv.setup_info->salt; - ps_ctx->len_s = sizeof(hap_priv.setup_info->salt); - mu_srp_srv_pubkey_from_salt_verifier(&ps_ctx->srp_hd, &bytes_B, &len_B); - } - if (!ps_ctx->bytes_s || !bytes_B) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP-6a Verifier Creation Failed"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - - hex_dbg_with_name("salt", (uint8_t *)ps_ctx->bytes_s, ps_ctx->len_s); - hex_dbg_with_name("acc_srp_public_key", (uint8_t *)bytes_B, len_B); - - /* Construct the response M2 */ - hap_tlv_data_t tlv_data; - tlv_data.bufptr = buf; - tlv_data.bufsize = bufsize; - tlv_data.curlen = 0; - state = STATE_M2; - if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) || - (add_tlv(&tlv_data, kTLVType_PublicKey, len_B, (void *)bytes_B) < 0) || - (add_tlv(&tlv_data, kTLVType_Salt, ps_ctx->len_s, ps_ctx->bytes_s) < 0 )) { - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - /* Not adding any error check here, because without the pairing flags, the pairing will - * anyways fail later. - */ - if (ps_ctx->pairing_flags_len) { - add_tlv(&tlv_data, kTLVType_Flags, ps_ctx->pairing_flags_len, &ps_ctx->pairing_flags); - } - *outlen = tlv_data.curlen; - ps_ctx->state = state; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M2 Successful"); - hap_report_event(HAP_EVENT_PAIRING_STARTED, NULL, 0); - return HAP_SUCCESS; -} - - -static int hap_pair_setup_process_srp_verify(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen, - int bufsize, int *outlen) -{ - uint8_t state; - char ctrl_public_key[384]; - int ctrl_public_key_len; - char ctrl_proof[64]; - int ctrl_proof_len; - - if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || - ((ctrl_public_key_len = get_value_from_tlv(buf, inlen, kTLVType_PublicKey, - ctrl_public_key, sizeof(ctrl_public_key))) < 0) || - ((ctrl_proof_len = get_value_from_tlv(buf, inlen, kTLVType_Proof, - ctrl_proof, sizeof(ctrl_proof))) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - if (state != STATE_M3) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M3 Received"); - - hex_dbg_with_name("ctrl_srp_public_key", (uint8_t *)ctrl_public_key, ctrl_public_key_len); - hex_dbg_with_name("ctrl_proof", (uint8_t *)ctrl_proof, ctrl_proof_len); - mu_srp_get_session_key(&ps_ctx->srp_hd, ctrl_public_key, ctrl_public_key_len, &ps_ctx->shared_secret, &ps_ctx->secret_len); - char host_proof[SHA512HashSize]; - int ret = mu_srp_exchange_proofs(&ps_ctx->srp_hd, "Pair-Setup", ctrl_proof, host_proof); - if (ret != 1) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SRP Verify: Controller Authentication failed"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen); - hap_report_event(HAP_EVENT_PAIRING_ABORTED, NULL, 0); - return HAP_FAIL; - } - int acc_proof_length = SHA512HashSize; - - hkdf(SHA512, (uint8_t *) PAIR_SETUP_ENCRYPT_SALT, strlen(PAIR_SETUP_ENCRYPT_SALT), - (uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len, - (uint8_t *) PAIR_SETUP_ENCRYPT_INFO, strlen(PAIR_SETUP_ENCRYPT_INFO), - ps_ctx->session_key, sizeof(ps_ctx->session_key)); - - /* Construct the response M4 */ - hap_tlv_data_t tlv_data; - tlv_data.bufptr = buf; - tlv_data.bufsize = bufsize; - tlv_data.curlen = 0; - state = STATE_M4; - if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) || - (add_tlv(&tlv_data, kTLVType_Proof, acc_proof_length, - (void *)host_proof) < 0)) { - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); - return HAP_FAIL; - } - hap_tlv_error_t tlv_error = 0; - if (hap_pair_setup_manage_mfi_auth(ps_ctx, &tlv_data, &tlv_error) != ESP_OK) { - hap_prepare_error_tlv(STATE_M4, tlv_error, buf, bufsize, outlen); - return HAP_FAIL; - } - *outlen = tlv_data.curlen; - ps_ctx->state = state; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M4 Successful"); - return HAP_SUCCESS; -} -static int hap_pair_setup_process_exchange(pair_setup_ctx_t *ps_ctx, uint8_t *buf, int inlen, - int bufsize, int *outlen) -{ - uint8_t state; - uint8_t edata[220]; - int edata_len; - int ret; - - if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || - ((edata_len = get_value_from_tlv(buf, inlen, kTLVType_EncryptedData, - edata, sizeof(edata))) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); - hap_prepare_error_tlv(STATE_M6, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - hex_dbg_with_name("recv_encrypted_data", edata, edata_len); - if (state != STATE_M5) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received"); - hap_prepare_error_tlv(STATE_M6, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup M5 Received"); - edata_len -= 16; /* 16 bytes for the authTag */ - uint8_t newnonce[12]; - memset(newnonce, 0, sizeof newnonce); - memcpy(newnonce+4, (uint8_t *)PS_NONCE2, 8); - ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached(edata, NULL, edata, edata_len, - &edata[edata_len], NULL, 0, newnonce, ps_ctx->session_key); - if (ret != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Decryption Failed"); - hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen); - return HAP_FAIL; - } - hex_dbg_with_name("subtlv", edata, edata_len); - int ctrl_id_len; - unsigned char ed_sign[64]; - unsigned long long ed_sign_len; - if (((ctrl_id_len = get_value_from_tlv(edata, edata_len, kTLVType_Identifier, - ps_ctx->ctrl->info.id, sizeof(ps_ctx->ctrl->info.id))) < 0) || - (get_value_from_tlv(edata, edata_len, kTLVType_PublicKey, - ps_ctx->ctrl->info.ltpk, ED_KEY_LEN) != ED_KEY_LEN) || - (get_value_from_tlv(edata, edata_len, kTLVType_Signature, - ed_sign, sizeof(ed_sign)) != sizeof(ed_sign))) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid subTLV received"); - hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen); - return HAP_FAIL; - } - ps_ctx->ctrl->info.id[ctrl_id_len] = 0; /* NULL termination */ - hex_dbg_with_name("ctrl_id", (uint8_t *)ps_ctx->ctrl->info.id, ctrl_id_len); - hex_dbg_with_name("ltpkc", ps_ctx->ctrl->info.ltpk, ED_KEY_LEN); - hex_dbg_with_name("ctrl_sign", ed_sign, sizeof(ed_sign)); - - /* Derive iOSDeviceX from SRP shared secret using HKDF-SHA512 */ - uint8_t ios_device_x[32]; - hkdf(SHA512, (unsigned char *) PAIR_SETUP_CTRL_SIGN_SALT, - strlen(PAIR_SETUP_CTRL_SIGN_SALT), (uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len, - (unsigned char *) PAIR_SETUP_CTRL_SIGN_INFO, - strlen(PAIR_SETUP_CTRL_SIGN_INFO), - ios_device_x, sizeof(ios_device_x)); - /* Construct iOSDeviceInfo by concatenating - * iOSDeviceX - * iOSDevicePairingID (ctrl_id) - * iOSDeviceLTPK (ltpkc) - */ - uint8_t info_buf[HAP_CTRL_ID_LEN + 32 + ED_KEY_LEN]; - uint8_t *ios_dev_info = info_buf; - int ios_dev_info_len = 0; - memcpy(ios_dev_info, ios_device_x, sizeof(ios_device_x)); - ios_dev_info_len += sizeof(ios_device_x); - memcpy(&ios_dev_info[ios_dev_info_len], ps_ctx->ctrl->info.id, ctrl_id_len); - ios_dev_info_len += ctrl_id_len; - memcpy(&ios_dev_info[ios_dev_info_len], ps_ctx->ctrl->info.ltpk, ED_KEY_LEN); - ios_dev_info_len += ED_KEY_LEN; - - ret = crypto_sign_ed25519_verify_detached(ed_sign, ios_dev_info, ios_dev_info_len, ps_ctx->ctrl->info.ltpk); - /* Verify Signature of constructed iOSDeviceInfo using the iOSDeviceLTPK */ - if (ret != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid Signature"); - hap_prepare_error_tlv(STATE_M6, kTLVError_Authentication, buf, bufsize, outlen); - return HAP_FAIL; - } - - hex_dbg_with_name("ltpka", hap_priv.ltpka, sizeof(hap_priv.ltpka)); - - /* Derive AccessoryX from the SRP shared secret using HKDF-SHA512 */ - uint8_t acc_x[32]; - hkdf(SHA512, (unsigned char *) PAIR_SETUP_ACC_SIGN_SALT, - strlen(PAIR_SETUP_ACC_SIGN_SALT), (uint8_t *)ps_ctx->shared_secret, ps_ctx->secret_len, - (unsigned char *) PAIR_SETUP_ACC_SIGN_INFO, - strlen(PAIR_SETUP_ACC_SIGN_INFO), - acc_x, sizeof(acc_x)); - /* Construct AccessoryInfo by concatenating - * AccessoryX - * AccessoryPairingID (acc_id) - * AccessoryLTPK (ltpka) - */ - uint8_t *acc_info = info_buf; - int acc_info_len = 0; - memcpy(acc_info, acc_x, sizeof(acc_x)); - acc_info_len += sizeof(acc_x); - memcpy(&ios_dev_info[acc_info_len], hap_priv.acc_id, strlen(hap_priv.acc_id)); - acc_info_len += strlen(hap_priv.acc_id); - memcpy(&ios_dev_info[acc_info_len], hap_priv.ltpka, sizeof(hap_priv.ltpka)); - acc_info_len += sizeof(hap_priv.ltpka); - - /* Generate AccessorySignature by signing AccessoryInfo with AccessoryLTSK - */ - crypto_sign_ed25519_detached(ed_sign, &ed_sign_len, acc_info, acc_info_len, hap_priv.ltska); - hex_dbg_with_name("acc_sign", ed_sign, sizeof(ed_sign)); - - /* Create subTLV with: - * kTLVType_Identifier : Accessory ID (acc_id) - * kTLVType_PublicKey : Accessory LTPK - * kTLVType_Signature : AccessorySignature - */ - - uint8_t subtlv[6 + HAP_ACC_ID_LEN + ED_KEY_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN]; - - hap_tlv_data_t tlv_data; - tlv_data.bufptr = subtlv; - tlv_data.bufsize = sizeof(subtlv); - tlv_data.curlen = 0; - add_tlv(&tlv_data, kTLVType_Identifier, strlen(hap_priv.acc_id), hap_priv.acc_id); - add_tlv(&tlv_data, kTLVType_PublicKey, sizeof(hap_priv.ltpka), hap_priv.ltpka); - add_tlv(&tlv_data, kTLVType_Signature, sizeof(ed_sign), ed_sign); - int subtlv_len = tlv_data.curlen; - hex_dbg_with_name("subtlv", subtlv, subtlv_len); - - /* Encrypt the subTLV using the session key */ - - unsigned long long mlen = 16; - memset(newnonce, 0, sizeof newnonce); - memcpy(newnonce+4, (uint8_t *) PS_NONCE3, 8); - crypto_aead_chacha20poly1305_ietf_encrypt_detached(subtlv, &subtlv[subtlv_len], &mlen, subtlv, - subtlv_len, NULL, 0, NULL, newnonce, ps_ctx->session_key); - hex_dbg_with_name("send_encrypt_data", subtlv, subtlv_len + 16); - - /* Construct the response M6 */ - tlv_data.bufptr = buf; - tlv_data.bufsize = bufsize; - tlv_data.curlen = 0; - state = STATE_M6; - if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) || - (add_tlv(&tlv_data, kTLVType_EncryptedData, subtlv_len + 16, - subtlv) < 0)) { - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - *outlen = tlv_data.curlen; - ps_ctx->state = state; - ps_ctx->ctrl->info.perms = 1; /* Controller added using pair setup is always an admin */ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Setup Successful for %s", ps_ctx->ctrl->info.id); - /* Reset the Pairing Attempts count */ - hap_priv.pair_attempts = 0; - hap_controller_save(ps_ctx->ctrl); - hap_send_event(HAP_INTERNAL_EVENT_ACC_PAIRED); - return HAP_SUCCESS; -} -static uint8_t hap_pair_setup_get_received_state(uint8_t *buf, int inlen) -{ - uint8_t state = 0; - get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)); - return state; -} - -static void hap_pair_setup_timeout(TimerHandle_t handle) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Clearing Pair Setup Context due to inactivity"); - pair_setup_ctx_t *ps_ctx = pvTimerGetTimerID(handle); - if (ps_ctx) { - httpd_sess_trigger_close(hap_priv.server, ps_ctx->sock_fd); - hap_report_event(HAP_EVENT_PAIRING_ABORTED, NULL, 0); - } -} - -/* Pair Setup can have only a single context at a time as the specification does not allow - * multiple controllers to perform Pair Setup Simultaneously. - * - * The purpose of this function is to manage allocation and resetting of the context by - * using a static variable rather than a global variable. - */ -static pair_setup_ctx_t *hap_pair_setup_ctx_action(int action) -{ - static pair_setup_ctx_t *ps_ctx; - /* If the call is to initialise the context, check if it is already - * initialised. - */ - if (action == PS_CTX_INIT) { - /* If the context is already initialised, it means that pair setup - * is already in progress. So, return NULL. - * Else, allocate the context. - */ - if (ps_ctx) - return NULL; - else { - ps_ctx = hap_platform_memory_calloc(sizeof(pair_setup_ctx_t), 1); - if (ps_ctx) { - ps_ctx->timer = xTimerCreate("hap_setup_timer", HAP_SETUP_TIMEOUT_IN_TICKS, - pdFALSE, (void *) ps_ctx, hap_pair_setup_timeout); - xTimerStart(ps_ctx->timer, 0); - } - } - } else if (action == PS_CTX_DEINIT) { - /* If the call is to de-initialise the context, clean it up - * and set the pointer to NULL - */ - if (ps_ctx) { - if (ps_ctx->timer) { - xTimerStop(ps_ctx->timer, 0); - xTimerDelete(ps_ctx->timer, 100); - } - mu_srp_free(&ps_ctx->srp_hd); - hap_platform_memory_free(ps_ctx); - } - ps_ctx = NULL; - } - return ps_ctx; -} - - -void hap_pair_setup_ctx_clean(void *sess_ctx) -{ - if (sess_ctx) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Cleaning Pair Setup Context"); - hap_pair_setup_ctx_action(PS_CTX_DEINIT); - } -} - -int hap_pair_setup_context_init(int sock_fd, void **ctx, uint8_t *buf, int bufsize, int *outlen) -{ - pair_setup_ctx_t *ps_ctx = hap_pair_setup_ctx_action(PS_CTX_INIT); - - if (!ps_ctx) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR,"######## Aborted! Pair Setup in Progress with another controller ########"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Busy, buf, bufsize, outlen); - return HAP_FAIL; - } - ps_ctx->sock_fd = sock_fd; - *ctx = ps_ctx; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "######## Starting Pair Setup ########"); - return HAP_SUCCESS; - -} -int hap_pair_setup_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen) -{ - pair_setup_ctx_t *ps_ctx = (pair_setup_ctx_t *)(*ctx); - - uint8_t recv_state = hap_pair_setup_get_received_state(buf, inlen); - if (!ps_ctx) { - hap_prepare_error_tlv(recv_state + 1, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - /* Receiving STATE_M1 in the message while the pair-setup was already in progress means - * that pair setup was restarted. Handle it accordingly - */ - if ((recv_state == STATE_M1) && (ps_ctx->state != STATE_M0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Restarting Pair Setup"); - int sock_fd = ps_ctx->sock_fd; - hap_pair_setup_ctx_clean(ps_ctx); - int ret = hap_pair_setup_context_init(sock_fd, ctx, buf, bufsize, outlen); - if (ret != HAP_SUCCESS) - return ret; - ps_ctx = (pair_setup_ctx_t *)(*ctx); - } - if (ps_ctx->state == STATE_M0) { - return hap_pair_setup_process_srp_start(ps_ctx, buf, inlen, bufsize, outlen); - } else if (ps_ctx->state == STATE_M2) { - hap_priv.pair_attempts++; - int ret = hap_pair_setup_process_srp_verify(ps_ctx, buf, inlen, bufsize, outlen); - if (ps_ctx->session) { - *ctx = ps_ctx->session; - hap_pair_setup_ctx_clean(ps_ctx); - } - return ret; - } else if (ps_ctx->state == STATE_M4) { - int ret = hap_pair_setup_process_exchange(ps_ctx, buf, inlen, bufsize, outlen); - /* If last step of pair setup is successful, it means that the context would - * be no more required. Hence, clear it. - */ - if (ret == HAP_SUCCESS) { - hap_pair_setup_ctx_clean(ps_ctx); - *ctx = NULL; - } - return ret; - } - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; -} - -void hap_set_setup_code(const char *setup_code) -{ - if (hap_priv.setup_code) - hap_platform_memory_free(hap_priv.setup_code); - hap_priv.setup_code = strdup(setup_code); -} - -int hap_set_setup_info(const hap_setup_info_t *setup_info) -{ - if (!setup_info) - return HAP_FAIL; - if (hap_priv.setup_info) - hap_platform_memory_free(hap_priv.setup_info); - hap_priv.setup_info = hap_platform_memory_calloc(1, sizeof(hap_setup_info_t)); - if (!hap_priv.setup_info) - return HAP_FAIL; - memcpy(hap_priv.setup_info, setup_info, sizeof(hap_setup_info_t)); - return HAP_SUCCESS; -} - -int hap_set_setup_id(const char *setup_id) -{ - if (setup_id == NULL || strlen(setup_id) != SETUP_ID_LEN) - return HAP_FAIL; - strcpy(hap_priv.setup_id, setup_id); - return HAP_SUCCESS; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_setup.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_setup.h deleted file mode 100644 index a79e27a2f..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_setup.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_PAIR_SETUP_H_ -#define _HAP_PAIR_SETUP_H_ -#include -#include -#include -#include -#include - -#define PS_NONCE1 "PS-Msg04" -#define PS_NONCE2 "PS-Msg05" -#define PS_NONCE3 "PS-Msg06" - -#define PAIR_FLAG_TRANSIENT 0x00000010 -#define PAIR_FLAG_SPLIT 0x01000000 - - -typedef struct { - uint8_t state; - uint8_t method; - uint32_t pairing_flags; - int8_t pairing_flags_len; - int len_s; - char *bytes_s; - int secret_len; - char *shared_secret; - mu_srp_handle_t srp_hd; - hap_ctrl_data_t *ctrl; - uint8_t session_key[32]; - TimerHandle_t timer; - hap_secure_session_t *session; - int sock_fd; -} pair_setup_ctx_t; -int hap_pair_setup_context_init(int sock_fd, void **ctx, uint8_t *buf, int bufsize, int *outlen); -int hap_pair_setup_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen); -void hap_pair_setup_ctx_clean(void *sess_ctx); -int hap_pair_setup_manage_mfi_auth(pair_setup_ctx_t *ps_ctx, hap_tlv_data_t *tlv_data, hap_tlv_error_t *tlv_error); -#endif /* _HAP_PAIR_SETUP_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_verify.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_verify.c deleted file mode 100644 index 6c62bbfc0..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_verify.c +++ /dev/null @@ -1,464 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define PAIR_VERIFY_ENCRYPT_SALT "Pair-Verify-Encrypt-Salt" -#define PAIR_VERIFY_ENCRYPT_INFO "Pair-Verify-Encrypt-Info" -#define PV_NONCE1 "PV-Msg02" -#define PV_NONCE2 "PV-Msg03" -#define CONTROL_SALT "Control-Salt" -#define CONTROL_READ_INFO "Control-Read-Encryption-Key" -#define CONTROL_WRITE_INFO "Control-Write-Encryption-Key" - -typedef struct { - /* It is important that "state" should be the first element of the structure. - * It will be the first element, even in hap_secure_session_t. - * This will be useful while checking the state from the context, irrespective - * of whether the context points to pair_verify_ctx_t or hap_secure_session_t. - */ - uint8_t state; - uint8_t ctrl_curve_pk[CURVE_KEY_LEN]; - uint8_t acc_curve_pk[CURVE_KEY_LEN]; - uint8_t hkdf_key[ENCRYPT_KEY_LEN]; - uint8_t shared_secret[CURVE_KEY_LEN]; - hap_secure_session_t *session; -} pair_verify_ctx_t; - -void hap_close_ctrl_sessions(hap_ctrl_data_t *ctrl) -{ - if (!ctrl) - return; - int i; - printf("---- hap_close_ctrl_sessions begin -----\n"); - for (i = 0; i < HAP_MAX_SESSIONS; i++) { - if (!hap_priv.sessions[i]) - continue; - if (hap_priv.sessions[i]->ctrl == ctrl) { - hap_report_event(HAP_EVENT_CTRL_DISCONNECTED, (ctrl->info.id), - sizeof((ctrl->info.id))); - /* TODO: Use some generic function and not a direct HTTPD function - */ - printf("---- trigger_close fd: %d\n", hap_priv.sessions[i]->conn_identifier); - httpd_sess_trigger_close(hap_priv.server, hap_priv.sessions[i]->conn_identifier); - break; - } - } - printf("----hap_close_ctrl_sessions end ----\n"); -} - -int hap_get_ctrl_session_index(hap_secure_session_t *session) -{ - int i; - for (i = 0; i < HAP_MAX_SESSIONS; i++) { - if (hap_priv.sessions[i] == session) - return i; - } - return -1; -} - -void hap_close_all_sessions() -{ - int i; - for (i = 0; i < HAP_MAX_SESSIONS; i++) { - if (hap_priv.sessions[i]) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Closing Session"); - hap_close_ctrl_sessions(hap_priv.sessions[i]->ctrl); - } - } -} - -static void hap_add_secure_session(hap_secure_session_t *session) -{ - int i; - for (i = 0; i < HAP_MAX_SESSIONS; i++) { - if (hap_priv.sessions[i] == NULL) { - hap_priv.sessions[i] = session; - hap_report_event(HAP_EVENT_CTRL_CONNECTED, session->ctrl->info.id, - sizeof(session->ctrl->info.id)); - /* Set the disconnected_event_sent flag here to false so that an - * event can be sent later for a state change, when no controller - * is connected. - * HAP Spec R15 say that the state number should change only once - * between accessory disconneted (from all controllers) to connected - * state. - */ - hap_priv.disconnected_event_sent = false; - //ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HomeKit Session active"); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HomeKit Session active, fd: %d", session->conn_identifier); - break; - } - } -} - -void hap_free_session(void *session) -{ - if (!session) - return; - int i; - for (i = 0; i < HAP_MAX_SESSIONS; i++) { - if (hap_priv.sessions[i] == session) { - /* Disable all characteristic notifications on this session */ - int fd = (hap_priv.sessions[i])->conn_identifier; - hap_disable_all_char_notif(i); - hap_priv.sessions[i] = NULL; - //ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HomeKit Session terminated"); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "HomeKit Session terminated, fd: %d", fd); - break; - } - } - hap_platform_memory_free(session); -} - -static int hap_pair_verify_process_start(pair_verify_ctx_t *pv_ctx, uint8_t *buf, int inlen, - int bufsize, int *outlen) -{ - /* Parse the data received from the controller */ - uint8_t state; - if (!pv_ctx) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No context"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || - (get_value_from_tlv(buf, inlen, kTLVType_PublicKey, pv_ctx->ctrl_curve_pk, - CURVE_KEY_LEN) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - if (state != STATE_M1) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Verify M1 Received"); - hex_dbg_with_name("ctrl curve pk", pv_ctx->ctrl_curve_pk, 32); - - /* Generate a new Curve25519 Key Pair */ - uint8_t acc_curve_sk[CURVE_KEY_LEN]; - esp_mfi_get_random(acc_curve_sk, CURVE_KEY_LEN); - /* This particular value of basepoint is required to generate the public key - * from secret key - */ - uint8_t basepoint[32] = {9}; - if (crypto_scalarmult_curve25519(pv_ctx->acc_curve_pk, acc_curve_sk, basepoint) == -1) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Curve25519 Error"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - hex_dbg_with_name("acc curve sk", acc_curve_sk, 32); - hex_dbg_with_name("acc curve pk", pv_ctx->acc_curve_pk, 32); - if (crypto_scalarmult_curve25519(pv_ctx->shared_secret, acc_curve_sk, pv_ctx->ctrl_curve_pk) == -1) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Curve25519 Error"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - - hex_dbg_with_name("shared secret", pv_ctx->shared_secret, 32); - - /* Construct AccessoryInfo by concatenating - * a. Accessory's Curve25519 Public Key - * b. Accessory ID - * c. Controller's Curve25519 Public Key received in M1 - */ - uint8_t acc_info[2 * CURVE_KEY_LEN + HAP_ACC_ID_LEN]; - int acc_info_len = 0; - memcpy(acc_info, pv_ctx->acc_curve_pk, CURVE_KEY_LEN); - acc_info_len += CURVE_KEY_LEN; - memcpy(acc_info + acc_info_len, hap_priv.acc_id, strlen(hap_priv.acc_id)); - acc_info_len += strlen(hap_priv.acc_id); - memcpy(acc_info + acc_info_len, pv_ctx->ctrl_curve_pk, CURVE_KEY_LEN); - acc_info_len += CURVE_KEY_LEN; - - hex_dbg_with_name("acc_info", acc_info, acc_info_len); - - /* Use Ed25519 to generate AccessorySignature by signing AccessoryInfo - * with its Long Term Secret Key AccessoryLTSK - */ - unsigned char ed_sign[64]; - unsigned long long ed_sign_len; - crypto_sign_ed25519_detached(ed_sign, &ed_sign_len, acc_info, acc_info_len, hap_priv.ltska); - hex_dbg_with_name("sign", ed_sign, 64); - - /* Construct a subTLV with - * kTLVType_Identifier : Accessory Identifier - * kTLVType_Signature : AccessorySignature generated above - */ - uint8_t subtlv[4 + HAP_ACC_ID_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN]; - hap_tlv_data_t tlv_data; - tlv_data.bufptr = subtlv; - tlv_data.bufsize = sizeof(subtlv); - tlv_data.curlen = 0; - add_tlv(&tlv_data, kTLVType_Identifier, strlen(hap_priv.acc_id), hap_priv.acc_id); - add_tlv(&tlv_data, kTLVType_Signature, sizeof(ed_sign), ed_sign); - int subtlv_len = tlv_data.curlen; - hex_dbg_with_name("subtlv", subtlv, subtlv_len); - - /* Derive Symmetric Session encryption key SessionKey from the curve - * shared secret using HKDF-SHA-512 - */ - hkdf(SHA512, (unsigned char *) PAIR_VERIFY_ENCRYPT_SALT, - strlen(PAIR_VERIFY_ENCRYPT_SALT), - pv_ctx->shared_secret, sizeof(pv_ctx->shared_secret), - (unsigned char *) PAIR_VERIFY_ENCRYPT_INFO, - strlen(PAIR_VERIFY_ENCRYPT_INFO), - pv_ctx->hkdf_key, sizeof(pv_ctx->hkdf_key)); - /* Encrypt the sub TLV to get encryptedData and an authTag using - * Chacha20-Poly1305 AEAD Algorithm - */ - uint8_t edata[4 + HAP_ACC_ID_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN]; - unsigned long long mlen = 16; - uint8_t newnonce[12]; - memset(newnonce, 0, sizeof newnonce); - memcpy(newnonce+4, PV_NONCE1, 8); - - crypto_aead_chacha20poly1305_ietf_encrypt_detached(edata, edata + subtlv_len, &mlen, subtlv, subtlv_len, NULL, 0, NULL, newnonce, pv_ctx->hkdf_key); - - int edata_len = subtlv_len + POLY_AUTHTAG_LEN; - - hex_dbg_with_name("encrypt_data", edata, edata_len); - - /* Construct the response M2 */ - tlv_data.bufptr = buf; - tlv_data.bufsize = bufsize; - tlv_data.curlen = 0; - state = STATE_M2; - if ((add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) || - (add_tlv(&tlv_data, kTLVType_PublicKey, CURVE_KEY_LEN, - pv_ctx->acc_curve_pk) < 0) || - (add_tlv(&tlv_data, kTLVType_EncryptedData, edata_len, edata) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - *outlen = tlv_data.curlen; - hex_dbg_with_name("M2", buf, *outlen); - pv_ctx->state = STATE_M2; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Verify M2 Successful"); - return HAP_SUCCESS; -} - -static int hap_pair_verify_process_finish(pair_verify_ctx_t *pv_ctx, uint8_t *buf, int inlen, - int bufsize, int *outlen) -{ - /* Parse the data received from the controller */ - uint8_t state; - if (!pv_ctx) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No context"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - uint8_t edata[4 + HAP_CTRL_ID_LEN + ED_SIGN_LEN + POLY_AUTHTAG_LEN]; - int edata_len; - if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || - ((edata_len = get_value_from_tlv(buf, inlen, kTLVType_EncryptedData, - edata, sizeof(edata))) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - if (state != STATE_M3) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Incorrect State received"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Verify M3 Received"); - - /* Decrypt the received data to get the subTLV */ - uint8_t newnonce[12]; - memset(newnonce, 0, sizeof newnonce); - memcpy(newnonce+4, PV_NONCE2, 8); - int ret; - ret = crypto_aead_chacha20poly1305_ietf_decrypt_detached(edata, NULL, edata, edata_len - POLY_AUTHTAG_LEN, edata + edata_len - POLY_AUTHTAG_LEN, NULL, 0, newnonce, pv_ctx->hkdf_key); - if (ret != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Decryption error"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen); - return HAP_FAIL; - } - - /* Parse the subTLV to get the iOSDevicePairingID and iOSDeviceSignature - */ - edata_len = edata_len - POLY_AUTHTAG_LEN; - unsigned char ed_sign[64]; - char ctrl_id[HAP_CTRL_ID_LEN]; - memset(ctrl_id, 0, sizeof(ctrl_id)); - if ((get_value_from_tlv(edata, edata_len, kTLVType_Identifier, - ctrl_id, sizeof(ctrl_id)) < 0) || - (get_value_from_tlv(edata, edata_len, kTLVType_Signature, - ed_sign, sizeof(ed_sign)) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Wrong subTLV received"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - - /* Check if the controller is present in the database i.e. check - * if the controller was paired with the accessory - */ - hap_ctrl_data_t *ctrl = hap_get_controller(ctrl_id); - if (!ctrl) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "No ctrl details found"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen); - return HAP_FAIL; - } - - /* Construct iOSDeviceInfo by concatenating - * a. Controllers's Curve25519 Public Key (received in M1) - * b. Controller ID - * c. Accessory's Curve25519 Public Key (sent in M2) - */ - uint8_t ios_dev_info[2 * CURVE_KEY_LEN + HAP_CTRL_ID_LEN]; - int ios_dev_info_len = 0; - memcpy(ios_dev_info, pv_ctx->ctrl_curve_pk, CURVE_KEY_LEN); - ios_dev_info_len += CURVE_KEY_LEN; - memcpy(ios_dev_info + ios_dev_info_len, ctrl_id, strlen(ctrl_id)); - ios_dev_info_len += strlen(ctrl_id); - memcpy(ios_dev_info + ios_dev_info_len, pv_ctx->acc_curve_pk, - CURVE_KEY_LEN); - ios_dev_info_len += CURVE_KEY_LEN; - - /* Validate the signature with the received iOSDeviceSignature */ - if (crypto_sign_ed25519_verify_detached(ed_sign, ios_dev_info, ios_dev_info_len, ctrl->info.ltpk) != 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Signature mismatch"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Authentication, buf, bufsize, outlen); - return HAP_FAIL; - } - - /* Allocate memory for the secure session information */ - hap_secure_session_t *session = hap_platform_memory_calloc(sizeof(hap_secure_session_t), 1); - if (!session) { - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Memory allocation failed"); - return HAP_FAIL; - } - /* Construct the response M4 */ - hap_tlv_data_t tlv_data; - tlv_data.bufptr = buf; - tlv_data.bufsize = bufsize; - tlv_data.curlen = 0; - state = STATE_M4; - if (add_tlv(&tlv_data, kTLVType_State, 1, &state) < 0) { - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - hap_platform_memory_free(session); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); - return HAP_FAIL; - } - *outlen = tlv_data.curlen; - - /* Generate the Encryption and Decryption Keys. - * Since, read and write are from the controller's point of view, - * encryption key uses READ_INFO and decryption key uses WRITE_INFO - * - * Also, set the nonce to zero - */ - hkdf(SHA512, (unsigned char *) CONTROL_SALT, strlen(CONTROL_SALT), - pv_ctx->shared_secret, sizeof(pv_ctx->shared_secret), - (unsigned char *) CONTROL_READ_INFO, strlen(CONTROL_READ_INFO), - session->encrypt_key, sizeof(session->encrypt_key)); - - hkdf(SHA512, (unsigned char *) CONTROL_SALT, strlen(CONTROL_SALT), - pv_ctx->shared_secret, sizeof(pv_ctx->shared_secret), - (unsigned char *) CONTROL_WRITE_INFO, strlen(CONTROL_WRITE_INFO), - session->decrypt_key, sizeof(session->decrypt_key)); - - session->state = STATE_VERIFIED; - pv_ctx->state = STATE_VERIFIED; - - memset(session->encrypt_nonce, 0, sizeof(session->encrypt_nonce)); - memset(session->decrypt_nonce, 0, sizeof(session->decrypt_nonce)); - session->ctrl = ctrl; - - pv_ctx->session = session; - - /* Add the session information to database */ - hap_add_secure_session(session); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Pair Verify Successful for %s", ctrl_id); - return HAP_SUCCESS; -} - -int hap_pair_verify_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen) -{ - pair_verify_ctx_t *pv_ctx = (pair_verify_ctx_t *)(*ctx); - if (pv_ctx) { - if (pv_ctx->state == STATE_M0) - return hap_pair_verify_process_start(pv_ctx, buf, inlen, - bufsize, outlen); - else if (pv_ctx->state == STATE_M2) { - int ret = hap_pair_verify_process_finish(pv_ctx, buf, inlen, - bufsize, outlen); - /* Successful finish means that the pair verify was successful. - * So, we clear the old context and assign the secure_session - * as the new context - */ - if (ret == HAP_SUCCESS) { - hap_secure_session_t *session = pv_ctx->session; - hap_platform_memory_free(pv_ctx); - *ctx = session; - } - return ret; - } - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Error processing Pair Verify Data"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; -} - -int hap_pair_verify_context_init(void **ctx, uint8_t *buf, int bufsize, int *outlen) -{ - pair_verify_ctx_t *pv_ctx; - - pv_ctx = (pair_verify_ctx_t *) hap_platform_memory_calloc(sizeof(pair_verify_ctx_t), 1); - if (!pv_ctx) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Failed to create Pair Verify Context"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - *ctx = pv_ctx; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "######## Starting Pair Verify ########"); - return HAP_SUCCESS; -} - -uint8_t hap_pair_verify_get_state(void *ctx) -{ - pair_verify_ctx_t *pv_ctx = (pair_verify_ctx_t *)ctx; - if (pv_ctx) - return pv_ctx->state; - return 0; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_verify.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_verify.h deleted file mode 100644 index f40a9908e..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pair_verify.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_PAIR_VERIFY_H_ -#define _HAP_PAIR_VERIFY_H_ -#include -#include -int hap_pair_verify_context_init(void **ctx, uint8_t *buf, int bufsize, int *outlen); -int hap_pair_verify_process(void **ctx, uint8_t *buf, int inlen, int bufsize, int *outlen); -uint8_t hap_pair_verify_get_state(void *ctx); -void hap_free_session(void *session); -int hap_get_ctrl_session_index(hap_secure_session_t *session); -void hap_close_ctrl_sessions(hap_ctrl_data_t *ctrl); -void hap_close_all_sessions(); -#endif /* _HAP_PAIR_VERIFY_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pairings.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pairings.c deleted file mode 100644 index cffe3353d..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pairings.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -bool hap_is_req_admin(void *__session) -{ - hap_secure_session_t *session = (hap_secure_session_t *)__session; - if (!session) { - return false; - } - if ((session->state == STATE_VERIFIED) && (session->ctrl->info.perms == 1)) { - return true; - } - return false; -} - -char *hap_req_get_ctrl_id(void *__session) -{ - hap_secure_session_t *session = (hap_secure_session_t *)__session; - if (!session) - return NULL; - - if (session->state == STATE_VERIFIED) { - return session->ctrl->info.id; - } - return NULL; -} - -bool hap_is_req_secure(hap_secure_session_t *session) -{ - if (!session) { - return false; - } - if (session->state == STATE_VERIFIED) { - return true; - } - return false; -} - -void hap_remove_all_controllers() -{ - int i; - for (i = 0; i < HAP_MAX_CONTROLLERS; i++) { - if (hap_priv.controllers[i].valid) { - hap_close_ctrl_sessions(&hap_priv.controllers[i]); - hap_controller_remove(&hap_priv.controllers[i]); - } - } -} -static int hap_process_pair_remove(uint8_t *buf, int inlen, int bufsize, int *outlen) -{ - bool acc_unpaired = false; - char ctrl_id[HAP_CTRL_ID_LEN]; - memset(ctrl_id, 0, HAP_CTRL_ID_LEN); - if (get_value_from_tlv(buf, inlen, kTLVType_Identifier, - ctrl_id, sizeof(ctrl_id)) < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Identifier not found"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Removing Controller %s", ctrl_id); - hap_ctrl_data_t *ctrl = hap_get_controller(ctrl_id); - hap_close_ctrl_sessions(ctrl); - hap_controller_remove(ctrl); - - if (!is_admin_paired()) { - acc_unpaired = true; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Last Admin controller removed. Removing all other controllers."); - hap_remove_all_controllers(); - } - - hap_tlv_data_t tlv_data = { - .bufptr = buf, - .bufsize = bufsize, - .curlen = 0, - }; - uint8_t state = STATE_M2; - if (add_tlv(&tlv_data, kTLVType_State, sizeof(state), &state) < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - *outlen = tlv_data.curlen; - if (acc_unpaired) { - hap_send_event(HAP_INTERNAL_EVENT_ACC_UNPAIRED); - } - return HAP_SUCCESS; -} - -static int hap_process_pair_add(uint8_t *buf, int inlen, int bufsize, int *outlen) -{ - char ctrl_id[HAP_CTRL_ID_LEN]; - uint8_t ltpkc[ED_KEY_LEN]; - uint8_t perms; - memset(ctrl_id, 0, HAP_CTRL_ID_LEN); - if ((get_value_from_tlv(buf, inlen, kTLVType_Identifier, - ctrl_id, sizeof(ctrl_id)) < 0) || - (get_value_from_tlv(buf, inlen, kTLVType_PublicKey, - ltpkc, sizeof(ltpkc)) < 0) || - (get_value_from_tlv(buf, inlen, kTLVType_Permissions, - &perms, sizeof(perms)) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); - hap_prepare_error_tlv(STATE_M4, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - - hap_ctrl_data_t *ctrl = hap_get_controller(ctrl_id); - if (ctrl) { - /* If controller already exists, but the key does not match, return error */ - if (memcmp(ltpkc, ctrl->info.ltpk, ED_KEY_LEN)) { - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } else { - /* Else, just change the permissions */ - ctrl->info.perms = perms; - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Modifying Existing Controller %s", ctrl_id); - hap_controller_save(ctrl); - } - } else { - /* Check if there is space available for a new controller */ - ctrl = hap_controller_get_empty_loc(); - if (!ctrl) { - hap_prepare_error_tlv(STATE_M2, kTLVError_MaxPeers, buf, bufsize, outlen); - return HAP_FAIL; - } - strcpy(ctrl->info.id, ctrl_id); - memcpy(ctrl->info.ltpk, ltpkc, ED_KEY_LEN); - ctrl->info.perms = perms; - hap_controller_save(ctrl); - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Added Controller %s", ctrl_id); - } - hap_tlv_data_t tlv_data = { - .bufptr = buf, - .bufsize = bufsize, - .curlen = 0, - }; - uint8_t state = STATE_M2; - if (add_tlv(&tlv_data, kTLVType_State, sizeof(state), &state) < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - *outlen = tlv_data.curlen; - return HAP_SUCCESS; - -} -static int hap_process_pair_list(uint8_t *buf, int inlen, int bufsize, int *outlen) -{ - hap_tlv_data_t tlv_data = { - .bufptr = buf, - .bufsize = bufsize, - .curlen = 0, - }; - int i; - hap_ctrl_data_t *ctrl; - hap_ctrl_info_t *ctrl_info; - bool entry_added = false; - for (i = 0; i < HAP_MAX_CONTROLLERS; i++) { - ctrl = &hap_priv.controllers[i]; - if (!ctrl->valid) - continue; - /* If an entry is already added, include a separator */ - if (entry_added) { - if (add_tlv(&tlv_data, kTLVType_Separator, 0, NULL) < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, - buf, bufsize, outlen); - return HAP_FAIL; - } - } else { - /* Else, since this is the first entry, add the state */ - uint8_t state = STATE_M2; - if (add_tlv(&tlv_data, kTLVType_State, sizeof(state), &state) < 0) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, - buf, bufsize, outlen); - return HAP_FAIL; - } - } - ctrl_info = &ctrl->info; - if ((add_tlv(&tlv_data, kTLVType_Identifier, - strlen(ctrl_info->id), ctrl_info->id) < 0) || - (add_tlv(&tlv_data, kTLVType_PublicKey, - ED_KEY_LEN, ctrl_info->ltpk) < 0) || - (add_tlv(&tlv_data, kTLVType_Permissions, - 1, &ctrl_info->perms) < 0)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "TLV creation failed"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - entry_added = true; - } - *outlen = tlv_data.curlen; - return HAP_SUCCESS; -} - -int hap_pairings_process(void *ctx, uint8_t *buf, int inlen, int bufsize, int *outlen) -{ - if (!hap_is_req_admin(ctx)) { - hap_prepare_error_tlv(STATE_M2, kTLVError_Authentication, buf, bufsize, outlen); - return HAP_FAIL; - } - uint8_t state, method; - if ((get_value_from_tlv(buf, inlen, kTLVType_State, &state, sizeof(state)) < 0) || - (get_value_from_tlv(buf, inlen, kTLVType_Method, - &method, sizeof(method)) < 0) || - (state != STATE_M1)) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Invalid TLVs received"); - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; - } - if (method == HAP_METHOD_ADD_PAIRING) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Add Pairing received"); - return hap_process_pair_add(buf, inlen, bufsize, outlen); - } else if (method == HAP_METHOD_REMOVE_PAIRING) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Remove Pairing received"); - return hap_process_pair_remove(buf, inlen, bufsize, outlen); - } else if (method == HAP_METHOD_LIST_PAIRINGS) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "List Pairings received"); - return hap_process_pair_list(buf, inlen, bufsize, outlen); - } - hap_prepare_error_tlv(STATE_M2, kTLVError_Unknown, buf, bufsize, outlen); - return HAP_FAIL; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pairings.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pairings.h deleted file mode 100644 index 7b7eaab83..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_pairings.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_PAIRINGS_H_ -#define _HAP_PAIRINGS_H_ -#include -int hap_pairings_process(void *ctx, uint8_t *buf, int inlen, int bufsize, int *outlen); -bool hap_is_req_secure(hap_secure_session_t *session); -#endif /* _HAP_PAIRINGS_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_secure_message.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_secure_message.h deleted file mode 100644 index dbeb4b17e..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_secure_message.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_SECURE_MESSAGE_H_ -#define _HAP_SECURE_MESSAGE_H_ -#include -#include -/** Information for Software Token based authentication. - * To be used only if MFi chip is not present on the accessory - */ -typedef struct { - /** UUID for the accessory */ - uint8_t uuid[16]; - /** Token associated with the UUID */ - uint8_t *token; - /* Length of the above token */ - size_t token_len; -} hap_software_token_info_t; - -int hap_register_secure_message_handler(httpd_handle_t handle); -int hap_unregister_secure_message_handler(httpd_handle_t handle); -#endif /* _HAP_SECURE_MESSAGE_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.c deleted file mode 100644 index 0ab11ca41..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.c +++ /dev/null @@ -1,329 +0,0 @@ - /* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include - -#include -#include - -void hap_serv_mark_primary(hap_serv_t *hs) -{ - if (hs) { - ((__hap_serv_t *)hs)->primary = true; - } -} - -void hap_serv_mark_hidden(hap_serv_t *hs) -{ - if (hs) { - ((__hap_serv_t *)hs)->hidden = true; - } -} - -/** - * @brief get service hidden attribute - */ -bool hap_serv_get_hidden(hap_serv_t *hs) -{ - if (hs) { - return ((__hap_serv_t *)hs)->hidden; - } - return false; -} - - -void hap_serv_set_iid(hap_serv_t *hs, int32_t iid) -{ - if (hs) { - ((__hap_serv_t *)hs)->iid = iid; - } -} - -/** - * @brief get service "primary" attribute - */ -bool hap_serv_get_primary(hap_serv_t *hs) -{ - if (hs) { - return ((__hap_serv_t *)hs)->primary; - } - return false; -} - -hap_char_t *hap_serv_get_first_char(hap_serv_t *hs) -{ - return ((__hap_serv_t *)hs)->chars; -} -/** - * @brief get target characteristics by it's IID - */ -hap_char_t *hap_serv_get_char_by_iid(hap_serv_t *hs, int32_t iid) -{ - if (!hs) - return NULL; - - hap_char_t *hc; - for (hc = hap_serv_get_first_char(hs); hc; hc = hap_char_get_next(hc)) { - if (((__hap_char_t *)hc)->iid == iid) - return hc; - } - return NULL; -} - -/** - * @brief get target characteristics by it's UUID - */ -hap_char_t *hap_serv_get_char_by_uuid(hap_serv_t *hs, const char *uuid) -{ - if (!hs | !uuid) - return NULL; - - hap_char_t *hc; - for (hc = hap_serv_get_first_char(hs); hc; hc = hap_char_get_next(hc)) { - if (!strcmp(((__hap_char_t *)hc)->type_uuid, uuid)) - return hc; - } - return NULL; -} - -/** - * @brief get characteristics UUID prefix number - */ - const char *hap_serv_get_uuid(hap_serv_t *hs) - { - return ((__hap_serv_t *)hs)->type_uuid; - } - -/** - * Default service bulk read callback, which will be registered while creating a service. - * It will internally call the actual read routines - */ -static int hap_serv_def_bulk_read_cb(hap_read_data_t read_data[], int count, - void *serv_priv, void *read_priv) -{ - int i; - if (!count) { - return HAP_FAIL; - } - __hap_serv_t *hs = (__hap_serv_t *)hap_char_get_parent(read_data[0].hc); - /* If no read routine is registered, just return success so that the cached values - * will be used - */ - if (!hs->read_cb) { - return HAP_SUCCESS; - } - - int ret = HAP_SUCCESS; - for (i = 0; i < count; i++) { - if (hs->read_cb(read_data[i].hc, read_data[i].status, serv_priv, read_priv) != HAP_SUCCESS) { - ret = HAP_FAIL; - } - } - return ret; -} -/** - * @brief HAP create a service - */ -hap_serv_t *hap_serv_create(const char *type_uuid) -{ - ESP_MFI_ASSERT(type_uuid); - __hap_serv_t *_hs = hap_platform_memory_calloc(1, sizeof(__hap_serv_t)); - if (!_hs) { - return NULL; - } - - _hs->type_uuid = type_uuid; - _hs->bulk_read = hap_serv_def_bulk_read_cb; - - return (hap_serv_t *)_hs; -} - -int hap_serv_link_serv(hap_serv_t *hs, hap_serv_t *linked_serv) -{ - if (!hs || !linked_serv) - return HAP_FAIL; - - hap_linked_serv_t *cur = hap_platform_memory_calloc(1, sizeof(hap_linked_serv_t)); - if (!cur) - return HAP_FAIL; - cur->hs = linked_serv; - - __hap_serv_t *_hs = (__hap_serv_t *)hs; - hap_linked_serv_t *linked = _hs->linked_servs; - - if (!linked) { - _hs->linked_servs = cur; - return HAP_SUCCESS; - } else { - while(linked->next) { - linked = linked->next; - } - linked->next = cur; - return HAP_SUCCESS; - } - return HAP_FAIL; -} - -/** - * @brief HAP get target service IID - */ -uint32_t hap_serv_get_iid(hap_serv_t *hs) -{ - if (!hs) - return 0; - - __hap_serv_t *tmp = (__hap_serv_t *)hs; - - return tmp->iid; -} - -const char *hap_serv_get_type_uuid(hap_serv_t *hs) -{ - if (!hs) - return 0; - - __hap_serv_t *tmp = (__hap_serv_t *)hs; - - return tmp->type_uuid; -} - -/** - * @brief HAP delete target service - */ -void hap_serv_delete(hap_serv_t *hs) -{ - /* Returning success even if pointer is NULL, because it means - * that the service is absent and as good as deleted - */ - if (!hs) - return; - __hap_serv_t *_hs = (__hap_serv_t *)hs; - __hap_char_t *_hc = (__hap_char_t *)_hs->chars; - while (_hc) { - _hs->chars = _hc->next_char; - hap_char_delete((hap_char_t *)_hc); - _hc = (__hap_char_t *)_hs->chars; - } - if (_hs->linked_servs) { - hap_linked_serv_t *cur = _hs->linked_servs; - hap_linked_serv_t *next = cur->next; - while (next) { - hap_platform_memory_free(cur); - cur = next; - next = cur->next; - } - hap_platform_memory_free(cur); - } - hap_platform_memory_free(hs); -} - -/** - * @brief add a characteristics to a service - */ -int hap_serv_add_char(hap_serv_t *hs, hap_char_t *hc) -{ - if (!hs || !hc) - return -1; - __hap_serv_t *_hs = (__hap_serv_t *)hs; - __hap_char_t *_hc = (__hap_char_t *)hc; - - if (_hc->parent) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Characteristic already added"); - return HAP_FAIL; - } - - /* If the service has no characteristics, add this as the first */ - if (!_hs->chars) { - _hs->chars = hc; - } else { - /* Else loop through the characteristics to get to the last one, - * and add this at the end - */ - __hap_char_t *temp = (__hap_char_t *)_hs->chars; - while (temp->next_char) - temp = (__hap_char_t *)temp->next_char; - temp->next_char = hc; - } - if (_hs->parent) { - _hc->iid = ((__hap_acc_t *)(_hs->parent))->next_iid++; - } - _hc->parent = hs; - return 0; -} - -void hap_serv_set_write_cb(hap_serv_t *hs, hap_serv_write_t write) -{ - if (hs) { - ((__hap_serv_t *)hs)->write_cb = write; - } -} - -void hap_serv_set_read_cb(hap_serv_t *hs, hap_serv_read_t read) -{ - if (hs) { - ((__hap_serv_t *)hs)->read_cb = read; - } -} - -void hap_serv_set_bulk_read_cb(hap_serv_t *hs, hap_serv_bulk_read_t read) -{ - if (hs) { - ((__hap_serv_t *)hs)->bulk_read = read; - } -} - - -hap_serv_t *hap_serv_get_next(hap_serv_t *hs) -{ - if (hs) { - return ((__hap_serv_t *)hs)->next_serv; - } else { - return NULL; - } -} - -hap_acc_t *hap_serv_get_parent(hap_serv_t *hs) -{ - if (hs) { - return ((__hap_serv_t *)hs)->parent; - } else { - return NULL; - } -} - -void hap_serv_set_priv(hap_serv_t *hs, void *priv) -{ - if (hs) { - ((__hap_serv_t *)hs)->priv = priv; - } -} - -void *hap_serv_get_priv(hap_serv_t *hs) -{ - if (hs) { - return ((__hap_serv_t *)hs)->priv; - } else { - return NULL; - } -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.h deleted file mode 100644 index f3545db7a..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_serv.h +++ /dev/null @@ -1,80 +0,0 @@ - /* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _HAP_SERV_H_ -#define _HAP_SERV_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct hap_linked_serv { - hap_serv_t *hs; - struct hap_linked_serv *next; -} hap_linked_serv_t; - -typedef struct hap_linked_serv hap_linked_serv_t; - -/** - * HAP service information - */ -typedef struct { - const char *type_uuid; /* String that defines the type of the service. */ - - uint32_t iid; /* service instance ID */ - - bool hidden; /* If set it to be True, the service is not visible to user. */ - bool primary; /* If set it to be True, this is the primary service of the accessory. */ - - /** - * List of Characteristic objects. Must not be empty. The maximum number of characteristics - * allowed is 100, and each characteristic in the array must have a unique type. - */ - hap_char_t *chars; - hap_acc_t *parent; - hap_serv_t *next_serv; - - hap_serv_write_t write_cb; - hap_serv_read_t read_cb; - hap_serv_bulk_read_t bulk_read; - hap_linked_serv_t *linked_servs; - void *priv; -} __hap_serv_t; - -bool hap_serv_get_hidden(hap_serv_t *hs); -bool hap_serv_get_primary(hap_serv_t *hs); -hap_char_t *hap_serv_get_char_by_iid(hap_serv_t *hs, int32_t iid); -const char *hap_serv_get_uuid(hap_serv_t *hs); -hap_serv_t *hap_serv_create(const char *type_uuid); -void hap_serv_delete(hap_serv_t *hs); -int hap_serv_add_char(hap_serv_t *hs, hap_char_t *hc); -#ifdef __cplusplus -} -#endif - -#endif /* _HAP_SERV_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_setup_payload.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_setup_payload.c deleted file mode 100644 index 52cc79329..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_setup_payload.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include -#include - -#include - -static const char *TAG = "esp_hap_setup_payload"; - -#define SETUP_CODE_MASK 0x0000000007ffffff -#define HAP_OVER_IP_MASK 0x0000000010000000 -#define WAC_MASK 0x0000000040000000 -#define SETUP_PAYLOAD_PREFIX "X-HM://00" - -static void remove_chars(char *str, char c) -{ - int i = 0, j = 0; - while(str[i]) { - if (str[i] != c) { - str[j] = str[i]; - j++; - } - i++; - } - str[j] = 0; -} - -char *esp_hap_get_setup_payload(char *setup_code, char *setup_id, bool wac_support, hap_cid_t cid) -{ - if (!setup_code || !setup_id) { - ESP_LOGE(TAG, "Setup code or Setup ID cannot be NULL"); - return NULL; - } - uint64_t payload = 0; - if (strlen(setup_code) != 10 || strlen(setup_id) != 4) { - ESP_LOGE(TAG, "Setup code or Setup ID not correct. Eg. 111-22-333, ES32"); - return NULL; - } - char setup_code_copy[11]; - strcpy(setup_code_copy, setup_code); - remove_chars(setup_code_copy, '-'); - int64_t code = atoi(setup_code_copy); - int64_t category = cid; - category <<= 31; - - payload |= code; - payload |= category; - payload |= HAP_OVER_IP_MASK; - if (wac_support) { - payload |= WAC_MASK; - } - char *base36_str = base36_to_str(payload); - char setup_payload[24]; - snprintf(setup_payload, sizeof(setup_payload), "%s%s%s", SETUP_PAYLOAD_PREFIX, base36_str, setup_id); - free(base36_str); - return strdup(setup_payload); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wac.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wac.h deleted file mode 100644 index 8ea04f3e8..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wac.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _HAP_WAC_H_ -#define _HAP_WAC_H_ -int hap_wac_start(void); -int hap_wac2_network_switch(void); -int hap_wac2_finish(void); -int hap_wac2_stop(void); -bool hap_is_mfi_auth_enabled(); -#endif /* _HAP_WAC_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wifi.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wifi.c deleted file mode 100644 index b46adbc07..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wifi.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include -#include - -esp_err_t hap_wifi_is_provisioned(bool *provisioned) -{ - if (!provisioned) { - return ESP_ERR_INVALID_ARG; - } - - *provisioned = false; - - /* Get Wi-Fi Station configuration */ - wifi_config_t wifi_cfg; - if (esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg) != ESP_OK) { - return ESP_FAIL; - } - - if (strlen((const char *) wifi_cfg.sta.ssid)) { - *provisioned = true; - } - return ESP_OK; -} -bool hap_is_network_configured(void) -{ - /* If only the Ethernet is enabled, return true */ - if (hap_priv.transport == HAP_TRANSPORT_ETHERNET) { - return true; - } - - bool provisioned = false; - hap_wifi_is_provisioned(&provisioned); - return provisioned; -} - -void hap_erase_network_info(void) -{ - esp_wifi_restore(); -} - -esp_err_t hap_wifi_softap_start(char *ssid) -{ - if (!ssid) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "SSID cannot be NULL"); - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Starting SoftAP with SSID: %s", ssid); - wifi_config_t wifi_config = { - .ap = { - .ssid = "", - .ssid_len = 0, - .max_connection = 4, - .password = "", - .authmode = WIFI_AUTH_OPEN - }, - }; - size_t ssid_len = strnlen(ssid, sizeof(wifi_config.ap.ssid)); - memcpy(wifi_config.ap.ssid, ssid, ssid_len); - wifi_mode_t mode; - esp_wifi_get_mode(&mode); - if (mode == WIFI_MODE_STA) { - esp_wifi_set_mode(WIFI_MODE_APSTA); - } else { - esp_wifi_set_mode(WIFI_MODE_AP); - } - esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config); - esp_wifi_start(); - return ESP_OK; -} - -esp_err_t hap_wifi_softap_stop(void) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Stopping SoftAP."); - wifi_mode_t mode; - esp_wifi_get_mode(&mode); - if (mode == WIFI_MODE_AP) { - esp_wifi_stop(); - } - esp_wifi_set_mode(WIFI_MODE_STA); - return ESP_OK; -} - -esp_err_t hap_wifi_sta_connect(wifi_config_t *config) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_INFO, "Connecting to Wi-Fi."); - wifi_mode_t mode; - esp_wifi_get_mode(&mode); - if (mode == WIFI_MODE_AP || mode == WIFI_MODE_APSTA) { - esp_wifi_set_mode(WIFI_MODE_APSTA); - } else { - esp_wifi_set_mode(WIFI_MODE_STA); - } - esp_wifi_set_config(ESP_IF_WIFI_STA, config); - esp_wifi_start(); - esp_wifi_connect(); - return ESP_OK; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wifi.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wifi.h deleted file mode 100644 index 7b7f95814..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_hap_wifi.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_WIFI_H_ -#define _HAP_WIFI_H_ -#include -bool hap_is_network_configured(); -void hap_wifi_restart(); -void hap_erase_network_info(); -#endif /* _HAP_WIFI_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_aes.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_aes.c deleted file mode 100644 index a81b34d41..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_aes.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include - -#include "mbedtls/aes.h" -#include "esp_log.h" - -#include "esp_mfi_aes.h" - -static const char* TAG = "mfi_aes_adapter"; - -/*! - * @group AES 128-bit Counter Mode API - - * @abstract API to encrypt or decrypt using AES-128 in counter mode. - * - * Call esp_mfi_aes_ctr_init to initialize the context. Don't use the context until it has been initialized. - * Call esp_mfi_aes_ctr_update to encrypt or decrypt N bytes of input and generate N bytes of output. - * Call esp_mfi_aes_ctr_final to finalize the context. After finalizing, you must call AES_CTR_Init to use it again. -*/ - -typedef struct { - uint8_t key[MFI_AES_CTR_SIZE]; - uint8_t nonce[MFI_AES_CTR_SIZE]; -} aes_ctr_context_t; - -/** - * @bref Create AES context - * - * @param none - * - * @return the AES context point - */ -esp_mfi_aes_ctr_t esp_mfi_aes_ctr_new(void) -{ - aes_ctr_context_t *context = NULL; - context = (aes_ctr_context_t *) malloc(sizeof(aes_ctr_context_t)); - return context; -} - -/** - * @bref Initialize AES context, include initialize the key and nonce - * - * @param incontext AES context point - * inkey AES key - * innonce AES nonce - * - * @return the result - * 0 : sucessful - * others : failed - */ -int esp_mfi_aes_ctr_init(esp_mfi_aes_ctr_t incontext, const uint8_t inkey[MFI_AES_CTR_SIZE], const uint8_t innonce[MFI_AES_CTR_SIZE]) -{ - int ret = 0; - - if (incontext == NULL) - return -EINVAL; - - aes_ctr_context_t *context = incontext; - - memcpy(context->key, inkey, MFI_AES_CTR_SIZE); - memcpy(context->nonce, innonce, MFI_AES_CTR_SIZE); - - return ret; -} - -/** - * @bref Update AES context - * - * @param incontext AES context point - * insrc the data point of update - * insrclen the data length - * indst the data pint of output - * - * @return the result - * 0 : sucessful - * others : failed - */ -int esp_mfi_aes_ctr_update(esp_mfi_aes_ctr_t incontext, const void *insrc, uint16_t insrclen, void *indst) -{ - int ret = 0; - - if (incontext == NULL) - return -EINVAL; - - aes_ctr_context_t *context = incontext; - size_t offset = 0; - uint8_t stream_block[MFI_AES_CTR_SIZE]; - mbedtls_aes_context ctx; - mbedtls_aes_init(&ctx); - - ret = mbedtls_aes_setkey_enc( &ctx, context->key, 128); - - if (ret != 0) { - ESP_LOGE(TAG, "mfi aes setkey[%d]", ret); - ret = -EINVAL; - } else { - ret = mbedtls_aes_crypt_ctr(&ctx, insrclen, &offset, context->nonce, stream_block, (uint8_t *) insrc, indst); - if (ret != 0) { - ESP_LOGE(TAG, "mfi aes crypt[%d]", ret); - ret = -EINVAL; - } - } - - return ret; -} - -/** - * @bref Destory AES context point - * - * @param incontext AES context point - * - * @return none - */ -void esp_mfi_aes_ctr_final(esp_mfi_aes_ctr_t incontext) -{ - if (incontext) { - memset((aes_ctr_context_t *) incontext, 0, sizeof(aes_ctr_context_t)); - free(incontext); - } -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_aes.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_aes.h deleted file mode 100644 index c563ea185..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_aes.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef ESP_MFI_AES_H_ -#define ESP_MFI_AES_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define MFI_AES_CTR_SIZE 16 - -typedef void* esp_mfi_aes_ctr_t; - -/** - * @brief Create AES context - * - * @return pointer of the AES context - */ -esp_mfi_aes_ctr_t esp_mfi_aes_ctr_new(void); - -/** - * @brief Initialize AES context, including the key and nonce - * - * @param incontext pointer of the AES context - * @param inkey AES key - * @param innonce AES nonce - * - * @return - * - 0 : succeed - * - others : fail - */ -int esp_mfi_aes_ctr_init(esp_mfi_aes_ctr_t incontext, const uint8_t inkey[MFI_AES_CTR_SIZE], const uint8_t innonce[MFI_AES_CTR_SIZE]); - -/** - * @brief Update AES context - * - * @param incontext AES context point - * @param insrc pointer of the source data to be updated - * @param insrclen source data length - * @param indst pointer of the updated data - * - * @return - * - 0 : succeed - * - others : fail - */ -int esp_mfi_aes_ctr_update(esp_mfi_aes_ctr_t incontext, const void *insrc, uint16_t insrclen, void *indst); - -/** - * @brief Destroy AES context pointer - * - * @param incontext pointer of the AES context - */ -void esp_mfi_aes_ctr_final(esp_mfi_aes_ctr_t incontext); - -#ifdef __cplusplus -} -#endif - -#endif /* ESP_MFI_AES_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_base64.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_base64.c deleted file mode 100644 index 6d1cb6ffa..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_base64.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include - -#include "mbedtls/base64.h" - -/** - * @brief transform bin data to base64 data - */ -int esp_mfi_base64_encode(const char *src, int len, char *dest, int dest_len, int *out_len) -{ - int ret = mbedtls_base64_encode((unsigned char *)dest, dest_len, (size_t *)out_len, (unsigned char *)src, len); - if (ret != 0){ - return -EINVAL; - } else{ - return 0; - } -} - -/** - * @brief transform base64 data to bin data - */ -int esp_mfi_base64_decode(const char *src, int len, char *dest, int dest_len, int *out_len) -{ - int ret = 0; - ret = mbedtls_base64_decode((unsigned char *)dest, dest_len, (size_t *)out_len, (unsigned char *)src, len); - if (ret != 0) { - return -EINVAL; - } else { - return 0; - } -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_base64.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_base64.h deleted file mode 100644 index 28e87e78b..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_base64.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef ESP_MFI_BASE64_H_ -#define ESP_MFI_BASE64_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief transform bin data to base64 data - * - * @param src input data point - * @param len input data length - * @param dest output data point - * @param dest_len output data buffer length - * @param out_len output data length - * - * @return - * - 0 : succeed - * - others : fail - */ -int esp_mfi_base64_encode(const char *src, int len, char *dest, int dest_len, int *out_len); - -/** - * @brief transform base64 data to bin data - * - * @param src input data point - * @param len input data length - * @param dest output data point - * @param dest_len output data buffer length - * @param out_len output data length - * - * @return - * - 0 : succeed - * - others : fail - */ -int esp_mfi_base64_decode(const char *src, int len, char *dest, int dest_len, int *out_len); - -#ifdef __cplusplus -} -#endif - -#endif /* ESP_MFI_BASE64_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.c deleted file mode 100644 index ca8917aad..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include - -#define RED_CHAR 31 -#define GREEN_CHAR 32 -#define YELLOW_CHAR 33 -#define BLUE_CHAR 34 -#define CYAN_CHAR 36 -#define WHITE_CHAR 37 - -#ifdef CONFIG_MFI_DEBUG_LEVEL_INIT -#define MFI_DEBUG_LEVEL_INIT CONFIG_MFI_DEBUG_LEVEL_INIT -#else /* CONFIG_MFI_DEBUG_LEVEL_INIT */ -#define MFI_DEBUG_LEVEL_INIT 0 -#endif /* CONFIG_MFI_DEBUG_LEVEL_INIT */ - -static uint32_t mfi_debug_level = MFI_DEBUG_LEVEL_INIT; - -/** - * @bref set the MFI debugging level - */ -int esp_mfi_set_debug_level(uint32_t level) -{ - mfi_debug_level = level; - return 0; -} - -/** - * @bref get the MFI debugging level and output data color - */ -uint32_t esp_mfi_get_debug_level(uint32_t level, uint32_t *color) -{ - const uint32_t prospect_table[] = { - 0, /* no */ - WHITE_CHAR, /* information: 1, color(37: white) */ - GREEN_CHAR, /* warn : 3, color(32: green) */ - RED_CHAR, /* error : 3, color(31: red) */ - YELLOW_CHAR, /* assert : 4, color(33: yellow) */ - CYAN_CHAR /* block : 5, color(36: cyan) */ - /* others : n, color(34: blue) */ - }; - const uint32_t prospect_table_size = sizeof(prospect_table) / sizeof(prospect_table[0]); - - if (level < prospect_table_size) - *color = prospect_table[level]; - else - *color = BLUE_CHAR; - - return mfi_debug_level; -} - -void hap_set_debug_level(hap_debug_level_t level) -{ - esp_mfi_set_debug_level(level); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.h deleted file mode 100644 index 282276e9d..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_debug.h +++ /dev/null @@ -1,183 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef ESP_MFI_DEBUG_H_ -#define ESP_MFI_DEBUG_H_ - -#include -#include - -#ifdef __cplusplus -extern "C"{ -#endif - -#define ESP_MFI_DEBUG_FL "\n" -#define CONFIG_ESP_MFI_DEBUG_ENABLE -#ifdef CONFIG_ESP_MFI_DEBUG_ENABLE -// #define ESP_MFI_DEBUG_ENABLE -#endif /* CONFIG_ESP_MFI_DEBUG_ENABLE */ - -#define CONFIG_ESP_MFI_ASSERT -#ifdef CONFIG_ESP_MFI_ASSERT -// #define ESP_MFI_ASSERT_ENABLE -#endif /* CONFIG_ESP_MFI_ASSERT */ - -#define CONFIG_MFI_DEBUG_LEVEL_INIT 0 -#define CONFIG_ESP_MFI_ASSERT_BLOCK -#ifdef CONFIG_ESP_MFI_ASSERT_BLOCK -#define ESP_MFI_ASSERT_BLOCK() while (1) -#else /* CONFIG_ESP_MFI_ASSERT_BLOCK */ -#define ESP_MFI_ASSERT_BLOCK() -#endif /* CONFIG_ESP_MFI_ASSERT_BLOCK */ - -/* debug level with different color */ -#define ESP_MFI_DEBUG_INFO 1 -#define ESP_MFI_DEBUG_WARN 2 -#define ESP_MFI_DEBUG_ERR 3 -#define ESP_MFI_DEBUG_ASSERT 4 -#define ESP_MFI_DEBUG_BLOCK 5 - -/** - * @bref set the MFI debugging level - * - * @param level debugging level - * - * @return the result - * = 0 : OK - * others : failed - */ -int esp_mfi_set_debug_level(uint32_t level); - -/** - * @bref get the MFI debugging level and output data color - * - * @param level input debug level - * @param color data color - * - * @return MFI debugging level - */ -uint32_t esp_mfi_get_debug_level(uint32_t level, uint32_t *color); - -/** - * @bref format the string and data, then output it - * - * @param level if level > MFI_DEBUG_LEVEL then output it - * @param fmt format string - * @param ... parameters of format string - * - * @return none - * - * void ESP_MFI_DEBUG(unsigned int level, const char *fmt, ...); - */ -#ifdef ESP_MFI_DEBUG_ENABLE -/* -#define ESP_MFI_DEBUG(l, fmt, ...) \ - { \ - uint32_t __color_LINE; \ - if (l > esp_mfi_get_debug_level(l, &__color_LINE)) { \ - printf("\e[1;%dm" fmt "\e[0m" ESP_MFI_DEBUG_FL, \ - __color_LINE, ##__VA_ARGS__); \ - } \ - } -#define ESP_MFI_DEBUG_INTR(l, fmt, ...) \ - { \ - uint32_t __color_LINE; \ - if (l > esp_mfi_get_debug_level(l, &__color_LINE)) { \ - ets_printf("\e[1;%dm" fmt "\e[0m" ESP_MFI_DEBUG_FL, \ - __color_LINE, ##__VA_ARGS__); \ - } \ - } - -#define ESP_MFI_DEBUG(l, fmt, ...) \ - { \ - uint32_t __color_LINE; \ - if (l > esp_mfi_get_debug_level(l, &__color_LINE)) { \ - printf("[%7lu] " fmt "\n", ((unsigned long) (esp_timer_get_time() / 1000ULL)), ##__VA_ARGS__); \ - } \ - } -#define ESP_MFI_DEBUG_INTR(l, fmt, ...) \ - { \ - uint32_t __color_LINE; \ - if (l > esp_mfi_get_debug_level(l, &__color_LINE)) { \ - printf("[%7lu] " fmt "\n", ((unsigned long) (esp_timer_get_time() / 1000ULL)), ##__VA_ARGS__); \ - } \ - }*/ - -#define ESP_MFI_DEBUG(l, fmt, ...) \ - { \ - printf("[%7lu] " fmt "\n", ((unsigned long) (esp_timer_get_time() / 1000ULL)), ##__VA_ARGS__); \ - } -#define ESP_MFI_DEBUG_INTR(l, fmt, ...) \ - { \ - printf("[%7lu] " fmt "\n", ((unsigned long) (esp_timer_get_time() / 1000ULL)), ##__VA_ARGS__); \ - } -#else /* ESP_MFI_DEBUG_ENABLE */ -#define ESP_MFI_DEBUG(l, fmt, ...) -#define ESP_MFI_DEBUG_INTR(l, fmt, ...) -#endif /* ESP_MFI_DEBUG_ENABLE */ - -/** - * @bref if the signal is false(0) do something depended on configuration - * - * @param conditions checking conditions - * - * @return none - * - * void ESP_MFI_ASSERT(int conditions); - */ -#ifdef ESP_MFI_ASSERT_ENABLE -#define ESP_MFI_ASSERT(cond) \ -{ \ - if (!(cond)) { \ - printf("\e[1;33m" "ESP_MFI assert file %s line %d" ESP_MFI_DEBUG_FL, \ - __FILE__, __LINE__); \ - ESP_MFI_ASSERT_BLOCK(); \ - } \ -} -#else -#define ESP_MFI_ASSERT(cond) -#endif - -/** - * @bref check if data length matches given length - * - * @param optlen data length - * @param opttype data - * - * @return none - * - * void ESP_MFI_CHECK_OPTLEN(int conditions, (all type) data); - */ -#define ESP_MFI_CHECK_OPTLEN(optlen, opttype) \ - do { \ - if ((optlen) > sizeof(opttype)) { \ - return -1; \ - } \ - } while(0) \ - -#ifdef __cplusplus -} -#endif - -#endif /* ESP_MFI_DEBUG_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_dummy.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_dummy.c deleted file mode 100644 index 9ddcd1fc0..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_dummy.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include -#include -#include -#include - -ESP_EVENT_DEFINE_BASE(HAP_WAC_EVENT); - -int hap_pair_setup_manage_mfi_auth(pair_setup_ctx_t *ps_ctx, hap_tlv_data_t *tlv_data, hap_tlv_error_t *tlv_error) -{ - - if (ps_ctx->method == HAP_METHOD_PAIR_SETUP) { - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "Secure pair setup not supported. Please use MFi variant of the SDK."); - *tlv_error = kTLVError_Unknown; - return HAP_FAIL; - } - ESP_MFI_DEBUG(ESP_MFI_DEBUG_WARN, "Using pair-setup without MFi."); - return ESP_OK; -} - -int hap_enable_mfi_auth(hap_mfi_auth_type_t auth_type) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_WARN, "MFi auth not supported. Falling back to HAP_MFI_AUTH_NONE"); - hap_priv.auth_type = HAP_MFI_AUTH_NONE; - return 0; -} - -int hap_wac_start(void) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "WAC not supported. Please use MFi variant of the SDK."); - return ESP_FAIL; -} - -int hap_wac_stop(void) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "WAC not supported. Please use MFi variant of the SDK."); - return ESP_FAIL; -} -int hap_enable_hw_auth(void) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "MFi HW Auth not supported. Please use MFi variant of the SDK."); - return ESP_FAIL; - -} -int hap_enable_sw_auth(void) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "MFi SW Auth not supported. Please use MFi variant of the SDK."); - return ESP_FAIL; -} -int hap_register_secure_message_handler(httpd_handle_t handle) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "MFi SW Auth not supported. Please use MFi variant of the SDK."); - return ESP_FAIL; -} -int hap_unregister_secure_message_handler(httpd_handle_t handle) -{ - ESP_MFI_DEBUG(ESP_MFI_DEBUG_ERR, "MFi SW Auth not supported. Please use MFi variant of the SDK."); - return ESP_FAIL; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_i2c.c.0 b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_i2c.c.0 deleted file mode 100644 index c75e8b6f9..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_i2c.c.0 +++ /dev/null @@ -1,689 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include -#include -#ifdef CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/rom/ets_sys.h" -#else -#include "esp32/rom/ets_sys.h" -#endif - -#ifdef CONFIG_I2C_SOFTWARE -#include "driver/gpio.h" -#else -#include "driver/i2c.h" -#endif - -#include "esp_log.h" -#include "esp_mfi_i2c.h" - -static const char *TAG = "mfi_i2c"; - -#ifndef CONFIG_I2C_SOFTWARE - -#define I2C_MASTER_NUM I2C_NUM_0 -#define I2C_MASTER_FREQ_HZ CONFIG_IC2_SPEED -#define I2C_MASTER_RX_BUF_DISABLE 0 -#define I2C_MASTER_TX_BUF_DISABLE 0 -#define ACK_CHECK_EN 1 -#define ACK_VAL 0 -#define NACK_VAL 1 - -/* To use GPIOs 17/18 for the Hardware I2C, replace the numbers 26/27 below - */ -#define I2C_MASTER_SDA_GPIO CONFIG_SDA_GPIO -#define I2C_MASTER_SCL_GPIO CONFIG_SCL_GPIO - -#define I2C_MASTER_MAX_READ CONFIG_I2C_MAX_READ_COUNT -#define I2C_MASTER_RETRY_TIMES 500 -#define I2C_MASTER_TICKS_TIMES 2 * I2C_MASTER_RETRY_TIMES -#define I2C_MASTER_MAX_RETRY 10 -#define I2C_MASTER_INTERNAL_TIMES 8 * I2C_MASTER_RETRY_TIMES -/** - * @brief Initialize I2C information - */ -int esp_mfi_i2c_init(void) -{ - int ret = 0; - i2c_config_t conf; - int i2c_master_port = I2C_MASTER_NUM; - - conf.mode = I2C_MODE_MASTER; - conf.sda_io_num = I2C_MASTER_SDA_GPIO; - conf.sda_pullup_en = GPIO_PULLUP_ENABLE; - conf.scl_io_num = I2C_MASTER_SCL_GPIO; - conf.scl_pullup_en = GPIO_PULLUP_ENABLE; - conf.master.clk_speed = I2C_MASTER_FREQ_HZ; - - ret = i2c_param_config(i2c_master_port, &conf); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "I2C parameter initial fail %d", ret); - return -EINVAL; - } - - ret = i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "I2C driver initial fail %d", ret); - return -EINVAL; - } - - return 0; -} -/** - * @brief write data buffer to slave - */ -int esp_mfi_i2c_write(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len) -{ - uint16_t i; - - if (!buff) - return -EINVAL; - - ESP_LOGI(TAG, "Writing to HW I2C"); - - int ret = 0; - i2c_cmd_handle_t cmd = NULL; - i = 0; - - do { - cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - - // Send write address of the CP - i2c_master_write_byte(cmd, slvaddr, ACK_CHECK_EN); - // Send register address to slave. - i2c_master_write_byte(cmd, regaddr, ACK_CHECK_EN); - // Send data out. - i2c_master_write(cmd, buff, len, ACK_CHECK_EN); - - i2c_master_stop(cmd); - ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TICKS_TIMES / portTICK_RATE_MS); - i ++; - i2c_cmd_link_delete(cmd); - ets_delay_us(I2C_MASTER_RETRY_TIMES); - } while(ret != ESP_OK && i < I2C_MASTER_MAX_RETRY); - - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Write data to slave fail %d.", ret); - } - return ret; -} - -/** - * @brief read data form slave - */ -int esp_mfi_i2c_read(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len) -{ - uint16_t i, j = 0; - - if (!buff) - return -EINVAL; - - ESP_LOGI(TAG, "Reading from HW I2C"); - - int ret = 0; - i2c_cmd_handle_t cmd = NULL; - i = 0; - - do { - for (j = 0; j < I2C_MASTER_MAX_READ; j++) { - cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - - // Send write address of the CP - i2c_master_write_byte(cmd, slvaddr, ACK_CHECK_EN); - // Send register address to slave. - i2c_master_write_byte(cmd, regaddr, ACK_CHECK_EN); - - i2c_master_stop(cmd); - ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TICKS_TIMES / portTICK_RATE_MS); - i2c_cmd_link_delete(cmd); - if (ret == ESP_OK) { - break; - } else { - ets_delay_us(I2C_MASTER_INTERNAL_TIMES); - } - } - - ets_delay_us(I2C_MASTER_INTERNAL_TIMES); - - cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - - i2c_master_write_byte(cmd, slvaddr + 1, ACK_CHECK_EN); - if (len == 1) - i2c_master_read_byte(cmd, buff, NACK_VAL); - else { - i2c_master_read(cmd, buff, len - 1, ACK_VAL); - i2c_master_read_byte(cmd, buff + len - 1, NACK_VAL); - } - - i2c_master_stop(cmd); - ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, I2C_MASTER_TICKS_TIMES / portTICK_RATE_MS); - i ++; - i2c_cmd_link_delete(cmd); - } while (ret != ESP_OK && i < I2C_MASTER_MAX_RETRY); - - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Read data from slave fail %d.", ret); - } - - return ret; -} - -#else - -#define MFI_CP_BUSY_RETRY_TIMES CONFIG_I2C_RETRY_COUNT - -#define GPIO_Pin_26 GPIO_SEL_26 -#define GPIO_Pin_27 GPIO_SEL_27 - -#define gpio_set_output_level(a, b) gpio_set_level(a, b) -#define gpio_get_input_level(a) gpio_get_level(a) - -#define GPIO_Mode_Input_OutOD GPIO_MODE_INPUT_OUTPUT_OD -#define GPIO_PullDown_DIS GPIO_PULLDOWN_DISABLE -#define GPIO_PullUp_EN GPIO_PULLUP_ENABLE -#define GPIO_Mode_Out_OD GPIO_MODE_OUTPUT_OD - -#define I2C_MASTER_SDA_MUX PERIPHS_IO_MUX_GPIO26_U -#define I2C_MASTER_SCL_MUX PERIPHS_IO_MUX_GPIO27_U -#define I2C_MASTER_SDA_GPIO 26 -#define I2C_MASTER_SDA_PIN GPIO_Pin_26 -#define I2C_MASTER_SDA_FUNC FUNC_GPIO26_GPIO26 -#define I2C_MASTER_SCL_GPIO 27 -#define I2C_MASTER_SCL_PIN GPIO_Pin_27 -#define I2C_MASTER_SCL_FUNC FUNC_GPIO27_GPIO27 - -#define I2C_MASTER_SDA_HIGH_SCL_HIGH() \ - gpio_set_output_level(I2C_MASTER_SDA_GPIO,1); \ - gpio_set_output_level(I2C_MASTER_SCL_GPIO,1); - -#define I2C_MASTER_SDA_HIGH_SCL_LOW() \ - gpio_set_output_level(I2C_MASTER_SDA_GPIO,1); \ - gpio_set_output_level(I2C_MASTER_SCL_GPIO,0); - -#define I2C_MASTER_SDA_LOW_SCL_HIGH() \ - gpio_set_output_level(I2C_MASTER_SDA_GPIO,0); \ - gpio_set_output_level(I2C_MASTER_SCL_GPIO,1); - -#define I2C_MASTER_SDA_LOW_SCL_LOW() \ - gpio_set_output_level(I2C_MASTER_SDA_GPIO,0); \ - gpio_set_output_level(I2C_MASTER_SCL_GPIO,0); - -#define i2c_master_wait ets_delay_us - -static void i2c_master_init(void); -static void i2c_master_stop(void); - -static uint8_t s_last_sda; -static uint8_t s_last_scl; - -/** - * @brief set I2C SDA and SCL bit value for half CLK cycle - */ -static void i2c_master_setDC(uint8_t SDA, uint8_t SCL) -{ - SDA &= 0x01; - SCL &= 0x01; - s_last_sda = SDA; - s_last_scl = SCL; - - if ((0 == SDA) && (0 == SCL)) { - I2C_MASTER_SDA_LOW_SCL_LOW(); - } else if ((0 == SDA) && (1 == SCL)) { - I2C_MASTER_SDA_LOW_SCL_HIGH(); - } else if ((1 == SDA) && (0 == SCL)) { - I2C_MASTER_SDA_HIGH_SCL_LOW(); - } else { - I2C_MASTER_SDA_HIGH_SCL_HIGH(); - } -} - -/** - * @brief get I2C SDA bit value - */ -static uint8_t i2c_master_getDC(void) -{ - uint8_t sda_out; - - sda_out = gpio_get_input_level(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO)); - - return sda_out; -} - -/** - * @brief initialize I2C bus to enable i2c operations - */ -static void i2c_master_init(void) -{ - uint8_t i; - - i2c_master_setDC(1, 0); - i2c_master_wait(5); - - // when SCL = 0, toggle SDA to clear up - i2c_master_setDC(0, 0) ; - i2c_master_wait(5); - i2c_master_setDC(1, 0) ; - i2c_master_wait(5); - - // set data_cnt to max value - for (i = 0; i < 28; i++) { - i2c_master_setDC(1, 0); - i2c_master_wait(5); // sda 1, scl 0 - i2c_master_setDC(1, 1); - i2c_master_wait(5); // sda 1, scl 1 - } - - // reset all - i2c_master_stop(); -} - -/** - * @brief configure SDA and SCL GPIO to open-drain output mode - */ -static void i2c_master_gpio_init(void) -{ - - gpio_config_t io_config; - io_config.intr_type = GPIO_PIN_INTR_DISABLE; - io_config.mode = GPIO_MODE_INPUT_OUTPUT_OD; - io_config.pin_bit_mask = I2C_MASTER_SDA_PIN; - io_config.pull_down_en = GPIO_PULLDOWN_DISABLE; - io_config.pull_up_en = GPIO_PULLUP_ENABLE; - - gpio_config(&io_config); - - io_config.intr_type = GPIO_PIN_INTR_DISABLE; - io_config.mode = GPIO_MODE_OUTPUT_OD; - io_config.pin_bit_mask = I2C_MASTER_SCL_PIN; - io_config.pull_down_en = GPIO_PULLDOWN_DISABLE; - io_config.pull_up_en = GPIO_PULLUP_ENABLE; - - - gpio_config(&io_config); - - gpio_pullup_en(I2C_MASTER_SDA_GPIO); - gpio_pullup_en(I2C_MASTER_SCL_GPIO); - gpio_pulldown_dis(I2C_MASTER_SDA_GPIO); - gpio_pulldown_dis(I2C_MASTER_SCL_GPIO); - - i2c_master_init(); -} - -/** - * @brief set I2C to start operation - */ -static void i2c_master_start(void) -{ - i2c_master_setDC(1, s_last_scl); - i2c_master_wait(5); - i2c_master_setDC(1, 1); - i2c_master_wait(5); // sda 1, scl 1 - i2c_master_setDC(0, 1); - i2c_master_wait(5); // sda 0, scl 1 -} - -/** - * @brief set i2c to stop sending state - */ -static void i2c_master_stop(void) -{ - i2c_master_wait(5); - - i2c_master_setDC(0, s_last_scl); - i2c_master_wait(5); // sda 0 - i2c_master_setDC(0, 1); - i2c_master_wait(5); // sda 0, scl 1 - i2c_master_setDC(1, 1); - i2c_master_wait(5); // sda 1, scl 1 -} - -/** - * @brief set ack to i2c bus as level value - */ -static void i2c_master_setAck(uint8_t level) -{ - i2c_master_setDC(s_last_sda, 0); - i2c_master_wait(5); - i2c_master_setDC(level, 0); - i2c_master_wait(5); // sda level, scl 0 - i2c_master_setDC(level, 1); - i2c_master_wait(8); // sda level, scl 1 - i2c_master_setDC(level, 0); - i2c_master_wait(5); // sda level, scl 0 - i2c_master_setDC(1, 0); - i2c_master_wait(5); -} - -/** - * @brief confirm if peer send ack - */ -static uint8_t i2c_master_getAck(void) -{ - uint8_t retVal; - - i2c_master_setDC(s_last_sda, 0); - i2c_master_wait(5); - i2c_master_setDC(1, 0); - i2c_master_wait(5); - i2c_master_setDC(1, 1); - i2c_master_wait(5); - - retVal = i2c_master_getDC(); - i2c_master_wait(5); - i2c_master_setDC(1, 0); - i2c_master_wait(5); - - return retVal; -} - -/** - * @brief get I2C response - */ -static bool i2c_master_checkAck(void) -{ - if (i2c_master_getAck()) { - return false; - } else { - return true; - } -} - -/** - * @brief send I2C ack signal - */ -static void i2c_master_send_ack(void) -{ - i2c_master_setAck(0x0); -} - -/** - * @brief send I2C not ack signal - */ -static void i2c_master_send_nack(void) -{ - i2c_master_setAck(0x1); -} - -/** - * @brief read byte from i2c bus - */ -static uint8_t i2c_master_readByte(void) -{ - uint8_t retVal = 0; - uint8_t k, i; - - i2c_master_wait(5); - i2c_master_setDC(s_last_sda, 0); - i2c_master_wait(5); // sda 1, scl 0 - - for (i = 0; i < 8; i++) { - i2c_master_wait(5); - i2c_master_setDC(1, 0); - i2c_master_wait(5); // sda 1, scl 0 - i2c_master_setDC(1, 1); - i2c_master_wait(5); // sda 1, scl 1 - - k = i2c_master_getDC(); - i2c_master_wait(5); - - if (i == 7) { - i2c_master_wait(3); - } - - k <<= (7 - i); - retVal |= k; - } - - i2c_master_setDC(1, 0); - i2c_master_wait(5); // sda 1, scl 0 - - return retVal; -} - -/** - * @brief write byte to i2c - */ -static void i2c_master_writeByte(uint8_t wrdata) -{ - uint8_t dat; - int8_t i; - - i2c_master_wait(5); - i2c_master_setDC(s_last_sda, 0); - i2c_master_wait(5); - - for (i = 7; i >= 0; i--) { - dat = wrdata >> i; - i2c_master_setDC(dat, 0); - i2c_master_wait(5); - i2c_master_setDC(dat, 1); - i2c_master_wait(5); - - if (i == 0) { - i2c_master_wait(3); //// - } - - i2c_master_setDC(dat, 0); - i2c_master_wait(5); - } - -} - -/** - * @brief write byte to i2c and get check ack - */ -static bool i2c_write_byte(uint8_t data, uint8_t iter) -{ - if (iter == 0) { - iter = 1; - } - - while (iter--) { - i2c_master_writeByte(data); - - if (i2c_master_getAck()) { - i2c_master_stop(); - ets_delay_us(500); // Wait 500us and retry. - i2c_master_start(); - } else { - return true; - } - } - i2c_master_stop(); - return false; -} - -/** - * @brief write byte to target register of target I2C slave - */ -static void i2c_write_reg(uint8_t slave_add, uint8_t reg_add, uint16_t data) -{ - i2c_master_start(); - if (false == i2c_write_byte(slave_add, 30)) { - ESP_LOGE(TAG, "1Slave is busy, [%02x]TIME OUT\n", slave_add); - } - if (false == i2c_write_byte(reg_add, 30)) { - ESP_LOGE(TAG, "2Slave is busy, [%02x]TIME OUT\n", reg_add); - } - if (false == i2c_write_byte((data >> 8), 30)) { - ESP_LOGE(TAG, "3Slave is busy, [%02x]TIME OUT\n", data); - } - if (false == i2c_write_byte((data & 0xFF), 30)) { - ESP_LOGE(TAG, "3Slave is busy, [%02x]TIME OUT\n", data); - } - i2c_master_stop(); -} - -/** - * @brief a block of data to I2C - */ -static void i2s_write_arr(const uint8_t *data, size_t len) -{ - if (data == NULL || len <= 0) return; - - i2c_master_start(); - - int i = 0; - for (i = 0; i < len; ++i) { - if (false == i2c_write_byte(data[i], 30)) { - ESP_LOGE(TAG, "Slave is busy, [%02x]TIME OUT\n", data[i]); - } - } - i2c_master_stop(); -} - -/** - * @brief Initialize I2C information - */ -int esp_mfi_i2c_init(void) -{ - i2c_master_gpio_init(); - return 0; -} - -/** - * @brief Finish I2C information - */ -int esp_mfi_i2c_end(void) -{ - return 0; -} - -/** - * @brief write one byte data to slave - */ -static int esp_mfi_i2c_write_byte(uint8_t data, uint16_t retrytimes) -{ - uint16_t times = retrytimes; - if (0 == times) { - times = 1; - } - - while (times--) { - i2c_master_writeByte(data); - if (i2c_master_getAck()) { - i2c_master_wait(500); /**< Wait 500us and retry */ - i2c_master_stop(); - i2c_master_wait(500); /**< Wait 500us and retry */ - i2c_master_start(); - } else { - return 0; - } - } - - i2c_master_stop(); - - return -ETIME; -} - -/** - * @brief write data buffer to slave - */ -int esp_mfi_i2c_write(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len) -{ - uint16_t i; - - if (!buff) - return -EINVAL; - - ESP_LOGI(TAG, "Writing to SW I2C"); - - i2c_master_start(); - - /**< Send write address of the CP */ - if (esp_mfi_i2c_write_byte(slvaddr, MFI_CP_BUSY_RETRY_TIMES) != 0) { - ESP_LOGE(TAG, "Slave is busy, time out."); - return -ETIME; - } - - /**< Send register address to slave */ - if (esp_mfi_i2c_write_byte(regaddr, 0) != 0) { - ESP_LOGE(TAG, "Write register address[0x%02x] to slave.", regaddr); - return -ENODATA; - } - - /**< Send data out */ - for (i = 0; i < len; ++i) { - if (esp_mfi_i2c_write_byte(*buff++, 0) != 0) { - ESP_LOGE(TAG, "Write data[0x%02x] to slave.", *buff); - return -ENODATA; - } - } - - i2c_master_stop(); - - return 0; -} - -/** - * @brief read data form slave - */ -int esp_mfi_i2c_read(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len) -{ - uint16_t i; - - if (!buff) - return -EINVAL; - - ESP_LOGI(TAG, "Reading from SW I2C"); - - i2c_master_start(); - - /**< Send write address of the CP */ - if (esp_mfi_i2c_write_byte(slvaddr, MFI_CP_BUSY_RETRY_TIMES) != 0) { - ESP_LOGE(TAG, "Slave is busy, time out."); - return -ETIME; - } - - /**< Send register address to slave */ - if (esp_mfi_i2c_write_byte(regaddr, 0) != 0) { - ESP_LOGE(TAG, "Write register address[0x%02x] to slave.", regaddr); - return -ENODATA; - } - i2c_master_stop(); - - i2c_master_wait(4000); - - /**< Send read address of the CP */ - if (esp_mfi_i2c_write_byte((slvaddr + 1), MFI_CP_BUSY_RETRY_TIMES) != 0) { - ESP_LOGE(TAG, "Slave is busy, time out."); - return -ETIME; - } - - for (i = 0; i < len; ++i) { - buff[i] = i2c_master_readByte(); - - i2c_master_setAck((i == (len - 1)) ? 1 : 0); - } - - i2c_master_stop(); - - return 0; -} -#endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_i2c.h.0 b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_i2c.h.0 deleted file mode 100644 index 4813bc01e..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_i2c.h.0 +++ /dev/null @@ -1,84 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef ESP_MFI_I2C_H_ -#define ESP_MFI_I2C_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Initialize I2C - * - * @return - * - 0 : succeed - * - others : fail - */ -int esp_mfi_i2c_init(void); - -/** - * @brief I2C operation end - * - * @return - * - 0 : succeed - * - others : fail - */ -int esp_mfi_i2c_end(void); - -/** - * @brief Write data to I2C slave - * - * @param slvaddr address of slave - * @param regaddr address of register - * @param buff pointer of data to write - * @param len the data length - * - * @return - * - 0 : succeed - * - others : fail - */ -int esp_mfi_i2c_write(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len); - -/** - * @brief Read data from I2C slave - * - * @param slvaddr address of slave - * @param regaddr address of register - * @param buff pointer of data read - * @param len the data length - * - * @return - * - 0 : succeed - * - others : fail - */ -int esp_mfi_i2c_read(uint8_t slvaddr, uint8_t regaddr, uint8_t *buff, uint32_t len); - -#ifdef __cplusplus -} -#endif - -#endif /* ESP_MFI_I2C_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_rand.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_rand.c deleted file mode 100644 index 437da0fc8..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_rand.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include - -/** - * @bref Obtain a series of random bytes - * - * @param buf the random bytes were copied point - * len the number of bytes requested - * - * @return the result - * > 0 : the number of bytes that were copied to the buffer - * others : failed - */ -int esp_mfi_get_random(uint8_t *buf, uint16_t len) -{ - int i, j; - unsigned long tmp; - - for (i = 0; i < ((len + 3) & ~3) / 4; i++) { - tmp = esp_random(); - - for (j = 0; j < 4; j++) { - if ((i * 4 + j) < len) { - buf[i * 4 + j] = (uint8_t) (tmp >> (j * 8)); - } else { - break; - } - } - } - - return len; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_rand.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_rand.h deleted file mode 100644 index ad2808af9..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_rand.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef ESP_MFI_RAND_H_ -#define ESP_MFI_RAND_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Get a random number of bytes specified. - * - * @param buf pointer of the random number it gets - * @param len specified bytes of the random number - * - * @return - * - > 0 : the actual length(bytes) of the random number - * - others : failure - */ -int esp_mfi_get_random(uint8_t *buf, uint16_t len); - -#ifdef __cplusplus -} -#endif - -#endif /* ESP_MFI_RAND_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_sha.c b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_sha.c deleted file mode 100644 index 5bf80b0b3..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_sha.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include - -#include "mbedtls/sha1.h" -#include "mbedtls/sha256.h" -#include "mbedtls/sha512.h" - -#include "esp_mfi_sha.h" - -#ifdef CONFIG_IDF_TARGET_ESP8266 -#define mbedtls_sha512_starts mbedtls_sha512_starts_ret -#define mbedtls_sha512_update mbedtls_sha512_update_ret -#define mbedtls_sha512_finish mbedtls_sha512_finish_ret -#endif - -/** - * @bref Create SHA1 context - * - * @param none - * - * @return the SHA1 context point - */ -esp_mfi_sha_ctx_t esp_mfi_sha1_new(void) -{ - mbedtls_sha1_context *context = NULL; - context = (mbedtls_sha1_context *) malloc(sizeof(mbedtls_sha1_context)); - mbedtls_sha1_init(context); - return context; -} - -/** - * @bref Free SHA1 context - * - * @param ctx the SHA1 context point - * - * @return none - */ -void esp_mfi_sha1_free(esp_mfi_sha_ctx_t ctx) -{ - if (ctx) { - mbedtls_sha1_free( (mbedtls_sha1_context *)ctx); - free(ctx); - } -} - -/** - * @bref Init SHA1 context - * - * @param ctx the SHA1 context point - * - * @return none - */ -void esp_mfi_sha1_init(esp_mfi_sha_ctx_t ctx) -{ - if (ctx == NULL) - return; - - mbedtls_sha1_starts((mbedtls_sha1_context *) ctx); -} - -/** - * @bref Update SHA1 context - * - * @param ctx the SHA1 context point - * msg input data point - * len input data length - * - * @return none - */ -void esp_mfi_sha1_update(esp_mfi_sha_ctx_t ctx, const uint8_t * msg, int len) -{ - if (ctx == NULL || msg == NULL) - return; - - mbedtls_sha1_update((mbedtls_sha1_context *) ctx, msg, len); -} - -/** - * @bref Final SHA1 context - * - * @param digest output data point - * ctx the SHA1 context point - * - * @return none - */ -void esp_mfi_sha1_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest) -{ - if (ctx == NULL || digest == NULL) - return; - - mbedtls_sha1_finish((mbedtls_sha1_context *) ctx, digest); -} - -/* - * SHA256 declarations - */ - -/** - * @bref Create SHA256 context - * - * @param none - * - * @return the SHA256 context point - */ -esp_mfi_sha_ctx_t esp_mfi_sha256_new(void) -{ - mbedtls_sha256_context *context = NULL; - context = (mbedtls_sha256_context *) malloc(sizeof(mbedtls_sha256_context)); - mbedtls_sha256_init(context); - return context; -} - -/** - * @bref Free SHA256 context - * - * @param ctx the SHA256 context point - * - * @return none - */ -void esp_mfi_sha256_free(esp_mfi_sha_ctx_t ctx) -{ - if (ctx) { - mbedtls_sha256_free((mbedtls_sha256_context *)ctx); - free(ctx); - } -} - -/** - * @bref Init SHA256 context - * - * @param ctx the SHA256 context point - * - * @return none - */ -void esp_mfi_sha256_init(esp_mfi_sha_ctx_t ctx) -{ - if (ctx == NULL) - return; - - mbedtls_sha256_starts((mbedtls_sha256_context *) ctx, 0); -} - -/** - * @bref Update SHA256 context - * - * @param ctx the SHA256 context point - * msg input data point - * len input data length - * - * @return none - */ -void esp_mfi_sha256_update(esp_mfi_sha_ctx_t ctx, const uint8_t *input, int len) -{ - if (ctx == NULL || input == NULL) - return; - - mbedtls_sha256_update((mbedtls_sha256_context *) ctx, input, len); -} - -/** - * @bref Final SHA256 context - * - * @param digest output data point - * ctx the SHA256 context point - * - * @return none - */ -void esp_mfi_sha256_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest) -{ - if (ctx == NULL || digest == NULL) - return; - - mbedtls_sha256_finish((mbedtls_sha256_context *) ctx, digest); -} - -/* - * SHA512 declarations - */ - -/** - * @bref Create SHA512 context - * - * @param none - * - * @return the SHA512 context point - */ -esp_mfi_sha_ctx_t esp_mfi_sha512_new(void) -{ - mbedtls_sha512_context *context = NULL; - context = (mbedtls_sha512_context *) malloc(sizeof(mbedtls_sha512_context)); - mbedtls_sha512_init(context); - return context; -} - -/** - * @bref Free SHA512 context - * - * @param ctx the SHA512 context point - * - * @return none - */ -void esp_mfi_sha512_free(esp_mfi_sha_ctx_t ctx) -{ - if (ctx) { - mbedtls_sha512_free((mbedtls_sha512_context *)ctx); - free(ctx); - } -} - -/** - * @bref Init SHA512 context - * - * @param ctx the SHA512 context point - * - * @return none - */ -void esp_mfi_sha512_init(esp_mfi_sha_ctx_t ctx) -{ - if (ctx == NULL) - return; - - mbedtls_sha512_starts((mbedtls_sha512_context *) ctx, 0); -} - -/** - * @bref Update SHA512 context - * - * @param ctx the SHA512 context point - * msg input data point - * len input data length - * - * @return none - */ -void esp_mfi_sha512_update(esp_mfi_sha_ctx_t ctx, const uint8_t *input, int len) -{ - if (ctx == NULL || input == NULL) - return; - - mbedtls_sha512_update((mbedtls_sha512_context *) ctx, input, len); -} - -/** - * @bref Final SHA512 context - * - * @param digest output data point - * ctx the SHA512 context point - * - * @return none - */ -void esp_mfi_sha512_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest) -{ - if (ctx == NULL || digest == NULL) - return; - - mbedtls_sha512_finish((mbedtls_sha512_context *) ctx, digest); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_sha.h b/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_sha.h deleted file mode 100644 index 87d4058c6..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/esp_mfi_sha.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef ESP_MFI_SHA_H_ -#define ESP_MFI_SHA_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void* esp_mfi_sha_ctx_t; - -/* - * SHA1 declarations - */ - -#define MFI_SHA1_SIZE 20 - -/** - * @brief Create SHA1 context - * - * @return pointer of the SHA1 context - */ -esp_mfi_sha_ctx_t esp_mfi_sha1_new(void); - -/** - * @brief Init SHA1 context - * - * @param ctx pointer of the SHA1 context - */ -void esp_mfi_sha1_init(esp_mfi_sha_ctx_t ctx); - -/** - * @brief Update SHA1 context - * - * @param ctx pointer of the SHA1 context - * @param msg pointer of the input data - * @param len input data length - */ -void esp_mfi_sha1_update(esp_mfi_sha_ctx_t ctx, const uint8_t *msg, int len); - -/** - * @brief Final SHA1 context - * - * @param digest pointer of output data - * @param ctx pointer of the SHA1 context - */ -void esp_mfi_sha1_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest); - -/** - * @brief Free SHA1 context - * - * @param ctx pointer of the SHA1 context - */ -void esp_mfi_sha1_free(esp_mfi_sha_ctx_t ctx); - -/* - * SHA256 declarations - */ - -#define MFI_SHA256_SIZE 32 - -/** - * @brief Create SHA256 context - * - * @return pointer of the SHA256 context - */ -esp_mfi_sha_ctx_t esp_mfi_sha256_new(void); - -/** - * @brief Init SHA256 context - * - * @param ctx pointer of the SHA256 context - */ -void esp_mfi_sha256_init(esp_mfi_sha_ctx_t ctx); - -/** - * @brief Update SHA256 context - * - * @param ctx pointer of the SHA256 context - * @param msg pointer of input data - * @param len input data length - */ -void esp_mfi_sha256_update(esp_mfi_sha_ctx_t ctx, const uint8_t *input, int len); - -/** - * @brief Final SHA256 context - * - * @param digest pointer of output data - * @param ctx pointer of the SHA256 context - */ -void esp_mfi_sha256_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest); - -/** - * @brief Free SHA256 context - * - * @param ctx pointer of the SHA256 context - */ -void esp_mfi_sha256_free(esp_mfi_sha_ctx_t ctx); - -/* - * SHA512 declarations - */ - -#define MFI_SHA512_SIZE 64 - -/** - * @brief Create SHA512 context - * - * @return pointer of the SHA512 context - */ -esp_mfi_sha_ctx_t esp_mfi_sha512_new(void); - -/** - * @brief Init SHA512 context - * - * @param ctx pointer of the SHA512 context - */ -void esp_mfi_sha512_init(esp_mfi_sha_ctx_t ctx); - -/** - * @brief Update SHA512 context - * - * @param ctx pointer of the SHA512 context - * @param msg pointer of input data - * @param len input data length - */ -void esp_mfi_sha512_update(esp_mfi_sha_ctx_t ctx, const uint8_t *input, int len); - -/** - * @brief Final SHA512 context - * - * @param digest pointer of output data - * @param ctx pointer of the SHA512 context - */ -void esp_mfi_sha512_final(esp_mfi_sha_ctx_t ctx, uint8_t *digest); - -/** - * @brief Free SHA512 context - * - * @param ctx pointer of the SHA512 context - */ -void esp_mfi_sha512_free(esp_mfi_sha_ctx_t ctx); - -#ifdef __cplusplus -} -#endif - -#endif /* ESP_MFI_SHA_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap.h b/lib/libesp32_div/ESP32-HomeKit/src/hap.h deleted file mode 100755 index 1eb9f59a7..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap.h +++ /dev/null @@ -1,1572 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _HAP_H_ -#define _HAP_H_ - -#include -#include -#include -#include -#ifdef __cplusplus -extern "C" { -#endif - -#define HAP_CHAR_STRING_MAX_LEN 256 -#define HAP_CHAR_STRING_MAX_DEF_LEN 64 - -#define HAP_SUCCESS 0 -#define HAP_FAIL -1 - -typedef enum { - HAP_MFI_AUTH_NONE = 0, - HAP_MFI_AUTH_HW, - HAP_MFI_AUTH_SW -} hap_mfi_auth_type_t; - -/** HomeKit Transports to be enabled */ -typedef enum { - /** Unknown. Default uninitialized value */ - HAP_TRANSPORT_UNKNOWN = 0x00, - /** HAP over Wi-Fi */ - HAP_TRANSPORT_WIFI = 0x01, - /** HAP Over Ethernet (Wi-Fi disabled). - * To enable both Wi-Fi and Ethernet, use (HAP_TRANSPORT_WIFI | HAP_TRANSPORT_ETHERNET) for hap_init() - */ - HAP_TRANSPORT_ETHERNET = 0x02, -} hap_transport_t; - -/** - * HAP characteristic value formats - */ -typedef enum { - /** No Type/Invalid type */ - HAP_CHAR_FORMAT_NONE = 0, - /** Boolean (true or false)*/ - HAP_CHAR_FORMAT_BOOL, - /** Unsigned 8-bit integer */ - HAP_CHAR_FORMAT_UINT8, - /** Unsigned 16-bit integer */ - HAP_CHAR_FORMAT_UINT16, - /** Unsigned 32-bit integer */ - HAP_CHAR_FORMAT_UINT32, - /** Unsigned 64-bit integer */ - HAP_CHAR_FORMAT_UINT64, - /** Signed 32-bit integer */ - HAP_CHAR_FORMAT_INT, - /** Signed 32-bit floating point number */ - HAP_CHAR_FORMAT_FLOAT, - /** Unicode string */ - HAP_CHAR_FORMAT_STRING, - /** Base64 encoded set of one or more TLV8s */ - HAP_CHAR_FORMAT_TLV8, - /** base64 encoded data blob */ - HAP_CHAR_FORMAT_DATA, -} hap_char_format_t; - -/** Data value */ -typedef struct { - /** Pointer to an allocated buffer holding the data. This should remain valid - * throughout the lifetime of the characteristic. - */ - uint8_t *buf; - /** Length of the data */ - uint32_t buflen; -} hap_data_val_t; - -/** TLV8 value (Same as \ref hap_data_val_t) */ -typedef hap_data_val_t hap_tlv8_val_t; - -/** HAP Value */ -typedef union { - /** Boolean */ - bool b; - /** Unsigned integer (uint8, uint16, uint32) */ - uint32_t u; - /** Signed integer */ - int i; - /** 64 bit Unsigned integer */ - uint64_t i64; - /** Floating point number */ - float f; - /** Pointer to string */ - char *s; - /** Structure for Data */ - hap_data_val_t d; - /** Structure for TLV8 */ - hap_tlv8_val_t t; -} hap_val_t; - -/** Information about the Provisioned Network to which the accessory will connect */ -typedef struct { - /** SSID for the network */ - uint8_t ssid[64]; - /** Length of the SSID */ - size_t ssid_len; - /** Password for the network. Can be NULL for Open networks */ - uint8_t password[64]; - /** Length of the Password. Can be 0 for Open networks */ - size_t password_len; -} hap_provisioned_nw_t; - -/** - * HAP characteristics unit types - */ -#define HAP_CHAR_UNIT_CELSIUS "celsius" -#define HAP_CHAR_UNIT_PERCENTAGE "percentage" -#define HAP_CHAR_UNIT_ARCDEGREES "arcdegrees" -#define HAP_CHAR_UNIT_LUX "lux" -#define HAP_CHAR_UNIT_SECONDS "seconds" - -/** HAP Characteristic properties/permissions */ -/** Characteristic supports Paired Read */ -#define HAP_CHAR_PERM_PR (1 << 0) -/** Characteristic supports Paired Write */ -#define HAP_CHAR_PERM_PW (1 << 1) -/** Characteristic supports Event Notifications */ -#define HAP_CHAR_PERM_EV (1 << 2) -/** Characteristic supports Additional Authorization Data */ -#define HAP_CHAR_PERM_AA (1 << 3) -/** Characteristic supports Timed Writes */ -#define HAP_CHAR_PERM_TW (1 << 4) -/** Characteristic is hidden from the user */ -#define HAP_CHAR_PERM_HD (1 << 5) -/** Characterictic is of special read only type. - * Valid for characteristics like "Programmable Switch Event" wherein the value - * needs to be reported as NULL for a read, even when it is a uint8. Actual value - * is reported only using event notifications. - */ -#define HAP_CHAR_PERM_SPECIAL_READ (1 << 6) - -/** HAP object handle */ -typedef size_t hap_handle_t; - -/** HAP Characteristic handle */ -typedef hap_handle_t hap_char_t; -/** HAP Service handle */ -typedef hap_handle_t hap_serv_t; -/** HAP Accessory handle */ -typedef hap_handle_t hap_acc_t; - -/** HAP Status codes as per the HAP Specifications */ -typedef enum { - /** This specifies a success for the request. */ - HAP_STATUS_SUCCESS = 0, - /** Request denied due to insufficient privileges. */ - HAP_STATUS_NO_PRIVILEGE = -70401, - /** Unable to communicate with requested service. */ - HAP_STATUS_COMM_ERR = -70402, - /** Resource is busy, try again. */ - HAP_STATUS_RES_BUSY = -70403, - /** Cannot write to read only characteristic. */ - HAP_STATUS_WR_ON_RDONLY = -70404, - /** Cannot read from a write only characteristic. */ - HAP_STATUS_RD_ON_WRONLY = -70405, - /** Notification is not supported for characteristic */ - HAP_STATUS_NO_NOTIF = -70406, - /** Out of resources to process request. */ - HAP_STATUS_OO_RES = -70407, - /** Operation timed out. */ - HAP_STATUS_TIMEOUT = -70408, - /** Resource does not exist. */ - HAP_STATUS_RES_ABSENT = -70409, - /** Accessory received an invalid value in a write request. */ - HAP_STATUS_VAL_INVALID = -70410, - /** Insufficient Authorization. */ - HAP_STATUS_INSUFFICIENT_AUTH = -70411, -} hap_status_t; - -typedef enum { - HAP_CID_NONE = 0, - HAP_CID_OTHER, - HAP_CID_BRIDGE, - HAP_CID_FAN, - HAP_CID_GARAGE_DOOR_OPENER, - HAP_CID_LIGHTING, - HAP_CID_LOCK, - HAP_CID_OUTLET, - HAP_CID_SWITCH, - HAP_CID_THERMOSTAT, - HAP_CID_SENSOR, - HAP_CID_SECURITY_SYSTEM, - HAP_CID_DOOR, - HAP_CID_WINDOW, - HAP_CID_WINDOW_COVERING, - HAP_CID_PROGRAMMABLE_SWITCH, - HAP_CID_RESERVED, - HAP_CID_IP_CAMERA, - HAP_CID_VIDEO_DOORBELL, - HAP_CID_AIR_PURIFIER, - HAP_CID_HEATER, - HAP_CID_AIR_CONDITIONER, - HAP_CID_HUMIDIFIER, - HAP_CID_DEHUMIDIFIER, - HAP_CID_MAX, -} hap_cid_t; - -/** Prototype for Identify routine for the accessory - * - * @param[in] acc Handle of the accessory object - */ -typedef int (*hap_identify_routine_t) (hap_acc_t *acc); - -/** HAP Accessory configuration */ -typedef struct { - /** Name (Mandatory) */ - const char *name; - /** Model (Mandatory) */ - const char *model; - /** Manufacturer (Mandatory) */ - const char *manufacturer; - /** Serial Number (Mandatory) */ - const char *serial_num; - /** Firmware Revision number in format x[.y[.z]] (Mandatory) */ - const char *fw_rev; - /** Hardware revision number in format x[.y[.z]] (Optional. Can be NULL )*/ - const char *hw_rev; - /** HAP Protocol version supported by the accessory. Should be set to "1.1" - * @note The value set here will currently be ignored and assumed to be 1.1 - * as it is the only protocol version currently supported. - * This is valid only for the Primary accessory. - */ - const char *pv; - /** Category Identifier for the Accessory. This is valid only for the - * primary accessory - */ - hap_cid_t cid; - /** Identify routine for the accessory (Mandatory) */ - hap_identify_routine_t identify_routine; -} hap_acc_cfg_t; - -/** HomeKit Debug prints level - */ -typedef enum { - /** Basic information indicating what's happening in the HomeKit core */ - HAP_DEBUG_LEVEL_INFO = 0, - /** Warnings for incidents that can affect behavior, but not necessarily cause a failure*/ - HAP_DEBUG_LEVEL_WARN, - /** Errors which will affect the working, and may even halt the process */ - HAP_DEBUG_LEVEL_ERR, - /** Asserts for failures which will definitely cause system to halt */ - HAP_DEBUG_LEVEL_ASSERT -} hap_debug_level_t; - -/** - * @brief Set the HomeKit Debug prints level. - * - * This indicates the maximum level for which the debug messages - * will be printed. Default value is \ref HAP_DEBUG_LEVEL_INFO which means - * that all information, warnings, errors and asserts will be printed, as - * this is the lowest level. You can change it to any suitable higher level - * to reduce the prints. For Eg. Setting this to HAP_DEBUG_LEVEL_WARN will - * print all warnings, errors and asserts, but not the basic information. - * - * @param[in] level Maximum debug print level as per \ref hap_debug_level_t - */ -void hap_set_debug_level(hap_debug_level_t level); - -/** - * - * @brief Get the HAP SDK Version from the hap core - * - * @return Pointer to a NULL terminated Version string (Eg. 2.0.r1-0136161) - */ -const char *hap_get_version(); - -/** Unique Paramaters for HomeKit */ -typedef enum { - /** Nothing unique. - * Application code should ensure uniqueness of name and ssid. - * HAP Core will not change anything. - */ - UNIQUE_NONE = 0, - /** Unique SSID (default configuration). - * 3 bytes of MAC will be added to accessory name to create unique WAC SSID (Eg. Name-xxyyzz) */ - UNIQUE_SSID, - /** Unique Name. - * Name will be changed by adding 3 bytes of MAC to original name. - * Thi swill automatically make the SSID unique as the accessory name will be used as SSID. - */ - UNIQUE_NAME, -} hap_unique_param_t; - -/** HomeKit Configuration. - * Please do not change unless you understand the purpose of these */ -typedef struct { - /** Internal HomeKit Task's stack size */ - uint32_t task_stack_size; - /** Internal HomeKit Task's priority */ - uint8_t task_priority; - /** Maximum characteristics to which event notifications can be sent simultaneously. - * Default value is enough for standalone accessories. Change may be required only - * for bridges. - */ - uint8_t max_event_notif_chars; - /** Indicates what paramaters will be made unique by the HAP Core */ - hap_unique_param_t unique_param; - /** Timeout (in seconds) after which a socket data receive call will return for a pair verified - * socket, in case the call blocks. This has been added to avoid the webserver getting stalled on a read, - * especially in case wherein some garbage data is received on a pair verified connection. - */ - uint8_t recv_timeout; - /** Timeout (in seconds) after which a socket data send call will return for a pair verified - * socket, in case the call blocks. This has been added to avoid the webserver getting stalled on a write. - */ - uint8_t send_timeout; - /** Max length of the buffer to be used for handling SW Token Requests. The Default value has been kept - * as 1200 to help pass HCA Tests. This can be changed to 512 for practical purposes as the actual Apple - * tokens never really need more than that. - */ - size_t sw_token_max_len; - /** By default, config number (c#) incremenents on addition/removal of every bridged accessory after - * hap_start(). Setting this flag to true will disable this. Use hap_update_config_number() - * to increment c#. Note thar c# will still increment on a firmware upgrade though. - */ - bool disable_config_num_update; -} hap_cfg_t; - -/** Get HomeKit Configuration - * - * Gets the configuration that will be used by the HomeKit core. - * - * @param[out] cfg Pointer to an allocated \ref hap_cfg_t structure which will be populated - * with the configuration information. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on error - */ -int hap_get_config(hap_cfg_t *cfg); - -/** Set HomeKit Configuration - * - * This sets the HomeKit configuration. Please use hap_get_config() to get the old - * configuration first, before modifying any values. Eg. - * - * @code - * hap_cfg_t hap_cfg; - * hap_get_config(&hap_cfg); - * hap_cfg.unique_param = UNIQUE_NAME; - * hap_set_config(&hap_cfg); - * @endcode - * - * @note This should be called before hap_init(). - * - * @param[in] cfg Pointer to an allocated \ref hap_cfg_t structure which has the new values - * to set. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on error - */ -int hap_set_config(const hap_cfg_t *cfg); - -/* Update config number (c#) - * - * This increments the config number (c#) by 1 - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on error - */ -int hap_update_config_number(); - -/** - * @brief Initialize HAP Framework - * - * This internally initializes the MFi auth chip, TCP-IP stack, HomeKit Key Store, - * HomeKit database, Wi-Fi and mDNS. - * - * @return HAP_SUCCESS on success - * @return others on error - */ -int hap_init(hap_transport_t transport); - -/** - * @brief De-initialize HAP Framework. - * - * @note This currently does not do anything - * - * @return HAP_SUCCESS on success - * @return others on error - */ -int hap_deinit(); - -/** - * @brief Start the HAP framework - * - * This starts the webserver and also initializes WAC or HomeKit services - * as per the state of the accessory. - * - * @return HAP_SUCCESS on success - * @return others on error - */ -int hap_start(void); - -/** - * @brief Stop HAP framework and free all relevant resources - * - * @note This currently does not do anything - * - * @return HAP_SUCCESS on success - * @return others on error - */ -int hap_stop(void); - -/** - * @brief Create a HAP accessory object - * - * @param[in] acc_cfg Pointer to the accessory configuration \ref hap_acc_cfg_t - * - * @return Handle for the accessory object pre-populated with - * the Accessory Information Service (and Protocol Information Service - * for the first accessory created) - * - * @return NULL on error - */ -hap_acc_t *hap_acc_create(hap_acc_cfg_t *acc_cfg); - -/** - * @brief Add Accessory flags to the Accessory Info service - * - * This adds the optional Accessory Information Flag to the given accessory, - * with the value set to the one specified. Typically, the flags will be - * initialised with a value of 1, meaning that additional manufacturer specific - * setup is required. Once the setup is done, the flags should be reset to 0 - * using hap_acc_update_accessory_flags() - * - * @note Use of these flags requires explicit approval from Apple. - * - * @param[in] ha HAP Accessory object handle - * @param[in] flags Initial value of flags. Check the specs for valid values - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_acc_add_accessory_flags(hap_acc_t *ha, uint32_t flags); - -/** - * @brief Update the Accessory flags - * - * This updates the Accessory flags characteristic of the Accessory Info service - * of the given accessory, if it has been added using hap_acc_add_accessory_flags(). - * - * @param[in] ha HAP Accessory object handle - * @param[in] flags New value of flags. Check the specs for valid values - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_acc_update_accessory_flags(hap_acc_t *ha, uint32_t flags); - -/** - * @brief Add Product data - * - * As per HAP specs R15, this is the 8 byte product data assigned to the Product Plan. - * - * @param[in] ha HAP Accessory object handle - * @param[in] product_data Pointer to the product data value buffer - * @param[in] data_size Size of the buffer (should be 8 as per HAP Spec R15) - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_acc_add_product_data(hap_acc_t *ha, uint8_t *product_data, size_t data_size); - -/** - * @brief Add accessory to the HAP Object database - * - * @param[in] ha HAP Accessory object handle - */ -void hap_add_accessory(hap_acc_t *ha); - -/** - * @brief Add a bridged accessory to the HAP Object database - * - * This adds a bridged accessory to the Homekit Object database and assigns - * it the given AID. HomeKit requires that each accessory gets assigned a unique aid. - * To ensure this, a helper API hap_get_unique_aid() has been provided. This API - * requires some unique identifier of the accessory, say mac address, serial number, etc. - * - * Example: hap_add_bridged_accessory(ha, hap_get_unique_aid(mac_addr)); - * - * @param[in] aid The AID desired for the bridged accessory. If a 0 is passed, the - * next available AID will be assigned. However, this should be used only for - * evaluation, not production. - * - * @param[in] ha HAP Accessory object handle - */ -void hap_add_bridged_accessory(hap_acc_t *ha, int aid); - -/** - * @brief Remove a bridged accessory from the HAP Object database - * - * @param[in] ha HAP Accessory object handle - */ -void hap_remove_bridged_accessory(hap_acc_t *ha); - -/** - * @brief Delete HAP Accessory Object - * - * @note Primary accessory cannot be deleted - * - * @param[in] ha HAP Accessory object handle - * - */ -void hap_acc_delete(hap_acc_t *ha); - -/** - * @brief Delete all accessories - */ -void hap_delete_all_accessories(void); - -/** - * Get unique AID for the given identifier - * - * This API can be used to ensure that the same AID gets assigned to an accessory - * every time, even across reboots and irrespective of when it is added to the - * HomeKit database. It requires a unique identifier of the accessory, say a - * mac addtess, serial number, etc. If it is a new accessory, a new AID gets - * assigned and the id:aid combination gets stored in NVS (Non Volatile Storage). - * If the accessory was already added some time later, the original AID is fetched - * from the NVS and returned. This API should be used as the "aid" argument for - * hap_add_bridged_accessory() - * - * @param[in] id Unique identifier for the accessory - * - * @return Unique AID for the accessory - * @return -1 on error (NULL id) - */ -int hap_get_unique_aid(const char *id); - -/** - * @brief Get Accessory using AID - * - * @param[in] aid Accessory ID of the required accessory - * - * @return Handle for the accessory with given aid - * @return NULL if accessory not found - */ -hap_acc_t *hap_acc_get_by_aid(int32_t aid); - -/** - * @brief Get first accessory in the database - * - * @return Handle for the first accessory - */ -hap_acc_t *hap_get_first_acc(); - -/** - * @brief Get next accessory in the database - * - * @param[in] ha Current HAP Accessory object handle - * - * @return Pointer to the next accessory - * @return NULL if the current accessory is the last - */ -hap_acc_t *hap_acc_get_next(hap_acc_t *ha); - -/** - * @brief Get Service using IID - * - * @param[in] ha HAP Accessory object handle in which the service should be searched - * @param[in] iid Instance ID of the required service - * - * @return Handle for the service with given iid - * @return NULL if service not found - */ -hap_serv_t *hap_acc_get_serv_by_iid(hap_acc_t *ha, int32_t iid); - -/** - * @brief Get Service using Type UUID - * - * @param[in] ha HAP Accessory object handle in which the service should be searched - * @param[in] type_uuid UUID of the required service - * - * @return Handle for the service with given type_uuid - * @return NULL if service not found - */ -hap_serv_t *hap_acc_get_serv_by_uuid(hap_acc_t *ha, const char *type_uuid); - -/** - * @brief Get characteristic using IID - * - * @param[in] ha HAP Accessory object handle in which the characteristic should be searched - * @param[in] iid Instance ID of the required characteristic - * - * @return Handle for the characteristic with given iid - * @return NULL if characteristic not found - */ -hap_char_t *hap_acc_get_char_by_iid(hap_acc_t *ha, int32_t iid); - -/** - * @brief Get first service in a given accessory object - * - * This is useful for iterating over all services of an accessory. - * The subsequent services of the accessory can be iterated by using - * hap_serv_get_next(). - * - * @param[in] ha HAP Accessory object handle - * - * @return Handle for the first service in the accessory object - */ -hap_serv_t *hap_acc_get_first_serv(hap_acc_t *ha); - -/** - * @brief Create a Boolean Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_bool_create(const char *type_uuid, uint16_t perms, bool val); - -/** - * @brief Create an 8-bit unsigned integer Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_uint8_create(const char *type_uuid, uint16_t perms, uint8_t val); - -/** - * @brief Create a 16-bit unsigned integer Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_uint16_create(const char *type_uuid, uint16_t perms, uint16_t val); - -/** - * @brief Create a 32-bit unsigned integer Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_uint32_create(const char *type_uuid, uint16_t perms, uint32_t val); - -/** - * @brief Create a 64-bit unsigned integer Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_uint64_create(const char *type_uuid, uint16_t perms, uint64_t val); - -/** - * @brief Create a 32-bit signed integer Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_int_create(const char *type_uuid, uint16_t perms, int val); - -/** - * @brief Create a Floating point Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_float_create(const char *type_uuid, uint16_t perms, float val); - -/** - * @brief Create a String Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_string_create(const char *type_uuid, uint16_t perms, const char *val); - -/** - * @brief Create a Data Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Pointer to initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_data_create(const char *type_uuid, uint16_t perms, hap_data_val_t *val); - -/** - * @brief Create a TLV8 Characteristic Object - * - * @param[in] type_uuid UUID for the characteristic as per the HAP Specs - * @param[in] perms Logically OR of the various permissions supported by the characteristic - * @param[in] val Pointer to initial value of the characteristic - * - * @return Handle for the characteristic object created - * @return NULL on error - */ -hap_char_t *hap_char_tlv8_create(const char *type_uuid, uint16_t perms, hap_tlv8_val_t *val); - -/** - * @brief Delete a characteristic object - * - * @param[in] hc HAP Characteristic Object handle - */ -void hap_char_delete(hap_char_t *hc); - -/** - * @brief Create a HAP Service Object - * - * @param[in] type_uuid UUID for the service as per the HAP Specs - * - * @return Handle for the service object created - * @return NULL on error - */ -hap_serv_t *hap_serv_create(const char *type_uuid); - -/** - * @brief Delete a service object - * - * @param[in] hs HAP Service Object handle - */ -void hap_serv_delete(hap_serv_t *hs); - -/** - * @brief Get the AID for the given accessory - * - * @param[in] ha HAP Accessory Object handle - * - * @return aid for the accessory - */ -uint32_t hap_acc_get_aid(hap_acc_t *ha); - -/** - * @brief Get Characteristic using Type UUID - * - * @param[in] hs HAP Service object handle in which the characteristic should be searched - * @param[in] type_uuid UUID of the required characteristic - * - * @return Handle for the characteristic with given type_uuid - * @return NULL if characteristic not found - */ -hap_char_t *hap_serv_get_char_by_uuid(hap_serv_t *hs, const char *type_uuid); - -/** - * @brief Get parent Accessory for given Service - * - * @param[in] hs HAP Service object handle - * - * @return Handle for the parent accessory - * @return NULL if the service is not added in any accessory - */ -hap_acc_t *hap_serv_get_parent(hap_serv_t *hs); - -/** - * @brief Get the next service in a given accessory object - * - * This is useful for iterating over all services of an accessory. - * - * @param[in] Current service object handle - * - * @return Handle for next service in the accessory object - * @return NULL if the current service was the last one in the accessory - */ -hap_serv_t *hap_serv_get_next(hap_serv_t *hs); - -/** - * @brief Get first characteristic in a given service object - * - * This is useful for iterating over all characteristics of a service. - * The subsequent characteristics of the service can be - * iterated by using hap_char_get_next(). - * - * @param[in] hs HAP Service object handle - * - * @return Handle for the first chatracteristic in the service object - */ -hap_char_t *hap_serv_get_first_char(hap_serv_t *hs); - -/** - * @brief Get the IID for the given characteristic - * - * @param[in] hc HAP Characteristic Object handle - * - * @return iid for the characteristic - */ -uint32_t hap_char_get_iid(hap_char_t *hc); - -/** - * @brief Get the type UUID for the given characteristic - * - * @param[in] hc HAP Characteristic Object handle - * - * @return Type UUID for the characteristic - */ -const char * hap_char_get_type_uuid(hap_char_t *hc); - - -/** - * @brief Get the Permissions for the given characteristic - * - * @param[in] hc HAP Characteristic Object handle - * - * @return The permissions for the characteristics, the same as the ones passed while creating it. - * It will be a logically OR of the various permissions supported by the characteristic. - */ -uint16_t hap_char_get_perm(hap_char_t *hc); - - -/** - * @brief Get the format for the given characteristic - * - * @param[in] hc HAP Characteristic Object handle - * - * @return Format of the characteristic value - */ -hap_char_format_t hap_char_get_format(hap_char_t *hc); - -/** - * @brief Get the IID for the given service - * - * @param[in] hs HAP Service Object handle - * - * @return iid for the service - */ -uint32_t hap_serv_get_iid(hap_serv_t *hs); - -/** - * @brief Get the type UUID for the given service - * - * @param[in] hs HAP Service Object handle - * - * @return Type UUID for the service - */ -const char *hap_serv_get_type_uuid(hap_serv_t *hs); -/** - * @brief Get parent Service for given Characteristic - * - * @param[in] hc HAP Characteristic object handle - * - * @return Handle for the parent service - * @return NULL if the characteristic is not added in any service - */ -hap_serv_t *hap_char_get_parent(hap_char_t *hc); - -/** - * @brief Get the next characteristic in a given service object - * - * This is useful for iterating over all characteristics of a service. - * - * @param[in] Current characteristic object handle - * - * @return Handle for next characteristic in the service object - * @return NULL if the current characteristic was the last one in the service - */ -hap_char_t *hap_char_get_next(hap_char_t *hc); - -/** - * @brief Add Integer characteristic constraints - * - * @param[in] hc HAP Characteristic Object handle - * @param[in] min Minimum Value - * @param[in] max Maximum Value - * @param[in] step Step Value - */ -void hap_char_int_set_constraints(hap_char_t *hc, int min, int max, int step); - -/** - * @brief Add Integer characteristic constraints - * - * @param[in] hc HAP Characteristic Object handle - * @param[in] min Minimum Value - * @param[in] max Maximum Value - * @param[in] step Step Value - */ -void hap_char_float_set_constraints(hap_char_t *hc, float min, float max, float step); - -/** - * @brief Add String characteristic constraints - * - * @param[in] hc HAP Characteristic Object handle - * @param[in] maxlen Maximum Length of the string (default: 64, max: 256) - */ -void hap_char_string_set_maxlen(hap_char_t *hc, int maxlen); - -/** - * @brief Add Characteristic Description - * - * @param[in] hc HAP Characteristic Object handle - * @param[in] description Manufacturer defined String description for the characteristic - */ -void hap_char_add_description(hap_char_t *hc, const char *description); - -/** - * @brief Add Characteristic Unit - * - * @param[in] hc HAP Characteristic Object handle - * @param[in] unit Unit for the characteristic. Please see specs for valid strings. - */ -void hap_char_add_unit(hap_char_t *hc, const char *unit); - -/** - * @brief Add Valid Values for Characteristic - * - * Using this API will just add the valid-values metadata for a characteristic - * - * @param[in] hc HAP Characteristic Object handle - * @param[in] valid_vals Pointer to an array of valid values - * @param[in] valid_val_cnt Number of entries in the array - */ -void hap_char_add_valid_vals(hap_char_t *hc, const uint8_t *valid_vals, size_t valid_val_cnt); - -/** - * @brief Add Valid Values Range for Characteristic - * - * Using this API will just add the valid-values-range metadata for a characteristic - * - * @param[in] hc HAP Characteristic Object handle - * @param[in] start_val Start value of the range - * @param[in] end_val End value of the range - */ -void hap_char_add_valid_vals_range(hap_char_t *hc, uint8_t start_val, uint8_t end_val); -/** - * @brief Set IID for a given characteristic - * - * HomeKit specifications require that the IID for a given characteristic should remain the same, - * even after a firmware upgrade. Since the HomeKit core assigns the IIDs internally, - * it is possible that a different IID is getting assigned because of removal of - * some old service/characteristic or addition of a newer one in between. In such a case, - * in order to maintain the same IID, this API can be used. - * - * @note This must be used only if actually required, and that too after adding all services/ - * characteristics to an accessory, but before hap_start(). - * - * @param[in] hc HAP Characteristic Object Handle - * @param[in] iid Desired IID - */ -void hap_char_set_iid(hap_char_t *hc, int32_t iid); - -/** - * @brief Add a characteristic to a service - * - * @param[in] hs HAP service object handle - * @param[in] hc HAP characteristic object handle - * - * @return 0 on success - * @return other on error - */ -int hap_serv_add_char(hap_serv_t *hs, hap_char_t *hc); - -/** - * @brief HAP add a service to an accessory - * - * @param[in] ha HAP Accessory object handle - * @param[in] hs HAP Service object handle - * - * @return 0 on success - * @return other on error - */ -int hap_acc_add_serv(hap_acc_t *ha, hap_serv_t *hs); - -/** - * @brief Update characteristic value - * - * This should be called within service read/write callbacks to update the - * value of characteristic maintained by the HAP Core. This can also be called - * from some other thread, for accessories like sensors that periodically - * monitor some paramters. - * - * @param[in] hc HAP characteristic object handle - * @param[in] val Pointer to new value - * - * @return 0 on success - * @return other on error - */ -int hap_char_update_val(hap_char_t *hc, hap_val_t *val); - -/** - * @brief Get the current value of characteristic - * - * @param[in] hc HAP characteristic object handle - * - * @return Pointer to the current value - */ -const hap_val_t *hap_char_get_val(hap_char_t *hc); - -/** Authorization Data received in a write reqest - */ -typedef struct { - /** Pointer to the data. Will be NULL if no auth data was present */ - uint8_t *data; - /** Length of the data. Will be 0 if no auth data was present */ - int len; -} hap_auth_data_t; - -/** Write data for a characteristics received over HAP - */ -typedef struct { - /** Pointer to the characteristic object */ - hap_char_t *hc; - /** Value received in the write request. - * Appropriate value in the \ref hap_val_t union will be set as per the format. - */ - hap_val_t val; - /** Authorization data \ref hap_auth_data_t id any, received in the write request. - * It is the application's responsibility to handle and validate this data and - * report the status accordingly. - */ - hap_auth_data_t auth_data; - /** Indicates if the received request was a remote write - */ - bool remote; - /** This is an output parameter, which should be set in the service write - * routine as per the status of the write. - */ - hap_status_t *status; -} hap_write_data_t; - -/** Read data for a characteristic - */ -typedef struct { - /** Pointer to the characteristic object */ - hap_char_t *hc; - /** This is an output parameter, which should be set in the service read - * routine as per the status of the read - */ - hap_status_t *status; -} hap_read_data_t; - - -/** Service Write Function Prototype - * - * A function with this prototype must be registered with the HAP framework to handle - * writes for the characteristics in the given service - * - * @note For writes, an array is sent instead of individual writes to avoid cases wherein - * writes to multiple properties of a single accessory can cause unexpected behavior. - * Eg. For a light which is off, a write could ask it to be turned on at 50% brightness, - * with blue color. If 3 writes are issued for this, the light could first turn on to - * 100% with white color, then dim down to 50% and then change color. A single write will - * ensure that the hardware control takes care of all these at the same time. - * - * @param[in] write_data Array of characteristic write objects of type \ref hap_write_data_t - * which has relevant information like the characteristic object handle, new value received, etc. - * @param[in] count Number of entries in the write_data array. - * @param[in] serv_priv The private data for the service set using hap_serv_set_priv() - * @param[in] write_priv Can be used with hap_is_req_admin() - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL if an error is encountered even for a single characteristic. Actual error - * value must be reported in the status under \ref hap_write_data_t. - */ -typedef int (*hap_serv_write_t) (hap_write_data_t write_data[], int count, - void *serv_priv, void *write_priv); - -/** Service Read Function Prototype - * - * A function with this prototype must be registered with the HAP framework to handle - * reads for the characteristics in the given service. The new value must be set - * by invoking hap_char_update_val(). - * - * @param[in] hc HAP Characteristic Object Handle. - * @param[out] status_code Status of the read, to be populated by the callback with - * values from \ref hap_status_t. - * @param[in] serv_priv The private data for the service set using hap_serv_set_priv() - * @param[in] read_priv Can be used with hap_is_req_admin() - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL if an error is encountered while reading. Actual error - * value must be reported in the status_code - */ -typedef int (*hap_serv_read_t) (hap_char_t *hc, hap_status_t *status_code, - void *serv_priv, void *read_priv); - -/** Service Bulk Read Function Prototype - * - * A function with this prototype can be registered with the HAP framework to handle - * bulk reads for the characteristics in the given service. The new values must be set - * by invoking hap_char_update_val() for each characteristic. - * - * @note This should be used only under special circumstances for cases like - * bridges, wherein fetching individual values from bridged accessories could - * be time consuming. If this is used, it will override the handler of - * type \ref hap_serv_read_t registered for the same service. - * - * @param[in] read_data Array of characteristic write objects of type \ref hap_read_data_t - * which has characteristic object handle and read status pointer. - * @param[in] count Number of entries in the read_data array. - * @param[in] serv_priv The private data for the service set using hap_serv_set_priv() - * @param[in] read_priv Can be used with hap_is_req_admin() - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL if an error is encountered even for a single characteristic. - * Actual error value must be reported in the status under \ref hap_read_data_t. - */ -typedef int (*hap_serv_bulk_read_t) (hap_read_data_t read_data[], int count, - void *serv_priv, void *read_priv); - -/** - * @brief Register Service Write callback - * - * @param[in] hs HAP Service Object Handle - * @param[in] write Callback of type \ref hap_serv_write_t - */ -void hap_serv_set_write_cb(hap_serv_t *hs, hap_serv_write_t write); - -/** - * @brief Register Service Read callback - * - * @param[in] hs HAP Service Object Handle - * @param[in] read Callback of type \ref hap_serv_read_t - */ -void hap_serv_set_read_cb(hap_serv_t *hs, hap_serv_read_t read); - -/** - * @brief Register Service Bulk read callback - * - * @note This should be used only under special circumstances for cases like - * bridges, wherein fetching individual values from bridged accessories could - * be time consuming. If this is used, the callback registered using - * @ref hap_serv_set_read_cb() will be overriden. - * - * @param[in] hs HAP Service Object Handle - * @param[in] read Callback of type \ref hap_serv_bulk_read_t - */ -void hap_serv_set_bulk_read_cb(hap_serv_t *hs, hap_serv_bulk_read_t read); - -/** - * @brief Set service private data - * - * This will be available in the read/write callbacks - * - * @param[in] hs HAP Service Object Handle - * @param[in] priv Private data for the service - */ -void hap_serv_set_priv(hap_serv_t *hs, void *priv); - -/** - * @brief Get Service private - * - * This will get the private data associated with the service, which - * was set using hap_serv_set_priv(). - * - * @param[in] hs HAP Service Object Handle - * - * @return Pointer to the private data (can be NULL) - */ -void *hap_serv_get_priv(hap_serv_t *hs); - -/** - * @brief Mark service as primary - * - * @param[in] hs HAP Service Object Handle - */ -void hap_serv_mark_primary(hap_serv_t *hs); - -/** - * @brief Mark service as hidden - * - * @param[in] hs HAP Service Object Handle - */ -void hap_serv_mark_hidden(hap_serv_t *hs); - -/** - * @brief Link a HomeKit service to other service - * - * @param[in] hs HAP Service Object Handle - * @param[in] linked_serv HAP Service Object Handle of the service to be linked - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_serv_link_serv(hap_serv_t *hs, hap_serv_t *linked_serv); - -/** - * @brief Set IID for a given sService - * - * HomeKit specifications require that the IID for a given service should remain the same, - * even after a firmware upgrade. Since the HomeKit core assigns the IIDs internally, - * it is possible that a different IID is getting assigned because of removal of - * some old service/characteristic or addition of a newer one in between. In such a case, - * in order to maintain the same IID, this API can be used. - * - * @note This must be used only if actually required, and that too after adding all services/ - * characteristics to a service, but before hap_start(). - * - * @param[in] hs HAP Service Object Handle - * @param[in] iid Desired IID - */ -void hap_serv_set_iid(hap_serv_t *hs, int32_t iid); - -/** HomeKit Setup Information */ -typedef struct { - /** SRP Salt */ - uint8_t salt[16]; - /** SRP Verifier */ - uint8_t verifier[384]; -} hap_setup_info_t; - -/** - * @brief Set the Setup info for HomeKit Pairing - * - * HomeKit Pairing/Accessory Setup uses a Setup Code (Also called Pairing PIN). - * However, the specs recommend that, instead of storing the PIN on the accessory, - * the salt and verifier for the PIN should be stored. - * - * This API should be used to provide this information. - * - * @param[in] setup_info Pointer to the Setup Information structure which has - * the Salt and Verifier. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure (like setup_info being NULL); - */ -int hap_set_setup_info(const hap_setup_info_t *setup_info); - -/** - * @brief Set the setup code (i.e. pairing pin) - * - * @note Ideally, the PIN should not be present in the firmware. Instead, - * the salt and verifier should be stored on the accessory and provided using - * hap_set_setup_info(). This API should be used only for testing purposes. - * - * Using this API overrides the setup information provided by hap_set_setup_info(). - * - * @param[in] setup_code NULL terminated Setup code of the format xxx-xx-xxx where each - * x is a number - */ -void hap_set_setup_code(const char *setup_code); - -/** - * @brief Set the setup ID - * - * @param[in] setup_id NULL terminated Setup ID, which will be a 4 character - * long alpha numeric string (with capital alphabets) - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_set_setup_id(const char *setup_id); - -/** - * Check if the MFi authentication co-processor is connected - * - * @note This should be called before hap_init() - * - * @return HAP_SUCCESS if an MFi co-processor is detected - * @return HAP_FAIL if no MFi co-processor is detected - */ -int hap_check_mfi_chip(); - -/** - * @brief Reboot the accessory - * - * This closes all the active HomeKit sessions and reboots the accessory. - * It is recommended to use this API instead of the standard platform reboot/restart - * APIs, for cleaner operation. - * - * @note This is an asynchronous API (actual action executed in HomeKit core thread context) - * and can be invoked even from interrupt context. The \ref HAP_EVENT_ACC_REBOOTING - * event will be invoked after this. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_reboot_accessory(); - -/** - * @brief Reset to Factory Settings - * - * This resets the accessory to factory settings and reboots it. - * All pairing information, network information and accessory specific information - * (like accessory ID, keys, config number, etc.) is erased. Even all application - * data written to NVS partition is erased. - * - * @note This is an asynchronous API (actual action executed in HomeKit core thread context) - * and can be invoked even from interrupt context. The \ref HAP_EVENT_ACC_REBOOTING - * event will be invoked after this. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_reset_to_factory(); - -/** - * @brief Reset the Network Credentials - * - * This resets only the network credntials (keeping the pairing and any other information - * intact) and reboots the accessory. - * - * @note This is an asynchronous API (actual action executed in HomeKit core thread context) - * and can be invoked even from interrupt context. The \ref HAP_EVENT_ACC_REBOOTING - * event will be invoked after this. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_reset_network(); - -/** - * @brief Reset HomeKit Data - * - * This resets all the data stored by the HomeKit Framework, which includes - * all pairing information, network information and accessory specific information - * (like accessory ID, keys, config number, etc.) - * - * @note This is an asynchronous API (actual action executed in HomeKit core thread context) - * and can be invoked even from interrupt context. The \ref HAP_EVENT_ACC_REBOOTING - * event will be invoked after this. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_reset_homekit_data(); - -/** - * @brief Reset HomeKit Pairings - * - * This API resets the HomeKit Pairing Information and also the accessory specific - * information (like accessory ID, keys, config number, etc.). The accessory id is - * reset because else, the paired controllers would consider the accessory as paired, - * as they would still have the keys for the given accessory id. - * - * @note This is an asynchronous API (actual action executed in HomeKit core thread context) - * and can be invoked even from interrupt context. The \ref HAP_EVENT_ACC_REBOOTING - * event will be invoked after this. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_reset_pairings(); - -/** - * @brief Check if the request is from Admin Controller - * - * This API can be used inside service read (\ref hap_serv_read_t) and service write - * (\ref hap_serv_write_t) callbacks to check if the request was from an admin controller. - * Pass the write_priv or read_priv pointer to this API - * - * @return true if request is from an admin controller - * @return false if request is from a non-admin controller - */ -bool hap_is_req_admin(void *priv); - -/** - * @brief Get the ID of the controller who sent the request - * - * This API can be used inside service read (\ref hap_serv_read_t) and service write - * (\ref hap_serv_write_t) callbacks to check the id of the controller who sent the request. - * Pass the write_priv or read_priv pointer to this API - * - * @return pointer to a null terminated controller id string on success. - * @return NULL on failure. - */ -char *hap_req_get_ctrl_id(void *priv); - -/** - * - * @brief Get a value from factory NVS keystore - * - * This API can be used to fetch information from the factory_nvs flash partition. - * This is treated as a Read-Only partition and so, no "set" API has been provided. - * - * @param[in] name_space NVS name space from which the value needs to be read. - * @param[in] key The NVS key for the value - * @param[out] val Buffer which will be used to hold the value, if found - * @param[in,out] val_size Holds the size of the val buffer. Will be populated with the length of - * the value by this function. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_factory_keystore_get(const char *name_space, const char *key, uint8_t *val, size_t *val_size); - -/** - * Enable MFi authentication - * - * @param[in] auth_type The authentication type desired. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL on failure - */ -int hap_enable_mfi_auth(hap_mfi_auth_type_t auth_type); - -/** - * @brief Enable Software Token based authentication. - * - * This is valid for HomeKit Accessory Protocol Spec R12 (or later) and works with iOS 11.3 (or later) only. - * - * This API enables the Software Token based authentication for HomeKit pairing. It requires the accessory - * UUID and Token to be programmed in the factory_nvs partition. Please check the README for more details. - * - * Please refer HomeKit Software Authentication Server Specification to understand the server side - * implications of using this method for HomeKit Pairing. The tokens fetched from Apple server need to - * be programmed on the accessory - * - * @note Software Authentication is not recommended for new accessories. It should be used only if HomeKit - * functionality needs to be enabled on accessories which are already in field, or if an existing hardware - * design needs to be re-used for cost or other considerations. For any other use cases, please get in touch - * with your Apple contact. - * - * @return HAP_SUCCESS on success - * @return HAP_FAIL if the correct UUID or Token is not provided in the factory_nvs partition - */ -static inline int hap_enable_software_auth() -{ - return hap_enable_mfi_auth(HAP_MFI_AUTH_SW); -} - -#define HAP_REBOOT_REASON_UNKNOWN "unknown" -#define HAP_REBOOT_REASON_RESET_TO_FACTORY "reset_to_factory" -#define HAP_REBOOT_REASON_REBOOT_ACC "reboot_acc" -#define HAP_REBOOT_REASON_RESET_NETWORK "reset_network" -#define HAP_REBOOT_REASON_RESET_PAIRINGS "reset_pairings" -#define HAP_REBOOT_REASON_RESET_HOMEKIT_DATA "reset_homekit_data" - -/** HomeKit Event Base */ -ESP_EVENT_DECLARE_BASE(HAP_EVENT); -/** HomeKit Events */ -typedef enum { - /** A new controller was paired/added/modified. - * Associated data is a NULL terminated controller identifier string. - */ - HAP_EVENT_CTRL_PAIRED = 1, - /** A controller was removed - * Associated data is a NULL terminated controller identifier string. - */ - HAP_EVENT_CTRL_UNPAIRED, - /** A paired controller connected to the accessory (extablished a pair verified session). - * Associated data is a NULL terminated controller identifier string. - */ - HAP_EVENT_CTRL_CONNECTED, - /** A controller disconnected from the accessory. This event is reported before the - * actual disconnection, because for cases like pair-remove, the controller information - * gets erased before the disconnection, and so the controller id is not available - * after disconnection. - * Associated data is a NULL terminated controller identifier string. - */ - HAP_EVENT_CTRL_DISCONNECTED, - /** A Pair Setup attempt has started. Waiting for Setup Code */ - HAP_EVENT_PAIRING_STARTED, - /** Pair Setup was aborted because of inactivity or a wrong setup code */ - HAP_EVENT_PAIRING_ABORTED, - /** A GET on /accessories was successfully completed */ - HAP_EVENT_GET_ACC_COMPLETED, - /** A GET on /characteristics was successfully completed */ - HAP_EVENT_GET_CHAR_COMPLETED, - /** A PUT (Set value) on /characteristics was successfully completed. - * This event can also mean that notifications were enabled for some - * characteristics as the same is also done in PUT /characteristics */ - HAP_EVENT_SET_CHAR_COMPLETED, - /* Accessory is about to reboot. Will be triggered for operations like hap_reset_to_factory(), - * hap_reboot_accessory(), hap_reset_network(), hap_reset_pairings() and hap_reset_homekit_data() - * just before rebooting. Associated data is a pointer to a string indicating the reboot reason. - * Reefer the HAP_REBOOT_REASON_* macros for possible values. - */ - HAP_EVENT_ACC_REBOOTING, -} hap_event_t; - -/** Prototype for HomeKit Event handler - * - * @param[in] event The event id of type \ref hap_event_t - * @param[in] data Data associated with the event (if applicable). - * Please refer \ref hap_event_t documentation for information regarding - * data for each event. - */ -typedef void (*hap_event_handler_t) (hap_event_t event, void *data); - -/** Register HomeKit Event Handler - * - * If applications are interested in HomeKit specific events, they can - * write their own event handler and register with HomeKit core using - * this API. - * - * @param[in] handler Application specific HomeKit event handler. - */ -void hap_register_event_handler(hap_event_handler_t handler); - -/** Get Paired controller count - * - * This API can be used to get a count of number of paired controllers. - * Thi can be used only after hap_init(). - * - * @return Number of paired controllers - */ -int hap_get_paired_controller_count(); - -/* - * Enable Simple HTTP Debugging - * - * Calling this API will enable HTTP Debugging which will show some HomeKit HTTP Debug - * info like the URL and data. - */ -void hap_http_debug_enable(); - -/** - * Disable Simple HTTP Debugging - * - * Calling this API will disable HTTP Debugging which was enabled by hap_enable_http_debug() - */ -void hap_http_debug_disable(); - -/** Get Setup payload - * - * This gives the setup payload for the given information - * - * @param[in] setup_code NULL terminated setup code. Eg. "111-22-333" - * @param[in] setup_id NULL terminated setup id. Eg. "ES32" - * @param[in] wac_support Boolean indicating if WAC provisioning is supported. - * @param[in] cid Accessory category identifier. - * - * @return On success, an allocated NULL terminal setup paylod string. Eg. "X-HM://003363Z4TES32". Should be freed by the caller. - * @return NULL on failure. - */ -char *esp_hap_get_setup_payload(char *setup_code, char *setup_id, bool wac_support, hap_cid_t cid); -#ifdef __cplusplus -} -#endif - -#endif /* _ESP_HAP_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c deleted file mode 100755 index 0b811e3c9..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.c +++ /dev/null @@ -1,1497 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include - -/* Char: Brightness */ -hap_char_t *hap_char_brightness_create(int brightness) -{ - hap_char_t *hc = hap_char_int_create(HAP_CHAR_UUID_BRIGHTNESS, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, brightness); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 100, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Brightness */ -hap_char_t *hap_char_wattage_create(float watts) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, watts); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, -10000.0, 10000.0, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_LUX); - - return hc; -} - -/* Char: Cooling Threshold Temperature */ -hap_char_t *hap_char_cooling_threshold_temperature_create(float cooling_threshold_temp) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_COOLING_THRESHOLD_TEMPERATURE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, cooling_threshold_temp); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 10.0, 35.0, 0.1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_CELSIUS); - - return hc; -} - -/* Char: Current Door State */ -hap_char_t *hap_char_current_door_state_create(uint8_t curr_door_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CURRENT_DOOR_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_door_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 4, 1); - - return hc; -} - -/* Char: Current Heating Cooling State */ -hap_char_t *hap_char_current_heating_cooling_state_create(uint8_t curr_heating_cooling_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CURRENT_HEATING_COOLING_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_heating_cooling_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Current Relative Humidity */ -hap_char_t *hap_char_current_relative_humidity_create(float curr_rel_humidity) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CURRENT_RELATIVE_HUMIDITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_rel_humidity); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Current Temperature */ -hap_char_t *hap_char_current_temperature_create(float curr_temp) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CURRENT_TEMPERATURE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_temp); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 0.1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_CELSIUS); - - return hc; -} - -/* Char: Firmware Revision */ -hap_char_t *hap_char_firmware_revision_create(const char *fw_rev) -{ - hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_FIRMWARE_REVISION, - HAP_CHAR_PERM_PR, fw_rev); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Hardware Revision */ -hap_char_t *hap_char_hardware_revision_create(const char *hw_rev) -{ - hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_HARDWARE_REVISION, - HAP_CHAR_PERM_PR, hw_rev); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Heating Threshold Temperature */ -hap_char_t *hap_char_heating_threshold_temperature_create(float heating_threshold_temp) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_HEATING_THRESHOLD_TEMPERATURE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, heating_threshold_temp); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 25.0, 0.1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_CELSIUS); - - return hc; -} - -/* Char: Hue */ -hap_char_t *hap_char_hue_create(float hue) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_HUE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, hue); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 360.0, 1.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_ARCDEGREES); - - return hc; -} - -/* Char: Identify */ -hap_char_t *hap_char_identify_create(void) -{ - hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_IDENTIFY, HAP_CHAR_PERM_PW, false); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Lock Current State */ -hap_char_t *hap_char_lock_current_state_create(uint8_t lock_curr_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_LOCK_CURRENT_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, lock_curr_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 3, 1); - - return hc; -} - -/* Char: Lock Target State */ -hap_char_t *hap_char_lock_target_state_create(uint8_t lock_targ_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_LOCK_TARGET_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, lock_targ_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Manufacturer */ -hap_char_t *hap_char_manufacturer_create(const char *manufacturer) -{ - hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_MANUFACTURER, - HAP_CHAR_PERM_PR, manufacturer); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Model */ -hap_char_t *hap_char_model_create(const char *model) -{ - hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_MODEL, - HAP_CHAR_PERM_PR, model); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Motion Detected */ -hap_char_t *hap_char_motion_detected_create(bool motion_detected) -{ - hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_MOTION_DETECTED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, motion_detected); - if (!hc) { - return NULL; - } - - return hc; -} - -/* Char: Name */ -hap_char_t *hap_char_name_create(const char *name) -{ - hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_NAME, - HAP_CHAR_PERM_PR, name); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Obstruction Detected */ -hap_char_t *hap_char_obstruction_detect_create(bool obstr_detect) -{ - hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_OBSTRUCTION_DETECTED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, obstr_detect); - if (!hc) { - return NULL; - } - - return hc; -} - -/* Char: On */ -hap_char_t *hap_char_on_create(bool on) -{ - hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_ON, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, on); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Outlet in Use */ -hap_char_t *hap_char_outlet_in_use_create(bool outlet_in_use) -{ - hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_OUTLET_IN_USE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, outlet_in_use); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Rotation Direction */ -hap_char_t *hap_char_rotation_direction_create(int rotation_direction) -{ - hap_char_t *hc = hap_char_int_create(HAP_CHAR_UUID_ROTATION_DIRECTION, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, rotation_direction); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Rotation Speed */ -hap_char_t *hap_char_rotation_speed_create(float rotation_speed) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_ROTATION_SPEED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, rotation_speed); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Saturation */ -hap_char_t *hap_char_saturation_create(float saturation) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_SATURATION, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, saturation); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Serial Number */ -hap_char_t *hap_char_serial_number_create(const char *serial_num) -{ - hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_SERIAL_NUMBER, - HAP_CHAR_PERM_PR, serial_num); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Target Door State */ -hap_char_t *hap_char_target_door_state_create(uint8_t targ_door_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_TARGET_DOOR_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_door_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Target Heating Cooling State */ -hap_char_t *hap_char_target_heating_cooling_state_create(uint8_t targ_heating_cooling_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_TARGET_HEATING_COOLING_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_heating_cooling_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 3, 1); - - return hc; -} - -/* Char: Target Relative Humidity */ -hap_char_t *hap_char_target_relative_humidity_create(float targ_rel_humidity) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_TARGET_RELATIVE_HUMIDITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_rel_humidity); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Target Temperature */ -hap_char_t *hap_char_target_temperature_create(float targ_temp) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_TARGET_TEMPERATURE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_temp); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 10.0, 38.0, 0.1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_CELSIUS); - - return hc; -} - -/* Char: Temperature Display Units */ -hap_char_t *hap_char_temperature_display_units_create(uint8_t temp_disp_units) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_TEMPERATURE_DISPLAY_UNITS, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, temp_disp_units); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Version */ -hap_char_t *hap_char_version_create(const char *version) -{ - hap_char_t *hc = hap_char_string_create(HAP_CHAR_UUID_VERSION, - HAP_CHAR_PERM_PR, version); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Security System Current State */ -hap_char_t *hap_char_security_system_current_state_create(uint8_t security_sys_curr_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_SECURITY_SYSTEM_CURRENT_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, security_sys_curr_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 4, 1); - - return hc; -} - -/* Char: Security System Target State */ -hap_char_t *hap_char_security_system_target_state_create(uint8_t security_sys_targ_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_SECURITY_SYSTEM_TARGET_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, security_sys_targ_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 3, 1); - - return hc; -} - -/* Char: Battery Level */ -hap_char_t *hap_char_battery_level_create(uint8_t battery_level) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_BATTERY_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, battery_level); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 100, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Carbon Monoxide Detected */ -hap_char_t *hap_char_carbon_monoxide_detected_create(uint8_t carbon_monoxide_detected) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CARBON_MONOXIDE_DETECTED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, carbon_monoxide_detected); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Contact Sensor State */ -hap_char_t *hap_char_contact_sensor_state_create(uint8_t contact_sensor_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CONTACT_SENSOR_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, contact_sensor_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Current Ambient Light Level */ -hap_char_t *hap_char_current_ambient_light_level_create(float curr_ambient_light_level) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_ambient_light_level); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0001, 100000.0, 0.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_LUX); - - return hc; -} - -/* Char: Current Horizontal Tilt Angle */ -hap_char_t *hap_char_current_horizontal_tilt_angle_create(int curr_horiz_tilt_angle) -{ - hap_char_t *hc = hap_char_int_create(HAP_CHAR_UUID_CURRENT_HORIZONTAL_TILT_ANGLE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_horiz_tilt_angle); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, -90, 90, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_ARCDEGREES); - - return hc; -} - -/* Char: Current Position */ -hap_char_t *hap_char_current_position_create(uint8_t curr_pos) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CURRENT_POSITION, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_pos); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 100, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Current Vertical Tilt Angle */ -hap_char_t *hap_char_current_vertical_tilt_angle_create(int curr_vert_tilt_angle) -{ - hap_char_t *hc = hap_char_int_create(HAP_CHAR_UUID_CURRENT_VERTICAL_TILT_ANGLE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_vert_tilt_angle); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, -90, 90, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_ARCDEGREES); - - return hc; -} - -/* Char: Hold Position */ -hap_char_t *hap_char_hold_position_create(bool hold_pos) -{ - hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_HOLD_POSITION, - HAP_CHAR_PERM_PW, hold_pos); - if (!hc) { - return NULL; - } - - return hc; -} - -/* Char: Leak Detected */ -hap_char_t *hap_char_leak_detected_create(uint8_t leak_detected) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_LEAK_DETECTED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, leak_detected); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Occupancy Detected */ -hap_char_t *hap_char_occupancy_detected_create(uint8_t occupancy_detected) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_OCCUPANCY_DETECTED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, occupancy_detected); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Position State */ -hap_char_t *hap_char_position_state_create(uint8_t pos_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_POSITION_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, pos_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Programmable Switch Event */ -hap_char_t *hap_char_programmable_switch_event_create(uint8_t programmable_switch_event) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_PROGRAMMABLE_SWITCH_EVENT, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV | HAP_CHAR_PERM_SPECIAL_READ, - programmable_switch_event); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Status Active */ -hap_char_t *hap_char_status_active_create(bool status_active) -{ - hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_STATUS_ACTIVE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, status_active); - if (!hc) { - return NULL; - } - - return hc; -} - -/* Char: Smoke Detected */ -hap_char_t *hap_char_smoke_detected_create(uint8_t smoke_detected) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_SMOKE_DETECTED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, smoke_detected); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Status Fault */ -hap_char_t *hap_char_status_fault_create(uint8_t status_fault) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_STATUS_FAULT, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, status_fault); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Status Low Battery */ -hap_char_t *hap_char_status_low_battery_create(uint8_t status_low_battery) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_STATUS_LOW_BATTERY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, status_low_battery); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Status Tampered */ -hap_char_t *hap_char_status_tampered_create(uint8_t status_tampered) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_STATUS_TAMPERED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, status_tampered); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Target Horizontal Tilt Angle */ -hap_char_t *hap_char_target_horizontal_tilt_angle_create(int targ_horiz_tilt_angle) -{ - hap_char_t *hc = hap_char_int_create(HAP_CHAR_UUID_TARGET_HORIZONTAL_TILT_ANGLE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_horiz_tilt_angle); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, -90, 90, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_ARCDEGREES); - - return hc; -} - -/* Char: Target Position */ -hap_char_t *hap_char_target_position_create(uint8_t targ_pos) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_TARGET_POSITION, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_pos); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 100, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Target Vertical Tilt Angle */ -hap_char_t *hap_char_target_vertical_tilt_angle_create(int targ_vert_tilt_angle) -{ - hap_char_t *hc = hap_char_int_create(HAP_CHAR_UUID_TARGET_VERTICAL_TILT_ANGLE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_vert_tilt_angle); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, -90, 90, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_ARCDEGREES); - - return hc; -} - -/* Char: Security System Alarm Type */ -hap_char_t *hap_char_security_system_alarm_type_create(uint8_t security_sys_alarm_type) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_STATUS_SECURITY_SYSTEM_ALARM_TYPE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, security_sys_alarm_type); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Charging State */ -hap_char_t *hap_char_charging_state_create(uint8_t charging_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CHARGING_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, charging_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Carbon Monoxide Level */ -hap_char_t *hap_char_carbon_monoxide_level_create(float carbon_monoxide_level) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CARBON_MONOXIDE_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, carbon_monoxide_level); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 0.0); - - return hc; -} - -/* Char: Carbon Monoxide Peak Level */ -hap_char_t *hap_char_carbon_monoxide_peak_level_create(float carbon_monoxide_peak_level) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CARBON_MONOXIDE_PEAK_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, carbon_monoxide_peak_level); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 0.0); - - return hc; -} - -/* Char: Carbon Dioxide Detected */ -hap_char_t *hap_char_carbon_dioxide_detected_create(uint8_t carbon_dioxide_detected) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CARBON_DIOXIDE_DETECTED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, carbon_dioxide_detected); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Carbon Dioxide Level */ -hap_char_t *hap_char_carbon_dioxide_level_create(float carbon_dioxide_level) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CARBON_DIOXIDE_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, carbon_dioxide_level); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100000.0, 0.0); - - return hc; -} - -/* Char: Carbon Dioxide Peak Level */ -hap_char_t *hap_char_carbon_dioxide_peak_level_create(float carbon_dioxide_peak_level) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_CARBON_DIOXIDE_PEAK_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, carbon_dioxide_peak_level); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100000.0, 0.0); - - return hc; -} - - -/* Char: Air Quality */ -hap_char_t *hap_char_air_quality_create(uint8_t air_quality) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_AIR_QUALITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, air_quality); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 5, 1); - - return hc; -} - -/* Char: Accessory Flags */ -hap_char_t *hap_char_accessory_flags_create(uint32_t flags) -{ - hap_char_t *hc = hap_char_uint32_create(HAP_CHAR_UUID_ACCESSORY_FLAGS, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, flags); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Product Data */ -hap_char_t *hap_char_product_data_create(hap_data_val_t *product_data) -{ - hap_char_t *hc = hap_char_data_create(HAP_CHAR_UUID_PRODUCT_DATA, - HAP_CHAR_PERM_PR , product_data); - if (!hc) { - return NULL; - } - return hc; -} - -/* Char: Lock Physical Controls */ -hap_char_t *hap_char_lock_physical_controls_create(uint8_t lock_physical_controls) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_LOCK_PHYSICAL_CONTROLS, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, lock_physical_controls); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Current Air Purifier State */ -hap_char_t *hap_char_current_air_purifier_state_create(uint8_t curr_air_purifier_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CURRENT_AIR_PURIFIER_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_air_purifier_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Current Slat State */ -hap_char_t *hap_char_current_slat_state_create(uint8_t curr_slat_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CURRENT_SLAT_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_slat_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Slat Type */ -hap_char_t *hap_char_slat_type_create(uint8_t slat_type) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_SLAT_TYPE, - HAP_CHAR_PERM_PR, slat_type); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Filter Life Level */ -hap_char_t *hap_char_filter_life_level_create(float filter_life_level) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_FILTER_LIFE_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, filter_life_level); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - - return hc; -} - -/* Char: Filter Change Indication */ -hap_char_t *hap_char_filter_change_indication_create(uint8_t filter_change_indication) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_FILTER_CHANGE_INDICATION, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, filter_change_indication); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Reset Filter Indication */ -hap_char_t *hap_char_reset_filter_indication_create(uint8_t reset_filter_indication) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_RESET_FILTER_INDICATION, - HAP_CHAR_PERM_PW, reset_filter_indication); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 1, 1, 0); - - return hc; -} - -/* Char: Target Air Purifier State */ -hap_char_t *hap_char_target_air_purifier_state_create(uint8_t targ_air_purifier_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_TARGET_AIR_PURIFIER_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_air_purifier_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Target Fan State */ -hap_char_t *hap_char_target_fan_state_create(uint8_t targ_fan_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_TARGET_FAN_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_fan_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Current Fan State */ -hap_char_t *hap_char_current_fan_state_create(uint8_t curr_fan_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CURRENT_FAN_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_fan_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Active State */ -hap_char_t *hap_char_active_create(uint8_t active) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_ACTIVE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, active); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Swing Mode */ -hap_char_t *hap_char_swing_mode_create(uint8_t swing_mode) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_SWING_MODE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, swing_mode); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Current Tilt Angle */ -hap_char_t *hap_char_current_tilt_angle_create(int curr_tilt_angle) -{ - hap_char_t *hc = hap_char_int_create(HAP_CHAR_UUID_CURRENT_TILT_ANGLE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_tilt_angle); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, -90, 90, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_ARCDEGREES); - - return hc; -} - -/* Char: Target Tilt Angle */ -hap_char_t *hap_char_target_tilt_angle_create(int targ_tilt_angle) -{ - hap_char_t *hc = hap_char_int_create(HAP_CHAR_UUID_TARGET_TILT_ANGLE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_tilt_angle); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, -90, 90, 1); - hap_char_add_unit(hc, HAP_CHAR_UNIT_ARCDEGREES); - - return hc; -} - -/* Char: Ozone Density */ -hap_char_t *hap_char_ozone_density_create(float ozone_density) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_OZONE_DENSITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, ozone_density); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 1000.0, 0.0); - - return hc; -} - -/* Char: Nitrogen Dioxide Density */ -hap_char_t *hap_char_nitrogen_dioxide_density_create(float nitrogen_dioxide_density) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_NITROGEN_DIOXIDE_DENSITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, nitrogen_dioxide_density); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 1000.0, 0.0); - - return hc; -} - -/* Char: Sulphur Dioxide Density */ -hap_char_t *hap_char_sulphur_dioxide_density_create(float sulphur_dioxide_density) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_SULPHUR_DIOXIDE_DENSITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, sulphur_dioxide_density); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 1000.0, 0.0); - - return hc; -} - -/* Char: PM2.5 Density */ -hap_char_t *hap_char_pm_2_5_density_create(float pm_2_5_density) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_PM_2_5_DENSITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, pm_2_5_density); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 1000.0, 0.0); - - return hc; -} - -/* Char: PM10 Density */ -hap_char_t *hap_char_pm_10_density_create(float pm_10_density) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_PM_10_DENSITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, pm_10_density); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 1000.0, 0.0); - - return hc; -} - -/* Char: VOC Density */ -hap_char_t *hap_char_voc_density_create(float voc_density) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_VOC_DENSITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, voc_density); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 1000.0, 0.0); - - return hc; -} - -/* Char: Service Label Index */ -hap_char_t *hap_char_service_label_index_create(uint8_t service_label_index) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_SERVICE_LABEL_INDEX, - HAP_CHAR_PERM_PR, service_label_index); - if (!hc) { - return NULL; - } - - return hc; -} - -/* Char: Service Label Namespace */ -hap_char_t *hap_char_service_label_namespace_create(uint8_t service_label_namespace) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_SERVICE_LABEL_NAMESPACE, - HAP_CHAR_PERM_PR, service_label_namespace); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Color Temperature */ -hap_char_t *hap_char_color_temperature_create(uint32_t color_temp) -{ - hap_char_t *hc = hap_char_uint32_create(HAP_CHAR_UUID_COLOR_TEMPERATURE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, color_temp); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 50, 400, 1); - - return hc; -} - -/* Char: Current Heater Cooler State */ -hap_char_t *hap_char_current_heater_cooler_state_create(uint8_t curr_heater_cooler_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CURRENT_HEATER_COOLER_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_heater_cooler_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 3, 1); - - return hc; -} - -/* Char: Target Heater Cooler State */ -hap_char_t *hap_char_target_heater_cooler_state_create(uint8_t targ_heater_cooler_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_TARGET_HEATER_COOLER_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_heater_cooler_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Current Humidifier Dehumidifier State */ -hap_char_t *hap_char_current_humidifier_dehumidifier_state_create(uint8_t curr_humidifier_dehumidifier_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, curr_humidifier_dehumidifier_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 3, 1); - - return hc; -} - -/* Char: Target Humidifier Dehumidifier State */ -hap_char_t *hap_char_target_humidifier_dehumidifier_state_create(uint8_t targ_humidifier_dehumidifier_state) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, targ_humidifier_dehumidifier_state); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: Water Level */ -hap_char_t *hap_char_water_level_create(float water_level) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_WATER_LEVEL, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, water_level); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - - return hc; -} - -/* Char: Relative Humidity Dehumidifier Threshold */ -hap_char_t *hap_char_relative_humidity_dehumidifier_threshold_create(float rel_humidity_dehumidifier_threshold) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, rel_humidity_dehumidifier_threshold); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_PERCENTAGE); - - return hc; -} - -/* Char: Relative Humidity Humidifier Threshold */ -hap_char_t *hap_char_relative_humidity_humidifier_threshold_create(float rel_humidity_humidifier_threshold) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, rel_humidity_humidifier_threshold); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0.0, 100.0, 1.0); - hap_char_add_unit(hc, HAP_CHAR_UNIT_LUX); - - return hc; -} - -/* Char: Program Mode */ -hap_char_t *hap_char_program_mode_create(uint8_t prog_mode) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_PROGRAM_MODE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, prog_mode); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 2, 1); - - return hc; -} - -/* Char: In Use */ -hap_char_t *hap_char_in_use_create(uint8_t in_use) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_IN_USE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, in_use); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Set Duration */ -hap_char_t *hap_char_set_duration_create(uint32_t set_duration) -{ - hap_char_t *hc = hap_char_uint32_create(HAP_CHAR_UUID_SET_DURATION, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, set_duration); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 3600, 1); - - return hc; -} - -/* Char: Remaining Duration */ -hap_char_t *hap_char_remaining_duration_create(uint32_t remaining_duration) -{ - hap_char_t *hc = hap_char_uint32_create(HAP_CHAR_UUID_REMAINING_DURATION, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, remaining_duration); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 3600, 1); - - return hc; -} - -/* Char: Valve Type */ -hap_char_t *hap_char_valve_type_create(uint8_t valve_type) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_VALVE_TYPE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, valve_type); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 3, 1); - - return hc; -} - -/* Char: Is Configured */ -hap_char_t *hap_char_is_configured_create(uint8_t is_configured) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_IS_CONFIGURED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, is_configured); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Status Jammed */ -hap_char_t *hap_char_status_jammed_create(uint8_t status_jammed) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_STATUS_JAMMED, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV, status_jammed); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} - -/* Char: Administrator Only Access */ -hap_char_t *hap_char_administrator_only_access_create(bool administrator_only_access) -{ - hap_char_t *hc = hap_char_bool_create(HAP_CHAR_UUID_ADMINISTRATOR_ONLY_ACCESS, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, - administrator_only_access); - if (!hc) { - return NULL; - } - - return hc; -} - -/* Char: Lock Control Point */ -hap_char_t *hap_char_lock_control_point_create(hap_tlv8_val_t *lock_control_point) -{ - hap_char_t *hc = hap_char_tlv8_create(HAP_CHAR_UUID_LOCK_CONTROL_POINT, - HAP_CHAR_PERM_PW , lock_control_point); - if (!hc) { - return NULL; - } - - return hc; -} - -/* Char: Lock Last Known Action */ -hap_char_t *hap_char_lock_last_known_action_create(uint8_t lock_last_known_action) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_LOCK_LAST_KNOWN_ACTION, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV , lock_last_known_action); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 8, 1); - - return hc; -} - -/* Char: Lock Management Auto Security Timeout */ -hap_char_t *hap_char_lock_management_auto_security_timeout_create(uint32_t lock_management_auto_security_timeout) -{ - hap_char_t *hc = hap_char_uint32_create(HAP_CHAR_UUID_LOCK_MANAGEMENT_AUTO_SECURITY_TIMEOUT, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_PW | HAP_CHAR_PERM_EV, - lock_management_auto_security_timeout); - if (!hc) { - return NULL; - } - - hap_char_add_unit(hc, HAP_CHAR_UNIT_SECONDS); - - return hc; -} - -/* Char: Logs */ -hap_char_t *hap_char_logs_create(hap_tlv8_val_t *logs) -{ - hap_char_t *hc = hap_char_tlv8_create(HAP_CHAR_UUID_LOGS, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV , logs); - if (!hc) { - return NULL; - } - - return hc; -} - -/* Char: Air Particulate Density */ -hap_char_t *hap_char_air_particulate_density_create(float air_particulate_density) -{ - hap_char_t *hc = hap_char_float_create(HAP_CHAR_UUID_AIR_PARTICULATE_DENSITY, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV , air_particulate_density); - if (!hc) { - return NULL; - } - - hap_char_float_set_constraints(hc, 0, 1000, 0.0); - - return hc; -} - -/* Char: Air Particulate Size */ -hap_char_t *hap_char_air_particulate_size_create(uint8_t air_particulate_size) -{ - hap_char_t *hc = hap_char_uint8_create(HAP_CHAR_UUID_AIR_PARTICULATE_SIZE, - HAP_CHAR_PERM_PR | HAP_CHAR_PERM_EV , air_particulate_size); - if (!hc) { - return NULL; - } - - hap_char_int_set_constraints(hc, 0, 1, 1); - - return hc; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h deleted file mode 100755 index 6fcc69697..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_chars.h +++ /dev/null @@ -1,1425 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -/** HAP Apple Characteristics - * - * This offers helper APIs for all the standard HomeKit Characteristics defined by Apple - */ -#ifndef _HAP_APPLE_CHARS_H_ -#define _HAP_APPLE_CHARS_H_ - -#include -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define HAP_CHAR_UUID_ADMINISTRATOR_ONLY_ACCESS "1" -#define HAP_CHAR_UUID_BRIGHTNESS "8" -#define HAP_CHAR_UUID_COOLING_THRESHOLD_TEMPERATURE "D" -#define HAP_CHAR_UUID_CURRENT_DOOR_STATE "E" -#define HAP_CHAR_UUID_CURRENT_HEATING_COOLING_STATE "F" -#define HAP_CHAR_UUID_CURRENT_RELATIVE_HUMIDITY "10" -#define HAP_CHAR_UUID_CURRENT_TEMPERATURE "11" -#define HAP_CHAR_UUID_FIRMWARE_REVISION "52" -#define HAP_CHAR_UUID_HARDWARE_REVISION "53" -#define HAP_CHAR_UUID_HEATING_THRESHOLD_TEMPERATURE "12" -#define HAP_CHAR_UUID_HUE "13" -#define HAP_CHAR_UUID_IDENTIFY "14" -#define HAP_CHAR_UUID_LOCK_CONTROL_POINT "19" -#define HAP_CHAR_UUID_LOCK_CURRENT_STATE "1D" -#define HAP_CHAR_UUID_LOCK_LAST_KNOWN_ACTION "1C" -#define HAP_CHAR_UUID_LOCK_MANAGEMENT_AUTO_SECURITY_TIMEOUT "1A" -#define HAP_CHAR_UUID_LOCK_TARGET_STATE "1E" -#define HAP_CHAR_UUID_LOGS "1F" -#define HAP_CHAR_UUID_MANUFACTURER "20" -#define HAP_CHAR_UUID_MODEL "21" -#define HAP_CHAR_UUID_MOTION_DETECTED "22" -#define HAP_CHAR_UUID_NAME "23" -#define HAP_CHAR_UUID_OBSTRUCTION_DETECTED "24" -#define HAP_CHAR_UUID_ON "25" -#define HAP_CHAR_UUID_OUTLET_IN_USE "26" -#define HAP_CHAR_UUID_ROTATION_DIRECTION "28" -#define HAP_CHAR_UUID_ROTATION_SPEED "29" -#define HAP_CHAR_UUID_SATURATION "2F" -#define HAP_CHAR_UUID_SERIAL_NUMBER "30" -#define HAP_CHAR_UUID_TARGET_DOOR_STATE "32" -#define HAP_CHAR_UUID_TARGET_HEATING_COOLING_STATE "33" -#define HAP_CHAR_UUID_TARGET_RELATIVE_HUMIDITY "34" -#define HAP_CHAR_UUID_TARGET_TEMPERATURE "35" -#define HAP_CHAR_UUID_TEMPERATURE_DISPLAY_UNITS "36" -#define HAP_CHAR_UUID_VERSION "37" -#define HAP_CHAR_UUID_AIR_PARTICULATE_DENSITY "64" -#define HAP_CHAR_UUID_AIR_PARTICULATE_SIZE "65" -#define HAP_CHAR_UUID_SECURITY_SYSTEM_CURRENT_STATE "66" -#define HAP_CHAR_UUID_SECURITY_SYSTEM_TARGET_STATE "67" -#define HAP_CHAR_UUID_BATTERY_LEVEL "68" -#define HAP_CHAR_UUID_CARBON_MONOXIDE_DETECTED "69" -#define HAP_CHAR_UUID_CONTACT_SENSOR_STATE "6A" -#define HAP_CHAR_UUID_CURRENT_AMBIENT_LIGHT_LEVEL "6B" -#define HAP_CHAR_UUID_CURRENT_HORIZONTAL_TILT_ANGLE "6C" -#define HAP_CHAR_UUID_CURRENT_POSITION "6D" -#define HAP_CHAR_UUID_CURRENT_VERTICAL_TILT_ANGLE "6E" -#define HAP_CHAR_UUID_HOLD_POSITION "6F" -#define HAP_CHAR_UUID_LEAK_DETECTED "70" -#define HAP_CHAR_UUID_OCCUPANCY_DETECTED "71" -#define HAP_CHAR_UUID_POSITION_STATE "72" -#define HAP_CHAR_UUID_PROGRAMMABLE_SWITCH_EVENT "73" -#define HAP_CHAR_UUID_STATUS_ACTIVE "75" -#define HAP_CHAR_UUID_SMOKE_DETECTED "76" -#define HAP_CHAR_UUID_STATUS_FAULT "77" -#define HAP_CHAR_UUID_STATUS_JAMMED "78" -#define HAP_CHAR_UUID_STATUS_LOW_BATTERY "79" -#define HAP_CHAR_UUID_STATUS_TAMPERED "7A" -#define HAP_CHAR_UUID_TARGET_HORIZONTAL_TILT_ANGLE "7B" -#define HAP_CHAR_UUID_TARGET_POSITION "7C" -#define HAP_CHAR_UUID_TARGET_VERTICAL_TILT_ANGLE "7D" -#define HAP_CHAR_UUID_STATUS_SECURITY_SYSTEM_ALARM_TYPE "8E" -#define HAP_CHAR_UUID_CHARGING_STATE "8F" -#define HAP_CHAR_UUID_CARBON_MONOXIDE_LEVEL "90" -#define HAP_CHAR_UUID_CARBON_MONOXIDE_PEAK_LEVEL "91" -#define HAP_CHAR_UUID_CARBON_DIOXIDE_DETECTED "92" -#define HAP_CHAR_UUID_CARBON_DIOXIDE_LEVEL "93" -#define HAP_CHAR_UUID_CARBON_DIOXIDE_PEAK_LEVEL "94" -#define HAP_CHAR_UUID_AIR_QUALITY "95" -#define HAP_CHAR_UUID_ACCESSORY_FLAGS "A6" -#define HAP_CHAR_UUID_LOCK_PHYSICAL_CONTROLS "A7" -#define HAP_CHAR_UUID_CURRENT_AIR_PURIFIER_STATE "A9" -#define HAP_CHAR_UUID_CURRENT_SLAT_STATE "AA" -#define HAP_CHAR_UUID_SLAT_TYPE "C0" -#define HAP_CHAR_UUID_FILTER_LIFE_LEVEL "AB" -#define HAP_CHAR_UUID_FILTER_CHANGE_INDICATION "AC" -#define HAP_CHAR_UUID_RESET_FILTER_INDICATION "AD" -#define HAP_CHAR_UUID_TARGET_AIR_PURIFIER_STATE "A8" -#define HAP_CHAR_UUID_TARGET_FAN_STATE "BF" -#define HAP_CHAR_UUID_CURRENT_FAN_STATE "AF" -#define HAP_CHAR_UUID_ACTIVE "B0" -#define HAP_CHAR_UUID_SWING_MODE "B6" -#define HAP_CHAR_UUID_CURRENT_TILT_ANGLE "C1" -#define HAP_CHAR_UUID_TARGET_TILT_ANGLE "C2" -#define HAP_CHAR_UUID_OZONE_DENSITY "C3" -#define HAP_CHAR_UUID_NITROGEN_DIOXIDE_DENSITY "C4" -#define HAP_CHAR_UUID_SULPHUR_DIOXIDE_DENSITY "C5" -#define HAP_CHAR_UUID_PM_2_5_DENSITY "C6" -#define HAP_CHAR_UUID_PM_10_DENSITY "C7" -#define HAP_CHAR_UUID_VOC_DENSITY "C8" -#define HAP_CHAR_UUID_SERVICE_LABEL_INDEX "CB" -#define HAP_CHAR_UUID_SERVICE_LABEL_NAMESPACE "CD" -#define HAP_CHAR_UUID_COLOR_TEMPERATURE "CE" -#define HAP_CHAR_UUID_CURRENT_HEATER_COOLER_STATE "B1" -#define HAP_CHAR_UUID_TARGET_HEATER_COOLER_STATE "B2" -#define HAP_CHAR_UUID_CURRENT_HUMIDIFIER_DEHUMIDIFIER_STATE "B3" -#define HAP_CHAR_UUID_TARGET_HUMIDIFIER_DEHUMIDIFIER_STATE "B4" -#define HAP_CHAR_UUID_WATER_LEVEL "B5" -#define HAP_CHAR_UUID_RELATIVE_HUMIDITY_DEHUMIDIFIER_THRESHOLD "C9" -#define HAP_CHAR_UUID_RELATIVE_HUMIDITY_HUMIDIFIER_THRESHOLD "CA" -#define HAP_CHAR_UUID_PROGRAM_MODE "D1" -#define HAP_CHAR_UUID_IN_USE "D2" -#define HAP_CHAR_UUID_SET_DURATION "D3" -#define HAP_CHAR_UUID_REMAINING_DURATION "D4" -#define HAP_CHAR_UUID_VALVE_TYPE "D5" -#define HAP_CHAR_UUID_IS_CONFIGURED "D6" -#define HAP_CHAR_UUID_WATTAGE "DC" -#define HAP_CHAR_UUID_PRODUCT_DATA "220" - -/** Create Brightness Characteristic - * - * This API creates the Brightness characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] brightness Initial value of brightness - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_brightness_create(int brightness); - -/** Cooling Threshold Temperature Characteristic - * - * This API creates the Cooling Threshold Temperature characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] cooling_threshold_temp Cooling Threshold Value of Cooling Threshold Temperature characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_cooling_threshold_temperature_create(float cooling_threshold_temp); - -/** Create Current Door State Characteristic - * - * This API creates the Current Door State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_door_state Initial value of Current Door State - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_door_state_create(uint8_t curr_door_state); - -/** Create Current Heating Cooling State Characteristic - * - * This API creates the Current Heating Cooling State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_heating_cooling_state Initial value of current heating cooling state characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_heating_cooling_state_create(uint8_t curr_heating_cooling_state); - -/** Current Relative Humidity Characteristic - * - * This API creates the Current Relative Humidity characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_rel_humidity Current Relative Humidity Value - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_relative_humidity_create(float curr_rel_humidity); - -/** Current Temperature Characteristic - * - * This API creates the Current Temperature characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_temp Initial value of current temperature characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_temperature_create(float curr_temp); - -/** Create Firmware Revision Characteristic - * - * This API creates the firmware revision characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] fw_rev Firmware Revision string - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_firmware_revision_create(const char *fw_rev); - -/** Create Hardware Revision Characteristic - * - * This API creates the name characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] hw_rev Hardware Revision string - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_hardware_revision_create(const char *hw_rev); - -/** Heating Threshold Temperature Characteristic - * - * This API creates the Heating Threshold Temperature characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] heating_threshold_temp Heating Threshold Value of Heating Threshold Temperature characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_heating_threshold_temperature_create(float heating_threshold_temp); - -/** Create Hue Characteristic - * - * This API creates the hue characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] hue Initial value of hue - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_hue_create(float hue); - -/** Create Identify Characteristic - * - * This API creates the Identify characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_identify_create(void); - -/** Lock Current State Characteristic - * - * This API creates the Lock Current State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] lock_curr_state Current lock state value of characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_lock_current_state_create(uint8_t lock_curr_state); - -/** Lock Target State Characteristic - * - * This API creates the Lock Target State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] lock_targ_state Target lock state value of characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_lock_target_state_create(uint8_t lock_targ_state); - -/** Create Manufacturer Characteristic - * - * This API creates the Manufacturer characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] manufacturer Manufacturer string - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_manufacturer_create(const char *manufacturer); - -/** Create Model Characteristic - * - * This API creates the Model characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] model Model string - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_model_create(const char *model); - -/** Create Motion Detected Characteristic - * - * This API creates the Motion Detected characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] motion_detected Value of Motion Detected Charateristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_motion_detected_create(bool motion_detected); - -/** Create Name Characteristic - * - * This API creates the Name characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] name Name string - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_name_create(const char *name); - -/** Create Obstruction Detected Characteristic - * - * This API creates the Obstruction Detected characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] obstr_detect Initial value of obstruction detected characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_obstruction_detect_create(bool obstr_detect); - -/** Create On Characteristic - * - * This API creates the On characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] on Initial value of on - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_on_create(bool on); - -/** Create Outlet in Use Characteristic - * - * This API creates the Outlet in Use characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] outlet_in_use Initial value of outlet in use - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_outlet_in_use_create(bool outlet_in_use); - -/** Create Rotation Direction Characteristic - * - * This API creates the Rotation Direction characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] rotation_direction Initial value of Rotation Direction - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_rotation_direction_create(int rotation_direction); - -/** Create Rotation Speed Characteristic - * - * This API creates the Rotation Speed characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] rotation_speed Initial value of Rotation Speed - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_rotation_speed_create(float rotation_speed); - -/** Create Saturation Characteristic - * - * This API creates the saturation characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] saturation Initial value of saturation - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_saturation_create(float saturation); - -/** Create Serial Number Characteristic - * - * This API creates the serial number characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] serial_num Serial Number string - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_serial_number_create(const char *serial_num); - -/** Create Target Door State Characteristic - * - * This API creates the Target Door State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_door_state Initial value of Target Door State - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_door_state_create(uint8_t targ_door_state); - -/** Create Target Heating Cooling State Characteristic - * - * This API creates the Target Heating Cooling State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_heating_cooling_state Value of target heating cooling state characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_heating_cooling_state_create(uint8_t targ_heating_cooling_state); - -/** Target Relative Humidity Characteristic - * - * This API creates the Target Relative Humidity characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_rel_humidity Target Relative Humidity Value - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_relative_humidity_create(float targ_rel_humidity); - -/** Target Temperature Characteristic - * - * This API creates the Target Temperature characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_temp Target value of target temperature characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_temperature_create(float targ_temp); - -/** Temperature Display Units Characteristic - * - * This API creates the Temperature Display Units characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] temp_disp_units Initial value of Temperature Display Units characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_temperature_display_units_create(uint8_t temp_disp_units); - -/** Create Version Characteristic - * - * This API creates the version characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] version Version String - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_version_create(const char *version); - -/** Create Security System Current State Characteristic - * - * This API creates the Security System Current State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] security_sys_curr_state Initial value of Security System Current State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_security_system_current_state_create(uint8_t security_sys_curr_state); - -/** Create Security System Target State Characteristic - * - * This API creates the Security System Target State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] security_sys_targ_state Initial value of Security System Target State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_security_system_target_state_create(uint8_t security_sys_targ_state); - -/** Create Battery Level Characteristic - * - * This API creates the Battery Level characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] battery_level Initial value of Battery Level characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_battery_level_create(uint8_t battery_level); - -/** Current Position Characteristic - * - * This API creates the Current Position characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_pos Initial value of Cuurent Position characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_position_create(uint8_t curr_pos); - -/** Current Vertical Tilt Angle Characteristic - * - * This API creates the Current Vertical Tilt Angle characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_vert_tilt_angle Initial value of Current Vertical Tilt Angle characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_vertical_tilt_angle_create(int curr_vert_tilt_angle); - -/** Hold Position Characteristic - * - * This API creates the Hold Position characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] hold_pos Initial value of Hold Position characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_hold_position_create(bool hold_pos); - -/** Leak Detected Characteristic - * - * This API creates the Leak Detected characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] leak_detected Initial value of Leak Detected characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_leak_detected_create(uint8_t leak_detected); - -/** Occupancy Detected Characteristic - * - * This API creates the Occupancy Detected characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] occupancy_detected Initial value of Occupancy Detected characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_occupancy_detected_create(uint8_t occupancy_detected); - -/** Status Active Characteristic - * - * This API creates the Status Active characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] status_active Initial value of Status Active characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_status_active_create(bool status_active); - -/** Smoke Detected Characteristic - * - * This API creates the Smoke Detected characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] smoke_detected Initial value of Smoke Detected characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_smoke_detected_create(uint8_t smoke_detected); - -/** Status Fault Characteristic - * - * This API creates the Status Fault characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] status_fault Initial value of Status Fault characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_status_fault_create(uint8_t status_fault); - -/** Status Low Battery Characteristic - * - * This API creates the Status Low Battery characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] status_low_battery Initial value of Status Low Battery characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_status_low_battery_create(uint8_t status_low_battery); - -/** Status Tampered Characteristic - * - * This API creates the Status Tampered characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] status_tampered Initial value of Status Tampered characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_status_tampered_create(uint8_t status_tampered); - -/** Target Horizontal Tilt Angle Characteristic - * - * This API creates the Target Horizontal Tilt Angle characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_horiz_tilt_angle Initial value of Target Horizontal Tilt Angle characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_horizontal_tilt_angle_create(int targ_horiz_tilt_angle); - -/** Target Position Characteristic - * - * This API creates the Target Position characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_pos Initial value of Target Position characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_position_create(uint8_t targ_pos); - -/** Target Vertical Tilt Angle Characteristic - * - * This API creates the Target Vertical Tilt Angle characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_vert_tilt_angle Initial value of Target Vertical Tilt Angle characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_vertical_tilt_angle_create(int targ_vert_tilt_angle); - -/** Security System Alarm Type Characteristic - * - * This API creates the Security System Alarm Type characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] security_sys_alarm_type Initial value of Security System Alarm Type characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_security_system_alarm_type_create(uint8_t security_sys_alarm_type); - -/** Charging State Characteristic - * - * This API creates the Charging State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] charging_state Charging State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_charging_state_create(uint8_t charging_state); - -/** Carbon Monoxide Level Characteristic - * - * This API creates the Carbon Monoxide Level characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] carbon_monoxide_level Initial value of Carbon Monoxide Level characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_carbon_monoxide_level_create(float carbon_monoxide_level); - -/** Carbon Monoxide Peak Level Characteristic - * - * This API creates the Carbon Monoxide Peak Level characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] carbon_monoxide_peak_level Initial value of Carbon Monoxide Peak Level characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_carbon_monoxide_peak_level_create(float carbon_monoxide_peak_level); - -/** Carbon Dioxide Detected Characteristic - * - * This API creates the Carbon Dioxide Detected characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] carbon_dioxide_detected Initial value of Carbon Dioxide Detected characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_carbon_dioxide_detected_create(uint8_t carbon_dioxide_detected); - -/** Carbon Dioxide Level Characteristic - * - * This API creates the Carbon Dioxide Level characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] carbon_dioxide_level Initial value of Carbon Dioxide Level characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_carbon_dioxide_level_create(float carbon_dioxide_level); - -/** Carbon Dioxide Peak Level Characteristic - * - * This API creates the Carbon Dioxide Peak Level characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] carbon_dioxide_peak_level Initial value of Carbon Dioxide Peak Level characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_carbon_dioxide_peak_level_create(float carbon_dioxide_peak_level); - -/** Carbon Monoxide Detected Characteristic - * - * This API creates the Carbon Monoxide Detected characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] carbon_monoxide_detected Initial value of Carbon Monoxide Detected characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_carbon_monoxide_detected_create(uint8_t carbon_monoxide_detected); - -/** Contact Sensor State Characteristic - * - * This API creates the Contact Sensor State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] contact_sensor_state Initial value of Contact Sensor State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_contact_sensor_state_create(uint8_t contact_sensor_state); - -/** Current Ambient Light Level Characteristic - * - * This API creates the Current Ambient Light Level characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_ambient_light_level Initial value of Current Ambient Light Level characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_ambient_light_level_create(float curr_ambient_light_level); - -/** Current Horizontal Tilt Angle Characteristic - * - * This API creates the Current Horizontal Tilt Angle characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_horiz_tilt_angle Initial value of Current Horizontal Tilt Angle characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_horizontal_tilt_angle_create(int curr_horiz_tilt_angle); - -/** Air Quality Characteristic - * - * This API creates the Air Quality characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] air_quality Initial value of Air Quality characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_air_quality_create(uint8_t air_quality); - -/** Create Accessory Flags Characteristic - * - * This API creates the Accessory Flags characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] flags Initial value of flags - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_accessory_flags_create(uint32_t flags); - - -/** Create Product Data Characteristic - * - * This API creates the Product Data characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] product_data Value of the product data - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_product_data_create(hap_data_val_t *product_data); - -/** Create Lock Physical Controls Characteristic - * - * This API creates the Lock Physical Controls characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] lock_physical_controls Initial value of Lock Physical Controls characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_lock_physical_controls_create(uint8_t lock_physical_controls); - -/** Current Air Purifier State Characteristic - * - * This API creates the Current Air Purifier State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_air_purifier_state Initial value of Current Air Purifier State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_air_purifier_state_create(uint8_t curr_air_purifier_state); - -/** Current Slat State Characteristic - * - * This API creates the Current Slat State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_slat_state Initial value of Current Slat State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_slat_state_create(uint8_t curr_slat_state); - -/** Slat Type Characteristic - * - * This API creates the Slat Type characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] slat_type Value of Slat Type characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_slat_type_create(uint8_t slat_type); - -/** Filter Life Level Characteristic - * - * This API creates the Filter Life Level characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] filter_life_level Initial value of Filter Life Level characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_filter_life_level_create(float filter_life_level); - -/** Current Filter Change Indication Characteristic - * - * This API creates the Filter Change Indication characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] filter_change_indication Initial value of Filter Change Indication characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_filter_change_indication_create(uint8_t filter_change_indication); - -/** Reset Filter Indication Characteristic - * - * This API creates the Reset Filter Indication characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] reset_filter_indication Initial value of Reset Filter Indication characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_reset_filter_indication_create(uint8_t reset_filter_indication); - -/** Target Air Purifier State Characteristic - * - * This API creates the Target Air Purifier State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_air_purifier_state Initial value of Target Air Purifier State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_air_purifier_state_create(uint8_t targ_air_purifier_state); - -/** Target Fan State Characteristic - * - * This API creates the Target Fan State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_fan_state Initial value of Target Fan State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_fan_state_create(uint8_t targ_fan_state); - -/** Current Fan State Characteristic - * - * This API creates the Current Fan State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_fan_state Initial value of Current Fan State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_fan_state_create(uint8_t curr_fan_state); - -/** Position State Characteristic - * - * This API creates the Position State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] pos_state Initial value of Position State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_position_state_create(uint8_t pos_state); - -/** Programmable Switch Event Characteristic - * - * This API creates the Programmable Switch Event characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] programmable_switch_event Initial value of Programmable Switch Event characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_programmable_switch_event_create(uint8_t programmable_switch_event); - -/** Active Characteristic - * - * This API creates the Active characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] active Initial value of active characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_active_create(uint8_t active); - -/** Swing Mode Characteristic - * - * This API creates the Swing Mode characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] swing_mode Initial value of Swing Mode characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_swing_mode_create(uint8_t swing_mode); - -/** Current Tilt Angle Characteristic - * - * This API creates the Current Tilt Angle characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_tilt_angle Initial value of Current Tilt Angle characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_tilt_angle_create(int curr_tilt_angle); - -/** Target Tilt Angle Characteristic - * - * This API creates the Target Tilt Angle characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_tilt_angle Initial value of Target Tilt Angle characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ - hap_char_t *hap_char_target_tilt_angle_create(int targ_tilt_angle); - -/** Ozone Density Characteristic - * - * This API creates the Ozone Density characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] ozone_density Initial value of Ozone Density characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_ozone_density_create(float ozone_density); - -/** Nitrogen Dioxide Density Characteristic - * - * This API creates the Nitrogen Dioxide Density characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] nitrogen_dioxide_density Initial value of Nitrogen Dioxide Density characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_nitrogen_dioxide_density_create(float nitrogen_dioxide_density); - -/** Sulphur Dioxide Density Characteristic - * - * This API creates the Sulphur Dioxide Density characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] sulphur_dioxide_density Initial value of Sulphur Dioxide Density characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_sulphur_dioxide_density_create(float sulphur_dioxide_density); - -/** PM2.5 Density Characteristic - * - * This API creates the PM2.5 Density characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] pm_2_5_density Initial value of PM2.5 Density characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_pm_2_5_density_create(float pm_2_5_density); - -/** PM10 Density Characteristic - * - * This API creates the PM10 Density characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] pm_10_density Initial value of PM10 Density characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_pm_10_density_create(float pm_10_density); - -/** VOC Density Characteristic - * - * This API creates the VOC Density characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] voc_density Initial value of VOC Density characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_voc_density_create(float voc_density); - -/** Create Service Label Index Characteristic - * - * This API creates the Service Label Index characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] service_label_index Initial value of Service Label Index characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_service_label_index_create(uint8_t service_label_index); - -/** Create Service Label Namespace Characteristic - * - * This API creates the Service Label Namespace characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] service_label_namespace Initial value of Service Label Namespace characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_service_label_namespace_create(uint8_t service_label_namespace); - -/** Create Color Temperature Characteristic - * - * This API creates the color temperature characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] color_temp Initial value of Color Temperature - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_color_temperature_create(uint32_t color_temp); - -/** Create Curr Heater Cooler State Characteristic - * - * This API creates the Curr Heater Cooler State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_heater_cooler_state Initial value of Curr Heater Cooler State - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_heater_cooler_state_create(uint8_t curr_heater_cooler_state); - -/** Create Target Heater Cooler State Characteristic - * - * This API creates the Target Heater Cooler State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_heater_cooler_state Initial value of Target Heater Cooler State - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_heater_cooler_state_create(uint8_t targ_heater_cooler_state); - -/** Create Current Humidifier Dehumidifier State Characteristic - * - * This API creates the Current Humidifier Dehumidifier State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] curr_humidifier_dehumidifier_state Initial value of Current Humidifier Dehumidifier State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_current_humidifier_dehumidifier_state_create(uint8_t curr_humidifier_dehumidifier_state); - -/** Create Target Humidifier Dehumidifier State Characteristic - * - * This API creates the Target Humidifier Dehumidifier State characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] targ_humidifier_dehumidifier_state Initial value of Target Humidifier Dehumidifier State characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_target_humidifier_dehumidifier_state_create(uint8_t targ_humidifier_dehumidifier_state); - -/** Create Water Level Characteristic - * - * This API creates the Water Level characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] water_level Initial value of Water Level characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_water_level_create(float water_level); - -/** Create Relative Humidity Dehumidifier Threshold Characteristic - * - * This API creates the Relative Humidity Dehumidifier Threshold characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] rel_humidity_dehumidifier_threshold Initial value of Relative Humidity Dehumidifier Threshold characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_relative_humidity_dehumidifier_threshold_create(float rel_humidity_dehumidifier_threshold); - -/** Create Relative Humidity Humidifier Threshold Characteristic - * - * This API creates the Relative Humidity Humidifier Threshold characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] rel_humidity_humidifier_threshold Initial value of Relative Humidity Humidifier Threshold characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_relative_humidity_humidifier_threshold_create(float rel_humidity_humidifier_threshold); - -/** Create Program Mode Characteristic - * - * This API creates the Program Mode characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] prog_mode Initial value of Program Mode characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_program_mode_create(uint8_t prog_mode); - -/** Create In Use Characteristic - * - * This API creates the In Use characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] in_use Initial value of In Use characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_in_use_create(uint8_t in_use); - -/** Create Set Duration Characteristic - * - * This API creates the Set Duration characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] set_duration Initial value of Set Duration characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_set_duration_create(uint32_t set_duration); - -/** Create Remaining Duration Characteristic - * - * This API creates the Remaining Duration characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] remaining_duration Initial value of Remaining Duration characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_remaining_duration_create(uint32_t remaining_duration); - -/** Create Valve Type Characteristic - * - * This API creates the Valve Type characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] valve_type Initial value of Valve Type characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_valve_type_create(uint8_t valve_type); - -/** Create Is Configured Characteristic - * - * This API creates the Is Configured characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] is_configured Initial value of Is Configured characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_is_configured_create(uint8_t is_configured); - -/** Status Jammed Characteristic - * - * This API creates the Status Jammed characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] status_jammed Initial value of Status Jammed characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_status_jammed_create(uint8_t status_jammed); - -/** Administrator Only Access Characteristic - * - * This API creates the Administrator Only Access characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] administrator_only_access Initial value of Administrator Only Access characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_administrator_only_access_create(bool administrator_only_access); - -/** Lock Control Point Characteristic - * - * This API creates the Lock Control Point characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] lock_control_point Initial value of Lock Control Point characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_lock_control_point_create(hap_tlv8_val_t *lock_control_point); - -/** Lock Last Known Action Characteristic - * - * This API creates the Lock Last Known Action characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] lock_last_known_action Initial value of Lock Last Known Action characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_lock_last_known_action_create(uint8_t lock_last_known_action); - -/** Lock Management Auto Security Timeout Characteristic - * - * This API creates the Lock Management Auto Security Timeout characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] lock_management_auto_security_timeout Initial value of Lock Management Auto Security Timeout characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_lock_management_auto_security_timeout_create(uint32_t lock_management_auto_security_timeout); - -/** Logs Characteristic - * - * This API creates the Logs characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] logs Initial value of Logs characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_logs_create(hap_tlv8_val_t *logs); - -/** Air Particulate Density Characteristic - * - * This API creates the Air Particulate Density characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] air_particulate_density Initial value of Air Particulate Density characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_air_particulate_density_create(float air_particulate_density); - -/** Air Particulate Size Characteristic - * - * This API creates the Air Particulate Size characteristic object with other metadata - * (format, constraints, permissions, etc.) set as per the HAP Specs - * - * @param[in] air_particulate_size Initial value of Air Particulate Size characteristic - * - * @return Pointer to the characteristic object on success - * @return NULL on failure - */ -hap_char_t *hap_char_air_particulate_size_create(uint8_t air_particulate_size); - -hap_char_t *hap_char_wattage_create(float watts); - -#ifdef __cplusplus -} -#endif - -#endif /* _HAP_APPLE_CHARS_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.c deleted file mode 100755 index fec046ffc..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.c +++ /dev/null @@ -1,721 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include - -hap_serv_t *hap_serv_accessory_information_create(hap_acc_cfg_t *cfg) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_ACCESSORY_INFORMATION); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_name_create(cfg->name)) != HAP_SUCCESS) { - goto err; - } - - if (hap_serv_add_char(hs, hap_char_model_create(cfg->model)) != HAP_SUCCESS) { - goto err; - } - - if (hap_serv_add_char(hs, hap_char_manufacturer_create(cfg->manufacturer)) != HAP_SUCCESS) { - goto err; - } - - if (hap_serv_add_char(hs, hap_char_serial_number_create(cfg->serial_num)) != HAP_SUCCESS) { - goto err; - } - - if (hap_serv_add_char(hs, hap_char_firmware_revision_create(cfg->fw_rev)) != HAP_SUCCESS) { - goto err; - } - - if (hap_serv_add_char(hs, hap_char_identify_create()) != HAP_SUCCESS) { - goto err; - } - - if (cfg->hw_rev) { - if (hap_serv_add_char(hs, hap_char_hardware_revision_create(cfg->hw_rev)) != HAP_SUCCESS) { - goto err; - } - } - - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_protocol_information_create(char *version) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_PROTOCOL_INFORMATION); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_version_create(version)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_fan_create(bool on) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_FAN); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_on_create(on)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_garage_door_opener_create(uint8_t curr_door_state, uint8_t targ_door_state, bool obstr_detect) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_GARAGE_DOOR_OPENER); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_current_door_state_create(curr_door_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_target_door_state_create(targ_door_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_obstruction_detect_create(obstr_detect)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_lightbulb_create(bool on) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LIGHTBULB); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_on_create(on)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_lock_management_create(hap_tlv8_val_t *lock_control_point, char * version) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LOCK_MANAGEMENT); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_lock_control_point_create(lock_control_point)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_version_create(version)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_lock_mechanism_create(uint8_t lock_curr_state, uint8_t lock_targ_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LOCK_MECHANISM); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_lock_current_state_create(lock_curr_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_lock_target_state_create(lock_targ_state)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_outlet_create(bool on, bool outlet_in_use) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_OUTLET); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_on_create(on)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_outlet_in_use_create(outlet_in_use)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_switch_create(bool on) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SWITCH); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_on_create(on)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_thermostat_create(uint8_t curr_heating_cooling_state, uint8_t targ_heating_cooling_state, float curr_temp, - float targ_temp, uint8_t temp_disp_units) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_THERMOSTAT); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_current_heating_cooling_state_create(curr_heating_cooling_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_target_heating_cooling_state_create(targ_heating_cooling_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_current_temperature_create(curr_temp)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_target_temperature_create(targ_temp)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_temperature_display_units_create(temp_disp_units)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_air_quality_sensor_create(uint8_t air_quality) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_AIR_QUALITY_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_air_quality_create(air_quality)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_security_system_create(uint8_t security_sys_curr_state, uint8_t security_sys_targ_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SECURITY_SYSTEM); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_security_system_current_state_create(security_sys_curr_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_security_system_target_state_create(security_sys_targ_state)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_carbon_monoxide_sensor_create(uint8_t carbon_monoxide_detected) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_CARBON_MONOXIDE_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_carbon_monoxide_detected_create(carbon_monoxide_detected)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_contact_sensor_create(uint8_t contact_sensor_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_CONTACT_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_contact_sensor_state_create(contact_sensor_state)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_door_create(uint8_t curr_pos, uint8_t targ_pos, uint8_t pos_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_DOOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_current_position_create(curr_pos)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_target_position_create(targ_pos)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_position_state_create(pos_state)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_humidity_sensor_create(float curr_rel_humidity) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_HUMIDITY_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_current_relative_humidity_create(curr_rel_humidity)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_leak_sensor_create(uint8_t leak_detected) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LEAK_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_leak_detected_create(leak_detected)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_light_sensor_create(float curr_ambient_light_level) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LIGHT_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_current_ambient_light_level_create(curr_ambient_light_level)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_motion_sensor_create(bool motion_detected) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_MOTION_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_motion_detected_create(motion_detected)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_occupancy_sensor_create(uint8_t occupancy_detected) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_OCCUPANCY_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_occupancy_detected_create(occupancy_detected)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_smoke_sensor_create(uint8_t smoke_detected) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SMOKE_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_smoke_detected_create(smoke_detected)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_stateless_programmable_switch_create(uint8_t programmable_switch_event) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_STATLESS_PROGRAMMABLE_SWITCH); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_programmable_switch_event_create(programmable_switch_event)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_wattage_create(float curr_watts) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_LIGHT_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_wattage_create(curr_watts)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - - -hap_serv_t *hap_serv_temperature_sensor_create(float curr_temp) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_TEMPERATURE_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_current_temperature_create(curr_temp)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_window_create(uint8_t curr_pos, uint8_t targ_pos, uint8_t pos_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_WINDOW); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_current_position_create(curr_pos)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_target_position_create(targ_pos)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_position_state_create(pos_state)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_window_covering_create(uint8_t targ_pos, uint8_t curr_pos, uint8_t pos_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_WINDOW_COVERING); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_target_position_create(targ_pos)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_current_position_create(curr_pos)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_position_state_create(pos_state)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_battery_service_create(uint8_t battery_level, uint8_t charging_state, uint8_t status_low_battery) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_BATTERY_SERVICE); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_battery_level_create(battery_level)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_charging_state_create(charging_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_status_low_battery_create(status_low_battery)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_carbon_dioxide_sensor_create(uint8_t carbon_dioxide_detected) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_CARBON_DIOXIDE_SENSOR); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_carbon_dioxide_detected_create(carbon_dioxide_detected)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_fan_v2_create(uint8_t active) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_FAN_V2); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_slat_create(uint8_t curr_slat_state, uint8_t slat_type) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SLAT); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_current_slat_state_create(curr_slat_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_slat_type_create(slat_type)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_filter_maintenance_create(uint8_t filter_change_indication) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_FILTER_MAINTENANCE); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_filter_change_indication_create(filter_change_indication)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_air_purifier_create(uint8_t active, uint8_t curr_air_purifier_state, uint8_t - targ_air_purifier_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_AIR_PURIFIER); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_current_air_purifier_state_create(curr_air_purifier_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_target_air_purifier_state_create(targ_air_purifier_state)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_heater_cooler_create(uint8_t active, float curr_temp, uint8_t curr_heater_cooler_state, uint8_t targ_heater_cooler_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_HEATER_COOLER); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_current_temperature_create(curr_temp)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_current_heater_cooler_state_create(curr_heater_cooler_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_target_heater_cooler_state_create(targ_heater_cooler_state)) != HAP_SUCCESS) { - goto err; - } - - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_humidifier_dehumidifier_create(uint8_t active, float curr_rel_humidity, uint8_t - curr_humid_dehumid_state, uint8_t targ_humid_dehumid_state) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_HUMIDIFIER_DEHUMIDIFIER); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_current_relative_humidity_create(curr_rel_humidity)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_current_humidifier_dehumidifier_state_create(curr_humid_dehumid_state)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_target_humidifier_dehumidifier_state_create(targ_humid_dehumid_state)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_service_label_create(uint8_t service_label_namespace) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_SERVICE_LABEL); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_service_label_namespace_create(service_label_namespace)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_irrigation_system_create(uint8_t active, uint8_t prog_mode, uint8_t in_use) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_IRRIGATION_SYSTEM); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_program_mode_create(prog_mode)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_in_use_create(in_use)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_valve_create(uint8_t active, uint8_t in_use, uint8_t valve_type) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_VALVE); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_in_use_create(in_use)) != HAP_SUCCESS) { - goto err; - } - if (hap_serv_add_char(hs, hap_char_valve_type_create(valve_type)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} - -hap_serv_t *hap_serv_faucet_create(uint8_t active) -{ - hap_serv_t *hs = hap_serv_create(HAP_SERV_UUID_FAUCET); - if (!hs) { - return NULL; - } - if (hap_serv_add_char(hs, hap_char_active_create(active)) != HAP_SUCCESS) { - goto err; - } - return hs; -err: - hap_serv_delete(hs); - return NULL; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.h deleted file mode 100755 index f1e65e441..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_apple_servs.h +++ /dev/null @@ -1,564 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -/** HAP Apple Services - * - * This offers helper APIs for all the standard HomeKit Services defined by Apple - */ -#ifndef _HAP_APPLE_SERVS_H_ -#define _HAP_APPLE_SERVS_H_ - -#include -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define HAP_SERV_UUID_ACCESSORY_INFORMATION "3E" -#define HAP_SERV_UUID_PROTOCOL_INFORMATION "A2" -#define HAP_SERV_UUID_FAN "40" -#define HAP_SERV_UUID_GARAGE_DOOR_OPENER "41" -#define HAP_SERV_UUID_LIGHTBULB "43" -#define HAP_SERV_UUID_LOCK_MANAGEMENT "44" -#define HAP_SERV_UUID_LOCK_MECHANISM "45" -#define HAP_SERV_UUID_SWITCH "49" -#define HAP_SERV_UUID_OUTLET "47" -#define HAP_SERV_UUID_THERMOSTAT "4A" -#define HAP_SERV_UUID_AIR_QUALITY_SENSOR "8D" -#define HAP_SERV_UUID_SECURITY_SYSTEM "7E" -#define HAP_SERV_UUID_CARBON_MONOXIDE_SENSOR "7F" -#define HAP_SERV_UUID_CONTACT_SENSOR "80" -#define HAP_SERV_UUID_DOOR "81" -#define HAP_SERV_UUID_HUMIDITY_SENSOR "82" -#define HAP_SERV_UUID_LEAK_SENSOR "83" -#define HAP_SERV_UUID_LIGHT_SENSOR "84" -#define HAP_SERV_UUID_MOTION_SENSOR "85" -#define HAP_SERV_UUID_OCCUPANCY_SENSOR "86" -#define HAP_SERV_UUID_SMOKE_SENSOR "87" -#define HAP_SERV_UUID_STATLESS_PROGRAMMABLE_SWITCH "89" -#define HAP_SERV_UUID_TEMPERATURE_SENSOR "8A" -#define HAP_SERV_UUID_WINDOW "8B" -#define HAP_SERV_UUID_WINDOW_COVERING "8C" -#define HAP_SERV_UUID_BATTERY_SERVICE "96" -#define HAP_SERV_UUID_CARBON_DIOXIDE_SENSOR "97" -#define HAP_SERV_UUID_FAN_V2 "B7" -#define HAP_SERV_UUID_SLAT "B9" -#define HAP_SERV_UUID_FILTER_MAINTENANCE "BA" -#define HAP_SERV_UUID_AIR_PURIFIER "BB" -#define HAP_SERV_UUID_HEATER_COOLER "BC" -#define HAP_SERV_UUID_HUMIDIFIER_DEHUMIDIFIER "BD" -#define HAP_SERV_UUID_SERVICE_LABEL "CC" -#define HAP_SERV_UUID_IRRIGATION_SYSTEM "CF" -#define HAP_SERV_UUID_VALVE "D0" -#define HAP_SERV_UUID_FAUCET "D7" - - -/** Create Accessory Information Service - * - * This API will create the Accessory Information Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] cfg The accessory configuration to be used to create the service - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_accessory_information_create(hap_acc_cfg_t *cfg); - -/** Create Protocol Information Service - * - * This API will create the Protocol Information Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] version The Protocol Version string - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_protocol_information_create(char *version); - -/** Create Fan Service - * - * This API will create the Fan Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] on Initial "On" state of the service - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_fan_create(bool on); - -/** Create Garage Door Opener Service - * - * This API will create the Garage Door Opener Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] curr_door_state Initial value of the current door state characteristic - * @param[in] targ_door_state Value of the target door state characteristic - * @param[in] obstr_detect Value of the obstruction detected characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_garage_door_opener_create(uint8_t curr_door_state, uint8_t targ_door_state, bool obstr_detect) -; - -/** Create Light Bulb Service - * - * This API will create the Light Bulb Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] on Initial "On" state of the service - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_lightbulb_create(bool on); - -/** Create Lock Management Service - * - * This API will create the Lock Management Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] lock_control_point Accepts data from TLV8 commands - * @param[in] version The Protocol Version string - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_lock_management_create(hap_tlv8_val_t *lock_control_point, char * version); - -/** Create Lock Mechanism Service - * - * This API will create the Lock Mechanism Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] lock_curr_state Current lock state of the service - * @param[in] lock_targ_state Target lock state of the service - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_lock_mechanism_create(uint8_t lock_curr_state, uint8_t lock_targ_state); - -/** Create Outlet Service - * - * This API will create the Outlet Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] on Initial "On" state of the service - * @param[in] outlet_in_use Initial value of the outlet in use characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_outlet_create(bool on, bool outlet_in_use); - -/** Create Switch Service - * - * This API will create the Switch Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] on Initial "On" state of the service - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_switch_create(bool on); - -/** Create Thermostat Service - * - * This API will create the Thermostat Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] curr_heating_cooling_state Initial value of Current Heating Cooling State characteristic - * @param[in] targ_heating_cooling_state Initial value of Target Heating Cooling State characteristic - * @param[in] curr_temp Initial value of Current Temperature characteristic - * @param[in] targ_temp Initial value of Target Temperature characteristic - * @param[in] temp_disp_units Initial value of Temperature Display Units characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_thermostat_create(uint8_t curr_heating_cooling_state, uint8_t targ_heating_cooling_state, float curr_temp, float targ_temp, uint8_t temp_disp_units); - -/** Create Air Quality Sensor Service - * - * This API will create the Air Quality Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] air_quality Initial value of Air Quality characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_air_quality_sensor_create(uint8_t air_quality); - -/** Create Security System Current State Service - * - * This API will create the Security System Current State Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] security_sys_curr_state Initial value of Security System Current State characteristic - * @param[in] security_sys_targ_state Initial value of Security System Target State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_security_system_create(uint8_t security_sys_curr_state, uint8_t security_sys_targ_state); - -/** Create Carbon Monoxide Sensor Service - * - * This API will create the Carbon Monoxide Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] carbon_monoxide_detected Initial value of Carbon Monoxide Sensor characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_carbon_monoxide_sensor_create(uint8_t carbon_monoxide_detected); - -/** Create Contact Sensor Service - * - * This API will create the Contact Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] contact_sensor_state Initial value of Contact Sensor State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_contact_sensor_create(uint8_t contact_sensor_state); - -/** Create Door Service - * - * This API will create the Door Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] curr_pos Initial value of Current Position characteristic - * @param[in] targ_pos Initial value of Target Position characteristic - * @param[in] pos_state Initial value of Position State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_door_create(uint8_t curr_pos, uint8_t targ_pos, uint8_t pos_state); - -/** Create Humidity Sensor Service - * - * This API will create the Humidity Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] curr_relative_humidity Initial value of Humidity Sensor State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_humidity_sensor_create(float curr_relative_humidity); - -/** Leak Sensor Service - * - * This API will create the Leak Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] leak_detected Initial value of Leak Detected State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_leak_sensor_create(uint8_t leak_detected); - -/** Light Sensor Service - * - * This API will create the Light Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] curr_ambient_light_level Initial value of Current Ambient Light Level characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_light_sensor_create(float curr_ambient_light_level); - -/** Motion Sensor Service - * - * This API will create the Motion Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] motion_detected Initial value of Motion Detected characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_motion_sensor_create(bool motion_detected); - -/** Occupancy Sensor Service - * - * This API will create the Occupancy Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] occupancy_detected Initial value of Occupancy Detected characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_occupancy_sensor_create(uint8_t occupancy_detected); - -/** Smoke Sensor Service - * - * This API will create the Smoke Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] smoke_detected Initial value of Smoke Detected characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_smoke_sensor_create(uint8_t smoke_detected); - -/** Stateless Programmable Switch Service - * - * This API will create the Stateless Programmable Switch Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] programmable_switch_event Initial value of Programmable Switch Event characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_stateless_programmable_switch_create(uint8_t programmable_switch_event); - -/** Temperature Sensor Service - * - * This API will create the Temperature Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] curr_temp Initial value of Current Temprature characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_temperature_sensor_create(float curr_temp); - -/** Window Service - * - * This API will create the Window Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] curr_pos Initial value of Current Position characteristic - * @param[in] targ_pos Initial value of Target Position characteristic - * @param[in] pos_state Initial value of Position State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_window_create(uint8_t curr_pos, uint8_t targ_pos, uint8_t pos_state); - -/** Window Covering Service - * - * This API will create the Window Covering Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] targ_pos Initial value of Target Position characteristic - * @param[in] curr_pos Initial value of Current Position characteristic - * @param[in] pos_state Initial value of Position State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_window_covering_create(uint8_t targ_pos, uint8_t curr_pos, uint8_t pos_state); - -/** Battery Service - * - * This API will create the Battery Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] battery_level Initial value of Battery Level characteristic - * @param[in] charging_state Initial value of Charging State characteristic - * @param[in] status_low_battery Initial value of Status Low Battery characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_battery_service_create(uint8_t battery_level, uint8_t charging_state, uint8_t status_low_battery); - -/** Create Carbon Dioxide Sensor Service - * - * This API will create the Carbon Dioxide Sensor Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] carbon_dioxide_detected Initial value of Carbon Dioxide Sensor characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_carbon_dioxide_sensor_create(uint8_t carbon_dioxide_detected); - -/** Fan v2 Service - * - * This API will create the Fan v2 Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] active Value of Active characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_fan_v2_create(uint8_t active); - -/** Slat Service - * - * This API will create the Slat Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] curr_slat_state Value of Current Slat State characteristic - * @param[in] slat_type Value of Slat Type characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_slat_create(uint8_t curr_slat_state, uint8_t slat_type); - -/** Filter Maintenance Service - * - * This API will create the Filter Maintenance Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] filter_change_indication Value of Filter Change Indication characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_filter_maintenance_create(uint8_t filter_change_indication); - -/** Air Purifier Service - * - * This API will create the Air Purifier Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] active Value of Active characteristic - * @param[in] curr_air_purifier_state Value of Current Air Purifier State characteristic - * @param[in] targ_air_purifier_state Value of Target Air Purifier State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_air_purifier_create(uint8_t active, uint8_t curr_air_purifier_state, uint8_t - targ_air_purifier_state); - -/** Heater Cooler Service - * - * This API will create the Heater Cooler Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] active Value of Active characteristic - * @param[in] curr_temp Value of Current Temperature characteristic - * @param[in] curr_heater_cooler_state Value of Current Heater Cooler State characteristic - * @param[in] targ_heater_cooler_state Value of Target Heater Cooler State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_heater_cooler_create(uint8_t active, float curr_temp, uint8_t curr_heater_cooler_state, uint8_t targ_heater_cooler_state); - -/** Create Humidifer Dehumidfier Service - * - * This API will create the Humidifer Dehumidfier Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] active Initial value of Active characteristic - * @param[in] curr_rel_humid Initial value of Current Relative Humidity characteristic - * @param[in] curr_humid_dehumid_state Initial value of Current Humidifier Dehumidifier State characteristic - * @param[in] targ_humid_dehumid_state Initial value of Target Humidifier Dehumidifier State characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_humidifier_dehumidifier_create(uint8_t active, float curr_rel_humid, uint8_t - curr_humid_dehumid_state, uint8_t targ_humid_dehumid_state); - -/** Create Service Label Service - * - * This API will create the Service Label Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] service_label_namespace Initial value of Service Label Service characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_service_label_create(uint8_t service_label_namespace); - -/** Create Irrigation System Service - * - * This API will create the Irrigation System Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] active Initial value of active characteristic - * @param[in] prog_mode Initial value of Program Mode characteristic - * @param[in] in_use Initial value of In Use characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_irrigation_system_create(uint8_t active, uint8_t prog_mode, uint8_t in_use); - -/** Create Valve Service - * - * This API will create the Valve Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] active Initial value of active characteristic - * @param[in] in_use Initial value of In Use characteristic - * @param[in] valve_type Initial value of Valve Type characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_valve_create(uint8_t active, uint8_t in_use, uint8_t valve_type); - -/** Create Faucet Service - * - * This API will create the Faucet Service with the mandatory - * characteristics as per the HAP Specs. - * - * @param[in] active Initial value of active characteristic - * - * @return Pointer to the service object on success - * @return NULL on failure - */ -hap_serv_t *hap_serv_faucet_create(uint8_t active); - - -hap_serv_t *hap_serv_wattage_create(float curr_watts); - -#ifdef __cplusplus -} -#endif - -#endif /* _HAP_APPLE_SERVS_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_bct.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_bct.h deleted file mode 100644 index 6a65e5588..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_bct.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_BCT_H_ -#define _HAP_BCT_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Change the name of the Bonjour Service for BCT - * - * This is required as per the "Manual Name Change" step of "Tester Interaction" - * section of Bonjour Conformance Test. - * - * @param[in] name The desired new name for the service. For BCT 1.4 or earlier: "New - Bonjour Service Name". - * For BCT 1.5 or later: "New-BCT" - */ -void hap_bct_change_name(const char *name); - -/** - * @brief Trigger a Hot plug of the network interface for BCT - * - * This is required as per the "Cable Change Handling" and "Hot Plugging" steps - * of "Tester Interaction" section of Bonjout Conformance Test - */ -void hap_bct_hot_plug(); - -#ifdef __cplusplus -} -#endif - -#endif /* _HAP_BCT_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.c deleted file mode 100644 index 7d19b62e8..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include <_esp_hap_config.h> - -httpd_handle_t *int_handle; -int hap_platform_httpd_start(httpd_handle_t *handle) -{ - httpd_config_t config = { - .task_priority = tskIDLE_PRIORITY+5, - .stack_size = CONFIG_HAP_HTTP_STACK_SIZE, - .server_port = CONFIG_HAP_HTTP_SERVER_PORT, - .ctrl_port = CONFIG_HAP_HTTP_CONTROL_PORT, - .max_open_sockets = CONFIG_HAP_HTTP_MAX_OPEN_SOCKETS, - .max_uri_handlers = CONFIG_HAP_HTTP_MAX_URI_HANDLERS, - .max_resp_headers = 8, - .backlog_conn = 5, - .lru_purge_enable = true, - .recv_wait_timeout = 5, - .send_wait_timeout = 5, - }; - esp_err_t err = httpd_start(handle, &config); - if (err == ESP_OK) { - int_handle = handle; - } - return err; -} - -int hap_platform_httpd_stop(httpd_handle_t *handle) -{ - esp_err_t err = httpd_stop(*handle); - if (err == ESP_OK) { - int_handle = NULL; - } - return err; -} - -int hap_platform_httpd_get_port() -{ - return CONFIG_HAP_HTTP_SERVER_PORT; -} - -void * hap_platform_httpd_get_sess_ctx(httpd_req_t *req) -{ - if (req) { - return req->sess_ctx; - } - return NULL; -} - -esp_err_t hap_platform_httpd_set_sess_ctx(httpd_req_t *req, void *ctx, httpd_free_ctx_fn_t free_ctx, bool ignore_ctx_changes) -{ - if (req) { - req->sess_ctx = ctx; - req->free_ctx = free_ctx; -#ifndef CONFIG_IDF_TARGET_ESP8266 - req->ignore_sess_ctx_changes = ignore_ctx_changes; -#endif - return ESP_OK; - } - return ESP_FAIL; -} - -static const char * hap_platform_httpd_rqtype_to_string(int method) -{ - switch (method) { - case HTTP_GET: - return "GET"; - case HTTP_POST: - return "POST"; - case HTTP_PUT: - return "PUT"; - default: - return "INVALID"; - } -} - -const char *hap_platform_httpd_get_req_method(httpd_req_t *req) -{ - if (req) { - return hap_platform_httpd_rqtype_to_string(req->method); - } - return NULL; -} - -const char *hap_platform_httpd_get_req_uri(httpd_req_t *req) -{ - if (req) { - return req->uri; - } - return NULL; -} - -int hap_platform_httpd_get_content_len(httpd_req_t *req) -{ - if (req) { - return req->content_len; - } - return -1; -} - -httpd_handle_t *hap_platform_httpd_get_handle() -{ - return int_handle; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.h deleted file mode 100644 index ce5b0dc1f..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_httpd.h +++ /dev/null @@ -1,136 +0,0 @@ - -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_PLATFORM_HTTPD_H_ -#define _HAP_PLATFORM_HTTPD_H_ -#include -#ifdef __cplusplus -extern "C" { -#endif - -/** Start the webserver - * - * This API will be called by the HAP Core to start the webserver. - * - * @param[out] handle Pointer to the handle that should be populated by this - * function on a success. - * - * @return ESP_OK on success - * @return error code otherwise - */ -int hap_platform_httpd_start(httpd_handle_t *handle); - -/** Stop the webserver - * - * This API will be called by the HAP Core to stop the webserver. - * - * @param[in] handle Pointer to the handle created in hap_platform_httpd_start - * - * @return ESP_OK on success - * @return error code otherwise - */ -int hap_platform_httpd_stop(httpd_handle_t *handle); - -/** Get the current HTTP Port - * - * This API will be called by the HAP Core to get the HTTP Port being used. This will - * be used for the mDNS announcement - * - * @return Configured HTTP Port - */ -int hap_platform_httpd_get_port(); - -/** Get the HTTPD session context - * - * This API will be called by the HAP Core to get the context associated with a given - * session. It is generally used to maintain pairing information. - * - * @param[in] req HTTPD Request structure. - * - * @return pointer to the session context. - */ -void * hap_platform_httpd_get_sess_ctx(httpd_req_t *req); - -/** Set the HTTPD session context - * - * This API will be called by the HAP Core to set the context associated with a given - * session. It is generally used to maintain pairing information. - * - * @param[in] req HTTPD Request structure. - * @param[in] ctx The context to be set for the given session. - * @param[in] free_fn Pointer to a function that will be used by the HTTP Server to clear the context when the session closes - * @param[in] ignore_ctx_changes Flag to indicate if the HTTP Server should ignore changes to the context across different requests. - * If set to false, the server will try clearing the old context, if it detects any change. - * - * @return ESP_OK in success - * @return ESP_FAIL if req is nULL - */ -esp_err_t hap_platform_httpd_set_sess_ctx(httpd_req_t *req, void *ctx, httpd_free_ctx_fn_t free_ctx, bool ignore_ctx_changes); - -/** Get the HTTP request method - * - * This API will be called by the HAP Core to get the HTTP request method - * in string format (Eg. GET, POST, etc.) - * - * @param[in] HTTPD Request structure. - * - * @return Pointer to a string indicating the HTTP method. - */ -const char *hap_platform_httpd_get_req_method(httpd_req_t *req); - -/** Get the HTTP request URI - * - * This API will be called by the HAP Core to get the request URI string. - * - * @param[in] HTTPD Request structure. - * - * @return Pointer to the URI string. - */ -const char *hap_platform_httpd_get_req_uri(httpd_req_t *req); - -/** Get the HTTP request content length - * - * This API will be called by the HAP Core to get the content length of the request. - * - * @param[in] HTTPD Request structure. - * - * @return Content length. - */ -int hap_platform_httpd_get_content_len(httpd_req_t *req); - -/** - * Get the HAP HTTPD Handle - * - * If an application wants to register additional HTTPD endpoints on the same server - * instance being used by HomeKit, this API can be used to get the handle. This - * should be used only after hap_start(). - * - * @return HomeKit HTTPD Handle - */ -httpd_handle_t *hap_platform_httpd_get_handle(); - -#ifdef __cplusplus -} -#endif -#endif /* _HAP_PLATFORM_HTTPD_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.cpp b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.cpp deleted file mode 100755 index 8e4656ea1..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - - -#include -#include -#include -#include - -#define HAP_PLATFORM_DEF_NVS_PARTITION "nvs" -#define HAP_PLATFORM_DEF_FACTORY_NVS_PARTITION "factory_nvs" - -extern "C" { - -static const char *TAG = "hap_platform_keystore"; - -const char * hap_platform_keystore_get_nvs_partition_name() { - return HAP_PLATFORM_DEF_NVS_PARTITION; -} - -const char * hap_platform_keystore_get_factory_nvs_partition_name() { - return HAP_PLATFORM_DEF_FACTORY_NVS_PARTITION; -} - -#define HAP_USE_LITTLEFS - -#ifdef HAP_USE_LITTLEFS - -#include - -extern FS *ffsp; - -int hap_platform_keystore_init_partition(const char *part_name, bool read_only) { - return 0; -} - -int hap_platform_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size) { - char path[48]; - strcpy(path, "/"); - strcat(path, part_name); - - File fp = ffsp->open(path, "r"); - if (!fp) { - ffsp->mkdir(path); - return -1; - } - fp.close(); - - strcat(path, "/"); - strcat(path, name_space); - fp = ffsp->open(path, "r"); - if (!fp) { - ffsp->mkdir(path); - return -1; - } - fp.close(); - - strcat(path, "/"); - strcat(path, key); - fp = ffsp->open(path, "r"); - if (fp) { - fp.read(val, *val_size); - fp.close(); - } else { - *val_size = 0; - return -1; - } - return 0; -} - -int hap_platform_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len) { - char path[48]; - strcpy(path, "/"); - strcat(path, part_name); - - File fp = ffsp->open(path, "r"); - if (!fp) { - ffsp->mkdir(path); - } - fp.close(); - - strcat(path, "/"); - strcat(path, name_space); - fp = ffsp->open(path, "r"); - if (!fp) { - ffsp->mkdir(path); - } - fp.close(); - - strcat(path, "/"); - strcat(path, key); - fp = ffsp->open(path, "w"); - if (fp) { - fp.write(val, val_len); - fp.close(); - } else { - return -1; - } - return 0; -} - -int hap_platform_keystore_delete(const char *part_name, const char *name_space, const char *key) { - char path[48]; - strcpy(path, "/"); - strcat(path, part_name); - strcat(path, "/"); - strcat(path, name_space); - strcat(path, "/"); - strcat(path, key); - ffsp->remove(path); - return 0; -} - -// should -int hap_platform_keystore_delete_namespace(const char *part_name, const char *name_space) { - char path[48]; - strcpy(path, "/"); - strcat(path, part_name); - strcat(path, "/"); - strcat(path, name_space); - File fp = ffsp->open(path, "r"); - if (fp.isDirectory()) { - while (true) { - File entry = fp.openNextFile(); - if (!entry) break; - char p[48]; - strcpy(p,entry.name()); - entry.close(); - ffsp->remove(p); - } - } - return 0; -} - -// last resort only -int hap_platfrom_keystore_erase_partition(const char *part_name) { -char path[48]; -strcpy(path, "/"); -strcat(path, part_name); -File fp = ffsp->open(path, "r"); -if (fp.isDirectory()) { - while (true) { - File entry = fp.openNextFile(); - if (!entry) break; - const char *ep = entry.name(); - if (*ep=='/') ep++; - char *lcp = strrchr(ep,'/'); - if (lcp) { - ep = lcp + 1; - } - char p[48]; - strcpy(p,entry.name()); - if (entry.isDirectory()) { - hap_platform_keystore_delete_namespace(part_name, ep); - entry.close(); - ffsp->rmdir(p); - } else { - entry.close(); - ffsp->remove(p); - } - - } -} - return 0; -} - -#else - -#ifdef CONFIG_NVS_ENCRYPTION -int hap_platform_keystore_init_partition(const char *part_name, bool read_only) -{ - esp_err_t err; - nvs_sec_cfg_t *cfg = NULL; - nvs_sec_cfg_t sec_cfg; - esp_partition_iterator_t iterator = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS, NULL); - if (iterator) { - const esp_partition_t *partition = esp_partition_get(iterator); - err = nvs_flash_read_security_cfg(partition, &sec_cfg); - if (err == ESP_OK) { - cfg = &sec_cfg; - } else { - ESP_LOGE(TAG, "No NVS keys found"); - } - } else { - ESP_LOGE(TAG, "No NVS keys partition found"); - } - if (!cfg) { - ESP_LOGE(TAG, "NVS partition '%s' not encrypted", part_name); - } else { - ESP_LOGI(TAG, "NVS partition '%s' is encrypted", part_name); - } - if (read_only) { - err = nvs_flash_secure_init_partition(part_name, cfg); - } else { - err = nvs_flash_secure_init_partition(part_name, cfg); - if (err == ESP_ERR_NVS_NO_FREE_PAGES) { - ESP_ERROR_CHECK(nvs_flash_erase_partition(part_name)); - err = nvs_flash_secure_init_partition(part_name, cfg); - } - } - if (err == ESP_OK) { - return 0; - } - return -1; -} -#else -int hap_platform_keystore_init_partition(const char *part_name, bool read_only) -{ - esp_err_t err; - if (read_only) { - err = nvs_flash_init_partition(part_name); - } else { - err = nvs_flash_init_partition(part_name); - if (err == ESP_ERR_NVS_NO_FREE_PAGES) { - ESP_ERROR_CHECK(nvs_flash_erase_partition(part_name)); - err = nvs_flash_init_partition(part_name); - } - } - if (err == ESP_OK) { - return 0; - } - return -1; -} -#endif /* CONFIG_NVS_ENCRYPTION */ - -int hap_platform_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size) -{ - nvs_handle handle; - esp_err_t err = nvs_open_from_partition(part_name, name_space, NVS_READONLY, &handle); - if (err != ESP_OK) { - return -1; - } else { - err = nvs_get_blob(handle, key, val, val_size); - nvs_close(handle); - } - if (err == ESP_OK) { - return 0; - } - return -1; -} - -int hap_platform_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len) - -{ - nvs_handle handle; - esp_err_t err = nvs_open_from_partition(part_name, name_space, NVS_READWRITE, &handle); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Error (%d) opening NVS handle!", err); - } else { - err = nvs_set_blob(handle, key, val, val_len); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to write %s", key); - } else { - nvs_commit(handle); - } - nvs_close(handle); - } - if (err == ESP_OK) { - return 0; - } - return -1; -} - -int hap_platform_keystore_delete(const char *part_name, const char *name_space, const char *key) -{ - nvs_handle handle; - esp_err_t err = nvs_open_from_partition(part_name, name_space, NVS_READWRITE, &handle); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Error (%d) opening NVS handle!", err); - } else { - err = nvs_erase_key(handle, key); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to delete %s", key); - } else { - nvs_commit(handle); - } - nvs_close(handle); - } - if (err == ESP_OK) { - return 0; - } - return -1; -} - -int hap_platform_keystore_delete_namespace(const char *part_name, const char *name_space) -{ - nvs_handle handle; - esp_err_t err = nvs_open_from_partition(part_name, name_space, NVS_READWRITE, &handle); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Error (%d) opening NVS handle!", err); - } else { - err = nvs_erase_all(handle); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to delete %s", name_space); - } else { - nvs_commit(handle); - } - nvs_close(handle); - } - if (err == ESP_OK) { - return 0; - } - return -1; -} - -int hap_platfrom_keystore_erase_partition(const char *part_name) -{ - esp_err_t err = nvs_flash_erase_partition(part_name); - if (err == ESP_OK) { - return 0; - } - return -1; -} -#endif // USE_LITTLEFS - -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.h deleted file mode 100644 index 6be1c47cb..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_keystore.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _HAP_PLATFORM_KEYSTORE_H_ -#define _HAP_PLATFORM_KEYSTORE_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** Get NVS Partition Name - * - * @return pointer to an allocated string indicating NVS partition Name - */ -char * hap_platform_keystore_get_nvs_partition_name(); - - -/** Get Factory NVS Partition Name - * - * @return pointer to an allocated string indicating Factory NVS partition Name - */ -char * hap_platform_keystore_get_factory_nvs_partition_name(); - -/** Initialise Key Store Partition - * - * @param[in] part_name Name of Partition - * @param[in] read_only True for Read-Only, False for Read-Write - * - * @return 0 on success - * @return -1 on error - */ -int hap_platform_keystore_init_partition(const char *part_name, bool read_only); - -/** Get Value from Key Store - * - * @param[in] part_name Name of Partition - * @param[in] name_space Name space for the key - * @param[in] key Name of the key - * @param[out] val Allocated buffer into which the value will be read - * @param[in,out] val_size Size of the allocated value buffer. Will hold the size of value read on success - * - * @return 0 on success - * @return -1 on error - */ -int hap_platform_keystore_get(const char *part_name, const char *name_space, const char *key, uint8_t *val, size_t *val_size); - -/** Set Value in Key Store - * - * @param[in] part_name Name of Partition - * @param[in] name_space Name space for the key - * @param[in] key Name of the key - * @param[in] val Pointer to the value buffer - * @param[in] val_len Length of the value buffer - * - * @return 0 on success - * @return -1 on error - */ -int hap_platform_keystore_set(const char *part_name, const char *name_space, const char *key, const uint8_t *val, const size_t val_len); - -/** Delete Entry from Key Store - * - * @param[in] part_name Name of Partition - * @param[in] name_space Name space for the key - * @param[in] key Name of the key - * - * @return 0 on success - * @return -1 on error - */ -int hap_platform_keystore_delete(const char *part_name, const char *name_space, const char *key); - -/** Delete Name space from Key Store - * - * @param[in] part_name Name of Partition - * @param[in] name_space Name space for the key - * - * @return 0 on success - * @return -1 on error - */ -int hap_platform_keystore_delete_namespace(const char *part_name, const char *name_space); - -/** Erase a Key Store partition - * - * @param[in] part_name Name of Partition - * - * @return 0 on success - * @return -1 on error - */ -int hap_platfrom_keystore_erase_partition(const char *part_name); -#ifdef __cplusplus -} -#endif -#endif /* _HAP_PLATFORM_KEYSTORE_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_memory.cpp b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_memory.cpp deleted file mode 100644 index ad63fc0fc..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_memory.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include - -//Tasmota Patch -extern void *special_malloc(uint32_t size); -extern void *special_calloc(size_t num, size_t size); - -extern "C" { -void * hap_platform_memory_malloc(size_t size) -{ - return special_malloc((uint32_t)size); - // return malloc(size); -} - -void * hap_platform_memory_calloc(size_t count, size_t size) -{ - return special_calloc(count,size); - // return calloc(count, size); -} - -void hap_platform_memory_free(void *ptr) -{ - free(ptr); -} -} //extern "C" \ No newline at end of file diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_memory.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_memory.h deleted file mode 100644 index ce8f39ec2..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_memory.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_PLATFORM_MEMORY_H_ -#define _HAP_PLATFORM_MEMORY_H_ -#include -#ifdef __cplusplus -extern "C" { -#endif - - -/** Allocate memory - * - * This API allocates "size" bytes of memory and returns a pointer to the allocated memory. - * - * @param[in] size Number of bytes to be allocated - * - * @return pointer to the allocated memory - * @return NULL on failure - */ -void * hap_platform_memory_malloc(size_t size); - -/** Allocate contiguous memory for items - * - * This API contiguously allocates enough space for "count" objects that are "size" bytes of memory each - * and returns a pointer to the allocated memory. The allocated memory is filled with bytes of value zero. - * - * @param[in] count Number of items - * @param[in] size Size of each item - * - * @return pointer to the allocated memory - * @return NULL on failure - */ -void * hap_platform_memory_calloc(size_t count, size_t size); - -/** Free allocate memory - * - * This API frees the memory allocated by hap_platform_memory_malloc() or hap_platform_memory_calloc() - * - * @param[in] ptr Pointer to the allocated memory - */ -void hap_platform_memory_free(void *ptr); - -#ifdef __cplusplus -} -#endif -#endif /* _HAP_PLATFORM_MEMORY_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_os.c b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_os.c deleted file mode 100644 index 29e23b11b..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_os.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include -#include -#include -#include - -uint16_t hap_platform_os_get_msec_per_tick() -{ - return portTICK_PERIOD_MS; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_os.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_os.h deleted file mode 100644 index 1270ba76d..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_platform_os.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2019 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#ifndef _HAP_PLATFORM_OS_H_ -#define _HAP_PLATFORM_OS_H_ -#include -#ifdef __cplusplus -extern "C" { -#endif - - -/** Return the OS tick period in milliseconds - * - * @return the milliseconds per tick as configured for the OS - */ -uint16_t hap_platform_os_get_msec_per_tick(); - -#ifdef __cplusplus -} -#endif -#endif /* _HAP_PLATFORM_OS_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hap_wac.h b/lib/libesp32_div/ESP32-HomeKit/src/hap_wac.h deleted file mode 100644 index e106c2389..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hap_wac.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * ESPRESSIF MIT License - * - * Copyright (c) 2020 - * - * Permission is hereby granted for use on ESPRESSIF SYSTEMS products only, in which case, - * it is free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished - * to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef _HAP_WAC_H_ -#define _HAP_WAC_H_ -#include -#include -#include -#include -/** HomeKit Event Base */ -ESP_EVENT_DECLARE_BASE(HAP_WAC_EVENT); -/** HomeKit Events */ -typedef enum { - /* WAC has started. Associated data is NULL */ - HAP_WAC_EVENT_STARTED, - /** WAC has timed out because of inactivity. Associated data is NULL. - * Appropriate indications should be given to the user, so that the accessory can be rebooted - * for restarting WAC. - */ - HAP_WAC_EVENT_TIMEOUT, - /** WAC was successful and will stop after some time. Associated data is NULL. - */ - HAP_WAC_EVENT_SUCCESS, - /** WAC is requesting to start SoftAP. Associated data is a pointer to a NULL terminated SSID. - * Using this SSID isn't required, but recommended. The network security should be "Open" for - * WAC to work. If SoftAP has already been started, nothing needs to be done for this event. - * The helper function hap_wifi_softap_start() can be used for this. - */ - HAP_WAC_EVENT_REQ_SOFTAP_START, - /** WAC is requesting to stop SoftAP. Associated data is NULL. - * The helper function hap_wifi_softap_stop() can be used for this. - */ - HAP_WAC_EVENT_REQ_SOFTAP_STOP, - /** WAC has received the Wi-Fi credentials. Associated data is a pointer to wifi_config_t - * structure. This should be used to connect to the Wi-Fi network. - * The helper function hap_wifi_sta_connect() can be used for this. - */ - HAP_WAC_EVENT_RECV_CRED, - /** WAC has stopped */ - HAP_WAC_EVENT_STOPPED -} hap_wac_event_t; - -/** Start WAC Provisioning. - * - * This should be called when the accessory boots up in an unprovisioned mode. - * The helper function hap_wifi_is_provisioned() function can be used to find - * if the accessory is provisioned or not. - * - * @return 0 on success. - * @return -1 on failure. - */ -int hap_wac_start(void); - -/** Stop WAC Provisioning. - * - * This should be used only if WAC needs to be stopped explicitly (say, after - * provisioning was done using some other means). Else, WAC stops automatically, - * either after the timeout or after successful provisioning. - * - * @return 0 on success. - * @return -1 on failure. - */ -int hap_wac_stop(void); - -/** Check is accessory is provisioned - * - * @param[out] provisioned Pointer to an allocated boolean variable. Will - * be set to true if accessory is provisioned, else false. - * - * @return ESP_OK on success. - * @return error on failure. - */ -esp_err_t hap_wifi_is_provisioned(bool *provisioned); - -/** Start SoftAP - * - * @param[in] ssid NULL terminated ssid string. - * - * @return ESP_OK on success. - * @return error on failure. - */ -esp_err_t hap_wifi_softap_start(char *ssid); - -/** Stop Soft AP - * - * @return ESP_OK on success. - * @return error on failure. - */ -esp_err_t hap_wifi_softap_stop(void); - -/** Connect to Wi-Fi network with given configuration - * - * @param[in] config Pointer to \ref wifi_config_t structure. - * - * @return ESP_OK on success. - * @return error on failure. - */ -esp_err_t hap_wifi_sta_connect(wifi_config_t *config); - -#endif /* _HAP_WAC_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hexbin.c b/lib/libesp32_div/ESP32-HomeKit/src/hexbin.c deleted file mode 100644 index 745152519..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hexbin.c +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include -static int hex2bin_byte(uint8_t *byte) -{ - if (*byte >= '0' && *byte <= '9') - *byte -= '0'; - else if (*byte >= 'a' && *byte <= 'f') - *byte -= ('a' - 0x0a); - else if (*byte >= 'A' && *byte <= 'F') - *byte -= ('A' - 0x0a); - else - return -1; - return 0; -} - -int hex2bin(const char *ihex, size_t ilen, uint8_t *obin, size_t *olen) -{ - if (ilen > (2 * (*olen))) { - return -1; - } else if (ilen % 2) { - return -1; - } - int i, j; - uint8_t byte; - for (i = 0, j = 0; i < ilen / 2; i++) { - byte = ihex[j++]; - if (hex2bin_byte(&byte) < 0) { - return -1; - } - obin[i] = (byte << 4); - byte = ihex[j++]; - if (hex2bin_byte(&byte) < 0) { - return -1; - } - obin[i] |= byte; - } - *olen = i; - return 0; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hexbin.h b/lib/libesp32_div/ESP32-HomeKit/src/hexbin.h deleted file mode 100644 index ced744bab..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hexbin.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef _HEXBIN_H_ -#define _HEXBIN_H_ -#include -#include -int hex2bin(const char *ihex, size_t ilen, uint8_t *obin, size_t *olen); -#endif /* _HEXBIN_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hexdump.c b/lib/libesp32_div/ESP32-HomeKit/src/hexdump.c deleted file mode 100644 index dfa3a56fe..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hexdump.c +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include - -//#define HEX_DBG_ENABLE - -#ifdef HEX_DBG_ENABLE -void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len) -{ - int i; - printf("%s: ", name); - for (i = 0; i < buf_len; i++) { - if (i % 16 == 0) - printf("\r\n"); - printf("%02x ", buf[i]); - } - printf("\r\n"); -} -#else -void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len) -{ -} -#endif /* HEX_DBG_ENABLED */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hexdump.h b/lib/libesp32_div/ESP32-HomeKit/src/hexdump.h deleted file mode 100644 index e6b0009e5..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hexdump.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef _HEXDUMP_H_ -#define _HEXDUMP_H_ -void hex_dbg_with_name(const char *name, unsigned char *buf, int buf_len); - -#endif /* _HEXDUMP_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hkdf-sha.h b/lib/libesp32_div/ESP32-HomeKit/src/hkdf-sha.h deleted file mode 100644 index 276c3685b..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hkdf-sha.h +++ /dev/null @@ -1,358 +0,0 @@ -/**************************** sha.h ****************************/ -/***************** See RFC 6234 for details. *******************/ -/* - Copyright (c) 2011 IETF Trust and the persons identified as - authors of the code. All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - - Redistributions of source code must retain the above - copyright notice, this list of conditions and - the following disclaimer. - - - Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - - Neither the name of Internet Society, IETF or IETF Trust, nor - the names of specific contributors, may be used to endorse or - promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef _SHA_H_ -#define _SHA_H_ - -/* - * Description: - * This file implements the Secure Hash Algorithms - * as defined in the U.S. National Institute of Standards - * and Technology Federal Information Processing Standards - * Publication (FIPS PUB) 180-3 published in October 2008 - * and formerly defined in its predecessors, FIPS PUB 180-1 - * and FIP PUB 180-2. - * - * A combined document showing all algorithms is available at - * http://csrc.nist.gov/publications/fips/ - * fips180-3/fips180-3_final.pdf - * - * The five hashes are defined in these sizes: - * SHA-1 20 byte / 160 bit - * SHA-224 28 byte / 224 bit - * SHA-256 32 byte / 256 bit - * SHA-384 48 byte / 384 bit - * SHA-512 64 byte / 512 bit - * - * Compilation Note: - * These files may be compiled with two options: - * USE_32BIT_ONLY - use 32-bit arithmetic only, for systems - * without 64-bit integers - * - * USE_MODIFIED_MACROS - use alternate form of the SHA_Ch() - * and SHA_Maj() macros that are equivalent - * and potentially faster on many systems - * - */ - -#include -/* - * If you do not have the ISO standard stdint.h header file, then you - * must typedef the following: - * name meaning - * uint64_t unsigned 64-bit integer - * uint32_t unsigned 32-bit integer - * uint8_t unsigned 8-bit integer (i.e., unsigned char) - * int_least16_t integer of >= 16 bits - * - * See stdint-example.h - */ - -#ifndef _SHA_enum_ -#define _SHA_enum_ -/* - * All SHA functions return one of these values. - */ -enum { - shaSuccess = 0, - shaNull, /* Null pointer parameter */ - shaInputTooLong, /* input data too long */ - shaStateError, /* called Input after FinalBits or Result */ - shaBadParam /* passed a bad parameter */ -}; -#endif /* _SHA_enum_ */ - -/* - * These constants hold size information for each of the SHA - * hashing operations - */ -enum { - SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, - SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128, - SHA512_Message_Block_Size = 128, - USHA_Max_Message_Block_Size = SHA512_Message_Block_Size, - - SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, - SHA384HashSize = 48, SHA512HashSize = 64, - USHAMaxHashSize = SHA512HashSize, - - SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, - SHA256HashSizeBits = 256, SHA384HashSizeBits = 384, - SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits -}; - -/* - * These constants are used in the USHA (Unified SHA) functions. - */ -typedef enum SHAversion { - SHA1, SHA224, SHA256, SHA384, SHA512 -} SHAversion; - -/* - * This structure will hold context information for the SHA-1 - * hashing operation. - */ -typedef struct SHA1Context { - uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ - - uint32_t Length_High; /* Message length in bits */ - uint32_t Length_Low; /* Message length in bits */ - - int_least16_t Message_Block_Index; /* Message_Block array index */ - /* 512-bit message blocks */ - uint8_t Message_Block[SHA1_Message_Block_Size]; - - int Computed; /* Is the hash computed? */ - int Corrupted; /* Cumulative corruption code */ -} SHA1Context; - -/* - * This structure will hold context information for the SHA-256 - * hashing operation. - */ -typedef struct SHA256Context { - uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */ - - uint32_t Length_High; /* Message length in bits */ - uint32_t Length_Low; /* Message length in bits */ - - int_least16_t Message_Block_Index; /* Message_Block array index */ - /* 512-bit message blocks */ - uint8_t Message_Block[SHA256_Message_Block_Size]; - - int Computed; /* Is the hash computed? */ - int Corrupted; /* Cumulative corruption code */ -} SHA256Context; - -/* - * This structure will hold context information for the SHA-512 - * hashing operation. - */ -typedef struct SHA512Context { -#ifdef USE_32BIT_ONLY - uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */ - uint32_t Length[4]; /* Message length in bits */ -#else /* !USE_32BIT_ONLY */ - uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */ - uint64_t Length_High, Length_Low; /* Message length in bits */ -#endif /* USE_32BIT_ONLY */ - - int_least16_t Message_Block_Index; /* Message_Block array index */ - /* 1024-bit message blocks */ - uint8_t Message_Block[SHA512_Message_Block_Size]; - - int Computed; /* Is the hash computed?*/ - int Corrupted; /* Cumulative corruption code */ -} SHA512Context; - -/* - * This structure will hold context information for the SHA-224 - * hashing operation. It uses the SHA-256 structure for computation. - */ -typedef struct SHA256Context SHA224Context; - -/* - * This structure will hold context information for the SHA-384 - * hashing operation. It uses the SHA-512 structure for computation. - */ -typedef struct SHA512Context SHA384Context; - -/* - * This structure holds context information for all SHA - * hashing operations. - */ -typedef struct USHAContext { - int whichSha; /* which SHA is being used */ - union { - SHA1Context sha1Context; - SHA224Context sha224Context; SHA256Context sha256Context; - SHA384Context sha384Context; SHA512Context sha512Context; - } ctx; - -} USHAContext; - -/* - * This structure will hold context information for the HMAC - * keyed-hashing operation. - */ -typedef struct HMACContext { - int whichSha; /* which SHA is being used */ - int hashSize; /* hash size of SHA being used */ - int blockSize; /* block size of SHA being used */ - USHAContext shaContext; /* SHA context */ - unsigned char k_opad[USHA_Max_Message_Block_Size]; - /* outer padding - key XORd with opad */ - int Computed; /* Is the MAC computed? */ - int Corrupted; /* Cumulative corruption code */ - -} HMACContext; - -/* - * This structure will hold context information for the HKDF - * extract-and-expand Key Derivation Functions. - */ -typedef struct HKDFContext { - int whichSha; /* which SHA is being used */ - HMACContext hmacContext; - int hashSize; /* hash size of SHA being used */ - unsigned char prk[USHAMaxHashSize]; - /* pseudo-random key - output of hkdfInput */ - int Computed; /* Is the key material computed? */ - int Corrupted; /* Cumulative corruption code */ -} HKDFContext; - -/* - * Function Prototypes - */ - -/* SHA-1 */ -extern int SHA1Reset(SHA1Context *); -extern int SHA1Input(SHA1Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA1FinalBits(SHA1Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA1Result(SHA1Context *, - uint8_t Message_Digest[SHA1HashSize]); - -/* SHA-224 */ -extern int SHA224Reset(SHA224Context *); -extern int SHA224Input(SHA224Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA224FinalBits(SHA224Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA224Result(SHA224Context *, - uint8_t Message_Digest[SHA224HashSize]); - -/* SHA-256 */ -extern int SHA256Reset(SHA256Context *); -extern int SHA256Input(SHA256Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA256FinalBits(SHA256Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA256Result(SHA256Context *, - uint8_t Message_Digest[SHA256HashSize]); - -/* SHA-384 */ -extern int SHA384Reset(SHA384Context *); -extern int SHA384Input(SHA384Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA384FinalBits(SHA384Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA384Result(SHA384Context *, - uint8_t Message_Digest[SHA384HashSize]); - -/* SHA-512 */ -extern int SHA512Reset(SHA512Context *); -extern int SHA512Input(SHA512Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA512FinalBits(SHA512Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA512Result(SHA512Context *, - uint8_t Message_Digest[SHA512HashSize]); - -/* Unified SHA functions, chosen by whichSha */ -extern int USHAReset(USHAContext *context, SHAversion whichSha); -extern int USHAInput(USHAContext *context, - const uint8_t *bytes, unsigned int bytecount); -extern int USHAFinalBits(USHAContext *context, - uint8_t bits, unsigned int bit_count); -extern int USHAResult(USHAContext *context, - uint8_t Message_Digest[USHAMaxHashSize]); -extern int USHABlockSize(enum SHAversion whichSha); -extern int USHAHashSize(enum SHAversion whichSha); -extern int USHAHashSizeBits(enum SHAversion whichSha); -extern const char *USHAHashName(enum SHAversion whichSha); - -/* - * HMAC Keyed-Hashing for Message Authentication, RFC 2104, - * for all SHAs. - * This interface allows a fixed-length text input to be used. - */ -extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */ - const unsigned char *text, /* pointer to data stream */ - int text_len, /* length of data stream */ - const unsigned char *key, /* pointer to authentication key */ - int key_len, /* length of authentication key */ - uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ - -/* - * HMAC Keyed-Hashing for Message Authentication, RFC 2104, - * for all SHAs. - * This interface allows any length of text input to be used. - */ -extern int hmacReset(HMACContext *context, enum SHAversion whichSha, - const unsigned char *key, int key_len); -extern int hmacInput(HMACContext *context, const unsigned char *text, - int text_len); -extern int hmacFinalBits(HMACContext *context, uint8_t bits, - unsigned int bit_count); -extern int hmacResult(HMACContext *context, - uint8_t digest[USHAMaxHashSize]); - -/* - * HKDF HMAC-based Extract-and-Expand Key Derivation Function, - * RFC 5869, for all SHAs. - */ -extern int hkdf(SHAversion whichSha, const unsigned char *salt, - int salt_len, const unsigned char *ikm, int ikm_len, - const unsigned char *info, int info_len, - uint8_t okm[ ], int okm_len); -extern int hkdfExtract(SHAversion whichSha, const unsigned char *salt, - int salt_len, const unsigned char *ikm, - int ikm_len, uint8_t prk[USHAMaxHashSize]); -extern int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], - int prk_len, const unsigned char *info, - int info_len, uint8_t okm[ ], int okm_len); - -/* - * HKDF HMAC-based Extract-and-Expand Key Derivation Function, - * RFC 5869, for all SHAs. - * This interface allows any length of text input to be used. - */ -extern int hkdfReset(HKDFContext *context, enum SHAversion whichSha, - const unsigned char *salt, int salt_len); -extern int hkdfInput(HKDFContext *context, const unsigned char *ikm, - int ikm_len); -extern int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, - unsigned int ikm_bit_count); -extern int hkdfResult(HKDFContext *context, - uint8_t prk[USHAMaxHashSize], - const unsigned char *info, int info_len, - uint8_t okm[USHAMaxHashSize], int okm_len); -#endif /* _SHA_H_ */ - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hkdf.c b/lib/libesp32_div/ESP32-HomeKit/src/hkdf.c deleted file mode 100644 index bd12ef2e1..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hkdf.c +++ /dev/null @@ -1,335 +0,0 @@ -/**************************** hkdf.c ***************************/ -/***************** See RFC 6234 for details. *******************/ -/* Copyright (c) 2011 IETF Trust and the persons identified as */ -/* authors of the code. All rights reserved. */ -/* See sha.h for terms of use and redistribution. */ - -/* - * Description: - * This file implements the HKDF algorithm (HMAC-based - * Extract-and-Expand Key Derivation Function, RFC 5869), - * expressed in terms of the various SHA algorithms. - */ - -#include "sha.h" -#include -#include - -/* - * hkdf - * - * Description: - * This function will generate keying material using HKDF. - * - * Parameters: - * whichSha: [in] - * One of SHA1, SHA224, SHA256, SHA384, SHA512 - * salt[ ]: [in] - * The optional salt value (a non-secret random value); - * if not provided (salt == NULL), it is set internally - * to a string of HashLen(whichSha) zeros. - * salt_len: [in] - * The length of the salt value. (Ignored if salt == NULL.) - * ikm[ ]: [in] - * Input keying material. - * ikm_len: [in] - * The length of the input keying material. - * info[ ]: [in] - * The optional context and application specific information. - * If info == NULL or a zero-length string, it is ignored. - * info_len: [in] - * The length of the optional context and application specific - * information. (Ignored if info == NULL.) - * okm[ ]: [out] - * Where the HKDF is to be stored. - * okm_len: [in] - * The length of the buffer to hold okm. - * okm_len must be <= 255 * USHABlockSize(whichSha) - * - * Notes: - * Calls hkdfExtract() and hkdfExpand(). - * - * Returns: - * sha Error Code. - * - */ -int hkdf(SHAversion whichSha, - const unsigned char *salt, int salt_len, - const unsigned char *ikm, int ikm_len, - const unsigned char *info, int info_len, - uint8_t okm[ ], int okm_len) -{ - uint8_t prk[USHAMaxHashSize]; - return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) || - hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info, - info_len, okm, okm_len); -} - -/* - * hkdfExtract - * - * Description: - * This function will perform HKDF extraction. - * - * Parameters: - * whichSha: [in] - * One of SHA1, SHA224, SHA256, SHA384, SHA512 - * salt[ ]: [in] - * The optional salt value (a non-secret random value); - * if not provided (salt == NULL), it is set internally - * to a string of HashLen(whichSha) zeros. - * salt_len: [in] - * The length of the salt value. (Ignored if salt == NULL.) - * ikm[ ]: [in] - * Input keying material. - * ikm_len: [in] - * The length of the input keying material. - * prk[ ]: [out] - * Array where the HKDF extraction is to be stored. - * Must be larger than USHAHashSize(whichSha); - * - * Returns: - * sha Error Code. - * - */ -int hkdfExtract(SHAversion whichSha, - const unsigned char *salt, int salt_len, - const unsigned char *ikm, int ikm_len, - uint8_t prk[USHAMaxHashSize]) -{ - unsigned char nullSalt[USHAMaxHashSize]; - if (salt == 0) { - salt = nullSalt; - salt_len = USHAHashSize(whichSha); - memset(nullSalt, '\0', salt_len); - } else if (salt_len < 0) { - return shaBadParam; - } - return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk); -} - -/* - * hkdfExpand - * - * Description: - * This function will perform HKDF expansion. - * - * Parameters: - * whichSha: [in] - * One of SHA1, SHA224, SHA256, SHA384, SHA512 - * prk[ ]: [in] - * The pseudo-random key to be expanded; either obtained - * directly from a cryptographically strong, uniformly - * distributed pseudo-random number generator, or as the - * output from hkdfExtract(). - * prk_len: [in] - * The length of the pseudo-random key in prk; - * should at least be equal to USHAHashSize(whichSHA). - * info[ ]: [in] - * The optional context and application specific information. - * If info == NULL or a zero-length string, it is ignored. - * info_len: [in] - * The length of the optional context and application specific - * information. (Ignored if info == NULL.) - * okm[ ]: [out] - * Where the HKDF is to be stored. - * okm_len: [in] - * The length of the buffer to hold okm. - * okm_len must be <= 255 * USHABlockSize(whichSha) - * - * Returns: - * sha Error Code. - * - */ -int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], int prk_len, - const unsigned char *info, int info_len, - uint8_t okm[ ], int okm_len) -{ - int hash_len, N; - unsigned char T[USHAMaxHashSize]; - int Tlen, where, i; - - if (info == 0) { - info = (const unsigned char *)""; - info_len = 0; - } else if (info_len < 0) { - return shaBadParam; - } - if (okm_len <= 0) return shaBadParam; - if (!okm) return shaBadParam; - - hash_len = USHAHashSize(whichSha); - if (prk_len < hash_len) return shaBadParam; - N = okm_len / hash_len; - if ((okm_len % hash_len) != 0) N++; - if (N > 255) return shaBadParam; - - Tlen = 0; - where = 0; - for (i = 1; i <= N; i++) { - HMACContext context; - unsigned char c = i; - int ret = hmacReset(&context, whichSha, prk, prk_len) || - hmacInput(&context, T, Tlen) || - hmacInput(&context, info, info_len) || - hmacInput(&context, &c, 1) || - hmacResult(&context, T); - if (ret != shaSuccess) return ret; - memcpy(okm + where, T, - (i != N) ? hash_len : (okm_len - where)); - where += hash_len; - Tlen = hash_len; - } - return shaSuccess; -} - -/* - * hkdfReset - * - * Description: - * This function will initialize the hkdfContext in preparation - * for key derivation using the modular HKDF interface for - * arbitrary length inputs. - * - * Parameters: - * context: [in/out] - * The context to reset. - * whichSha: [in] - * One of SHA1, SHA224, SHA256, SHA384, SHA512 - * salt[ ]: [in] - * The optional salt value (a non-secret random value); - * if not provided (salt == NULL), it is set internally - * to a string of HashLen(whichSha) zeros. - * salt_len: [in] - * The length of the salt value. (Ignored if salt == NULL.) - * - * Returns: - * sha Error Code. - * - */ -int hkdfReset(HKDFContext *context, enum SHAversion whichSha, - const unsigned char *salt, int salt_len) -{ - unsigned char nullSalt[USHAMaxHashSize]; - if (!context) return shaNull; - - context->whichSha = whichSha; - context->hashSize = USHAHashSize(whichSha); - if (salt == 0) { - salt = nullSalt; - salt_len = context->hashSize; - memset(nullSalt, '\0', salt_len); - } - - return hmacReset(&context->hmacContext, whichSha, salt, salt_len); -} - -/* - * hkdfInput - * - * Description: - * This function accepts an array of octets as the next portion - * of the input keying material. It may be called multiple times. - * - * Parameters: - * context: [in/out] - * The HKDF context to update. - * ikm[ ]: [in] - * An array of octets representing the next portion of - * the input keying material. - * ikm_len: [in] - * The length of ikm. - * - * Returns: - * sha Error Code. - * - */ -int hkdfInput(HKDFContext *context, const unsigned char *ikm, - int ikm_len) -{ - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - return hmacInput(&context->hmacContext, ikm, ikm_len); -} - -/* - * hkdfFinalBits - * - * Description: - * This function will add in any final bits of the - * input keying material. - * - * Parameters: - * context: [in/out] - * The HKDF context to update - * ikm_bits: [in] - * The final bits of the input keying material, in the upper - * portion of the byte. (Use 0b###00000 instead of 0b00000### - * to input the three bits ###.) - * ikm_bit_count: [in] - * The number of bits in message_bits, between 1 and 7. - * - * Returns: - * sha Error Code. - */ -int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, - unsigned int ikm_bit_count) -{ - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - return hmacFinalBits(&context->hmacContext, ikm_bits, ikm_bit_count); -} - -/* - * hkdfResult - * - * Description: - * This function will finish the HKDF extraction and perform the - * final HKDF expansion. - * - * Parameters: - * context: [in/out] - * The HKDF context to use to calculate the HKDF hash. - * prk[ ]: [out] - * An optional location to store the HKDF extraction. - * Either NULL, or pointer to a buffer that must be - * larger than USHAHashSize(whichSha); - * info[ ]: [in] - * The optional context and application specific information. - * If info == NULL or a zero-length string, it is ignored. - * info_len: [in] - * The length of the optional context and application specific - * information. (Ignored if info == NULL.) - * okm[ ]: [out] - * Where the HKDF is to be stored. - * okm_len: [in] - * The length of the buffer to hold okm. - * okm_len must be <= 255 * USHABlockSize(whichSha) - * - * Returns: - * sha Error Code. - * - */ -int hkdfResult(HKDFContext *context, - uint8_t prk[USHAMaxHashSize], - const unsigned char *info, int info_len, - uint8_t okm[ ], int okm_len) -{ - uint8_t prkbuf[USHAMaxHashSize]; - int ret; - - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - if (!okm) return context->Corrupted = shaBadParam; - if (!prk) prk = prkbuf; - - ret = hmacResult(&context->hmacContext, prk) || - hkdfExpand(context->whichSha, prk, context->hashSize, info, - info_len, okm, okm_len); - context->Computed = 1; - return context->Corrupted = ret; -} - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/hmac.c b/lib/libesp32_div/ESP32-HomeKit/src/hmac.c deleted file mode 100644 index b09c50e54..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/hmac.c +++ /dev/null @@ -1,249 +0,0 @@ -/**************************** hmac.c ***************************/ -/***************** See RFC 6234 for details. *******************/ -/* Copyright (c) 2011 IETF Trust and the persons identified as */ -/* authors of the code. All rights reserved. */ -/* See sha.h for terms of use and redistribution. */ - -/* - * Description: - * This file implements the HMAC algorithm (Keyed-Hashing for - * Message Authentication, [RFC 2104]), expressed in terms of - * the various SHA algorithms. - */ - -#include "sha.h" - -/* - * hmac - * - * Description: - * This function will compute an HMAC message digest. - * - * Parameters: - * whichSha: [in] - * One of SHA1, SHA224, SHA256, SHA384, SHA512 - * message_array[ ]: [in] - * An array of octets representing the message. - * Note: in RFC 2104, this parameter is known - * as 'text'. - * length: [in] - * The length of the message in message_array. - * key[ ]: [in] - * The secret shared key. - * key_len: [in] - * The length of the secret shared key. - * digest[ ]: [out] - * Where the digest is to be returned. - * NOTE: The length of the digest is determined by - * the value of whichSha. - * - * Returns: - * sha Error Code. - * - */ - -int hmac(SHAversion whichSha, - const unsigned char *message_array, int length, - const unsigned char *key, int key_len, - uint8_t digest[USHAMaxHashSize]) -{ - HMACContext context; - return hmacReset(&context, whichSha, key, key_len) || - hmacInput(&context, message_array, length) || - hmacResult(&context, digest); -} - -/* - * hmacReset - * - * Description: - * This function will initialize the hmacContext in preparation - * for computing a new HMAC message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * whichSha: [in] - * One of SHA1, SHA224, SHA256, SHA384, SHA512 - * key[ ]: [in] - * The secret shared key. - * key_len: [in] - * The length of the secret shared key. - * - * Returns: - * sha Error Code. - * - */ -int hmacReset(HMACContext *context, enum SHAversion whichSha, - const unsigned char *key, int key_len) -{ - int i, blocksize, hashsize, ret; - - /* inner padding - key XORd with ipad */ - unsigned char k_ipad[USHA_Max_Message_Block_Size]; - - /* temporary buffer when keylen > blocksize */ - unsigned char tempkey[USHAMaxHashSize]; - - if (!context) return shaNull; - context->Computed = 0; - context->Corrupted = shaSuccess; - - blocksize = context->blockSize = USHABlockSize(whichSha); - hashsize = context->hashSize = USHAHashSize(whichSha); - context->whichSha = whichSha; - - /* - * If key is longer than the hash blocksize, - * reset it to key = HASH(key). - */ - if (key_len > blocksize) { - USHAContext tcontext; - int err = USHAReset(&tcontext, whichSha) || - USHAInput(&tcontext, key, key_len) || - USHAResult(&tcontext, tempkey); - if (err != shaSuccess) return err; - - key = tempkey; - key_len = hashsize; - } - - /* - * The HMAC transform looks like: - * - * SHA(K XOR opad, SHA(K XOR ipad, text)) - * - * where K is an n byte key, 0-padded to a total of blocksize bytes, - * ipad is the byte 0x36 repeated blocksize times, - * opad is the byte 0x5c repeated blocksize times, - * and text is the data being protected. - */ - - /* store key into the pads, XOR'd with ipad and opad values */ - for (i = 0; i < key_len; i++) { - k_ipad[i] = key[i] ^ 0x36; - context->k_opad[i] = key[i] ^ 0x5c; - } - /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ - for ( ; i < blocksize; i++) { - k_ipad[i] = 0x36; - context->k_opad[i] = 0x5c; - } - - /* perform inner hash */ - /* init context for 1st pass */ - ret = USHAReset(&context->shaContext, whichSha) || - /* and start with inner pad */ - USHAInput(&context->shaContext, k_ipad, blocksize); - return context->Corrupted = ret; -} - -/* - * hmacInput - * - * Description: - * This function accepts an array of octets as the next portion - * of the message. It may be called multiple times. - * - * Parameters: - * context: [in/out] - * The HMAC context to update. - * text[ ]: [in] - * An array of octets representing the next portion of - * the message. - * text_len: [in] - * The length of the message in text. - * - * Returns: - * sha Error Code. - * - */ -int hmacInput(HMACContext *context, const unsigned char *text, - int text_len) -{ - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - /* then text of datagram */ - return context->Corrupted = - USHAInput(&context->shaContext, text, text_len); -} - -/* - * hmacFinalBits - * - * Description: - * This function will add in any final bits of the message. - * - * Parameters: - * context: [in/out] - * The HMAC context to update. - * message_bits: [in] - * The final bits of the message, in the upper portion of the - * byte. (Use 0b###00000 instead of 0b00000### to input the - * three bits ###.) - * length: [in] - * The number of bits in message_bits, between 1 and 7. - * - * Returns: - * sha Error Code. - */ -int hmacFinalBits(HMACContext *context, - uint8_t bits, unsigned int bit_count) -{ - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - /* then final bits of datagram */ - return context->Corrupted = - USHAFinalBits(&context->shaContext, bits, bit_count); -} - -/* - * hmacResult - * - * Description: - * This function will return the N-byte message digest into the - * Message_Digest array provided by the caller. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the HMAC hash. - * digest[ ]: [out] - * Where the digest is returned. - * NOTE 2: The length of the hash is determined by the value of - * whichSha that was passed to hmacReset(). - * - * Returns: - * sha Error Code. - * - */ -int hmacResult(HMACContext *context, uint8_t *digest) -{ - int ret; - if (!context) return shaNull; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - - /* finish up 1st pass */ - /* (Use digest here as a temporary buffer.) */ - ret = - USHAResult(&context->shaContext, digest) || - - /* perform outer SHA */ - /* init context for 2nd pass */ - USHAReset(&context->shaContext, context->whichSha) || - - /* start with outer pad */ - USHAInput(&context->shaContext, context->k_opad, - context->blockSize) || - - /* then results of 1st hash */ - USHAInput(&context->shaContext, digest, context->hashSize) || - /* finish up 2nd pass */ - USHAResult(&context->shaContext, digest); - - context->Computed = 1; - return context->Corrupted = ret; -} - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/jsmn/jsmn.h b/lib/libesp32_div/ESP32-HomeKit/src/jsmn/jsmn.h deleted file mode 100644 index 3178dcc97..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/jsmn/jsmn.h +++ /dev/null @@ -1,471 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2010 Serge Zaitsev - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef JSMN_H -#define JSMN_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef JSMN_STATIC -#define JSMN_API static -#else -#define JSMN_API extern -#endif - -/** - * JSON type identifier. Basic types are: - * o Object - * o Array - * o String - * o Other primitive: number, boolean (true/false) or null - */ -typedef enum { - JSMN_UNDEFINED = 0, - JSMN_OBJECT = 1, - JSMN_ARRAY = 2, - JSMN_STRING = 3, - JSMN_PRIMITIVE = 4 -} jsmntype_t; - -enum jsmnerr { - /* Not enough tokens were provided */ - JSMN_ERROR_NOMEM = -1, - /* Invalid character inside JSON string */ - JSMN_ERROR_INVAL = -2, - /* The string is not a full JSON packet, more bytes expected */ - JSMN_ERROR_PART = -3 -}; - -/** - * JSON token description. - * type type (object, array, string etc.) - * start start position in JSON data string - * end end position in JSON data string - */ -typedef struct jsmntok { - jsmntype_t type; - int start; - int end; - int size; -#ifdef JSMN_PARENT_LINKS - int parent; -#endif -} jsmntok_t; - -/** - * JSON parser. Contains an array of token blocks available. Also stores - * the string being parsed now and current position in that string. - */ -typedef struct jsmn_parser { - unsigned int pos; /* offset in the JSON string */ - unsigned int toknext; /* next token to allocate */ - int toksuper; /* superior token node, e.g. parent object or array */ -} jsmn_parser; - -/** - * Create JSON parser over an array of tokens - */ -JSMN_API void jsmn_init(jsmn_parser *parser); - -/** - * Run JSON parser. It parses a JSON data string into and array of tokens, each - * describing - * a single JSON object. - */ -JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, - jsmntok_t *tokens, const unsigned int num_tokens); - -#ifndef JSMN_HEADER -/** - * Allocates a fresh unused token from the token pool. - */ -static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *tok; - if (parser->toknext >= num_tokens) { - return NULL; - } - tok = &tokens[parser->toknext++]; - tok->start = tok->end = -1; - tok->size = 0; -#ifdef JSMN_PARENT_LINKS - tok->parent = -1; -#endif - return tok; -} - -/** - * Fills token type and boundaries. - */ -static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, - const int start, const int end) { - token->type = type; - token->start = start; - token->end = end; - token->size = 0; -} - -/** - * Fills next available token with JSON primitive. - */ -static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, - const size_t len, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *token; - int start; - - start = parser->pos; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - switch (js[parser->pos]) { -#ifndef JSMN_STRICT - /* In strict mode primitive must be followed by "," or "}" or "]" */ - case ':': -#endif - case '\t': - case '\r': - case '\n': - case ' ': - case ',': - case ']': - case '}': - goto found; - default: - /* to quiet a warning from gcc*/ - break; - } - if (js[parser->pos] < 32 || js[parser->pos] >= 127) { - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } -#ifdef JSMN_STRICT - /* In strict mode primitive must be followed by a comma/object/array */ - parser->pos = start; - return JSMN_ERROR_PART; -#endif - -found: - if (tokens == NULL) { - parser->pos--; - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - parser->pos--; - return 0; -} - -/** - * Fills next token with JSON string. - */ -static int jsmn_parse_string(jsmn_parser *parser, const char *js, - const size_t len, jsmntok_t *tokens, - const size_t num_tokens) { - jsmntok_t *token; - - int start = parser->pos; - - parser->pos++; - - /* Skip starting quote */ - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c = js[parser->pos]; - - /* Quote: end of string */ - if (c == '\"') { - if (tokens == NULL) { - return 0; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - parser->pos = start; - return JSMN_ERROR_NOMEM; - } - jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - return 0; - } - - /* Backslash: Quoted symbol expected */ - if (c == '\\' && parser->pos + 1 < len) { - int i; - parser->pos++; - switch (js[parser->pos]) { - /* Allowed escaped symbols */ - case '\"': - case '/': - case '\\': - case 'b': - case 'f': - case 'r': - case 'n': - case 't': - break; - /* Allows escaped symbol \uXXXX */ - case 'u': - parser->pos++; - for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; - i++) { - /* If it isn't a hex character we have an error */ - if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ - (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ - (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ - parser->pos = start; - return JSMN_ERROR_INVAL; - } - parser->pos++; - } - parser->pos--; - break; - /* Unexpected symbol */ - default: - parser->pos = start; - return JSMN_ERROR_INVAL; - } - } - } - parser->pos = start; - return JSMN_ERROR_PART; -} - -/** - * Parse JSON string and fill tokens. - */ -JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, - jsmntok_t *tokens, const unsigned int num_tokens) { - int r; - int i; - jsmntok_t *token; - int count = parser->toknext; - - for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { - char c; - jsmntype_t type; - - c = js[parser->pos]; - switch (c) { - case '{': - case '[': - count++; - if (tokens == NULL) { - break; - } - token = jsmn_alloc_token(parser, tokens, num_tokens); - if (token == NULL) { - return JSMN_ERROR_NOMEM; - } - if (parser->toksuper != -1) { - jsmntok_t *t = &tokens[parser->toksuper]; -#ifdef JSMN_STRICT - /* In strict mode an object or array can't become a key */ - if (t->type == JSMN_OBJECT) { - return JSMN_ERROR_INVAL; - } -#endif - t->size++; -#ifdef JSMN_PARENT_LINKS - token->parent = parser->toksuper; -#endif - } - token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); - token->start = parser->pos; - parser->toksuper = parser->toknext - 1; - break; - case '}': - case ']': - if (tokens == NULL) { - break; - } - type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); -#ifdef JSMN_PARENT_LINKS - if (parser->toknext < 1) { - return JSMN_ERROR_INVAL; - } - token = &tokens[parser->toknext - 1]; - for (;;) { - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - token->end = parser->pos + 1; - parser->toksuper = token->parent; - break; - } - if (token->parent == -1) { - if (token->type != type || parser->toksuper == -1) { - return JSMN_ERROR_INVAL; - } - break; - } - token = &tokens[token->parent]; - } -#else - for (i = parser->toknext - 1; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - if (token->type != type) { - return JSMN_ERROR_INVAL; - } - parser->toksuper = -1; - token->end = parser->pos + 1; - break; - } - } - /* Error if unmatched closing bracket */ - if (i == -1) { - return JSMN_ERROR_INVAL; - } - for (; i >= 0; i--) { - token = &tokens[i]; - if (token->start != -1 && token->end == -1) { - parser->toksuper = i; - break; - } - } -#endif - break; - case '\"': - r = jsmn_parse_string(parser, js, len, tokens, num_tokens); - if (r < 0) { - return r; - } - count++; - if (parser->toksuper != -1 && tokens != NULL) { - tokens[parser->toksuper].size++; - } - break; - case '\t': - case '\r': - case '\n': - case ' ': - break; - case ':': - parser->toksuper = parser->toknext - 1; - break; - case ',': - if (tokens != NULL && parser->toksuper != -1 && - tokens[parser->toksuper].type != JSMN_ARRAY && - tokens[parser->toksuper].type != JSMN_OBJECT) { -#ifdef JSMN_PARENT_LINKS - parser->toksuper = tokens[parser->toksuper].parent; -#else - for (i = parser->toknext - 1; i >= 0; i--) { - if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { - if (tokens[i].start != -1 && tokens[i].end == -1) { - parser->toksuper = i; - break; - } - } - } -#endif - } - break; -#ifdef JSMN_STRICT - /* In strict mode primitives are: numbers and booleans */ - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 't': - case 'f': - case 'n': - /* And they must not be keys of the object */ - if (tokens != NULL && parser->toksuper != -1) { - const jsmntok_t *t = &tokens[parser->toksuper]; - if (t->type == JSMN_OBJECT || - (t->type == JSMN_STRING && t->size != 0)) { - return JSMN_ERROR_INVAL; - } - } -#else - /* In non-strict mode every unquoted value is a primitive */ - default: -#endif - r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); - if (r < 0) { - return r; - } - count++; - if (parser->toksuper != -1 && tokens != NULL) { - tokens[parser->toksuper].size++; - } - break; - -#ifdef JSMN_STRICT - /* Unexpected char in strict mode */ - default: - return JSMN_ERROR_INVAL; -#endif - } - } - - if (tokens != NULL) { - for (i = parser->toknext - 1; i >= 0; i--) { - /* Unmatched opened object or array */ - if (tokens[i].start != -1 && tokens[i].end == -1) { - return JSMN_ERROR_PART; - } - } - } - - return count; -} - -/** - * Creates a new parser based over a given buffer with an array of tokens - * available. - */ -JSMN_API void jsmn_init(jsmn_parser *parser) { - parser->pos = 0; - parser->toknext = 0; - parser->toksuper = -1; -} - -#endif /* JSMN_HEADER */ - -#ifdef __cplusplus -} -#endif - -#endif /* JSMN_H */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/json_generator.c b/lib/libesp32_div/ESP32-HomeKit/src/json_generator.c deleted file mode 100644 index 61102f92f..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/json_generator.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2020 Piyush Shah - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include - -#include - -#define MAX_INT_IN_STR 24 -#define MAX_FLOAT_IN_STR 30 - -static inline int json_gen_get_empty_len(json_gen_str_t *jstr) -{ - return (jstr->buf_size - (jstr->free_ptr - jstr->buf) - 1); -} - -/* This will add the incoming string to the JSON string buffer - * and flush it out if the buffer is full. Note that the data being - * flushed out will always be equal to the size of the buffer unless - * this is the last chunk being flushed out on json_gen_end_str() - */ -static int json_gen_add_to_str(json_gen_str_t *jstr, const char *str) -{ - if (!str) { - return 0; - } - int len = strlen(str); - const char *cur_ptr = str; - while (1) { - int len_remaining = json_gen_get_empty_len(jstr); - int copy_len = len_remaining > len ? len : len_remaining; - memmove(jstr->free_ptr, cur_ptr, copy_len); - cur_ptr += copy_len; - jstr->free_ptr += copy_len; - len -= copy_len; - if (len) { - *jstr->free_ptr = '\0'; - /* Report error if the buffer is full and no flush callback - * is registered - */ - if (!jstr->flush_cb) { - return -1; - } - jstr->flush_cb(jstr->buf, jstr->priv); - jstr->free_ptr = jstr->buf; - } else - break; - } - return 0; -} - - -void json_gen_str_start(json_gen_str_t *jstr, char *buf, int buf_size, - json_gen_flush_cb_t flush_cb, void *priv) -{ - memset(jstr, 0, sizeof(json_gen_str_t)); - jstr->buf = buf; - jstr->buf_size = buf_size; - jstr->flush_cb = flush_cb; - jstr->free_ptr = buf; - jstr->priv = priv; -} - -void json_gen_str_end(json_gen_str_t *jstr) -{ - *jstr->free_ptr = '\0'; - if (jstr->flush_cb) - jstr->flush_cb(jstr->buf, jstr->priv); - memset(jstr, 0, sizeof(json_gen_str_t)); -} - -static inline void json_gen_handle_comma(json_gen_str_t *jstr) -{ - if (jstr->comma_req) - json_gen_add_to_str(jstr, ","); -} - - -static int json_gen_handle_name(json_gen_str_t *jstr, const char *name) -{ - json_gen_add_to_str(jstr, "\""); - json_gen_add_to_str(jstr, name); - return json_gen_add_to_str(jstr, "\":"); -} - - -int json_gen_start_object(json_gen_str_t *jstr) -{ - json_gen_handle_comma(jstr); - jstr->comma_req = false; - return json_gen_add_to_str(jstr, "{"); -} - -int json_gen_end_object(json_gen_str_t *jstr) -{ - jstr->comma_req = true; - return json_gen_add_to_str(jstr, "}"); -} - - -int json_gen_start_array(json_gen_str_t *jstr) -{ - json_gen_handle_comma(jstr); - jstr->comma_req = false; - return json_gen_add_to_str(jstr, "["); -} - -int json_gen_end_array(json_gen_str_t *jstr) -{ - jstr->comma_req = true; - return json_gen_add_to_str(jstr, "]"); -} - -int json_gen_push_object(json_gen_str_t *jstr, const char *name) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - jstr->comma_req = false; - return json_gen_add_to_str(jstr, "{"); -} - -int json_gen_pop_object(json_gen_str_t *jstr) -{ - jstr->comma_req = true; - return json_gen_add_to_str(jstr, "}"); -} - -int json_gen_push_object_str(json_gen_str_t *jstr, const char *name, char *object_str) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - jstr->comma_req = true; - return json_gen_add_to_str(jstr, object_str); -} - -int json_gen_push_array(json_gen_str_t *jstr, const char *name) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - jstr->comma_req = false; - return json_gen_add_to_str(jstr, "["); -} -int json_gen_pop_array(json_gen_str_t *jstr) -{ - jstr->comma_req = true; - return json_gen_add_to_str(jstr, "]"); -} - -int json_gen_push_array_str(json_gen_str_t *jstr, const char *name, char *array_str) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - jstr->comma_req = true; - return json_gen_add_to_str(jstr, array_str); -} - -static int json_gen_set_bool(json_gen_str_t *jstr, bool val) -{ - jstr->comma_req = true; - if (val) - return json_gen_add_to_str(jstr, "true"); - else - return json_gen_add_to_str(jstr, "false"); -} -int json_gen_obj_set_bool(json_gen_str_t *jstr, const char *name, bool val) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - return json_gen_set_bool(jstr, val); -} - -int json_gen_arr_set_bool(json_gen_str_t *jstr, bool val) -{ - json_gen_handle_comma(jstr); - return json_gen_set_bool(jstr, val); -} - -static int json_gen_set_int(json_gen_str_t *jstr, int val) -{ - jstr->comma_req = true; - char str[MAX_INT_IN_STR]; - snprintf(str, MAX_INT_IN_STR, "%d", val); - return json_gen_add_to_str(jstr, str); -} - -int json_gen_obj_set_int(json_gen_str_t *jstr, const char *name, int val) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - return json_gen_set_int(jstr, val); -} - -int json_gen_arr_set_int(json_gen_str_t *jstr, int val) -{ - json_gen_handle_comma(jstr); - return json_gen_set_int(jstr, val); -} - - -static int json_gen_set_float(json_gen_str_t *jstr, float val) -{ - jstr->comma_req = true; - char str[MAX_FLOAT_IN_STR]; - snprintf(str, MAX_FLOAT_IN_STR, "%.*f", JSON_FLOAT_PRECISION, val); - return json_gen_add_to_str(jstr, str); -} -int json_gen_obj_set_float(json_gen_str_t *jstr, const char *name, float val) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - return json_gen_set_float(jstr, val); -} -int json_gen_arr_set_float(json_gen_str_t *jstr, float val) -{ - json_gen_handle_comma(jstr); - return json_gen_set_float(jstr, val); -} - -static int json_gen_set_string(json_gen_str_t *jstr, const char *val) -{ - jstr->comma_req = true; - json_gen_add_to_str(jstr, "\""); - json_gen_add_to_str(jstr, val); - return json_gen_add_to_str(jstr, "\""); -} - -int json_gen_obj_set_string(json_gen_str_t *jstr, const char *name, const char *val) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - return json_gen_set_string(jstr, val); -} - -int json_gen_arr_set_string(json_gen_str_t *jstr, const char *val) -{ - json_gen_handle_comma(jstr); - return json_gen_set_string(jstr, val); -} - -static int json_gen_set_long_string(json_gen_str_t *jstr, const char *val) -{ - jstr->comma_req = true; - json_gen_add_to_str(jstr, "\""); - return json_gen_add_to_str(jstr, val); -} - -int json_gen_obj_start_long_string(json_gen_str_t *jstr, const char *name, const char *val) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - return json_gen_set_long_string(jstr, val); -} - -int json_gen_arr_start_long_string(json_gen_str_t *jstr, const char *val) -{ - json_gen_handle_comma(jstr); - return json_gen_set_long_string(jstr, val); -} - -int json_gen_add_to_long_string(json_gen_str_t *jstr, const char *val) -{ - return json_gen_add_to_str(jstr, val); -} - -int json_gen_end_long_string(json_gen_str_t *jstr) -{ - return json_gen_add_to_str(jstr, "\""); -} -static int json_gen_set_null(json_gen_str_t *jstr) -{ - jstr->comma_req = true; - return json_gen_add_to_str(jstr, "null"); -} -int json_gen_obj_set_null(json_gen_str_t *jstr, const char *name) -{ - json_gen_handle_comma(jstr); - json_gen_handle_name(jstr, name); - return json_gen_set_null(jstr); -} - -int json_gen_arr_set_null(json_gen_str_t *jstr) -{ - json_gen_handle_comma(jstr); - return json_gen_set_null(jstr); -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/json_generator.h b/lib/libesp32_div/ESP32-HomeKit/src/json_generator.h deleted file mode 100644 index b4cf4be11..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/json_generator.h +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright 2020 Piyush Shah - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * JSON String Generator - * - * This module can be used to create JSON strings with a facility - * to flush out data if the destination buffer is full. All commas - * and colons as required are automatically added by the APIs - * - */ -#ifndef _JSON_GENERATOR_H -#define _JSON_GENERATOR_H - -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** Float precision i.e. number of digits after decimal point */ -#ifndef JSON_FLOAT_PRECISION -#define JSON_FLOAT_PRECISION 5 -#endif - -/** JSON string flush callback prototype - * - * This is a prototype of the function that needs to be passed to - * json_gen_str_start() and which will be invoked by the JSON generator - * module either when the buffer is full or json_gen_str_end() ins invoked. - * - * \param[in] buf Pointer to a NULL terminated JSON string - * \param[in] priv Private data to be passed to the flush callback. Will - * be the same as the one passed to json_gen_str_start() - */ -typedef void (*json_gen_flush_cb_t) (char *buf, void *priv); - -/** JSON String structure - * - * Please do not set/modify any elements. - * Just define this structure and pass a pointer to it in the APIs below - */ -typedef struct { - /** Pointer to the JSON buffer provided by the calling function */ - char *buf; - /** Size of the above buffer */ - int buf_size; - /** (Optional) callback function to invoke when the buffer gets full */ - json_gen_flush_cb_t flush_cb; - /** (Optional) Private data to pass to the callback function */ - void *priv; - /** (For Internal use only) */ - bool comma_req; - /** (For Internal use only) */ - char *free_ptr; -} json_gen_str_t; - -/** Start a JSON String - * - * This is the first function to be called for creating a JSON string. - * It initializes the internal data structures. After the JSON string - * generation is over, the json_gen_str_end() function should be called. - * - * \param[out] jstr Pointer to an allocated \ref json_gen_str_t structure. - * This will be initialised internally and needs to be passed to all - * subsequent function calls - * \param[out] buf Pointer to an allocated buffer into which the JSON - * string will be written - * \param[in] buf_size Size of the buffer - * \param[in] flush_cb Pointer to the flushing function of type \ref json_gen_flush_cb_t - * which will be invoked either when the buffer is full or when json_gen_str_end() - * is invoked. Can be left NULL. - * \param[in] priv Private data to be passed to the flushing function callback. - * Can be something like a session identifier (Eg. socket). Can be left NULL. - */ -void json_gen_str_start(json_gen_str_t *jstr, char *buf, int buf_size, - json_gen_flush_cb_t flush_cb, void *priv); - -/** End JSON string - * - * This should be the last function to be called after the entire JSON string - * has been generated. - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - */ -void json_gen_str_end(json_gen_str_t *jstr); - -/** Start a JSON object - * - * This starts a JSON object by adding a '{' - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_start_object(json_gen_str_t *jstr); - -/** End a JSON object - * - * This ends a JSON object by adding a '}' - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_end_object(json_gen_str_t *jstr); - -/** Start a JSON array - * - * This starts a JSON object by adding a '[' - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_start_array(json_gen_str_t *jstr); - -/** End a JSON object - * - * This ends a JSON object by adding a ']' - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_end_array(json_gen_str_t *jstr); - -/** Push a named JSON object - * - * This adds a JSON object like "name":{ - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the object - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_push_object(json_gen_str_t *jstr, const char *name); - -/** Pop a named JSON object - * - * This ends a JSON object by adding a '}'. This is basically same as - * json_gen_end_object() but included so as to complement json_gen_push_object() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_pop_object(json_gen_str_t *jstr); - -/** Push a JSON object string - * - * This adds a complete pre-formatted JSON object string to the JSON object. - * - * Eg. json_gen_push_object_str(jstr, "pre-formatted", "{\"a\":1,\"b\":2}"); - * This will add "pre-formatted":{"a":1,"b":2} - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the JSON object string - * \param[in] object_str The pre-formatted JSON object string - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that. - */ -int json_gen_push_object_str(json_gen_str_t *jstr, const char *name, char *object_str); - -/** Push a named JSON array - * - * This adds a JSON array like "name":[ - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the array - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_push_array(json_gen_str_t *jstr, const char *name); - -/** Pop a named JSON array - * - * This ends a JSON array by adding a ']'. This is basically same as - * json_gen_end_array() but included so as to complement json_gen_push_array() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_pop_array(json_gen_str_t *jstr); - -/** Push a JSON array string - * - * This adds a complete pre-formatted JSON array string to the JSON object. - * - * Eg. json_gen_push_object_str(jstr, "pre-formatted", "[1,2,3]"); - * This will add "pre-formatted":[1,2,3] - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the JSON array string - * \param[in] array_str The pre-formatted JSON array string - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that. - */ -int json_gen_push_array_str(json_gen_str_t *jstr, const char *name, char *array_str); - -/** Add a boolean element to an object - * - * This adds a boolean element to an object. Eg. "bool_val":true - * - * \note This must be called between json_gen_start_object()/json_gen_push_object() - * and json_gen_end_object()/json_gen_pop_object() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the element - * \param[in] val Boolean value of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_obj_set_bool(json_gen_str_t *jstr, const char *name, bool val); - -/** Add an integer element to an object - * - * This adds an integer element to an object. Eg. "int_val":28 - * - * \note This must be called between json_gen_start_object()/json_gen_push_object() - * and json_gen_end_object()/json_gen_pop_object() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the element - * \param[in] val Integer value of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_obj_set_int(json_gen_str_t *jstr, const char *name, int val); - -/** Add a float element to an object - * - * This adds a float element to an object. Eg. "float_val":23.8 - * - * \note This must be called between json_gen_start_object()/json_gen_push_object() - * and json_gen_end_object()/json_gen_pop_object() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the element - * \param[in] val Float value of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_obj_set_float(json_gen_str_t *jstr, const char *name, float val); - -/** Add a string element to an object - * - * This adds a string element to an object. Eg. "string_val":"my_string" - * - * \note This must be called between json_gen_start_object()/json_gen_push_object() - * and json_gen_end_object()/json_gen_pop_object() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the element - * \param[in] val Null terminated string value of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_obj_set_string(json_gen_str_t *jstr, const char *name, const char *val); - -/** Add a NULL element to an object - * - * This adds a NULL element to an object. Eg. "null_val":null - * - * \note This must be called between json_gen_start_object()/json_gen_push_object() - * and json_gen_end_object()/json_gen_pop_object() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_obj_set_null(json_gen_str_t *jstr, const char *name); - -/** Add a boolean element to an array - * - * \note This must be called between json_gen_start_array()/json_gen_push_array() - * and json_gen_end_array()/json_gen_pop_array() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] val Boolean value of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_arr_set_bool(json_gen_str_t *jstr, bool val); - -/** Add an integer element to an array - * - * \note This must be called between json_gen_start_array()/json_gen_push_array() - * and json_gen_end_array()/json_gen_pop_array() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] val Integer value of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_arr_set_int(json_gen_str_t *jstr, int val); - -/** Add a float element to an array - * - * \note This must be called between json_gen_start_array()/json_gen_push_array() - * and json_gen_end_array()/json_gen_pop_array() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] val Float value of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_arr_set_float(json_gen_str_t *jstr, float val); - -/** Add a string element to an array - * - * \note This must be called between json_gen_start_array()/json_gen_push_array() - * and json_gen_end_array()/json_gen_pop_array() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] val Null terminated string value of the element - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_arr_set_string(json_gen_str_t *jstr, const char *val); - -/** Add a NULL element to an array - * - * \note This must be called between json_gen_start_array()/json_gen_push_array() - * and json_gen_end_array()/json_gen_pop_array() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_arr_set_null(json_gen_str_t *jstr); - -/** Start a Long string in an object - * - * This starts a string in an object, but does not end it (i.e., does not add the - * terminating quotes. This is useful for long strings. Eg. "string_val":"my_string. - * The API json_gen_add_to_long_string() must be used to add to this string and the API - * json_gen_end_long_string() must be used to terminate it (i.e. add the ending quotes). - * - * \note This must be called between json_gen_start_object()/json_gen_push_object() - * and json_gen_end_object()/json_gen_pop_object() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] name Name of the element - * \param[in] val Null terminated initial part of the string value. It can also be NULL - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_obj_start_long_string(json_gen_str_t *jstr, const char *name, const char *val); - -/** Start a Long string in an array - * - * This starts a string in an arrayt, but does not end it (i.e., does not add the - * terminating quotes. This is useful for long strings. - * The API json_gen_add_to_long_string() must be used to add to this string and the API - * json_gen_end_long_string() must be used to terminate it (i.e. add the ending quotes). - * - * \note This must be called between json_gen_start_array()/json_gen_push_array() - * and json_gen_end_array()/json_gen_pop_array() - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by - * json_gen_str_start() - * \param[in] val Null terminated initial part of the string value. It can also be NULL - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_arr_start_long_string(json_gen_str_t *jstr, const char *val); - -/** Add to a JSON Long string - * - * This extends the string initialised by json_gen_obj_start_long_string() or - * json_gen_arr_start_long_string(). After the entire string is created, it should be terminated - * with json_gen_end_long_string(). - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by json_gen_str_start() - * \param[in] val Null terminated extending part of the string value. - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_add_to_long_string(json_gen_str_t *jstr, const char *val); - -/** End a JSON Long string - * - * This ends the string initialised by json_gen_obj_start_long_string() or - * json_gen_arr_start_long_string() by adding the ending quotes. - * - * \param[in] jstr Pointer to the \ref json_gen_str_t structure initialised by json_gen_str_start() - * - * - * \return 0 on Success - * \return -1 if buffer is out of space (possible only if no callback function - * is passed to json_gen_str_start(). Else, buffer will be flushed out and new data - * added after that - */ -int json_gen_end_long_string(json_gen_str_t *jstr); -#ifdef __cplusplus -} -#endif -#endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/json_parser.c b/lib/libesp32_div/ESP32-HomeKit/src/json_parser.c deleted file mode 100644 index e6c47fb68..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/json_parser.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright 2020 Piyush Shah - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include -#define JSMN_PARENT_LINKS -#define JSMN_STRICT -#define JSMN_STATIC -#include -#include - -static bool token_matches_str(jparse_ctx_t *ctx, json_tok_t *tok, const char *str) -{ - char *js = ctx->js; - return ((strncmp(js + tok->start, str, strlen(str)) == 0) - && (strlen(str) == (size_t) (tok->end - tok->start))); -} - -static json_tok_t *json_skip_elem(json_tok_t *token) -{ - json_tok_t *cur = token; - int cnt = cur->size; - while (cnt--) { - cur++; - cur = json_skip_elem(cur); - } - return cur; -} - -static int json_tok_to_bool(jparse_ctx_t *jctx, json_tok_t *tok, bool *val) -{ - if (token_matches_str(jctx, tok, "true") || token_matches_str(jctx, tok, "1")) { - *val = true; - } else if (token_matches_str(jctx, tok, "false") || token_matches_str(jctx, tok, "0")) { - *val = false; - } else - return -OS_FAIL; - return OS_SUCCESS; -} - -static int json_tok_to_int(jparse_ctx_t *jctx, json_tok_t *tok, int *val) -{ - char *tok_start = &jctx->js[tok->start]; - char *tok_end = &jctx->js[tok->end]; - char *endptr; - int i = strtoul(tok_start, &endptr, 10); - if (endptr == tok_end) { - *val = i; - return OS_SUCCESS; - } - return -OS_FAIL; -} - -static int json_tok_to_int64(jparse_ctx_t *jctx, json_tok_t *tok, int64_t *val) -{ - char *tok_start = &jctx->js[tok->start]; - char *tok_end = &jctx->js[tok->end]; - char *endptr; - int64_t i64 = strtoull(tok_start, &endptr, 10); - if (endptr == tok_end) { - *val = i64; - return OS_SUCCESS; - } - return -OS_FAIL; -} - -static int json_tok_to_float(jparse_ctx_t *jctx, json_tok_t *tok, float *val) -{ - char *tok_start = &jctx->js[tok->start]; - char *tok_end = &jctx->js[tok->end]; - char *endptr; - float f = strtof(tok_start, &endptr); - if (endptr == tok_end) { - *val = f; - return OS_SUCCESS; - } - return -OS_FAIL; -} - -static int json_tok_to_string(jparse_ctx_t *jctx, json_tok_t *tok, char *val, int size) -{ - if ((tok->end - tok->start) > (size - 1)) - return -OS_FAIL; - strncpy(val, jctx->js + tok->start, tok->end - tok->start); - val[tok->end - tok->start] = 0; - return OS_SUCCESS; -} - -static json_tok_t *json_obj_search(jparse_ctx_t *jctx, const char *key) -{ - json_tok_t *tok = jctx->cur; - int size = tok->size; - if (size <= 0) - return NULL; - if (tok->type != JSMN_OBJECT) - return NULL; - - while (size--) { - tok++; - if (token_matches_str(jctx, tok, key)) - return tok; - tok = json_skip_elem(tok); - } - return NULL; -} - -static json_tok_t *json_obj_get_val_tok(jparse_ctx_t *jctx, const char *name, jsmntype_t type) -{ - json_tok_t *tok = json_obj_search(jctx, name); - if (!tok) - return NULL; - tok++; - if (tok->type != type) - return NULL; - return tok; -} - -int json_obj_get_array(jparse_ctx_t *jctx, const char *name, int *num_elem) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY); - if (!tok) - return -OS_FAIL; - jctx->cur = tok; - *num_elem = tok->size; - return OS_SUCCESS; -} - -int json_obj_leave_array(jparse_ctx_t *jctx) -{ - /* The array's parent will be the key */ - if (jctx->cur->parent < 0) - return -OS_FAIL; - jctx->cur = &jctx->tokens[jctx->cur->parent]; - - /* The key's parent will be the actual parent object */ - if (jctx->cur->parent < 0) - return -OS_FAIL; - jctx->cur = &jctx->tokens[jctx->cur->parent]; - return OS_SUCCESS; -} - -int json_obj_get_object(jparse_ctx_t *jctx, const char *name) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT); - if (!tok) - return -OS_FAIL; - jctx->cur = tok; - return OS_SUCCESS; -} - -int json_obj_leave_object(jparse_ctx_t *jctx) -{ - /* The objects's parent will be the key */ - if (jctx->cur->parent < 0) - return -OS_FAIL; - jctx->cur = &jctx->tokens[jctx->cur->parent]; - - /* The key's parent will be the actual parent object */ - if (jctx->cur->parent < 0) - return -OS_FAIL; - jctx->cur = &jctx->tokens[jctx->cur->parent]; - return OS_SUCCESS; -} - -int json_obj_get_bool(jparse_ctx_t *jctx, const char *name, bool *val) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE); - if (!tok) - return -OS_FAIL; - return json_tok_to_bool(jctx, tok, val); -} - -int json_obj_get_int(jparse_ctx_t *jctx, const char *name, int *val) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE); - if (!tok) - return -OS_FAIL; - return json_tok_to_int(jctx, tok, val); -} - -int json_obj_get_int64(jparse_ctx_t *jctx, const char *name, int64_t *val) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE); - if (!tok) - return -OS_FAIL; - return json_tok_to_int64(jctx, tok, val); -} - -int json_obj_get_float(jparse_ctx_t *jctx, const char *name, float *val) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_PRIMITIVE); - if (!tok) - return -OS_FAIL; - return json_tok_to_float(jctx, tok, val); -} - -int json_obj_get_string(jparse_ctx_t *jctx, const char *name, char *val, int size) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_STRING); - if (!tok) - return -OS_FAIL; - return json_tok_to_string(jctx, tok, val, size); -} - -int json_obj_get_strlen(jparse_ctx_t *jctx, const char *name, int *strlen) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_STRING); - if (!tok) - return -OS_FAIL; - *strlen = tok->end - tok->start; - return OS_SUCCESS; -} - -int json_obj_get_object_str(jparse_ctx_t *jctx, const char *name, char *val, int size) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT); - if (!tok) - return -OS_FAIL; - return json_tok_to_string(jctx, tok, val, size); -} - -int json_obj_get_object_strlen(jparse_ctx_t *jctx, const char *name, int *strlen) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_OBJECT); - if (!tok) - return -OS_FAIL; - *strlen = tok->end - tok->start; - return OS_SUCCESS; -} -int json_obj_get_array_str(jparse_ctx_t *jctx, const char *name, char *val, int size) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY); - if (!tok) - return -OS_FAIL; - return json_tok_to_string(jctx, tok, val, size); -} - -int json_obj_get_array_strlen(jparse_ctx_t *jctx, const char *name, int *strlen) -{ - json_tok_t *tok = json_obj_get_val_tok(jctx, name, JSMN_ARRAY); - if (!tok) - return -OS_FAIL; - *strlen = tok->end - tok->start; - return OS_SUCCESS; -} - -static json_tok_t *json_arr_search(jparse_ctx_t *ctx, uint32_t index) -{ - json_tok_t *tok = ctx->cur; - if ((tok->type != JSMN_ARRAY) || (tok->size <= 0)) - return NULL; - if (index > (uint32_t)(tok->size - 1)) - return NULL; - /* Increment by 1, so that token points to index 0 */ - tok++; - while (index--) { - tok = json_skip_elem(tok); - tok++; - } - return tok; -} -static json_tok_t *json_arr_get_val_tok(jparse_ctx_t *jctx, uint32_t index, jsmntype_t type) -{ - json_tok_t *tok = json_arr_search(jctx, index); - if (!tok) - return NULL; - if (tok->type != type) - return NULL; - return tok; -} - -int json_arr_get_array(jparse_ctx_t *jctx, uint32_t index) -{ - json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_ARRAY); - if (!tok) - return -OS_FAIL; - jctx->cur = tok; - return OS_SUCCESS; -} - -int json_arr_leave_array(jparse_ctx_t *jctx) -{ - if (jctx->cur->parent < 0) - return -OS_FAIL; - jctx->cur = &jctx->tokens[jctx->cur->parent]; - return OS_SUCCESS; -} - -int json_arr_get_object(jparse_ctx_t *jctx, uint32_t index) -{ - json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_OBJECT); - if (!tok) - return -OS_FAIL; - jctx->cur = tok; - return OS_SUCCESS; -} - -int json_arr_leave_object(jparse_ctx_t *jctx) -{ - if (jctx->cur->parent < 0) - return -OS_FAIL; - jctx->cur = &jctx->tokens[jctx->cur->parent]; - return OS_SUCCESS; -} - -int json_arr_get_bool(jparse_ctx_t *jctx, uint32_t index, bool *val) -{ - json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE); - if (!tok) - return -OS_FAIL; - return json_tok_to_bool(jctx, tok, val); -} - -int json_arr_get_int(jparse_ctx_t *jctx, uint32_t index, int *val) -{ - json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE); - if (!tok) - return -OS_FAIL; - return json_tok_to_int(jctx, tok, val); -} - -int json_arr_get_int64(jparse_ctx_t *jctx, uint32_t index, int64_t *val) -{ - json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE); - if (!tok) - return -OS_FAIL; - return json_tok_to_int64(jctx, tok, val); -} - -int json_arr_get_float(jparse_ctx_t *jctx, uint32_t index, float *val) -{ - json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_PRIMITIVE); - if (!tok) - return -OS_FAIL; - return json_tok_to_float(jctx, tok, val); -} - -int json_arr_get_string(jparse_ctx_t *jctx, uint32_t index, char *val, int size) -{ - json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_STRING); - if (!tok) - return -OS_FAIL; - return json_tok_to_string(jctx, tok, val, size); -} - -int json_arr_get_strlen(jparse_ctx_t *jctx, uint32_t index, int *strlen) -{ - json_tok_t *tok = json_arr_get_val_tok(jctx, index, JSMN_STRING); - if (!tok) - return -OS_FAIL; - *strlen = tok->end - tok->start; - return OS_SUCCESS; -} - -int json_parse_start(jparse_ctx_t *jctx, char *js, int len) -{ - memset(jctx, 0, sizeof(jparse_ctx_t)); - jsmn_init(&jctx->parser); - int num_tokens = jsmn_parse(&jctx->parser, js, len, NULL, 0); - if (num_tokens <= 0) - return -OS_FAIL; - jctx->num_tokens = num_tokens; - jctx->tokens = calloc(num_tokens, sizeof(json_tok_t)); - if (!jctx->tokens) - return -OS_FAIL; - jctx->js = js; - jsmn_init(&jctx->parser); - int ret = jsmn_parse(&jctx->parser, js, len, jctx->tokens, jctx->num_tokens); - if (ret <= 0) { - free(jctx->tokens); - memset(jctx, 0, sizeof(jparse_ctx_t)); - return -OS_FAIL; - } - jctx->cur = jctx->tokens; - return OS_SUCCESS; -} - -int json_parse_end(jparse_ctx_t *jctx) -{ - if (jctx->tokens) - free(jctx->tokens); - memset(jctx, 0, sizeof(jparse_ctx_t)); - return OS_SUCCESS; -} diff --git a/lib/libesp32_div/ESP32-HomeKit/src/json_parser.h b/lib/libesp32_div/ESP32-HomeKit/src/json_parser.h deleted file mode 100644 index 42163d7fc..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/json_parser.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2020 Piyush Shah - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef _JSON_PARSER_H_ -#define _JSON_PARSER_H_ - -#define JSMN_HEADER -#include -#include -#include - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define OS_SUCCESS 0 -#define OS_FAIL -1 - -typedef jsmn_parser json_parser_t; -typedef jsmntok_t json_tok_t; - -typedef struct { - json_parser_t parser; - char *js; - json_tok_t *tokens; - json_tok_t *cur; - int num_tokens; -} jparse_ctx_t; - -int json_parse_start(jparse_ctx_t *jctx, char *js, int len); -int json_parse_end(jparse_ctx_t *jctx); - -int json_obj_get_array(jparse_ctx_t *jctx, const char *name, int *num_elem); -int json_obj_leave_array(jparse_ctx_t *jctx); -int json_obj_get_object(jparse_ctx_t *jctx, const char *name); -int json_obj_leave_object(jparse_ctx_t *jctx); -int json_obj_get_bool(jparse_ctx_t *jctx, const char *name, bool *val); -int json_obj_get_int(jparse_ctx_t *jctx, const char *name, int *val); -int json_obj_get_int64(jparse_ctx_t *jctx, const char *name, int64_t *val); -int json_obj_get_float(jparse_ctx_t *jctx, const char *name, float *val); -int json_obj_get_string(jparse_ctx_t *jctx, const char *name, char *val, int size); -int json_obj_get_strlen(jparse_ctx_t *jctx, const char *name, int *strlen); -int json_obj_get_object_str(jparse_ctx_t *jctx, const char *name, char *val, int size); -int json_obj_get_object_strlen(jparse_ctx_t *jctx, const char *name, int *strlen); -int json_obj_get_array_str(jparse_ctx_t *jctx, const char *name, char *val, int size); -int json_obj_get_array_strlen(jparse_ctx_t *jctx, const char *name, int *strlen); - -int json_arr_get_array(jparse_ctx_t *jctx, uint32_t index); -int json_arr_leave_array(jparse_ctx_t *jctx); -int json_arr_get_object(jparse_ctx_t *jctx, uint32_t index); -int json_arr_leave_object(jparse_ctx_t *jctx); -int json_arr_get_bool(jparse_ctx_t *jctx, uint32_t index, bool *val); -int json_arr_get_int(jparse_ctx_t *jctx, uint32_t index, int *val); -int json_arr_get_int64(jparse_ctx_t *jctx, uint32_t index, int64_t *val); -int json_arr_get_float(jparse_ctx_t *jctx, uint32_t index, float *val); -int json_arr_get_string(jparse_ctx_t *jctx, uint32_t index, char *val, int size); -int json_arr_get_strlen(jparse_ctx_t *jctx, uint32_t index, int *strlen); - -#ifdef __cplusplus -} -#endif - -#endif /* _JSON_PARSER_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/mu_bignum.h b/lib/libesp32_div/ESP32-HomeKit/src/mu_bignum.h deleted file mode 100644 index 1bc60995a..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/mu_bignum.h +++ /dev/null @@ -1,232 +0,0 @@ -#ifndef _MU_BIGNUM_H_ -#define _MU_BIGNUM_H_ - -#define BIGNUM_MBEDTLS - -#ifdef BIGNUM_OPENSSL -#include - - -typedef BIGNUM mu_bn_t; -typedef BN_CTX mu_bn_ctx_t; - - -static inline mu_bn_t *mu_bn_new_from_hex(const char *hex) -{ - mu_bn_t *a = BN_new(); - if (a) - BN_hex2bn(&a, hex); - return a; -} - -static inline mu_bn_t *mu_bn_new_from_bin(const char *str, int str_len) -{ - return BN_bin2bn((unsigned char *)str, str_len, NULL); -} - -static inline mu_bn_t *mu_bn_new() -{ - return BN_new(); -} - -static inline void mu_bn_free(mu_bn_t *bn) -{ - return BN_free(bn); -} - -static inline mu_bn_ctx_t *mu_bn_ctx_new() -{ - return BN_CTX_new(); -} - -static inline void mu_bn_ctx_free(mu_bn_ctx_t *ctx) -{ - return BN_CTX_free(ctx); -} - -static inline unsigned int mu_bn_sizeof(mu_bn_t *bn) -{ - return BN_num_bytes(bn); -} - - -static inline char *mu_bn_to_bin(mu_bn_t *bn, int *len) -{ - *len = mu_bn_sizeof(bn); - char *p = malloc(*len); - if (p) { - BN_bn2bin(bn, (unsigned char *)p); - } - return p; -} - -static inline int mu_bn_get_rand(mu_bn_t *bn, int bits, int top, int bottom) -{ - return BN_rand(bn, bits, top, bottom); -} - -static inline int mu_bn_a_exp_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx) -{ - return BN_mod_exp(result, a, b, c, ctx); -} - -static inline int mu_bn_a_mul_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx) -{ - return BN_mod_mul(result, a, b, c, ctx); -} - -static inline int mu_bn_a_add_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx) -{ - if (BN_add(result, a, b) != 1) - return 1; - return BN_mod(result, result, c, ctx); -} -#endif /* BIGNUM_OPENSSL */ - - -#ifdef BIGNUM_MBEDTLS -#include -#include -#ifdef CONFIG_IDF_TARGET_ESP8266 -#include -#endif -typedef mbedtls_mpi mu_bn_t; -typedef mu_bn_t mu_bn_ctx_t; - -static inline mu_bn_t *mu_bn_new() -{ - mu_bn_t *a = malloc(sizeof (mu_bn_t)); - if (!a) - return NULL; - mbedtls_mpi_init(a); - return a; -} -static inline mu_bn_t *mu_bn_new_from_hex(const char *hex) -{ - mu_bn_t *a = mu_bn_new(); - if (!a) - return NULL; - - mbedtls_mpi_read_string(a, 16, hex); - return a; -} - -static inline mu_bn_t *mu_bn_new_from_bin(const char *str, int str_len) -{ - - mu_bn_t *a = mu_bn_new(); - if (!a) { - return NULL; - } - mbedtls_mpi_read_binary(a, (unsigned char *)str, str_len); - return a; -} - - -static inline void mu_bn_free(mu_bn_t *bn) -{ - if (bn) { - mbedtls_mpi_free(bn); - free(bn); - } -} - -static inline mu_bn_ctx_t *mu_bn_ctx_new() -{ - mu_bn_t *bn = mu_bn_new(); - return ( mu_bn_ctx_t *)bn; -} - -static inline void mu_bn_ctx_free(mu_bn_ctx_t *ctx) -{ - mu_bn_free((mu_bn_t *)ctx); -} - -static inline unsigned int mu_bn_sizeof(mu_bn_t *bn) -{ - return mbedtls_mpi_size(bn); -} - - -static inline char *mu_bn_to_bin(mu_bn_t *bn, int *len) -{ - *len = mu_bn_sizeof(bn); - char *p = malloc(*len); - if (p) { - mbedtls_mpi_write_binary(bn, (unsigned char *)p, *len); - } - return p; -} - -static inline int mu_get_random(void *ctx, unsigned char *data, size_t len) -{ - esp_fill_random(data, len); - return 0; -} -static inline int mu_bn_get_rand(mu_bn_t *bn, int bits, int top, int bottom) -{ - - return mbedtls_mpi_fill_random(bn, bits / 8, mu_get_random, NULL); -} - -#ifdef CONFIG_IDF_TARGET_ESP8266 -static inline int mu_bn_a_exp_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx) -{ - int ret; - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M); - ret = mbedtls_mpi_exp_mod(result, a, b, c, (mu_bn_t *) ctx); - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M); - return ret; -} -static inline int mu_bn_a_mul_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx) -{ - mbedtls_mpi tmp_result; - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M); - mbedtls_mpi_init(&tmp_result); - mbedtls_mpi_mul_mpi(&tmp_result, a, b); - mbedtls_mpi_mod_mpi(result, &tmp_result, c); - mbedtls_mpi_free(&tmp_result); - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M); - return 0; -} -#else - -#include "port/bignum.h" -#include "port/bignum_impl.h" - -static inline int mu_bn_a_exp_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx) -{ - //return mbedtls_mpi_exp_mod(result, a, b, c, (mu_bn_t *) ctx); - // wangbin changed - printf("esp_mpi_exp_mod\n"); - return esp_mpi_exp_mod(result, a, b, c, (mu_bn_t *) ctx); -} - - -static inline int mu_bn_a_mul_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx) -{ - printf("esp_mpi_mul_mpi_mod\n"); - return esp_mpi_mul_mpi_mod(result, a, b, c); -} -#endif /* !CONFIG_IDF_TARGET_ESP8266 */ - -static inline int mu_bn_a_add_b_mod_c(mu_bn_t *result, mu_bn_t *a, mu_bn_t *b, mu_bn_t *c, mu_bn_ctx_t *ctx) -{ - int res; - mbedtls_mpi t; -#ifdef CONFIG_IDF_TARGET_ESP8266 - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M); -#endif - mbedtls_mpi_init(&t); - res = mbedtls_mpi_add_mpi(&t, a, b); - if (res == 0) { - res = mbedtls_mpi_mod_mpi(result, &t, c); - } - mbedtls_mpi_free(&t); -#ifdef CONFIG_IDF_TARGET_ESP8266 - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M); -#endif - return res; -} -#endif /* BIGNUM_MBEDTLS */ -#endif /* ! _MU_BIGNUM_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.c b/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.c deleted file mode 100644 index 0b7ad0b98..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.c +++ /dev/null @@ -1,489 +0,0 @@ -#include -#include "hkdf-sha.h" -#include "mu_bignum.h" -#include "mu_srp.h" - -#ifdef SRP_DEBUG -#include -#define srp_print printf -static void hex_dbg(char *name, void *buf, int buf_len) -{ - char *p = (char *)buf; - int i; - srp_print("%s (%d): ", name, buf_len); - for (i = 0; i < buf_len; i++) { - if (i % 16 == 0) - srp_print("\r\n"); - srp_print("%02x ", (unsigned)(unsigned char)p[i]); - } - srp_print("\r\n"); -} - -static void hex_dbg_bn(char *name, mu_bn_t *bn) -{ - int len; - char *str = mu_bn_to_bin(bn, &len); - if (str) { - hex_dbg(name, str, len); - free(str); - } -} -#else -#define srp_print(...) -#define hex_dbg(...) -#define hex_dbg_bn(...) -#endif - -static inline void SHA512_hash(const uint8_t *bytes, unsigned int byte_count, - uint8_t digest[SHA512HashSize]) -{ - SHA512Context ctx; - SHA512Reset(&ctx); - SHA512Input(&ctx, bytes, byte_count); - SHA512Result(&ctx, digest); -} - -/************************* SRP Stuff */ -char N_3072[] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, - 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, - 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, - 0x34, 0x04, 0xDD, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, - 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, - 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, - 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, - 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, - 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, - 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, - 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, - 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08, - 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, 0xE3, 0x9E, 0x77, - 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, 0xB5, 0xC5, - 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, 0x39, - 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, - 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D, 0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, - 0x33, 0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64, 0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, - 0xEF, 0x0A, 0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D, 0xB3, 0x97, 0x0F, 0x85, 0xA6, - 0xE1, 0xE4, 0xC7, 0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7, 0x1E, 0x8C, 0x94, 0xE0, - 0x4A, 0x25, 0x61, 0x9D, 0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B, 0xF1, 0x2F, 0xFA, - 0x06, 0xD9, 0x8A, 0x08, 0x64, 0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64, 0x52, 0x1F, - 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C, 0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C, 0x77, - 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2, 0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31, - 0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E, 0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, - 0xCA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF -}; -char g_3072[] = { 5 }; - - -int mu_srp_init(mu_srp_handle_t *hd, mu_ng_type_t ng) -{ - if (hd->allocated) - mu_srp_free(hd); - - memset(hd, 0, sizeof(*hd)); - hd->allocated = 1; - - hd->ctx = mu_bn_ctx_new(); - if (! hd->ctx) - goto error; - if (ng != MU_NG_3072) - goto error; - - hd->n = mu_bn_new_from_bin(N_3072, sizeof(N_3072)); - hd->bytes_n = N_3072; - hd->len_n = sizeof(N_3072); - if (! hd->n) - goto error; - - hd->g = mu_bn_new_from_bin(g_3072, sizeof(g_3072)); - hd->bytes_g = g_3072; - hd->len_g = sizeof(g_3072); - if (! hd->g) - goto error; - hd->type = ng; - return 0; - error: - mu_srp_free(hd); - return -1; -} - -void mu_srp_free(mu_srp_handle_t *hd) -{ - if (hd->allocated != 1) - return; - - if (hd->ctx) - mu_bn_ctx_free(hd->ctx); - if (hd->n) - mu_bn_free(hd->n); - if (hd->g) - mu_bn_free(hd->g); - if (hd->s) - mu_bn_free(hd->s); - if (hd->bytes_s) - free(hd->bytes_s); - if (hd->v) - mu_bn_free(hd->v); - if (hd->B) - mu_bn_free(hd->B); - if (hd->bytes_B) - free(hd->bytes_B); - if (hd->b) - mu_bn_free(hd->b); - if (hd->A) - mu_bn_free(hd->A); - if (hd->bytes_A) - free(hd->bytes_A); - if (hd->session_key) - free(hd->session_key); - memset(hd, 0, sizeof(*hd)); -} - -static mu_bn_t *calculate_x(char *bytes_salt, int salt_len, const char *username, const char *pass, int pass_len) -{ - unsigned char digest[SHA512HashSize]; - SHA512Context ctx; - srp_print("username:%s:\npass:%s:\npass_len:%d:\n", username, pass, pass_len); - hex_dbg("salt", bytes_salt, salt_len); - SHA512Reset(&ctx); - SHA512Input(&ctx, (unsigned char *)username, strlen(username)); - SHA512Input(&ctx, (unsigned char *)":", 1); - SHA512Input(&ctx, (unsigned char *)pass, pass_len); - SHA512Result(&ctx, digest); - - SHA512Reset(&ctx); - SHA512Input(&ctx, (unsigned char *)bytes_salt, salt_len); - SHA512Input(&ctx, digest, sizeof(digest)); - SHA512Result(&ctx, digest); - - hex_dbg("Digest", digest, sizeof(digest)); - return mu_bn_new_from_bin((char *)digest, sizeof(digest)); -} - -static mu_bn_t *calculate_padded_hash(mu_srp_handle_t *hd, char *a, int len_a, char *b, int len_b) -{ - unsigned char digest[SHA512HashSize]; - SHA512Context ctx; - int pad_len; - char *s = NULL; - - if (len_a > len_b) { - pad_len = hd->len_n - len_b; - } else { - pad_len = hd->len_n - len_a; - } - - if (pad_len) { - s = malloc(pad_len); - if (s) { - memset(s, 0, pad_len); - } - } - - SHA512Reset(&ctx); - /* PAD (a) */ - if (s && (len_a != hd->len_n)) { - SHA512Input(&ctx, (unsigned char *)s, hd->len_n - len_a); - } - - SHA512Input(&ctx, (unsigned char *)a, len_a); - - /* PAD (b) */ - if (s && (len_b != hd->len_n)) { - SHA512Input(&ctx, (unsigned char *)s, hd->len_n - len_b); - } - - SHA512Input(&ctx, (unsigned char *)b, len_b); - - SHA512Result(&ctx, digest); - - if (s) { - free(s); - } - - hex_dbg("value", digest, sizeof(digest)); - return mu_bn_new_from_bin((char *)digest, sizeof(digest)); -} - -/* k = SHA (N, PAD(g)) - * - * https://tools.ietf.org/html/draft-ietf-tls-srp-08 - */ -static mu_bn_t *calculate_k(mu_srp_handle_t *hd) -{ - srp_print("k-->"); - return calculate_padded_hash(hd, hd->bytes_n, hd->len_n, hd->bytes_g, hd->len_g); -} - -static mu_bn_t *calculate_u(mu_srp_handle_t *hd, char *A, int len_A) -{ - srp_print("u-->"); - return calculate_padded_hash(hd, A, len_A, hd->bytes_B, hd->len_B); -} - -int __mu_srp_srv_pubkey(mu_srp_handle_t *hd, char **bytes_B, int *len_B) -{ - mu_bn_t *k = calculate_k(hd); - mu_bn_t *kv = NULL; - mu_bn_t *gb = NULL; - if (!k) - goto error; - - hd->b = mu_bn_new(); - if (!hd->b) - goto error; - mu_bn_get_rand(hd->b, 256, -1, 0); - hex_dbg_bn("b", hd->b); - - /* B = kv + g^b */ - kv = mu_bn_new(); - gb = mu_bn_new(); - hd->B = mu_bn_new(); - if (!kv || !gb || ! hd->B) - goto error; - mu_bn_a_mul_b_mod_c(kv, k, hd->v, hd->n, hd->ctx); - mu_bn_a_exp_b_mod_c(gb, hd->g, hd->b, hd->n, hd->ctx); - mu_bn_a_add_b_mod_c(hd->B, kv, gb, hd->n, hd->ctx); - hd->bytes_B = mu_bn_to_bin(hd->B, len_B); - hd->len_B = *len_B; - *bytes_B = hd->bytes_B; - - mu_bn_free(k); - mu_bn_free(kv); - mu_bn_free(gb); - return 0; - error: - if (k) - mu_bn_free(k); - if (kv) - mu_bn_free(kv); - if (gb) - mu_bn_free(gb); - if (hd->B) { - mu_bn_free(hd->B); - hd->B = NULL; - } - if (hd->b) { - mu_bn_free(hd->b); - hd->b = NULL; - } - return -1; - -} - -int mu_srp_srv_pubkey(mu_srp_handle_t *hd, const char *username, const char *pass, int pass_len, int salt_len, - char **bytes_B, int *len_B, char **bytes_salt) -{ - /* Get Salt */ - int str_salt_len; - mu_bn_t *x = NULL; - hd->s = mu_bn_new(); - if (! hd->s) - goto error; - mu_bn_get_rand(hd->s, 8 * salt_len, -1, 0); - *bytes_salt = mu_bn_to_bin(hd->s, &str_salt_len); - if (! *bytes_salt) - goto error; - hd->bytes_s = *bytes_salt; - hd->len_s = salt_len; - hex_dbg("Salt", *bytes_salt, str_salt_len); - - /* Calculate X which is simply a hash for all these things */ - x = calculate_x(*bytes_salt, str_salt_len, username, pass, pass_len); - if (! x) - goto error; - hex_dbg_bn("x", x); - - /* v = g^x % N */ - hd->v = mu_bn_new(); - if (! hd->v) - goto error; - mu_bn_a_exp_b_mod_c(hd->v, hd->g, x, hd->n, hd->ctx); - hex_dbg_bn("Verifier", hd->v); - - if (__mu_srp_srv_pubkey(hd, bytes_B, len_B) < 0 ) - goto error; - - mu_bn_free(x); - return 0; - -error: - if (hd->s) { - mu_bn_free(hd->s); - hd->s = NULL; - } - if (*bytes_salt) { - free(*bytes_salt); - *bytes_salt = NULL; - hd->bytes_s = NULL; - hd->len_s = 0; - } - if (x) { - mu_bn_free(x); - x = NULL; - } - if (hd->v) { - mu_bn_free(hd->v); - hd->v = NULL; - } - return -1; -} - -int mu_srp_srv_pubkey_from_salt_verifier(mu_srp_handle_t *hd, char **bytes_B, int *len_B) -{ - return __mu_srp_srv_pubkey(hd, bytes_B, len_B); -} - -int mu_srp_set_salt_verifier(mu_srp_handle_t *hd, const char *salt, int salt_len, - const char *verifier, int verifier_len) -{ - hd->bytes_s = malloc(salt_len); - if (!hd->bytes_s) { - goto error; - } - memcpy(hd->bytes_s, salt, salt_len); - hd->len_s = salt_len; - - hd->s = mu_bn_new_from_bin(salt, salt_len); - if (!hd->s) { - goto error; - } - - hd->v = mu_bn_new_from_bin(verifier, verifier_len); - if (!hd->v) { - goto error; - } - return 0; - -error: - if (hd->bytes_s) { - free(hd->bytes_s); - hd->bytes_s = NULL; - hd->len_s = 0; - } - if (hd->s) { - mu_bn_free(hd->s); - hd->s = NULL; - } - if (hd->v) { - mu_bn_free(hd->v); - hd->v = NULL; - } - return -1; -} - -int mu_srp_get_session_key(mu_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, int *len_key) -{ - mu_bn_t *u, *vu, *avu, *S; - char *bytes_S; - int len_S; - - u = vu = avu = S = NULL; - bytes_S = NULL; - - hd->bytes_A = malloc(len_A); - if (! hd->bytes_A) - goto error; - memcpy(hd->bytes_A, bytes_A, len_A); - hd->len_A = len_A; - - hd->A = mu_bn_new_from_bin(bytes_A, len_A); - if (! hd->A) - goto error; - u = calculate_u(hd, bytes_A, len_A); - if (! u) - goto error; - - /* S = (A v^u)^b */ - vu = mu_bn_new(); - avu = mu_bn_new(); - S = mu_bn_new(); - if (!vu || !avu || !S ) - goto error; - - mu_bn_a_exp_b_mod_c(vu, hd->v, u, hd->n, hd->ctx); - mu_bn_a_mul_b_mod_c(avu, hd->A, vu, hd->n, hd->ctx); - mu_bn_a_exp_b_mod_c(S, avu, hd->b, hd->n, hd->ctx); - hex_dbg_bn("S", S); - - bytes_S = mu_bn_to_bin(S, &len_S); - hd->session_key = malloc(SHA512HashSize); - if (!hd->session_key || ! bytes_S) - goto error; - - SHA512_hash((unsigned char *)bytes_S, len_S, (unsigned char *)hd->session_key); - *bytes_key = hd->session_key; - *len_key = SHA512HashSize; - - free(bytes_S); - mu_bn_free(vu); - mu_bn_free(avu); - mu_bn_free(S); - mu_bn_free(u); - return 0; - error: - if (bytes_S) - free(bytes_S); - if (vu) - mu_bn_free(vu); - if (avu) - mu_bn_free(avu); - if (S) - mu_bn_free(S); - if (u) - mu_bn_free(u); - if (hd->session_key) { - free(hd->session_key); - hd->session_key = NULL; - } - if (hd->A) { - mu_bn_free(hd->A); - hd->A = NULL; - } - if (hd->bytes_A) { - free(hd->bytes_A); - hd->bytes_A = NULL; - } - return -1; -} - -int mu_srp_exchange_proofs(mu_srp_handle_t *hd, const char *username, char *bytes_user_proof, char *bytes_host_proof) -{ - /* First calculate M */ - unsigned char hash_n[SHA512HashSize]; - unsigned char hash_g[SHA512HashSize]; - unsigned char hash_n_xor_g[SHA512HashSize]; - int i; - SHA512_hash((unsigned char *)hd->bytes_n, hd->len_n, (unsigned char *)hash_n); - SHA512_hash((unsigned char *)hd->bytes_g, hd->len_g, (unsigned char *)hash_g); - for (i = 0; i < SHA512HashSize; i++) - hash_n_xor_g[i] = hash_n[i] ^ hash_g[i]; - - unsigned char hash_I[SHA512HashSize]; - SHA512_hash((unsigned char *)username, strlen(username), (unsigned char *)hash_I); - - SHA512Context ctx; - unsigned char digest[SHA512HashSize]; - SHA512Reset(&ctx); - SHA512Input(&ctx, hash_n_xor_g, SHA512HashSize); - SHA512Input(&ctx, hash_I, SHA512HashSize); - SHA512Input(&ctx, (unsigned char *)hd->bytes_s, hd->len_s); - SHA512Input(&ctx, (unsigned char *)hd->bytes_A, hd->len_A); - SHA512Input(&ctx, (unsigned char *)hd->bytes_B, hd->len_B); - SHA512Input(&ctx, (unsigned char *)hd->session_key, SHA512HashSize); - SHA512Result(&ctx, digest); - - hex_dbg("M", digest, sizeof(digest)); - if (memcmp(bytes_user_proof, digest, SHA512HashSize) != 0) - return false; - /* M is now validated, let's proceed to H(AMK) */ - SHA512Reset(&ctx); - SHA512Input(&ctx, (unsigned char *)hd->bytes_A, hd->len_A); - SHA512Input(&ctx, digest, SHA512HashSize); - SHA512Input(&ctx, (unsigned char *)hd->session_key, SHA512HashSize); - SHA512Result(&ctx, (unsigned char *)bytes_host_proof); - hex_dbg("AMK", bytes_host_proof, SHA512HashSize); - - return true; -} -/************************* SRP Stuff Ends */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.h b/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.h deleted file mode 100644 index 80883bc77..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/mu_srp.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _MU_SRP_H_ -#define _MU_SRP_H_ - -#include -#include "mu_bignum.h" - -typedef enum { - MU_NG_3072 = 0, -} mu_ng_type_t; - -typedef struct mu_srp_handle { - int allocated; - mu_ng_type_t type; - mu_bn_ctx_t *ctx; - - /* N - * the bytes_n simply points to the static array - */ - mu_bn_t *n; - char *bytes_n; - int len_n; - - /* g - * the bytes_g simply points to the static array - */ - mu_bn_t *g; - char *bytes_g; - int len_g; - - /* Salt */ - mu_bn_t *s; - char *bytes_s; - int len_s; - /* Verifier */ - mu_bn_t *v; - /* B */ - mu_bn_t *B; - char *bytes_B; - int len_B; - /* b */ - mu_bn_t *b; - /* A */ - mu_bn_t *A; - char *bytes_A; - int len_A; - /* K - session key*/ - char *session_key; -} mu_srp_handle_t; - -int mu_srp_init(mu_srp_handle_t *hd, mu_ng_type_t ng); - -void mu_srp_free(mu_srp_handle_t *hd); -/* Returns B (pub key) and salt - * - * *bytes_B MUST NOT BE FREED BY THE CALLER - * *bytes_salt MUST NOT BE FREE BY THE CALLER - * - */ -int mu_srp_srv_pubkey(mu_srp_handle_t *hd, const char *username, const char *pass, int pass_len, int salt_len, - char **bytes_B, int *len_B, char **bytes_salt); - -/* Set the Salt and Verifier pre-generated for a given password. - * This should be used only if the actual password is not available. - * The public key can then be generated using mu_srp_srv_pubkey_from_salt_verifier() - * and not mu_srp_srv_pubkey() - */ -int mu_srp_set_salt_verifier(mu_srp_handle_t *hd, const char *salt, int salt_len, - const char *verifier, int verifier_len); - -/* Returns B (pub key) when the salt and verifier are set using mu_srp_set_salt_verifier() - * - * *bytes_B MUST NOT BE FREED BY THE CALLER - */ -int mu_srp_srv_pubkey_from_salt_verifier(mu_srp_handle_t *hd, char **bytes_B, int *len_B); - -/* Returns bytes_key - * *bytes_key MUST NOT BE FREED BY THE CALLER - */ -int mu_srp_get_session_key(mu_srp_handle_t *hd, char *bytes_A, int len_A, char **bytes_key, int *len_key); - -/* Exchange proofs - * Returns 1 if user's proof is ok. Also 1 when is returned, bytes_host_proof contains our proof. - * - * bytes_user_proof is parameter in - * bytes_host_proof is parameter out (should be SHA512_DIGEST_LENGTH) bytes in size - */ -int mu_srp_exchange_proofs(mu_srp_handle_t *hd, const char *username, char *bytes_user_proof, char *bytes_host_proof); - - - -#endif /* ! _MU_SRP_H_ */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h deleted file mode 100644 index 158c22cb1..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#pragma once - -#if CONFIG_IDF_TARGET_ESP32 -#include "bignum_ESP32.h" -#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 -#include "bignum_ESP32_C3.h" -#endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c deleted file mode 100644 index d21b44a80..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.c +++ /dev/null @@ -1,294 +0,0 @@ -/** - * \brief Multi-precision integer library, ESP-IDF hardware accelerated parts - * - * based on mbedTLS implementation - * - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved - * Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#if CONFIG_IDF_TARGET_ESP32 -#if __has_include("esp_idf_version.h") -#include "esp_idf_version.h" -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) -// #warning("IDF is 4 or later") -#include "soc/hwcrypto_periph.h" -#endif -#endif - -#include "soc/hwcrypto_reg.h" -#include "driver/periph_ctrl.h" -#include -#include "bignum_impl.h" -#include -#include -#if CONFIG_IDF_TARGET_ESP32C3 -#include "esp32c3/dport_access.h" -#endif -#if CONFIG_IDF_TARGET_ESP32S3 -#include "esp32s3/dport_access.h" -#endif - -static _lock_t mpi_lock; - -/* Round up number of words to nearest - 512 bit (16 word) block count. -*/ -size_t esp_mpi_hardware_words(size_t words) -{ - return (words + 0xF) & ~0xF; -} - -void esp_mpi_enable_hardware_hw_op( void ) -{ - /* newlib locks lazy initialize on ESP-IDF */ - _lock_acquire(&mpi_lock); - - /* Enable RSA hardware */ - periph_module_enable(PERIPH_RSA_MODULE); - DPORT_REG_CLR_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD); - - while (DPORT_REG_READ(RSA_CLEAN_REG) != 1) - { } - // Note: from enabling RSA clock to here takes about 1.3us -} - -void esp_mpi_disable_hardware_hw_op( void ) -{ - DPORT_REG_SET_BIT(DPORT_RSA_PD_CTRL_REG, DPORT_RSA_PD); - - /* Disable RSA hardware */ - periph_module_disable(PERIPH_RSA_MODULE); - - _lock_release(&mpi_lock); -} - - -/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'. - - If hw_words is higher than the number of words in the bignum then - these additional words will be zeroed in the memory buffer. - -*/ -static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t hw_words) -{ - uint32_t *pbase = (uint32_t *)mem_base; - uint32_t copy_words = MIN(hw_words, mpi->n); - - /* Copy MPI data to memory block registers */ - for (int i = 0; i < copy_words; i++) { - pbase[i] = mpi->p[i]; - } - - /* Zero any remaining memory block data */ - for (int i = copy_words; i < hw_words; i++) { - pbase[i] = 0; - } -} - -/* Read mbedTLS MPI bignum back from hardware memory block. - - Reads num_words words from block. - - Bignum 'x' should already be grown to at least num_words by caller (can be done while - calculation is in progress, to save some cycles) -*/ -static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words) -{ - assert(x->n >= num_words); - - /* Copy data from memory block registers */ - esp_dport_access_read_buffer(x->p, mem_base, num_words); - - /* Zero any remaining limbs in the bignum, if the buffer is bigger - than num_words */ - for (size_t i = num_words; i < x->n; i++) { - x->p[i] = 0; - } -} - - -/* Begin an RSA operation. op_reg specifies which 'START' register - to write to. -*/ -static inline void start_op(uint32_t op_reg) -{ - /* Clear interrupt status */ - DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1); - - /* Note: above REG_WRITE includes a memw, so we know any writes - to the memory blocks are also complete. */ - - DPORT_REG_WRITE(op_reg, 1); -} - -/* Wait for an RSA operation to complete. -*/ -static inline void wait_op_complete(void) -{ - while (DPORT_REG_READ(RSA_INTERRUPT_REG) != 1) - { } - - /* clear the interrupt */ - DPORT_REG_WRITE(RSA_INTERRUPT_REG, 1); -} - -/* Read result from last MPI operation */ -void esp_mpi_read_result_hw_op(mbedtls_mpi *Z, size_t z_words) -{ - wait_op_complete(); - mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, z_words); -} - -/* Z = (X * Y) mod M */ -void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words) -{ - /* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */ - mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, hw_words); - mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words); - mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Rinv, hw_words); - DPORT_REG_WRITE(RSA_M_DASH_REG, (uint32_t)Mprime); - - /* "mode" register loaded with number of 512-bit blocks, minus 1 */ - DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hw_words / 16) - 1); - - /* Execute first stage montgomery multiplication */ - start_op(RSA_MULT_START_REG); - - wait_op_complete(); - - /* execute second stage */ - /* Load Y to X input memory block, rerun */ - mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, hw_words); - - start_op(RSA_MULT_START_REG); -} - -/* Z = X * Y */ -void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t hw_words) -{ - /* Copy X (right-extended) & Y (left-extended) to memory block */ - mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words); - mpi_to_mem_block(RSA_MEM_Z_BLOCK_BASE + hw_words * 4, Y, hw_words); - /* NB: as Y is left-extended, we don't zero the bottom words_mult words of Y block. - This is OK for now because zeroing is done by hardware when we do esp_mpi_acquire_hardware(). - */ - - DPORT_REG_WRITE(RSA_M_DASH_REG, 0); - - /* "mode" register loaded with number of 512-bit blocks in result, - plus 7 (for range 9-12). (this is ((N~ / 32) - 1) + 8)) - */ - DPORT_REG_WRITE(RSA_MULT_MODE_REG, ((hw_words * 2) / 16) + 7); - - start_op(RSA_MULT_START_REG); - -} - - -int esp_mont_hw_op(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, - mbedtls_mpi_uint Mprime, - size_t hw_words, - bool again) -{ - // Note Z may be the same pointer as X or Y - int ret = 0; - - // montgomery mult prepare - if (again == false) { - mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, hw_words); - DPORT_REG_WRITE(RSA_M_DASH_REG, Mprime); - DPORT_REG_WRITE(RSA_MULT_MODE_REG, hw_words / 16 - 1); - } - - mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words); - mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Y, hw_words); - - start_op(RSA_MULT_START_REG); - Z->s = 1; // The sign of Z will be = M->s (but M->s is always 1) - MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, hw_words) ); - - wait_op_complete(); - - /* Read back the result */ - mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, hw_words); - - - /* from HAC 14.36 - 3. If Z >= M then Z = Z - M */ - if (mbedtls_mpi_cmp_mpi(Z, M) >= 0) { - MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(Z, Z, M)); - } -cleanup: - return ret; -} - - - -/* Special-case of mbedtls_mpi_mult_mpi(), where we use hardware montgomery mod - multiplication to calculate an mbedtls_mpi_mult_mpi result where either - A or B are >2048 bits so can't use the standard multiplication method. - - Result (z_words, based on A bits + B bits) must still be less than 4096 bits. - - This case is simpler than the general case modulo multiply of - esp_mpi_mul_mpi_mod() because we can control the other arguments: - - * Modulus is chosen with M=(2^num_bits - 1) (ie M=R-1), so output - isn't actually modulo anything. - * Mprime and Rinv are therefore predictable as follows: - Mprime = 1 - Rinv = 1 - - (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv) -*/ -void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words) -{ - size_t hw_words = num_words; - - /* M = 2^num_words - 1, so block is entirely FF */ - for (int i = 0; i < hw_words; i++) { - DPORT_REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, UINT32_MAX); - } - /* Mprime = 1 */ - DPORT_REG_WRITE(RSA_M_DASH_REG, 1); - - /* "mode" register loaded with number of 512-bit blocks, minus 1 */ - DPORT_REG_WRITE(RSA_MULT_MODE_REG, (hw_words / 16) - 1); - - /* Load X */ - mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, hw_words); - - /* Rinv = 1, write first word */ - DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE, 1); - - /* Zero out rest of the Rinv words */ - for (int i = 1; i < hw_words; i++) { - DPORT_REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0); - } - - start_op(RSA_MULT_START_REG); - - wait_op_complete(); - - /* finish the modular multiplication */ - /* Load Y to X input memory block, rerun */ - mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, hw_words); - - start_op(RSA_MULT_START_REG); - -} -#endif //CONFIG_IDF_TARGET_ESP32 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h deleted file mode 100644 index fa91a961f..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#if CONFIG_IDF_TARGET_ESP32 -#pragma once - -#include_next "mbedtls/bignum.h" -#include "sdkconfig.h" - -/** - * This is a wrapper for the main mbedtls/bignum.h. This wrapper - * provides a few additional ESP32-only functions. - * - * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we - * do for AES, SHA, etc. Because we still use most of the bignum.h - * implementation and just replace a few hardware accelerated - * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in - * esp_config.h). - * - * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no - * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this - * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation. - */ - -/** - * @brief Lock access to RSA Accelerator (MPI/bignum operations) - * - * RSA Accelerator hardware unit can only be used by one - * consumer at a time. - * - * @note This function is non-recursive (do not call it twice from the - * same task.) - * - * @note You do not need to call this if you are using the mbedTLS bignum.h - * API or esp_mpi_xxx functions. This function is only needed if you - * want to call ROM RSA functions or access the registers directly. - * - */ -void esp_mpi_acquire_hardware(void); - -/** - * @brief Unlock access to RSA Accelerator (MPI/bignum operations) - * - * Has to be called once for each call to esp_mpi_acquire_hardware(). - * - * @note You do not need to call this if you are using the mbedTLS bignum.h - * API or esp_mpi_xxx functions. This function is only needed if you - * want to call ROM RSA functions or access the registers directly. - */ -void esp_mpi_release_hardware(void); - -//#if CONFIG_MBEDTLS_HARDWARE_MPI - -/* @brief MPI modular mupltiplication function - * - * Calculates Z = (X * Y) mod M using MPI hardware acceleration. - * - * This is not part of the standard mbedTLS bignum API. - * - * @note All of X, Y & Z should be less than 4096 bit long or an error is returned. - * - * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init(). - * @param X First multiplication argument. - * @param Y Second multiplication argument. - * @param M Modulus value for result. - * - * @return 0 on success, mbedTLS MPI error codes on failure. - */ -int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); - -//#endif // CONFIG_MBEDTLS_HARDWARE_MPI -#endif //CONFIG_IDF_TARGET_ESP32 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c deleted file mode 100644 index 1c579005f..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.c +++ /dev/null @@ -1,108 +0,0 @@ -/** - * \brief Multi-precision integer library, ESP-IDF hardware accelerated parts - * - * based on mbedTLS implementation - * - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved - * Additions Copyright (C) 2016-2020, Espressif Systems (Shanghai) PTE Ltd - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 -#if __has_include("esp_idf_version.h") -#include "esp_idf_version.h" -#endif - -#include -#include "soc/hwcrypto_periph.h" -#include "driver/periph_ctrl.h" -#include "mbedtls/bignum.h" -#include "bignum_impl.h" -#include "soc/system_reg.h" -#include "soc/periph_defs.h" -#include "esp_crypto_lock.h" - -/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'. - - If hw_words is higher than the number of words in the bignum then - these additional words will be zeroed in the memory buffer. - -*/ -static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words) -{ - uint32_t *pbase = (uint32_t *)mem_base; - uint32_t copy_words = MIN(num_words, mpi->n); - - /* Copy MPI data to memory block registers */ - for (int i = 0; i < copy_words; i++) { - pbase[i] = mpi->p[i]; - } - - /* Zero any remaining memory block data */ - for (int i = copy_words; i < num_words; i++) { - pbase[i] = 0; - } -} - -/* Read mbedTLS MPI bignum back from hardware memory block. - - Reads num_words words from block. - - Bignum 'x' should already be grown to at least num_words by caller (can be done while - calculation is in progress, to save some cycles) -*/ -static inline void mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words) -{ - - /* Copy data from memory block registers */ - const size_t REG_WIDTH = sizeof(uint32_t); - for (size_t i = 0; i < num_words; i++) { - x->p[i] = REG_READ(mem_base + (i * REG_WIDTH)); - } - /* Zero any remaining limbs in the bignum, if the buffer is bigger - than num_words */ - for (size_t i = num_words; i < x->n; i++) { - x->p[i] = 0; - } - -} - -/* Begin an RSA operation. op_reg specifies which 'START' register - to write to. -*/ -static inline void start_op(uint32_t op_reg) -{ - /* Clear interrupt status */ - REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1); - - /* Note: above REG_WRITE includes a memw, so we know any writes - to the memory blocks are also complete. */ - - REG_WRITE(op_reg, 1); -} - -/* Wait for an RSA operation to complete. -*/ -static inline void wait_op_complete(void) -{ - while (REG_READ(RSA_QUERY_INTERRUPT_REG) != 1) - { } - - /* clear the interrupt */ - REG_WRITE(RSA_CLEAR_INTERRUPT_REG, 1); -} - -#endif //CONFIG_IDF_TARGET_ESP32C3 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h deleted file mode 100644 index e664dd779..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_ESP32_C3.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 -#pragma once - -#include_next "mbedtls/bignum.h" -#include "sdkconfig.h" - -/** - * This is a wrapper for the main mbedtls/bignum.h. This wrapper - * provides a few additional ESP32-only functions. - * - * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we - * do for AES, SHA, etc. Because we still use most of the bignum.h - * implementation and just replace a few hardware accelerated - * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in - * esp_config.h). - * - * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no - * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this - * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation. - */ - -/** - * @brief Lock access to RSA Accelerator (MPI/bignum operations) - * - * RSA Accelerator hardware unit can only be used by one - * consumer at a time. - * - * @note This function is non-recursive (do not call it twice from the - * same task.) - * - * @note You do not need to call this if you are using the mbedTLS bignum.h - * API or esp_mpi_xxx functions. This function is only needed if you - * want to call ROM RSA functions or access the registers directly. - * - */ -void esp_mpi_acquire_hardware(void); - -/** - * @brief Unlock access to RSA Accelerator (MPI/bignum operations) - * - * Has to be called once for each call to esp_mpi_acquire_hardware(). - * - * @note You do not need to call this if you are using the mbedTLS bignum.h - * API or esp_mpi_xxx functions. This function is only needed if you - * want to call ROM RSA functions or access the registers directly. - */ -void esp_mpi_release_hardware(void); - -//#if CONFIG_MBEDTLS_HARDWARE_MPI - -/* @brief MPI modular mupltiplication function - * - * Calculates Z = (X * Y) mod M using MPI hardware acceleration. - * - * This is not part of the standard mbedTLS bignum API. - * - * @note All of X, Y & Z should be less than 4096 bit long or an error is returned. - * - * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init(). - * @param X First multiplication argument. - * @param Y Second multiplication argument. - * @param M Modulus value for result. - * - * @return 0 on success, mbedTLS MPI error codes on failure. - */ -int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M); - -void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words); -static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words); -void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words); - - -//#endif // CONFIG_MBEDTLS_HARDWARE_MPI -#endif //CONFIG_IDF_TARGET_ESP32C3 diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h b/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h deleted file mode 100644 index 1b1fa8e56..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/bignum_impl.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _ESP_BIGNUM_H_ -#define _ESP_BIGNUM_H_ - -#include -#include - -/* Use montgomery exponentiation (HAC 14.94) for calculating X ^ Y mod M, - this may be faster for some targets. The hardware acceleration support for modular - exponentiation on the ESP32 is slow for public key operations, so use montgomery - exponentiation instead. -*/ - -// #define CONFIG_IDF_TARGET_ESP32 1 - -#if CONFIG_IDF_TARGET_ESP32 -#define ESP_MPI_USE_MONT_EXP - -#define MBEDTLS_MPI_EXP_MOD_ALT -//#define MBEDTLS_MPI_MUL_MPI_ALT -#endif - -#if CONFIG_IDF_TARGET_ESP32 -int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv ); - -/** - * @brief Enable the MPI hardware and acquire the lock - * - */ -void esp_mpi_enable_hardware_hw_op( void ); - -/** - * @brief Disable the MPI hardware and release the lock - * - */ -void esp_mpi_disable_hardware_hw_op( void ); - -/** - * @brief Calculate the number of words needed to represent the input word in hardware - * - * @param words The number of words to be represented - * - * @return size_t Number of words required - */ -size_t esp_mpi_hardware_words(size_t words); - -/** - * @brief Starts a (X * Y) Mod M calculation in hardware. Rinv and M_prime needs to be precalculated in software. - * - */ -void esp_mpi_mul_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words); - -/** - * @brief Starts a (X * Y) calculation in hardware. - * - */ -void esp_mpi_mul_mpi_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words); - -/** - * @brief Special-case of (X * Y), where we use hardware montgomery mod - multiplication to calculate result where either A or B are >2048 bits so - can't use the standard multiplication method. - * - */ -void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words); - -/** - * @brief Read out the result from the previous calculation. - * - */ -void esp_mpi_read_result_hw_op(mbedtls_mpi *Z, size_t z_words); - -#ifdef ESP_MPI_USE_MONT_EXP -/** - * @brief Starts a montgomery multiplication calculation in hardware - * - */ -int esp_mont_hw_op(mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi* Y, const mbedtls_mpi* M, - mbedtls_mpi_uint Mprime, - size_t hw_words, - bool again); - -#else - -/** - * @brief Starts a (X ^ Y) Mod M calculation in hardware. Rinv and M_prime needs to be precalculated in software. - * - */ -void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t hw_words); -#endif //CONFIG_IDF_TARGET_ESP32 -#endif //ESP_MPI_USE_MONT_EXP - -#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 -void esp_mpi_exp_mpi_mod_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, const mbedtls_mpi *Rinv, mbedtls_mpi_uint Mprime, size_t num_words); -extern int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv ); -extern size_t esp_mpi_hardware_words(size_t words); -extern void esp_mpi_enable_hardware_hw_op( void ); -extern void esp_mpi_disable_hardware_hw_op( void ); -extern void esp_mpi_read_result_hw_op(mbedtls_mpi *Z, size_t z_words); -extern void esp_mpi_mult_mpi_failover_mod_mult_hw_op(const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words); -#endif //CONFIG_IDF_TARGET_ESP32C3 - -#endif diff --git a/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c b/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c deleted file mode 100644 index 5b8e124ce..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/port/esp_bignum.c +++ /dev/null @@ -1,628 +0,0 @@ -/** - * \brief Multi-precision integer library, ESP32 hardware accelerated parts - * - * based on mbedTLS implementation - * - * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved - * Additions Copyright (C) 2016, Espressif Systems (Shanghai) PTE Ltd - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -#if __has_include("esp_idf_version.h") -#include "esp_idf_version.h" -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) -// #warning("IDF is 4 or later") -#include "soc/hwcrypto_periph.h" -#endif -#endif - -#include -#include -#include -#include -#include -#include -#include -#include "esp_system.h" -#include "esp_log.h" -#include "esp_attr.h" -#include "bignum_impl.h" -//#include "soc/soc_caps.h" - -#include - -// wangbin added -#if !defined(SOC_RSA_MAX_BIT_LEN) -#define SOC_RSA_MAX_BIT_LEN (4096) -#endif - - -/* Some implementation notes: - * - * - Naming convention x_words, y_words, z_words for number of words (limbs) used in a particular - * bignum. This number may be less than the size of the bignum - * - * - Naming convention hw_words for the hardware length of the operation. This number maybe be rounded up - * for targets that requres this (e.g. ESP32), and may be larger than any of the numbers - * involved in the calculation. - * - * - Timing behaviour of these functions will depend on the length of the inputs. This is fundamentally - * the same constraint as the software mbedTLS implementations, and relies on the same - * countermeasures (exponent blinding, etc) which are used in mbedTLS. - */ - -static const __attribute__((unused)) char *TAG = "bignum"; - -#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */ -#define biL (ciL << 3) /* bits in limb */ - - -/* Convert bit count to word count - */ -static inline size_t bits_to_words(size_t bits) -{ - return (bits + 31) / 32; -} - -/* Return the number of words actually used to represent an mpi - number. -*/ -#if defined(MBEDTLS_MPI_EXP_MOD_ALT) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) -static size_t mpi_words(const mbedtls_mpi *mpi) -{ - for (size_t i = mpi->n; i > 0; i--) { - if (mpi->p[i - 1] != 0) { - return i; - } - } - return 0; -} - -#endif //MBEDTLS_MPI_EXP_MOD_ALT - -/** - * - * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, - * where B^-1(B-1) mod N=1. Actually, only the least significant part of - * N' is needed, hence the definition N0'=N' mod b. We reproduce below the - * simple algorithm from an article by Dusse and Kaliski to efficiently - * find N0' from N0 and b - */ -static mbedtls_mpi_uint modular_inverse(const mbedtls_mpi *M) -{ - int i; - uint64_t t = 1; - uint64_t two_2_i_minus_1 = 2; /* 2^(i-1) */ - uint64_t two_2_i = 4; /* 2^i */ - uint64_t N = M->p[0]; - - for (i = 2; i <= 32; i++) { - if ((mbedtls_mpi_uint) N * t % two_2_i >= two_2_i_minus_1) { - t += two_2_i_minus_1; - } - - two_2_i_minus_1 <<= 1; - two_2_i <<= 1; - } - - return (mbedtls_mpi_uint)(UINT32_MAX - t + 1); -} - -/* Calculate Rinv = RR^2 mod M, where: - * - * R = b^n where b = 2^32, n=num_words, - * R = 2^N (where N=num_bits) - * RR = R^2 = 2^(2*N) (where N=num_bits=num_words*32) - * - * This calculation is computationally expensive (mbedtls_mpi_mod_mpi) - * so caller should cache the result where possible. - * - * DO NOT call this function while holding esp_mpi_enable_hardware_hw_op(). - * - */ -static int calculate_rinv(mbedtls_mpi *Rinv, const mbedtls_mpi *M, int num_words) -{ - int ret; - size_t num_bits = num_words * 32; - mbedtls_mpi RR; - mbedtls_mpi_init(&RR); - MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&RR, num_bits * 2, 1)); - MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(Rinv, &RR, M)); - -cleanup: - mbedtls_mpi_free(&RR); - - return ret; -} - - - - - -#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 0, 0) -/* Z = (X * Y) mod M - - Not an mbedTLS function -*/ -int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M) -{ - int ret = 0; - - size_t x_bits = mbedtls_mpi_bitlen(X); - size_t y_bits = mbedtls_mpi_bitlen(Y); - size_t m_bits = mbedtls_mpi_bitlen(M); - size_t z_bits = MIN(m_bits, x_bits + y_bits); - size_t x_words = bits_to_words(x_bits); - size_t y_words = bits_to_words(y_bits); - size_t m_words = bits_to_words(m_bits); - size_t z_words = bits_to_words(z_bits); - size_t hw_words = esp_mpi_hardware_words(MAX(x_words, MAX(y_words, m_words))); /* longest operand */ - mbedtls_mpi Rinv; - mbedtls_mpi_uint Mprime; - - /* Calculate and load the first stage montgomery multiplication */ - mbedtls_mpi_init(&Rinv); - MBEDTLS_MPI_CHK(calculate_rinv(&Rinv, M, hw_words)); - Mprime = modular_inverse(M); - - esp_mpi_enable_hardware_hw_op(); - /* Load and start a (X * Y) mod M calculation */ - esp_mpi_mul_mpi_mod_hw_op(X, Y, M, &Rinv, Mprime, hw_words); - - MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Z, z_words)); - - esp_mpi_read_result_hw_op(Z, z_words); - Z->s = X->s * Y->s; - -cleanup: - mbedtls_mpi_free(&Rinv); - esp_mpi_disable_hardware_hw_op(); - - return ret; -} - -#endif // ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 0, 0) - -#if defined(MBEDTLS_MPI_EXP_MOD_ALT) - -#ifdef ESP_MPI_USE_MONT_EXP -/* - * Return the most significant one-bit. - */ -static size_t mbedtls_mpi_msb( const mbedtls_mpi *X ) -{ - int i, j; - if (X != NULL && X->n != 0) { - for (i = X->n - 1; i >= 0; i--) { - if (X->p[i] != 0) { - for (j = biL - 1; j >= 0; j--) { - if ((X->p[i] & (1 << j)) != 0) { - return (i * biL) + j; - } - } - } - } - } - return 0; -} - -/* - * Montgomery exponentiation: Z = X ^ Y mod M (HAC 14.94) - */ -static int mpi_montgomery_exp_calc( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, - mbedtls_mpi *Rinv, - size_t hw_words, - mbedtls_mpi_uint Mprime ) -{ - int ret = 0; - mbedtls_mpi X_, one; - - mbedtls_mpi_init(&X_); - mbedtls_mpi_init(&one); - if ( ( ( ret = mbedtls_mpi_grow(&one, hw_words) ) != 0 ) || - ( ( ret = mbedtls_mpi_set_bit(&one, 0, 1) ) != 0 ) ) { - goto cleanup2; - } - - // Algorithm from HAC 14.94 - { - // 0 determine t (highest bit set in y) - int t = mbedtls_mpi_msb(Y); - - esp_mpi_enable_hardware_hw_op(); - - // 1.1 x_ = mont(x, R^2 mod m) - // = mont(x, rb) - MBEDTLS_MPI_CHK( esp_mont_hw_op(&X_, X, Rinv, M, Mprime, hw_words, false) ); - - // 1.2 z = R mod m - // now z = R mod m = Mont (R^2 mod m, 1) mod M (as Mont(x) = X&R^-1 mod M) - MBEDTLS_MPI_CHK( esp_mont_hw_op(Z, Rinv, &one, M, Mprime, hw_words, true) ); - - // 2 for i from t down to 0 - for (int i = t; i >= 0; i--) { - // 2.1 z = mont(z,z) - if (i != t) { // skip on the first iteration as is still unity - MBEDTLS_MPI_CHK( esp_mont_hw_op(Z, Z, Z, M, Mprime, hw_words, true) ); - } - - // 2.2 if y[i] = 1 then z = mont(A, x_) - if (mbedtls_mpi_get_bit(Y, i)) { - MBEDTLS_MPI_CHK( esp_mont_hw_op(Z, Z, &X_, M, Mprime, hw_words, true) ); - } - } - - // 3 z = Mont(z, 1) - MBEDTLS_MPI_CHK( esp_mont_hw_op(Z, Z, &one, M, Mprime, hw_words, true) ); - } - -cleanup: - esp_mpi_disable_hardware_hw_op(); - -cleanup2: - mbedtls_mpi_free(&X_); - mbedtls_mpi_free(&one); - return ret; -} - -#endif //USE_MONT_EXPONENATIATION - -/* - * Z = X ^ Y mod M - * - * _Rinv is optional pre-calculated version of Rinv (via calculate_rinv()). - * - * (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv) - * - */ -// wangbin changed mbedtls_mpi_exp_mod -> esp_mpi_exp_mod -int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv ) -{ - int ret = 0; - size_t x_words = mpi_words(X); - size_t y_words = mpi_words(Y); - size_t m_words = mpi_words(M); - - - /* "all numbers must be the same length", so choose longest number - as cardinal length of operation... - */ - size_t num_words = esp_mpi_hardware_words(MAX(m_words, MAX(x_words, y_words))); - - mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */ - mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */ - mbedtls_mpi_uint Mprime; - - if (mbedtls_mpi_cmp_int(M, 0) <= 0 || (M->p[0] & 1) == 0) { - return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; - } - - if (mbedtls_mpi_cmp_int(Y, 0) < 0) { - return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; - } - - if (mbedtls_mpi_cmp_int(Y, 0) == 0) { - return mbedtls_mpi_lset(Z, 1); - } - - if (num_words * 32 > SOC_RSA_MAX_BIT_LEN) { - return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; - } - - /* Determine RR pointer, either _RR for cached value - or local RR_new */ - if (_Rinv == NULL) { - mbedtls_mpi_init(&Rinv_new); - Rinv = &Rinv_new; - } else { - Rinv = _Rinv; - } - if (Rinv->p == NULL) { - MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words)); - } - - Mprime = modular_inverse(M); - - // Montgomery exponentiation: Z = X ^ Y mod M (HAC 14.94) -#ifdef ESP_MPI_USE_MONT_EXP - ret = mpi_montgomery_exp_calc(Z, X, Y, M, Rinv, num_words, Mprime) ; - MBEDTLS_MPI_CHK(ret); -#else - esp_mpi_enable_hardware_hw_op(); - - esp_mpi_exp_mpi_mod_hw_op(X, Y, M, Rinv, Mprime, num_words); - ret = mbedtls_mpi_grow(Z, m_words); - if (ret != 0) { - esp_mpi_disable_hardware_hw_op(); - goto cleanup; - } - esp_mpi_read_result_hw_op(Z, m_words); - esp_mpi_disable_hardware_hw_op(); -#endif - - // Compensate for negative X - if (X->s == -1 && (Y->p[0] & 1) != 0) { - Z->s = -1; - MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(Z, M, Z)); - } else { - Z->s = 1; - } - -cleanup: - if (_Rinv == NULL) { - mbedtls_mpi_free(&Rinv_new); - } - return ret; -} - -#endif /* MBEDTLS_MPI_EXP_MOD_ALT */ - -#if CONFIG_IDF_TARGET_ESP32C3 -int esp_mpi_exp_mod( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M, mbedtls_mpi *_Rinv ) -{ - int ret = 0; - size_t x_words = mpi_words(X); - size_t y_words = mpi_words(Y); - size_t m_words = mpi_words(M); - - - /* "all numbers must be the same length", so choose longest number - as cardinal length of operation... - */ - size_t num_words = esp_mpi_hardware_words(MAX(m_words, MAX(x_words, y_words))); - - mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */ - mbedtls_mpi *Rinv; /* points to _Rinv (if not NULL) othwerwise &RR_new */ - mbedtls_mpi_uint Mprime; - - if (mbedtls_mpi_cmp_int(M, 0) <= 0 || (M->p[0] & 1) == 0) { - return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; - } - - if (mbedtls_mpi_cmp_int(Y, 0) < 0) { - return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; - } - - if (mbedtls_mpi_cmp_int(Y, 0) == 0) { - return mbedtls_mpi_lset(Z, 1); - } - - if (num_words * 32 > SOC_RSA_MAX_BIT_LEN) { - return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; - } - - /* Determine RR pointer, either _RR for cached value - or local RR_new */ - if (_Rinv == NULL) { - mbedtls_mpi_init(&Rinv_new); - Rinv = &Rinv_new; - } else { - Rinv = _Rinv; - } - if (Rinv->p == NULL) { - MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words)); - } - - Mprime = modular_inverse(M); - - // Montgomery exponentiation: Z = X ^ Y mod M (HAC 14.94) -#ifdef ESP_MPI_USE_MONT_EXP - ret = mpi_montgomery_exp_calc(Z, X, Y, M, Rinv, num_words, Mprime) ; - MBEDTLS_MPI_CHK(ret); -#else - esp_mpi_enable_hardware_hw_op(); - - esp_mpi_exp_mpi_mod_hw_op(X, Y, M, Rinv, Mprime, num_words); - ret = mbedtls_mpi_grow(Z, m_words); - if (ret != 0) { - esp_mpi_disable_hardware_hw_op(); - goto cleanup; - } - esp_mpi_read_result_hw_op(Z, m_words); - esp_mpi_disable_hardware_hw_op(); -#endif - - // Compensate for negative X - if (X->s == -1 && (Y->p[0] & 1) != 0) { - Z->s = -1; - MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(Z, M, Z)); - } else { - Z->s = 1; - } - -cleanup: - if (_Rinv == NULL) { - mbedtls_mpi_free(&Rinv_new); - } - return ret; -} -#endif //CONFIG_IDF_TARGET_ESP32C3 - - - -#if defined(MBEDTLS_MPI_MUL_MPI_ALT) /* MBEDTLS_MPI_MUL_MPI_ALT */ - -static int mpi_mult_mpi_failover_mod_mult( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t z_words); -static int mpi_mult_mpi_overlong(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t y_words, size_t z_words); - -#if ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 0, 0) -/* Z = X * Y */ -int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y ) -{ - int ret = 0; - size_t x_bits = mbedtls_mpi_bitlen(X); - size_t y_bits = mbedtls_mpi_bitlen(Y); - size_t x_words = bits_to_words(x_bits); - size_t y_words = bits_to_words(y_bits); - size_t z_words = bits_to_words(x_bits + y_bits); - size_t hw_words = esp_mpi_hardware_words(MAX(x_words, y_words)); // length of one operand in hardware - - /* Short-circuit eval if either argument is 0 or 1. - - This is needed as the mpi modular division - argument will sometimes call in here when one - argument is too large for the hardware unit, but the other - argument is zero or one. - */ - if (x_bits == 0 || y_bits == 0) { - mbedtls_mpi_lset(Z, 0); - return 0; - } - if (x_bits == 1) { - ret = mbedtls_mpi_copy(Z, Y); - Z->s *= X->s; - return ret; - } - if (y_bits == 1) { - ret = mbedtls_mpi_copy(Z, X); - Z->s *= Y->s; - return ret; - } - - /* Grow Z to result size early, avoid interim allocations */ - MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, z_words) ); - - /* If either factor is over 2048 bits, we can't use the standard hardware multiplier - (it assumes result is double longest factor, and result is max 4096 bits.) - - However, we can fail over to mod_mult for up to 4096 bits of result (modulo - multiplication doesn't have the same restriction, so result is simply the - number of bits in X plus number of bits in in Y.) - */ - if (hw_words * 32 > SOC_RSA_MAX_BIT_LEN/2) { - if (z_words * 32 <= SOC_RSA_MAX_BIT_LEN) { - /* Note: it's possible to use mpi_mult_mpi_overlong - for this case as well, but it's very slightly - slower and requires a memory allocation. - */ - return mpi_mult_mpi_failover_mod_mult(Z, X, Y, z_words); - } else { - /* Still too long for the hardware unit... */ - if (y_words > x_words) { - return mpi_mult_mpi_overlong(Z, X, Y, y_words, z_words); - } else { - return mpi_mult_mpi_overlong(Z, Y, X, x_words, z_words); - } - } - } - - /* Otherwise, we can use the (faster) multiply hardware unit */ - esp_mpi_enable_hardware_hw_op(); - - esp_mpi_mul_mpi_hw_op(X, Y, hw_words); - esp_mpi_read_result_hw_op(Z, z_words); - - esp_mpi_disable_hardware_hw_op(); - - Z->s = X->s * Y->s; - -cleanup: - return ret; -} -#endif //ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 0, 0) - - - -/* Deal with the case when X & Y are too long for the hardware unit, by splitting one operand - into two halves. - - Y must be the longer operand - - Slice Y into Yp, Ypp such that: - Yp = lower 'b' bits of Y - Ypp = upper 'b' bits of Y (right shifted) - - Such that - Z = X * Y - Z = X * (Yp + Ypp<p, - .n = words_slice, - .s = Y->s - }; - /* Ypp holds upper bits of Y, right shifted (also reuses Y's array contents) */ - const mbedtls_mpi Ypp = { - .p = Y->p + words_slice, - .n = y_words - words_slice, - .s = Y->s - }; - mbedtls_mpi_init(&Ztemp); - - /* Get result Ztemp = Yp * X (need temporary variable Ztemp) */ - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(&Ztemp, X, &Yp) ); - - /* Z = Ypp * Y */ - MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi(Z, X, &Ypp) ); - - /* Z = Z << b */ - MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l(Z, words_slice * 32) ); - - /* Z += Ztemp */ - MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi(Z, Z, &Ztemp) ); - -cleanup: - mbedtls_mpi_free(&Ztemp); - - return ret; -} - -/* Special-case of mbedtls_mpi_mult_mpi(), where we use hardware montgomery mod - multiplication to calculate an mbedtls_mpi_mult_mpi result where either - A or B are >2048 bits so can't use the standard multiplication method. - - Result (number of words, based on A bits + B bits) must still be less than 4096 bits. - - This case is simpler than the general case modulo multiply of - esp_mpi_mul_mpi_mod() because we can control the other arguments: - - * Modulus is chosen with M=(2^num_bits - 1) (ie M=R-1), so output - * Mprime and Rinv are therefore predictable as follows: - isn't actually modulo anything. - Mprime 1 - Rinv 1 - - (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv) -*/ - -static int mpi_mult_mpi_failover_mod_mult( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t z_words) -{ - int ret; - size_t hw_words = esp_mpi_hardware_words(z_words); - - esp_mpi_enable_hardware_hw_op(); - - esp_mpi_mult_mpi_failover_mod_mult_hw_op(X, Y, hw_words ); - MBEDTLS_MPI_CHK( mbedtls_mpi_grow(Z, hw_words) ); - esp_mpi_read_result_hw_op(Z, hw_words); - - Z->s = X->s * Y->s; -cleanup: - esp_mpi_disable_hardware_hw_op(); - return ret; -} - -#endif /* MBEDTLS_MPI_MUL_MPI_ALT */ diff --git a/lib/libesp32_div/ESP32-HomeKit/src/sha-private.h b/lib/libesp32_div/ESP32-HomeKit/src/sha-private.h deleted file mode 100644 index 9ccc8dd26..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/sha-private.h +++ /dev/null @@ -1,29 +0,0 @@ -/************************ sha-private.h ************************/ -/***************** See RFC 6234 for details. *******************/ -#ifndef _SHA_PRIVATE__H -#define _SHA_PRIVATE__H -/* - * These definitions are defined in FIPS 180-3, section 4.1. - * Ch() and Maj() are defined identically in sections 4.1.1, - * 4.1.2, and 4.1.3. - * - * The definitions used in FIPS 180-3 are as follows: - */ - -#ifndef USE_MODIFIED_MACROS -#define SHA_Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) -#define SHA_Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) -#else /* USE_MODIFIED_MACROS */ -/* - * The following definitions are equivalent and potentially faster. - */ - -#define SHA_Ch(x, y, z) (((x) & ((y) ^ (z))) ^ (z)) -#define SHA_Maj(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) - -#endif /* USE_MODIFIED_MACROS */ - -#define SHA_Parity(x, y, z) ((x) ^ (y) ^ (z)) - -#endif /* _SHA_PRIVATE__H */ - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/sha.h b/lib/libesp32_div/ESP32-HomeKit/src/sha.h deleted file mode 100644 index 276c3685b..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/sha.h +++ /dev/null @@ -1,358 +0,0 @@ -/**************************** sha.h ****************************/ -/***************** See RFC 6234 for details. *******************/ -/* - Copyright (c) 2011 IETF Trust and the persons identified as - authors of the code. All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - - Redistributions of source code must retain the above - copyright notice, this list of conditions and - the following disclaimer. - - - Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - - Neither the name of Internet Society, IETF or IETF Trust, nor - the names of specific contributors, may be used to endorse or - promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef _SHA_H_ -#define _SHA_H_ - -/* - * Description: - * This file implements the Secure Hash Algorithms - * as defined in the U.S. National Institute of Standards - * and Technology Federal Information Processing Standards - * Publication (FIPS PUB) 180-3 published in October 2008 - * and formerly defined in its predecessors, FIPS PUB 180-1 - * and FIP PUB 180-2. - * - * A combined document showing all algorithms is available at - * http://csrc.nist.gov/publications/fips/ - * fips180-3/fips180-3_final.pdf - * - * The five hashes are defined in these sizes: - * SHA-1 20 byte / 160 bit - * SHA-224 28 byte / 224 bit - * SHA-256 32 byte / 256 bit - * SHA-384 48 byte / 384 bit - * SHA-512 64 byte / 512 bit - * - * Compilation Note: - * These files may be compiled with two options: - * USE_32BIT_ONLY - use 32-bit arithmetic only, for systems - * without 64-bit integers - * - * USE_MODIFIED_MACROS - use alternate form of the SHA_Ch() - * and SHA_Maj() macros that are equivalent - * and potentially faster on many systems - * - */ - -#include -/* - * If you do not have the ISO standard stdint.h header file, then you - * must typedef the following: - * name meaning - * uint64_t unsigned 64-bit integer - * uint32_t unsigned 32-bit integer - * uint8_t unsigned 8-bit integer (i.e., unsigned char) - * int_least16_t integer of >= 16 bits - * - * See stdint-example.h - */ - -#ifndef _SHA_enum_ -#define _SHA_enum_ -/* - * All SHA functions return one of these values. - */ -enum { - shaSuccess = 0, - shaNull, /* Null pointer parameter */ - shaInputTooLong, /* input data too long */ - shaStateError, /* called Input after FinalBits or Result */ - shaBadParam /* passed a bad parameter */ -}; -#endif /* _SHA_enum_ */ - -/* - * These constants hold size information for each of the SHA - * hashing operations - */ -enum { - SHA1_Message_Block_Size = 64, SHA224_Message_Block_Size = 64, - SHA256_Message_Block_Size = 64, SHA384_Message_Block_Size = 128, - SHA512_Message_Block_Size = 128, - USHA_Max_Message_Block_Size = SHA512_Message_Block_Size, - - SHA1HashSize = 20, SHA224HashSize = 28, SHA256HashSize = 32, - SHA384HashSize = 48, SHA512HashSize = 64, - USHAMaxHashSize = SHA512HashSize, - - SHA1HashSizeBits = 160, SHA224HashSizeBits = 224, - SHA256HashSizeBits = 256, SHA384HashSizeBits = 384, - SHA512HashSizeBits = 512, USHAMaxHashSizeBits = SHA512HashSizeBits -}; - -/* - * These constants are used in the USHA (Unified SHA) functions. - */ -typedef enum SHAversion { - SHA1, SHA224, SHA256, SHA384, SHA512 -} SHAversion; - -/* - * This structure will hold context information for the SHA-1 - * hashing operation. - */ -typedef struct SHA1Context { - uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ - - uint32_t Length_High; /* Message length in bits */ - uint32_t Length_Low; /* Message length in bits */ - - int_least16_t Message_Block_Index; /* Message_Block array index */ - /* 512-bit message blocks */ - uint8_t Message_Block[SHA1_Message_Block_Size]; - - int Computed; /* Is the hash computed? */ - int Corrupted; /* Cumulative corruption code */ -} SHA1Context; - -/* - * This structure will hold context information for the SHA-256 - * hashing operation. - */ -typedef struct SHA256Context { - uint32_t Intermediate_Hash[SHA256HashSize/4]; /* Message Digest */ - - uint32_t Length_High; /* Message length in bits */ - uint32_t Length_Low; /* Message length in bits */ - - int_least16_t Message_Block_Index; /* Message_Block array index */ - /* 512-bit message blocks */ - uint8_t Message_Block[SHA256_Message_Block_Size]; - - int Computed; /* Is the hash computed? */ - int Corrupted; /* Cumulative corruption code */ -} SHA256Context; - -/* - * This structure will hold context information for the SHA-512 - * hashing operation. - */ -typedef struct SHA512Context { -#ifdef USE_32BIT_ONLY - uint32_t Intermediate_Hash[SHA512HashSize/4]; /* Message Digest */ - uint32_t Length[4]; /* Message length in bits */ -#else /* !USE_32BIT_ONLY */ - uint64_t Intermediate_Hash[SHA512HashSize/8]; /* Message Digest */ - uint64_t Length_High, Length_Low; /* Message length in bits */ -#endif /* USE_32BIT_ONLY */ - - int_least16_t Message_Block_Index; /* Message_Block array index */ - /* 1024-bit message blocks */ - uint8_t Message_Block[SHA512_Message_Block_Size]; - - int Computed; /* Is the hash computed?*/ - int Corrupted; /* Cumulative corruption code */ -} SHA512Context; - -/* - * This structure will hold context information for the SHA-224 - * hashing operation. It uses the SHA-256 structure for computation. - */ -typedef struct SHA256Context SHA224Context; - -/* - * This structure will hold context information for the SHA-384 - * hashing operation. It uses the SHA-512 structure for computation. - */ -typedef struct SHA512Context SHA384Context; - -/* - * This structure holds context information for all SHA - * hashing operations. - */ -typedef struct USHAContext { - int whichSha; /* which SHA is being used */ - union { - SHA1Context sha1Context; - SHA224Context sha224Context; SHA256Context sha256Context; - SHA384Context sha384Context; SHA512Context sha512Context; - } ctx; - -} USHAContext; - -/* - * This structure will hold context information for the HMAC - * keyed-hashing operation. - */ -typedef struct HMACContext { - int whichSha; /* which SHA is being used */ - int hashSize; /* hash size of SHA being used */ - int blockSize; /* block size of SHA being used */ - USHAContext shaContext; /* SHA context */ - unsigned char k_opad[USHA_Max_Message_Block_Size]; - /* outer padding - key XORd with opad */ - int Computed; /* Is the MAC computed? */ - int Corrupted; /* Cumulative corruption code */ - -} HMACContext; - -/* - * This structure will hold context information for the HKDF - * extract-and-expand Key Derivation Functions. - */ -typedef struct HKDFContext { - int whichSha; /* which SHA is being used */ - HMACContext hmacContext; - int hashSize; /* hash size of SHA being used */ - unsigned char prk[USHAMaxHashSize]; - /* pseudo-random key - output of hkdfInput */ - int Computed; /* Is the key material computed? */ - int Corrupted; /* Cumulative corruption code */ -} HKDFContext; - -/* - * Function Prototypes - */ - -/* SHA-1 */ -extern int SHA1Reset(SHA1Context *); -extern int SHA1Input(SHA1Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA1FinalBits(SHA1Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA1Result(SHA1Context *, - uint8_t Message_Digest[SHA1HashSize]); - -/* SHA-224 */ -extern int SHA224Reset(SHA224Context *); -extern int SHA224Input(SHA224Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA224FinalBits(SHA224Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA224Result(SHA224Context *, - uint8_t Message_Digest[SHA224HashSize]); - -/* SHA-256 */ -extern int SHA256Reset(SHA256Context *); -extern int SHA256Input(SHA256Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA256FinalBits(SHA256Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA256Result(SHA256Context *, - uint8_t Message_Digest[SHA256HashSize]); - -/* SHA-384 */ -extern int SHA384Reset(SHA384Context *); -extern int SHA384Input(SHA384Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA384FinalBits(SHA384Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA384Result(SHA384Context *, - uint8_t Message_Digest[SHA384HashSize]); - -/* SHA-512 */ -extern int SHA512Reset(SHA512Context *); -extern int SHA512Input(SHA512Context *, const uint8_t *bytes, - unsigned int bytecount); -extern int SHA512FinalBits(SHA512Context *, uint8_t bits, - unsigned int bit_count); -extern int SHA512Result(SHA512Context *, - uint8_t Message_Digest[SHA512HashSize]); - -/* Unified SHA functions, chosen by whichSha */ -extern int USHAReset(USHAContext *context, SHAversion whichSha); -extern int USHAInput(USHAContext *context, - const uint8_t *bytes, unsigned int bytecount); -extern int USHAFinalBits(USHAContext *context, - uint8_t bits, unsigned int bit_count); -extern int USHAResult(USHAContext *context, - uint8_t Message_Digest[USHAMaxHashSize]); -extern int USHABlockSize(enum SHAversion whichSha); -extern int USHAHashSize(enum SHAversion whichSha); -extern int USHAHashSizeBits(enum SHAversion whichSha); -extern const char *USHAHashName(enum SHAversion whichSha); - -/* - * HMAC Keyed-Hashing for Message Authentication, RFC 2104, - * for all SHAs. - * This interface allows a fixed-length text input to be used. - */ -extern int hmac(SHAversion whichSha, /* which SHA algorithm to use */ - const unsigned char *text, /* pointer to data stream */ - int text_len, /* length of data stream */ - const unsigned char *key, /* pointer to authentication key */ - int key_len, /* length of authentication key */ - uint8_t digest[USHAMaxHashSize]); /* caller digest to fill in */ - -/* - * HMAC Keyed-Hashing for Message Authentication, RFC 2104, - * for all SHAs. - * This interface allows any length of text input to be used. - */ -extern int hmacReset(HMACContext *context, enum SHAversion whichSha, - const unsigned char *key, int key_len); -extern int hmacInput(HMACContext *context, const unsigned char *text, - int text_len); -extern int hmacFinalBits(HMACContext *context, uint8_t bits, - unsigned int bit_count); -extern int hmacResult(HMACContext *context, - uint8_t digest[USHAMaxHashSize]); - -/* - * HKDF HMAC-based Extract-and-Expand Key Derivation Function, - * RFC 5869, for all SHAs. - */ -extern int hkdf(SHAversion whichSha, const unsigned char *salt, - int salt_len, const unsigned char *ikm, int ikm_len, - const unsigned char *info, int info_len, - uint8_t okm[ ], int okm_len); -extern int hkdfExtract(SHAversion whichSha, const unsigned char *salt, - int salt_len, const unsigned char *ikm, - int ikm_len, uint8_t prk[USHAMaxHashSize]); -extern int hkdfExpand(SHAversion whichSha, const uint8_t prk[ ], - int prk_len, const unsigned char *info, - int info_len, uint8_t okm[ ], int okm_len); - -/* - * HKDF HMAC-based Extract-and-Expand Key Derivation Function, - * RFC 5869, for all SHAs. - * This interface allows any length of text input to be used. - */ -extern int hkdfReset(HKDFContext *context, enum SHAversion whichSha, - const unsigned char *salt, int salt_len); -extern int hkdfInput(HKDFContext *context, const unsigned char *ikm, - int ikm_len); -extern int hkdfFinalBits(HKDFContext *context, uint8_t ikm_bits, - unsigned int ikm_bit_count); -extern int hkdfResult(HKDFContext *context, - uint8_t prk[USHAMaxHashSize], - const unsigned char *info, int info_len, - uint8_t okm[USHAMaxHashSize], int okm_len); -#endif /* _SHA_H_ */ - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/sha1.c b/lib/libesp32_div/ESP32-HomeKit/src/sha1.c deleted file mode 100644 index 53f187212..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/sha1.c +++ /dev/null @@ -1,414 +0,0 @@ -/**************************** sha1.c ***************************/ -/***************** See RFC 6234 for details. *******************/ -/* Copyright (c) 2011 IETF Trust and the persons identified as */ -/* authors of the code. All rights reserved. */ -/* See sha.h for terms of use and redistribution. */ - -/* - * Description: - * This file implements the Secure Hash Algorithm SHA-1 - * as defined in the U.S. National Institute of Standards - * and Technology Federal Information Processing Standards - * Publication (FIPS PUB) 180-3 published in October 2008 - * and formerly defined in its predecessors, FIPS PUB 180-1 - * and FIP PUB 180-2. - * - * A combined document showing all algorithms is available at - * http://csrc.nist.gov/publications/fips/ - * fips180-3/fips180-3_final.pdf - * - * The SHA-1 algorithm produces a 160-bit message digest for a - * given data stream that can serve as a means of providing a - * "fingerprint" for a message. - * - * Portability Issues: - * SHA-1 is defined in terms of 32-bit "words". This code - * uses (included via "sha.h") to define 32- and - * 8-bit unsigned integer types. If your C compiler does - * not support 32-bit unsigned integers, this code is not - * appropriate. - * - * Caveats: - * SHA-1 is designed to work with messages less than 2^64 bits - * long. This implementation uses SHA1Input() to hash the bits - * that are a multiple of the size of an 8-bit octet, and then - * optionally uses SHA1FinalBits() to hash the final few bits of - * the input. - */ - -#include "sha.h" -#include "sha-private.h" - -/* - * Define the SHA1 circular left shift macro - */ -#define SHA1_ROTL(bits,word) \ - (((word) << (bits)) | ((word) >> (32-(bits)))) - -/* - * Add "length" to the length. - * Set Corrupted when overflow has occurred. - */ -static uint32_t addTemp; -#define SHA1AddLength(context, length) \ - (addTemp = (context)->Length_Low, \ - (context)->Corrupted = \ - (((context)->Length_Low += (length)) < addTemp) && \ - (++(context)->Length_High == 0) ? shaInputTooLong \ - : (context)->Corrupted ) - -/* Local Function Prototypes */ -static void SHA1ProcessMessageBlock(SHA1Context *context); -static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte); -static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte); - -/* - * SHA1Reset - * - * Description: - * This function will initialize the SHA1Context in preparation - * for computing a new SHA1 message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * - * Returns: - * sha Error Code. - * - */ -int SHA1Reset(SHA1Context *context) -{ - if (!context) return shaNull; - - context->Length_High = context->Length_Low = 0; - context->Message_Block_Index = 0; - - /* Initial Hash Values: FIPS 180-3 section 5.3.1 */ - context->Intermediate_Hash[0] = 0x67452301; - context->Intermediate_Hash[1] = 0xEFCDAB89; - context->Intermediate_Hash[2] = 0x98BADCFE; - context->Intermediate_Hash[3] = 0x10325476; - context->Intermediate_Hash[4] = 0xC3D2E1F0; - - context->Computed = 0; - context->Corrupted = shaSuccess; - - return shaSuccess; -} - -/* - * SHA1Input - * - * Description: - * This function accepts an array of octets as the next portion - * of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_array[ ]: [in] - * An array of octets representing the next portion of - * the message. - * length: [in] - * The length of the message in message_array. - * - * Returns: - * sha Error Code. - * - */ -int SHA1Input(SHA1Context *context, - const uint8_t *message_array, unsigned length) -{ - if (!context) return shaNull; - if (!length) return shaSuccess; - if (!message_array) return shaNull; - if (context->Computed) return context->Corrupted = shaStateError; - if (context->Corrupted) return context->Corrupted; - - while (length--) { - context->Message_Block[context->Message_Block_Index++] = - *message_array; - - if ((SHA1AddLength(context, 8) == shaSuccess) && - (context->Message_Block_Index == SHA1_Message_Block_Size)) - SHA1ProcessMessageBlock(context); - - message_array++; - } - - return context->Corrupted; -} - -/* - * SHA1FinalBits - * - * Description: - * This function will add in any final bits of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_bits: [in] - * The final bits of the message, in the upper portion of the - * byte. (Use 0b###00000 instead of 0b00000### to input the - * three bits ###.) - * length: [in] - * The number of bits in message_bits, between 1 and 7. - * - * Returns: - * sha Error Code. - */ -int SHA1FinalBits(SHA1Context *context, uint8_t message_bits, - unsigned int length) -{ - static uint8_t masks[8] = { - /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, - /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, - /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, - /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE - }; - - static uint8_t markbit[8] = { - /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, - /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, - /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, - /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 - }; - - if (!context) return shaNull; - if (!length) return shaSuccess; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - if (length >= 8) return context->Corrupted = shaBadParam; - - SHA1AddLength(context, length); - SHA1Finalize(context, - (uint8_t) ((message_bits & masks[length]) | markbit[length])); - - return context->Corrupted; -} - -/* - * SHA1Result - * - * Description: - * This function will return the 160-bit message digest - * into the Message_Digest array provided by the caller. - * NOTE: - * The first octet of hash is stored in the element with index 0, - * the last octet of hash in the element with index 19. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA-1 hash. - * Message_Digest[ ]: [out] - * Where the digest is returned. - * - * Returns: - * sha Error Code. - * - */ -int SHA1Result(SHA1Context *context, - uint8_t Message_Digest[SHA1HashSize]) -{ - int i; - - if (!context) return shaNull; - if (!Message_Digest) return shaNull; - if (context->Corrupted) return context->Corrupted; - - if (!context->Computed) - SHA1Finalize(context, 0x80); - - for (i = 0; i < SHA1HashSize; ++i) - Message_Digest[i] = (uint8_t) (context->Intermediate_Hash[i>>2] - >> (8 * ( 3 - ( i & 0x03 ) ))); - - return shaSuccess; -} - -/* - * SHA1ProcessMessageBlock - * - * Description: - * This helper function will process the next 512 bits of the - * message stored in the Message_Block array. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * - * Returns: - * Nothing. - * - * Comments: - * Many of the variable names in this code, especially the - * single character names, were used because those were the - * names used in the Secure Hash Standard. - */ -static void SHA1ProcessMessageBlock(SHA1Context *context) -{ - /* Constants defined in FIPS 180-3, section 4.2.1 */ - const uint32_t K[4] = { - 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 - }; - - int t; /* Loop counter */ - uint32_t temp; /* Temporary word value */ - uint32_t W[80]; /* Word sequence */ - uint32_t A, B, C, D, E; /* Word buffers */ - - /* - * Initialize the first 16 words in the array W - */ - for (t = 0; t < 16; t++) { - W[t] = ((uint32_t)context->Message_Block[t * 4]) << 24; - W[t] |= ((uint32_t)context->Message_Block[t * 4 + 1]) << 16; - W[t] |= ((uint32_t)context->Message_Block[t * 4 + 2]) << 8; - W[t] |= ((uint32_t)context->Message_Block[t * 4 + 3]); - } - - for (t = 16; t < 80; t++) - W[t] = SHA1_ROTL(1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); - - A = context->Intermediate_Hash[0]; - B = context->Intermediate_Hash[1]; - C = context->Intermediate_Hash[2]; - D = context->Intermediate_Hash[3]; - E = context->Intermediate_Hash[4]; - - for (t = 0; t < 20; t++) { - temp = SHA1_ROTL(5,A) + SHA_Ch(B, C, D) + E + W[t] + K[0]; - E = D; - D = C; - C = SHA1_ROTL(30,B); - B = A; - A = temp; - } - - for (t = 20; t < 40; t++) { - temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[1]; - E = D; - D = C; - C = SHA1_ROTL(30,B); - B = A; - A = temp; - } - - for (t = 40; t < 60; t++) { - temp = SHA1_ROTL(5,A) + SHA_Maj(B, C, D) + E + W[t] + K[2]; - E = D; - D = C; - C = SHA1_ROTL(30,B); - B = A; - A = temp; - } - - for (t = 60; t < 80; t++) { - temp = SHA1_ROTL(5,A) + SHA_Parity(B, C, D) + E + W[t] + K[3]; - E = D; - D = C; - C = SHA1_ROTL(30,B); - B = A; - A = temp; - } - - context->Intermediate_Hash[0] += A; - context->Intermediate_Hash[1] += B; - context->Intermediate_Hash[2] += C; - context->Intermediate_Hash[3] += D; - context->Intermediate_Hash[4] += E; - context->Message_Block_Index = 0; -} - -/* - * SHA1Finalize - * - * Description: - * This helper function finishes off the digest calculations. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * Pad_Byte: [in] - * The last byte to add to the message block before the 0-padding - * and length. This will contain the last bits of the message - * followed by another single bit. If the message was an - * exact multiple of 8-bits long, Pad_Byte will be 0x80. - * - * Returns: - * sha Error Code. - * - */ -static void SHA1Finalize(SHA1Context *context, uint8_t Pad_Byte) -{ - int i; - SHA1PadMessage(context, Pad_Byte); - /* message may be sensitive, clear it out */ - for (i = 0; i < SHA1_Message_Block_Size; ++i) - context->Message_Block[i] = 0; - context->Length_High = 0; /* and clear length */ - context->Length_Low = 0; - context->Computed = 1; -} - -/* - * SHA1PadMessage - * - * Description: - * According to the standard, the message must be padded to the next - * even multiple of 512 bits. The first padding bit must be a '1'. - * The last 64 bits represent the length of the original message. - * All bits in between should be 0. This helper function will pad - * the message according to those rules by filling the Message_Block - * array accordingly. When it returns, it can be assumed that the - * message digest has been computed. - * - * Parameters: - * context: [in/out] - * The context to pad. - * Pad_Byte: [in] - * The last byte to add to the message block before the 0-padding - * and length. This will contain the last bits of the message - * followed by another single bit. If the message was an - * exact multiple of 8-bits long, Pad_Byte will be 0x80. - * - * Returns: - * Nothing. - */ -static void SHA1PadMessage(SHA1Context *context, uint8_t Pad_Byte) -{ - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second - * block. - */ - if (context->Message_Block_Index >= (SHA1_Message_Block_Size - 8)) { - context->Message_Block[context->Message_Block_Index++] = Pad_Byte; - while (context->Message_Block_Index < SHA1_Message_Block_Size) - context->Message_Block[context->Message_Block_Index++] = 0; - - SHA1ProcessMessageBlock(context); - } else - context->Message_Block[context->Message_Block_Index++] = Pad_Byte; - - while (context->Message_Block_Index < (SHA1_Message_Block_Size - 8)) - context->Message_Block[context->Message_Block_Index++] = 0; - - /* - * Store the message length as the last 8 octets - */ - context->Message_Block[56] = (uint8_t) (context->Length_High >> 24); - context->Message_Block[57] = (uint8_t) (context->Length_High >> 16); - context->Message_Block[58] = (uint8_t) (context->Length_High >> 8); - context->Message_Block[59] = (uint8_t) (context->Length_High); - context->Message_Block[60] = (uint8_t) (context->Length_Low >> 24); - context->Message_Block[61] = (uint8_t) (context->Length_Low >> 16); - context->Message_Block[62] = (uint8_t) (context->Length_Low >> 8); - context->Message_Block[63] = (uint8_t) (context->Length_Low); - - SHA1ProcessMessageBlock(context); -} - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/sha224-256.c b/lib/libesp32_div/ESP32-HomeKit/src/sha224-256.c deleted file mode 100644 index 2c9bc9c14..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/sha224-256.c +++ /dev/null @@ -1,581 +0,0 @@ -/************************* sha224-256.c ************************/ -/***************** See RFC 6234 for details. *******************/ -/* Copyright (c) 2011 IETF Trust and the persons identified as */ -/* authors of the code. All rights reserved. */ -/* See sha.h for terms of use and redistribution. */ - -/* - * Description: - * This file implements the Secure Hash Algorithms SHA-224 and - * SHA-256 as defined in the U.S. National Institute of Standards - * and Technology Federal Information Processing Standards - * Publication (FIPS PUB) 180-3 published in October 2008 - * and formerly defined in its predecessors, FIPS PUB 180-1 - * and FIP PUB 180-2. - * - * A combined document showing all algorithms is available at - * http://csrc.nist.gov/publications/fips/ - * fips180-3/fips180-3_final.pdf - * - * The SHA-224 and SHA-256 algorithms produce 224-bit and 256-bit - * message digests for a given data stream. It should take about - * 2**n steps to find a message with the same digest as a given - * message and 2**(n/2) to find any two messages with the same - * digest, when n is the digest size in bits. Therefore, this - * algorithm can serve as a means of providing a - * "fingerprint" for a message. - * - * Portability Issues: - * SHA-224 and SHA-256 are defined in terms of 32-bit "words". - * This code uses (included via "sha.h") to define 32- - * and 8-bit unsigned integer types. If your C compiler does not - * support 32-bit unsigned integers, this code is not - * appropriate. - * - * Caveats: - * SHA-224 and SHA-256 are designed to work with messages less - * than 2^64 bits long. This implementation uses SHA224/256Input() - * to hash the bits that are a multiple of the size of an 8-bit - * octet, and then optionally uses SHA224/256FinalBits() - * to hash the final few bits of the input. - */ - -#include "sha.h" -#include "sha-private.h" - -/* Define the SHA shift, rotate left, and rotate right macros */ -#define SHA256_SHR(bits,word) ((word) >> (bits)) -#define SHA256_ROTL(bits,word) \ - (((word) << (bits)) | ((word) >> (32-(bits)))) -#define SHA256_ROTR(bits,word) \ - (((word) >> (bits)) | ((word) << (32-(bits)))) - -/* Define the SHA SIGMA and sigma macros */ -#define SHA256_SIGMA0(word) \ - (SHA256_ROTR( 2,word) ^ SHA256_ROTR(13,word) ^ SHA256_ROTR(22,word)) -#define SHA256_SIGMA1(word) \ - (SHA256_ROTR( 6,word) ^ SHA256_ROTR(11,word) ^ SHA256_ROTR(25,word)) -#define SHA256_sigma0(word) \ - (SHA256_ROTR( 7,word) ^ SHA256_ROTR(18,word) ^ SHA256_SHR( 3,word)) -#define SHA256_sigma1(word) \ - (SHA256_ROTR(17,word) ^ SHA256_ROTR(19,word) ^ SHA256_SHR(10,word)) - -/* - * Add "length" to the length. - * Set Corrupted when overflow has occurred. - */ -static uint32_t addTemp; -#define SHA224_256AddLength(context, length) \ - (addTemp = (context)->Length_Low, (context)->Corrupted = \ - (((context)->Length_Low += (length)) < addTemp) && \ - (++(context)->Length_High == 0) ? shaInputTooLong : \ - (context)->Corrupted ) - -/* Local Function Prototypes */ -static int SHA224_256Reset(SHA256Context *context, uint32_t *H0); -static void SHA224_256ProcessMessageBlock(SHA256Context *context); -static void SHA224_256Finalize(SHA256Context *context, - uint8_t Pad_Byte); -static void SHA224_256PadMessage(SHA256Context *context, - uint8_t Pad_Byte); -static int SHA224_256ResultN(SHA256Context *context, - uint8_t Message_Digest[ ], int HashSize); - -/* Initial Hash Values: FIPS 180-3 section 5.3.2 */ -static uint32_t SHA224_H0[SHA256HashSize/4] = { - 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939, - 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4 -}; - -/* Initial Hash Values: FIPS 180-3 section 5.3.3 */ -static uint32_t SHA256_H0[SHA256HashSize/4] = { - 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, - 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 -}; - -/* - * SHA224Reset - * - * Description: - * This function will initialize the SHA224Context in preparation - * for computing a new SHA224 message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * - * Returns: - * sha Error Code. - */ -int SHA224Reset(SHA224Context *context) -{ - return SHA224_256Reset(context, SHA224_H0); -} - -/* - * SHA224Input - * - * Description: - * This function accepts an array of octets as the next portion - * of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_array[ ]: [in] - * An array of octets representing the next portion of - * the message. - * length: [in] - * The length of the message in message_array. - * - * Returns: - * sha Error Code. - * - */ -int SHA224Input(SHA224Context *context, const uint8_t *message_array, - unsigned int length) -{ - return SHA256Input(context, message_array, length); -} - -/* - * SHA224FinalBits - * - * Description: - * This function will add in any final bits of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_bits: [in] - * The final bits of the message, in the upper portion of the - * byte. (Use 0b###00000 instead of 0b00000### to input the - * three bits ###.) - * length: [in] - * The number of bits in message_bits, between 1 and 7. - * - * Returns: - * sha Error Code. - */ -int SHA224FinalBits(SHA224Context *context, - uint8_t message_bits, unsigned int length) -{ - return SHA256FinalBits(context, message_bits, length); -} - -/* - * SHA224Result - * - * Description: - * This function will return the 224-bit message digest - * into the Message_Digest array provided by the caller. - * NOTE: - * The first octet of hash is stored in the element with index 0, - * the last octet of hash in the element with index 27. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA hash. - * Message_Digest[ ]: [out] - * Where the digest is returned. - * - * Returns: - * sha Error Code. - */ -int SHA224Result(SHA224Context *context, - uint8_t Message_Digest[SHA224HashSize]) -{ - return SHA224_256ResultN(context, Message_Digest, SHA224HashSize); -} - -/* - * SHA256Reset - * - * Description: - * This function will initialize the SHA256Context in preparation - * for computing a new SHA256 message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * - * Returns: - * sha Error Code. - */ -int SHA256Reset(SHA256Context *context) -{ - return SHA224_256Reset(context, SHA256_H0); -} - -/* - * SHA256Input - * - * Description: - * This function accepts an array of octets as the next portion - * of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_array[ ]: [in] - * An array of octets representing the next portion of - * the message. - * length: [in] - * The length of the message in message_array. - * - * Returns: - * sha Error Code. - */ -int SHA256Input(SHA256Context *context, const uint8_t *message_array, - unsigned int length) -{ - if (!context) return shaNull; - if (!length) return shaSuccess; - if (!message_array) return shaNull; - if (context->Computed) return context->Corrupted = shaStateError; - if (context->Corrupted) return context->Corrupted; - - while (length--) { - context->Message_Block[context->Message_Block_Index++] = - *message_array; - - if ((SHA224_256AddLength(context, 8) == shaSuccess) && - (context->Message_Block_Index == SHA256_Message_Block_Size)) - SHA224_256ProcessMessageBlock(context); - - message_array++; - } - - return context->Corrupted; - -} - -/* - * SHA256FinalBits - * - * Description: - * This function will add in any final bits of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_bits: [in] - * The final bits of the message, in the upper portion of the - * byte. (Use 0b###00000 instead of 0b00000### to input the - * three bits ###.) - * length: [in] - * The number of bits in message_bits, between 1 and 7. - * - * Returns: - * sha Error Code. - */ -int SHA256FinalBits(SHA256Context *context, - uint8_t message_bits, unsigned int length) -{ - static uint8_t masks[8] = { - /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, - /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, - /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, - /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE - }; - static uint8_t markbit[8] = { - /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, - /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, - /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, - /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 - }; - - if (!context) return shaNull; - if (!length) return shaSuccess; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - if (length >= 8) return context->Corrupted = shaBadParam; - - SHA224_256AddLength(context, length); - SHA224_256Finalize(context, (uint8_t) - ((message_bits & masks[length]) | markbit[length])); - - return context->Corrupted; -} - -/* - * SHA256Result - * - * Description: - * This function will return the 256-bit message digest - * into the Message_Digest array provided by the caller. - * NOTE: - * The first octet of hash is stored in the element with index 0, - * the last octet of hash in the element with index 31. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA hash. - * Message_Digest[ ]: [out] - * Where the digest is returned. - * - * Returns: - * sha Error Code. - */ -int SHA256Result(SHA256Context *context, - uint8_t Message_Digest[SHA256HashSize]) -{ - return SHA224_256ResultN(context, Message_Digest, SHA256HashSize); -} - -/* - * SHA224_256Reset - * - * Description: - * This helper function will initialize the SHA256Context in - * preparation for computing a new SHA-224 or SHA-256 message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * H0[ ]: [in] - * The initial hash value array to use. - * - * Returns: - * sha Error Code. - */ -static int SHA224_256Reset(SHA256Context *context, uint32_t *H0) -{ - if (!context) return shaNull; - - context->Length_High = context->Length_Low = 0; - context->Message_Block_Index = 0; - - context->Intermediate_Hash[0] = H0[0]; - context->Intermediate_Hash[1] = H0[1]; - context->Intermediate_Hash[2] = H0[2]; - context->Intermediate_Hash[3] = H0[3]; - context->Intermediate_Hash[4] = H0[4]; - context->Intermediate_Hash[5] = H0[5]; - context->Intermediate_Hash[6] = H0[6]; - context->Intermediate_Hash[7] = H0[7]; - - context->Computed = 0; - context->Corrupted = shaSuccess; - - return shaSuccess; -} - -/* - * SHA224_256ProcessMessageBlock - * - * Description: - * This helper function will process the next 512 bits of the - * message stored in the Message_Block array. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * - * Returns: - * Nothing. - * - * Comments: - * Many of the variable names in this code, especially the - * single character names, were used because those were the - * names used in the Secure Hash Standard. - */ -static void SHA224_256ProcessMessageBlock(SHA256Context *context) -{ - /* Constants defined in FIPS 180-3, section 4.2.2 */ - static const uint32_t K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, - 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, - 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, - 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, - 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, - 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, - 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, - 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, - 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, - 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - }; - int t, t4; /* Loop counter */ - uint32_t temp1, temp2; /* Temporary word value */ - uint32_t W[64]; /* Word sequence */ - uint32_t A, B, C, D, E, F, G, H; /* Word buffers */ - - /* - * Initialize the first 16 words in the array W - */ - for (t = t4 = 0; t < 16; t++, t4 += 4) - W[t] = (((uint32_t)context->Message_Block[t4]) << 24) | - (((uint32_t)context->Message_Block[t4 + 1]) << 16) | - (((uint32_t)context->Message_Block[t4 + 2]) << 8) | - (((uint32_t)context->Message_Block[t4 + 3])); - for (t = 16; t < 64; t++) - W[t] = SHA256_sigma1(W[t-2]) + W[t-7] + - SHA256_sigma0(W[t-15]) + W[t-16]; - - A = context->Intermediate_Hash[0]; - B = context->Intermediate_Hash[1]; - C = context->Intermediate_Hash[2]; - D = context->Intermediate_Hash[3]; - E = context->Intermediate_Hash[4]; - F = context->Intermediate_Hash[5]; - G = context->Intermediate_Hash[6]; - H = context->Intermediate_Hash[7]; - - for (t = 0; t < 64; t++) { - temp1 = H + SHA256_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; - temp2 = SHA256_SIGMA0(A) + SHA_Maj(A,B,C); - H = G; - G = F; - F = E; - E = D + temp1; - D = C; - C = B; - B = A; - A = temp1 + temp2; - } - - context->Intermediate_Hash[0] += A; - context->Intermediate_Hash[1] += B; - context->Intermediate_Hash[2] += C; - context->Intermediate_Hash[3] += D; - context->Intermediate_Hash[4] += E; - context->Intermediate_Hash[5] += F; - context->Intermediate_Hash[6] += G; - context->Intermediate_Hash[7] += H; - - context->Message_Block_Index = 0; -} - -/* - * SHA224_256Finalize - * - * Description: - * This helper function finishes off the digest calculations. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * Pad_Byte: [in] - * The last byte to add to the message block before the 0-padding - * and length. This will contain the last bits of the message - * followed by another single bit. If the message was an - * exact multiple of 8-bits long, Pad_Byte will be 0x80. - * - * Returns: - * sha Error Code. - */ -static void SHA224_256Finalize(SHA256Context *context, - uint8_t Pad_Byte) -{ - int i; - SHA224_256PadMessage(context, Pad_Byte); - /* message may be sensitive, so clear it out */ - for (i = 0; i < SHA256_Message_Block_Size; ++i) - context->Message_Block[i] = 0; - context->Length_High = 0; /* and clear length */ - context->Length_Low = 0; - context->Computed = 1; -} - -/* - * SHA224_256PadMessage - * - * Description: - * According to the standard, the message must be padded to the next - * even multiple of 512 bits. The first padding bit must be a '1'. - * The last 64 bits represent the length of the original message. - * All bits in between should be 0. This helper function will pad - * the message according to those rules by filling the - * Message_Block array accordingly. When it returns, it can be - * assumed that the message digest has been computed. - * - * Parameters: - * context: [in/out] - * The context to pad. - * Pad_Byte: [in] - * The last byte to add to the message block before the 0-padding - * and length. This will contain the last bits of the message - * followed by another single bit. If the message was an - * exact multiple of 8-bits long, Pad_Byte will be 0x80. - * - * Returns: - * Nothing. - */ -static void SHA224_256PadMessage(SHA256Context *context, - uint8_t Pad_Byte) -{ - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second - * block. - */ - if (context->Message_Block_Index >= (SHA256_Message_Block_Size-8)) { - context->Message_Block[context->Message_Block_Index++] = Pad_Byte; - while (context->Message_Block_Index < SHA256_Message_Block_Size) - context->Message_Block[context->Message_Block_Index++] = 0; - SHA224_256ProcessMessageBlock(context); - } else - context->Message_Block[context->Message_Block_Index++] = Pad_Byte; - - while (context->Message_Block_Index < (SHA256_Message_Block_Size-8)) - context->Message_Block[context->Message_Block_Index++] = 0; - - /* - * Store the message length as the last 8 octets - */ - context->Message_Block[56] = (uint8_t)(context->Length_High >> 24); - context->Message_Block[57] = (uint8_t)(context->Length_High >> 16); - context->Message_Block[58] = (uint8_t)(context->Length_High >> 8); - context->Message_Block[59] = (uint8_t)(context->Length_High); - context->Message_Block[60] = (uint8_t)(context->Length_Low >> 24); - context->Message_Block[61] = (uint8_t)(context->Length_Low >> 16); - context->Message_Block[62] = (uint8_t)(context->Length_Low >> 8); - context->Message_Block[63] = (uint8_t)(context->Length_Low); - - SHA224_256ProcessMessageBlock(context); -} - -/* - * SHA224_256ResultN - * - * Description: - * This helper function will return the 224-bit or 256-bit message - * digest into the Message_Digest array provided by the caller. - * NOTE: - * The first octet of hash is stored in the element with index 0, - * the last octet of hash in the element with index 27/31. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA hash. - * Message_Digest[ ]: [out] - * Where the digest is returned. - * HashSize: [in] - * The size of the hash, either 28 or 32. - * - * Returns: - * sha Error Code. - */ -static int SHA224_256ResultN(SHA256Context *context, - uint8_t Message_Digest[ ], int HashSize) -{ - int i; - - if (!context) return shaNull; - if (!Message_Digest) return shaNull; - if (context->Corrupted) return context->Corrupted; - - if (!context->Computed) - SHA224_256Finalize(context, 0x80); - - for (i = 0; i < HashSize; ++i) - Message_Digest[i] = (uint8_t) - (context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) )); - - return shaSuccess; -} - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/sha384-512.c b/lib/libesp32_div/ESP32-HomeKit/src/sha384-512.c deleted file mode 100644 index de5956f08..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/sha384-512.c +++ /dev/null @@ -1,1032 +0,0 @@ -/************************* sha384-512.c ************************/ -/***************** See RFC 6234 for details. *******************/ -/* Copyright (c) 2011 IETF Trust and the persons identified as */ -/* authors of the code. All rights reserved. */ -/* See sha.h for terms of use and redistribution. */ - -/* - * Description: - * This file implements the Secure Hash Algorithms SHA-384 and - * SHA-512 as defined in the U.S. National Institute of Standards - * and Technology Federal Information Processing Standards - * Publication (FIPS PUB) 180-3 published in October 2008 - * and formerly defined in its predecessors, FIPS PUB 180-1 - * and FIP PUB 180-2. - * - * A combined document showing all algorithms is available at - * http://csrc.nist.gov/publications/fips/ - * fips180-3/fips180-3_final.pdf - * - * The SHA-384 and SHA-512 algorithms produce 384-bit and 512-bit - * message digests for a given data stream. It should take about - * 2**n steps to find a message with the same digest as a given - * message and 2**(n/2) to find any two messages with the same - * digest, when n is the digest size in bits. Therefore, this - * algorithm can serve as a means of providing a - * "fingerprint" for a message. - * - * Portability Issues: - * SHA-384 and SHA-512 are defined in terms of 64-bit "words", - * but if USE_32BIT_ONLY is #defined, this code is implemented in - * terms of 32-bit "words". This code uses (included - * via "sha.h") to define the 64-, 32- and 8-bit unsigned integer - * types. If your C compiler does not support 64-bit unsigned - * integers and you do not #define USE_32BIT_ONLY, this code is - * not appropriate. - * - * Caveats: - * SHA-384 and SHA-512 are designed to work with messages less - * than 2^128 bits long. This implementation uses SHA384/512Input() - * to hash the bits that are a multiple of the size of an 8-bit - * octet, and then optionally uses SHA384/256FinalBits() - * to hash the final few bits of the input. - * - */ - -#include "sha.h" - -#ifdef USE_32BIT_ONLY -/* - * Define 64-bit arithmetic in terms of 32-bit arithmetic. - * Each 64-bit number is represented in a 2-word array. - * All macros are defined such that the result is the last parameter. - */ - -/* - * Define shift, rotate left, and rotate right functions - */ -#define SHA512_SHR(bits, word, ret) ( \ - /* (((uint64_t)((word))) >> (bits)) */ \ - (ret)[0] = (((bits) < 32) && ((bits) >= 0)) ? \ - ((word)[0] >> (bits)) : 0, \ - (ret)[1] = ((bits) > 32) ? ((word)[0] >> ((bits) - 32)) : \ - ((bits) == 32) ? (word)[0] : \ - ((bits) >= 0) ? \ - (((word)[0] << (32 - (bits))) | \ - ((word)[1] >> (bits))) : 0 ) - -#define SHA512_SHL(bits, word, ret) ( \ - /* (((uint64_t)(word)) << (bits)) */ \ - (ret)[0] = ((bits) > 32) ? ((word)[1] << ((bits) - 32)) : \ - ((bits) == 32) ? (word)[1] : \ - ((bits) >= 0) ? \ - (((word)[0] << (bits)) | \ - ((word)[1] >> (32 - (bits)))) : \ - 0, \ - (ret)[1] = (((bits) < 32) && ((bits) >= 0)) ? \ - ((word)[1] << (bits)) : 0 ) - -/* - * Define 64-bit OR - */ -#define SHA512_OR(word1, word2, ret) ( \ - (ret)[0] = (word1)[0] | (word2)[0], \ - (ret)[1] = (word1)[1] | (word2)[1] ) - -/* - * Define 64-bit XOR - */ -#define SHA512_XOR(word1, word2, ret) ( \ - (ret)[0] = (word1)[0] ^ (word2)[0], \ - (ret)[1] = (word1)[1] ^ (word2)[1] ) - -/* - * Define 64-bit AND - */ -#define SHA512_AND(word1, word2, ret) ( \ - (ret)[0] = (word1)[0] & (word2)[0], \ - (ret)[1] = (word1)[1] & (word2)[1] ) - -/* - * Define 64-bit TILDA - */ -#define SHA512_TILDA(word, ret) \ - ( (ret)[0] = ~(word)[0], (ret)[1] = ~(word)[1] ) - -/* - * Define 64-bit ADD - */ -#define SHA512_ADD(word1, word2, ret) ( \ - (ret)[1] = (word1)[1], (ret)[1] += (word2)[1], \ - (ret)[0] = (word1)[0] + (word2)[0] + ((ret)[1] < (word1)[1]) ) - -/* - * Add the 4word value in word2 to word1. - */ -static uint32_t ADDTO4_temp, ADDTO4_temp2; -#define SHA512_ADDTO4(word1, word2) ( \ - ADDTO4_temp = (word1)[3], \ - (word1)[3] += (word2)[3], \ - ADDTO4_temp2 = (word1)[2], \ - (word1)[2] += (word2)[2] + ((word1)[3] < ADDTO4_temp), \ - ADDTO4_temp = (word1)[1], \ - (word1)[1] += (word2)[1] + ((word1)[2] < ADDTO4_temp2), \ - (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO4_temp) ) - -/* - * Add the 2word value in word2 to word1. - */ -static uint32_t ADDTO2_temp; -#define SHA512_ADDTO2(word1, word2) ( \ - ADDTO2_temp = (word1)[1], \ - (word1)[1] += (word2)[1], \ - (word1)[0] += (word2)[0] + ((word1)[1] < ADDTO2_temp) ) - -/* - * SHA rotate ((word >> bits) | (word << (64-bits))) - */ -static uint32_t ROTR_temp1[2], ROTR_temp2[2]; -#define SHA512_ROTR(bits, word, ret) ( \ - SHA512_SHR((bits), (word), ROTR_temp1), \ - SHA512_SHL(64-(bits), (word), ROTR_temp2), \ - SHA512_OR(ROTR_temp1, ROTR_temp2, (ret)) ) - -/* - * Define the SHA SIGMA and sigma macros - * - * SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word) - */ -static uint32_t SIGMA0_temp1[2], SIGMA0_temp2[2], - SIGMA0_temp3[2], SIGMA0_temp4[2]; -#define SHA512_SIGMA0(word, ret) ( \ - SHA512_ROTR(28, (word), SIGMA0_temp1), \ - SHA512_ROTR(34, (word), SIGMA0_temp2), \ - SHA512_ROTR(39, (word), SIGMA0_temp3), \ - SHA512_XOR(SIGMA0_temp2, SIGMA0_temp3, SIGMA0_temp4), \ - SHA512_XOR(SIGMA0_temp1, SIGMA0_temp4, (ret)) ) - -/* - * SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word) - */ -static uint32_t SIGMA1_temp1[2], SIGMA1_temp2[2], - SIGMA1_temp3[2], SIGMA1_temp4[2]; -#define SHA512_SIGMA1(word, ret) ( \ - SHA512_ROTR(14, (word), SIGMA1_temp1), \ - SHA512_ROTR(18, (word), SIGMA1_temp2), \ - SHA512_ROTR(41, (word), SIGMA1_temp3), \ - SHA512_XOR(SIGMA1_temp2, SIGMA1_temp3, SIGMA1_temp4), \ - SHA512_XOR(SIGMA1_temp1, SIGMA1_temp4, (ret)) ) - -/* - * (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) - */ -static uint32_t sigma0_temp1[2], sigma0_temp2[2], - sigma0_temp3[2], sigma0_temp4[2]; -#define SHA512_sigma0(word, ret) ( \ - SHA512_ROTR( 1, (word), sigma0_temp1), \ - SHA512_ROTR( 8, (word), sigma0_temp2), \ - SHA512_SHR( 7, (word), sigma0_temp3), \ - SHA512_XOR(sigma0_temp2, sigma0_temp3, sigma0_temp4), \ - SHA512_XOR(sigma0_temp1, sigma0_temp4, (ret)) ) - -/* - * (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) - */ -static uint32_t sigma1_temp1[2], sigma1_temp2[2], - sigma1_temp3[2], sigma1_temp4[2]; -#define SHA512_sigma1(word, ret) ( \ - SHA512_ROTR(19, (word), sigma1_temp1), \ - SHA512_ROTR(61, (word), sigma1_temp2), \ - SHA512_SHR( 6, (word), sigma1_temp3), \ - SHA512_XOR(sigma1_temp2, sigma1_temp3, sigma1_temp4), \ - SHA512_XOR(sigma1_temp1, sigma1_temp4, (ret)) ) - -#ifndef USE_MODIFIED_MACROS -/* - * These definitions are the ones used in FIPS 180-3, section 4.1.3 - * Ch(x,y,z) ((x & y) ^ (~x & z)) - */ -static uint32_t Ch_temp1[2], Ch_temp2[2], Ch_temp3[2]; -#define SHA_Ch(x, y, z, ret) ( \ - SHA512_AND(x, y, Ch_temp1), \ - SHA512_TILDA(x, Ch_temp2), \ - SHA512_AND(Ch_temp2, z, Ch_temp3), \ - SHA512_XOR(Ch_temp1, Ch_temp3, (ret)) ) - -/* - * Maj(x,y,z) (((x)&(y)) ^ ((x)&(z)) ^ ((y)&(z))) - */ -static uint32_t Maj_temp1[2], Maj_temp2[2], - Maj_temp3[2], Maj_temp4[2]; -#define SHA_Maj(x, y, z, ret) ( \ - SHA512_AND(x, y, Maj_temp1), \ - SHA512_AND(x, z, Maj_temp2), \ - SHA512_AND(y, z, Maj_temp3), \ - SHA512_XOR(Maj_temp2, Maj_temp3, Maj_temp4), \ - SHA512_XOR(Maj_temp1, Maj_temp4, (ret)) ) -#else /* !USE_MODIFIED_MACROS */ -/* - * These definitions are potentially faster equivalents for the ones - * used in FIPS 180-3, section 4.1.3. - * ((x & y) ^ (~x & z)) becomes - * ((x & (y ^ z)) ^ z) - */ -#define SHA_Ch(x, y, z, ret) ( \ - (ret)[0] = (((x)[0] & ((y)[0] ^ (z)[0])) ^ (z)[0]), \ - (ret)[1] = (((x)[1] & ((y)[1] ^ (z)[1])) ^ (z)[1]) ) - -/* - * ((x & y) ^ (x & z) ^ (y & z)) becomes - * ((x & (y | z)) | (y & z)) - */ -#define SHA_Maj(x, y, z, ret) ( \ - ret[0] = (((x)[0] & ((y)[0] | (z)[0])) | ((y)[0] & (z)[0])), \ - ret[1] = (((x)[1] & ((y)[1] | (z)[1])) | ((y)[1] & (z)[1])) ) -#endif /* USE_MODIFIED_MACROS */ - -/* - * Add "length" to the length. - * Set Corrupted when overflow has occurred. - */ -static uint32_t addTemp[4] = { 0, 0, 0, 0 }; -#define SHA384_512AddLength(context, length) ( \ - addTemp[3] = (length), SHA512_ADDTO4((context)->Length, addTemp), \ - (context)->Corrupted = (((context)->Length[3] < (length)) && \ - ((context)->Length[2] == 0) && ((context)->Length[1] == 0) && \ - ((context)->Length[0] == 0)) ? shaInputTooLong : \ - (context)->Corrupted ) - -/* Local Function Prototypes */ -static int SHA384_512Reset(SHA512Context *context, - uint32_t H0[SHA512HashSize/4]); -static void SHA384_512ProcessMessageBlock(SHA512Context *context); -static void SHA384_512Finalize(SHA512Context *context, - uint8_t Pad_Byte); -static void SHA384_512PadMessage(SHA512Context *context, - uint8_t Pad_Byte); -static int SHA384_512ResultN( SHA512Context *context, - uint8_t Message_Digest[ ], int HashSize); - -/* Initial Hash Values: FIPS 180-3 sections 5.3.4 and 5.3.5 */ -static uint32_t SHA384_H0[SHA512HashSize/4] = { - 0xCBBB9D5D, 0xC1059ED8, 0x629A292A, 0x367CD507, 0x9159015A, - 0x3070DD17, 0x152FECD8, 0xF70E5939, 0x67332667, 0xFFC00B31, - 0x8EB44A87, 0x68581511, 0xDB0C2E0D, 0x64F98FA7, 0x47B5481D, - 0xBEFA4FA4 -}; -static uint32_t SHA512_H0[SHA512HashSize/4] = { - 0x6A09E667, 0xF3BCC908, 0xBB67AE85, 0x84CAA73B, 0x3C6EF372, - 0xFE94F82B, 0xA54FF53A, 0x5F1D36F1, 0x510E527F, 0xADE682D1, - 0x9B05688C, 0x2B3E6C1F, 0x1F83D9AB, 0xFB41BD6B, 0x5BE0CD19, - 0x137E2179 -}; - -#else /* !USE_32BIT_ONLY */ - -#include "sha-private.h" - -/* Define the SHA shift, rotate left and rotate right macros */ -#define SHA512_SHR(bits,word) (((uint64_t)(word)) >> (bits)) -#define SHA512_ROTR(bits,word) ((((uint64_t)(word)) >> (bits)) | \ - (((uint64_t)(word)) << (64-(bits)))) - -/* - * Define the SHA SIGMA and sigma macros - * - * SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word) - */ -#define SHA512_SIGMA0(word) \ - (SHA512_ROTR(28,word) ^ SHA512_ROTR(34,word) ^ SHA512_ROTR(39,word)) -#define SHA512_SIGMA1(word) \ - (SHA512_ROTR(14,word) ^ SHA512_ROTR(18,word) ^ SHA512_ROTR(41,word)) -#define SHA512_sigma0(word) \ - (SHA512_ROTR( 1,word) ^ SHA512_ROTR( 8,word) ^ SHA512_SHR( 7,word)) -#define SHA512_sigma1(word) \ - (SHA512_ROTR(19,word) ^ SHA512_ROTR(61,word) ^ SHA512_SHR( 6,word)) - -/* - * Add "length" to the length. - * Set Corrupted when overflow has occurred. - */ -static uint64_t addTemp; -#define SHA384_512AddLength(context, length) \ - (addTemp = context->Length_Low, context->Corrupted = \ - ((context->Length_Low += length) < addTemp) && \ - (++context->Length_High == 0) ? shaInputTooLong : \ - (context)->Corrupted) - -/* Local Function Prototypes */ -static int SHA384_512Reset(SHA512Context *context, - uint64_t H0[SHA512HashSize/8]); -static void SHA384_512ProcessMessageBlock(SHA512Context *context); -static void SHA384_512Finalize(SHA512Context *context, - uint8_t Pad_Byte); -static void SHA384_512PadMessage(SHA512Context *context, - uint8_t Pad_Byte); -static int SHA384_512ResultN(SHA512Context *context, - uint8_t Message_Digest[ ], int HashSize); - -/* Initial Hash Values: FIPS 180-3 sections 5.3.4 and 5.3.5 */ -static uint64_t SHA384_H0[ ] = { - 0xCBBB9D5DC1059ED8ll, 0x629A292A367CD507ll, 0x9159015A3070DD17ll, - 0x152FECD8F70E5939ll, 0x67332667FFC00B31ll, 0x8EB44A8768581511ll, - 0xDB0C2E0D64F98FA7ll, 0x47B5481DBEFA4FA4ll -}; -static uint64_t SHA512_H0[ ] = { - 0x6A09E667F3BCC908ll, 0xBB67AE8584CAA73Bll, 0x3C6EF372FE94F82Bll, - 0xA54FF53A5F1D36F1ll, 0x510E527FADE682D1ll, 0x9B05688C2B3E6C1Fll, - 0x1F83D9ABFB41BD6Bll, 0x5BE0CD19137E2179ll -}; - -#endif /* USE_32BIT_ONLY */ - -/* - * SHA384Reset - * - * Description: - * This function will initialize the SHA384Context in preparation - * for computing a new SHA384 message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * - * Returns: - * sha Error Code. - * - */ -int SHA384Reset(SHA384Context *context) -{ - return SHA384_512Reset(context, SHA384_H0); -} - -/* - * SHA384Input - * - * Description: - * This function accepts an array of octets as the next portion - * of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_array[ ]: [in] - * An array of octets representing the next portion of - * the message. - * length: [in] - * The length of the message in message_array. - * - * Returns: - * sha Error Code. - * - */ -int SHA384Input(SHA384Context *context, - const uint8_t *message_array, unsigned int length) -{ - return SHA512Input(context, message_array, length); -} - -/* - * SHA384FinalBits - * - * Description: - * This function will add in any final bits of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_bits: [in] - * The final bits of the message, in the upper portion of the - * byte. (Use 0b###00000 instead of 0b00000### to input the - * three bits ###.) - * length: [in] - * The number of bits in message_bits, between 1 and 7. - * - * Returns: - * sha Error Code. - * - */ -int SHA384FinalBits(SHA384Context *context, - uint8_t message_bits, unsigned int length) -{ - return SHA512FinalBits(context, message_bits, length); -} - -/* - * SHA384Result - * - * Description: - * This function will return the 384-bit message digest - * into the Message_Digest array provided by the caller. - * NOTE: - * The first octet of hash is stored in the element with index 0, - * the last octet of hash in the element with index 47. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA hash. - * Message_Digest[ ]: [out] - * Where the digest is returned. - * - * Returns: - * sha Error Code. - * - */ -int SHA384Result(SHA384Context *context, - uint8_t Message_Digest[SHA384HashSize]) -{ - return SHA384_512ResultN(context, Message_Digest, SHA384HashSize); -} - -/* - * SHA512Reset - * - * Description: - * This function will initialize the SHA512Context in preparation - * for computing a new SHA512 message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * - * Returns: - * sha Error Code. - * - */ -int SHA512Reset(SHA512Context *context) -{ - return SHA384_512Reset(context, SHA512_H0); -} - -/* - * SHA512Input - * - * Description: - * This function accepts an array of octets as the next portion - * of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_array[ ]: [in] - * An array of octets representing the next portion of - * the message. - * length: [in] - * The length of the message in message_array. - * - * Returns: - * sha Error Code. - * - */ -int SHA512Input(SHA512Context *context, - const uint8_t *message_array, - unsigned int length) -{ - if (!context) return shaNull; - if (!length) return shaSuccess; - if (!message_array) return shaNull; - if (context->Computed) return context->Corrupted = shaStateError; - if (context->Corrupted) return context->Corrupted; - - while (length--) { - context->Message_Block[context->Message_Block_Index++] = - *message_array; - - if ((SHA384_512AddLength(context, 8) == shaSuccess) && - (context->Message_Block_Index == SHA512_Message_Block_Size)) - SHA384_512ProcessMessageBlock(context); - - message_array++; - } - - return context->Corrupted; -} - -/* - * SHA512FinalBits - * - * Description: - * This function will add in any final bits of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_bits: [in] - * The final bits of the message, in the upper portion of the - * byte. (Use 0b###00000 instead of 0b00000### to input the - * three bits ###.) - * length: [in] - * The number of bits in message_bits, between 1 and 7. - * - * Returns: - * sha Error Code. - * - */ -int SHA512FinalBits(SHA512Context *context, - uint8_t message_bits, unsigned int length) -{ - static uint8_t masks[8] = { - /* 0 0b00000000 */ 0x00, /* 1 0b10000000 */ 0x80, - /* 2 0b11000000 */ 0xC0, /* 3 0b11100000 */ 0xE0, - /* 4 0b11110000 */ 0xF0, /* 5 0b11111000 */ 0xF8, - /* 6 0b11111100 */ 0xFC, /* 7 0b11111110 */ 0xFE - }; - static uint8_t markbit[8] = { - /* 0 0b10000000 */ 0x80, /* 1 0b01000000 */ 0x40, - /* 2 0b00100000 */ 0x20, /* 3 0b00010000 */ 0x10, - /* 4 0b00001000 */ 0x08, /* 5 0b00000100 */ 0x04, - /* 6 0b00000010 */ 0x02, /* 7 0b00000001 */ 0x01 - }; - - if (!context) return shaNull; - if (!length) return shaSuccess; - if (context->Corrupted) return context->Corrupted; - if (context->Computed) return context->Corrupted = shaStateError; - if (length >= 8) return context->Corrupted = shaBadParam; - - SHA384_512AddLength(context, length); - SHA384_512Finalize(context, (uint8_t) - ((message_bits & masks[length]) | markbit[length])); - - return context->Corrupted; -} - -/* - * SHA512Result - * - * Description: - * This function will return the 512-bit message digest - * into the Message_Digest array provided by the caller. - * NOTE: - * The first octet of hash is stored in the element with index 0, - * the last octet of hash in the element with index 63. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA hash. - * Message_Digest[ ]: [out] - * Where the digest is returned. - * - * Returns: - * sha Error Code. - * - */ -int SHA512Result(SHA512Context *context, - uint8_t Message_Digest[SHA512HashSize]) -{ - return SHA384_512ResultN(context, Message_Digest, SHA512HashSize); -} - -/* - * SHA384_512Reset - * - * Description: - * This helper function will initialize the SHA512Context in - * preparation for computing a new SHA384 or SHA512 message - * digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * H0[ ]: [in] - * The initial hash value array to use. - * - * Returns: - * sha Error Code. - * - */ -#ifdef USE_32BIT_ONLY -static int SHA384_512Reset(SHA512Context *context, - uint32_t H0[SHA512HashSize/4]) -#else /* !USE_32BIT_ONLY */ -static int SHA384_512Reset(SHA512Context *context, - uint64_t H0[SHA512HashSize/8]) -#endif /* USE_32BIT_ONLY */ -{ - int i; - if (!context) return shaNull; - context->Message_Block_Index = 0; - -#ifdef USE_32BIT_ONLY - context->Length[0] = context->Length[1] = - context->Length[2] = context->Length[3] = 0; - - for (i = 0; i < SHA512HashSize/4; i++) - context->Intermediate_Hash[i] = H0[i]; -#else /* !USE_32BIT_ONLY */ - context->Length_High = context->Length_Low = 0; - - for (i = 0; i < SHA512HashSize/8; i++) - context->Intermediate_Hash[i] = H0[i]; -#endif /* USE_32BIT_ONLY */ - - context->Computed = 0; - context->Corrupted = shaSuccess; - - return shaSuccess; -} - -/* - * SHA384_512ProcessMessageBlock - * - * Description: - * This helper function will process the next 1024 bits of the - * message stored in the Message_Block array. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * - * Returns: - * Nothing. - * - * Comments: - * Many of the variable names in this code, especially the - * single character names, were used because those were the - * names used in the Secure Hash Standard. - * - * - */ -static void SHA384_512ProcessMessageBlock(SHA512Context *context) -{ -#ifdef USE_32BIT_ONLY - /* Constants defined in FIPS 180-3, section 4.2.3 */ - static const uint32_t K[80*2] = { - 0x428A2F98, 0xD728AE22, 0x71374491, 0x23EF65CD, 0xB5C0FBCF, - 0xEC4D3B2F, 0xE9B5DBA5, 0x8189DBBC, 0x3956C25B, 0xF348B538, - 0x59F111F1, 0xB605D019, 0x923F82A4, 0xAF194F9B, 0xAB1C5ED5, - 0xDA6D8118, 0xD807AA98, 0xA3030242, 0x12835B01, 0x45706FBE, - 0x243185BE, 0x4EE4B28C, 0x550C7DC3, 0xD5FFB4E2, 0x72BE5D74, - 0xF27B896F, 0x80DEB1FE, 0x3B1696B1, 0x9BDC06A7, 0x25C71235, - 0xC19BF174, 0xCF692694, 0xE49B69C1, 0x9EF14AD2, 0xEFBE4786, - 0x384F25E3, 0x0FC19DC6, 0x8B8CD5B5, 0x240CA1CC, 0x77AC9C65, - 0x2DE92C6F, 0x592B0275, 0x4A7484AA, 0x6EA6E483, 0x5CB0A9DC, - 0xBD41FBD4, 0x76F988DA, 0x831153B5, 0x983E5152, 0xEE66DFAB, - 0xA831C66D, 0x2DB43210, 0xB00327C8, 0x98FB213F, 0xBF597FC7, - 0xBEEF0EE4, 0xC6E00BF3, 0x3DA88FC2, 0xD5A79147, 0x930AA725, - 0x06CA6351, 0xE003826F, 0x14292967, 0x0A0E6E70, 0x27B70A85, - 0x46D22FFC, 0x2E1B2138, 0x5C26C926, 0x4D2C6DFC, 0x5AC42AED, - 0x53380D13, 0x9D95B3DF, 0x650A7354, 0x8BAF63DE, 0x766A0ABB, - 0x3C77B2A8, 0x81C2C92E, 0x47EDAEE6, 0x92722C85, 0x1482353B, - 0xA2BFE8A1, 0x4CF10364, 0xA81A664B, 0xBC423001, 0xC24B8B70, - 0xD0F89791, 0xC76C51A3, 0x0654BE30, 0xD192E819, 0xD6EF5218, - 0xD6990624, 0x5565A910, 0xF40E3585, 0x5771202A, 0x106AA070, - 0x32BBD1B8, 0x19A4C116, 0xB8D2D0C8, 0x1E376C08, 0x5141AB53, - 0x2748774C, 0xDF8EEB99, 0x34B0BCB5, 0xE19B48A8, 0x391C0CB3, - 0xC5C95A63, 0x4ED8AA4A, 0xE3418ACB, 0x5B9CCA4F, 0x7763E373, - 0x682E6FF3, 0xD6B2B8A3, 0x748F82EE, 0x5DEFB2FC, 0x78A5636F, - 0x43172F60, 0x84C87814, 0xA1F0AB72, 0x8CC70208, 0x1A6439EC, - 0x90BEFFFA, 0x23631E28, 0xA4506CEB, 0xDE82BDE9, 0xBEF9A3F7, - 0xB2C67915, 0xC67178F2, 0xE372532B, 0xCA273ECE, 0xEA26619C, - 0xD186B8C7, 0x21C0C207, 0xEADA7DD6, 0xCDE0EB1E, 0xF57D4F7F, - 0xEE6ED178, 0x06F067AA, 0x72176FBA, 0x0A637DC5, 0xA2C898A6, - 0x113F9804, 0xBEF90DAE, 0x1B710B35, 0x131C471B, 0x28DB77F5, - 0x23047D84, 0x32CAAB7B, 0x40C72493, 0x3C9EBE0A, 0x15C9BEBC, - 0x431D67C4, 0x9C100D4C, 0x4CC5D4BE, 0xCB3E42B6, 0x597F299C, - 0xFC657E2A, 0x5FCB6FAB, 0x3AD6FAEC, 0x6C44198C, 0x4A475817 - }; - int t, t2, t8; /* Loop counter */ - uint32_t temp1[2], temp2[2], /* Temporary word values */ - temp3[2], temp4[2], temp5[2]; - uint32_t W[2*80]; /* Word sequence */ - uint32_t A[2], B[2], C[2], D[2], /* Word buffers */ - E[2], F[2], G[2], H[2]; - - /* Initialize the first 16 words in the array W */ - for (t = t2 = t8 = 0; t < 16; t++, t8 += 8) { - W[t2++] = ((((uint32_t)context->Message_Block[t8 ])) << 24) | - ((((uint32_t)context->Message_Block[t8 + 1])) << 16) | - ((((uint32_t)context->Message_Block[t8 + 2])) << 8) | - ((((uint32_t)context->Message_Block[t8 + 3]))); - W[t2++] = ((((uint32_t)context->Message_Block[t8 + 4])) << 24) | - ((((uint32_t)context->Message_Block[t8 + 5])) << 16) | - ((((uint32_t)context->Message_Block[t8 + 6])) << 8) | - ((((uint32_t)context->Message_Block[t8 + 7]))); - } - - for (t = 16; t < 80; t++, t2 += 2) { - /* W[t] = SHA512_sigma1(W[t-2]) + W[t-7] + - SHA512_sigma0(W[t-15]) + W[t-16]; */ - uint32_t *Wt2 = &W[t2-2*2]; - uint32_t *Wt7 = &W[t2-7*2]; - uint32_t *Wt15 = &W[t2-15*2]; - uint32_t *Wt16 = &W[t2-16*2]; - SHA512_sigma1(Wt2, temp1); - SHA512_ADD(temp1, Wt7, temp2); - SHA512_sigma0(Wt15, temp1); - SHA512_ADD(temp1, Wt16, temp3); - SHA512_ADD(temp2, temp3, &W[t2]); - } - - A[0] = context->Intermediate_Hash[0]; - A[1] = context->Intermediate_Hash[1]; - B[0] = context->Intermediate_Hash[2]; - B[1] = context->Intermediate_Hash[3]; - C[0] = context->Intermediate_Hash[4]; - C[1] = context->Intermediate_Hash[5]; - D[0] = context->Intermediate_Hash[6]; - D[1] = context->Intermediate_Hash[7]; - E[0] = context->Intermediate_Hash[8]; - E[1] = context->Intermediate_Hash[9]; - F[0] = context->Intermediate_Hash[10]; - F[1] = context->Intermediate_Hash[11]; - G[0] = context->Intermediate_Hash[12]; - G[1] = context->Intermediate_Hash[13]; - H[0] = context->Intermediate_Hash[14]; - H[1] = context->Intermediate_Hash[15]; - - for (t = t2 = 0; t < 80; t++, t2 += 2) { - /* - * temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; - */ - SHA512_SIGMA1(E,temp1); - SHA512_ADD(H, temp1, temp2); - SHA_Ch(E,F,G,temp3); - SHA512_ADD(temp2, temp3, temp4); - SHA512_ADD(&K[t2], &W[t2], temp5); - SHA512_ADD(temp4, temp5, temp1); - /* - * temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C); - */ - SHA512_SIGMA0(A,temp3); - SHA_Maj(A,B,C,temp4); - SHA512_ADD(temp3, temp4, temp2); - H[0] = G[0]; H[1] = G[1]; - G[0] = F[0]; G[1] = F[1]; - F[0] = E[0]; F[1] = E[1]; - SHA512_ADD(D, temp1, E); - D[0] = C[0]; D[1] = C[1]; - C[0] = B[0]; C[1] = B[1]; - B[0] = A[0]; B[1] = A[1]; - SHA512_ADD(temp1, temp2, A); - } - - SHA512_ADDTO2(&context->Intermediate_Hash[0], A); - SHA512_ADDTO2(&context->Intermediate_Hash[2], B); - SHA512_ADDTO2(&context->Intermediate_Hash[4], C); - SHA512_ADDTO2(&context->Intermediate_Hash[6], D); - SHA512_ADDTO2(&context->Intermediate_Hash[8], E); - SHA512_ADDTO2(&context->Intermediate_Hash[10], F); - SHA512_ADDTO2(&context->Intermediate_Hash[12], G); - SHA512_ADDTO2(&context->Intermediate_Hash[14], H); - -#else /* !USE_32BIT_ONLY */ - /* Constants defined in FIPS 180-3, section 4.2.3 */ - static const uint64_t K[80] = { - 0x428A2F98D728AE22ll, 0x7137449123EF65CDll, 0xB5C0FBCFEC4D3B2Fll, - 0xE9B5DBA58189DBBCll, 0x3956C25BF348B538ll, 0x59F111F1B605D019ll, - 0x923F82A4AF194F9Bll, 0xAB1C5ED5DA6D8118ll, 0xD807AA98A3030242ll, - 0x12835B0145706FBEll, 0x243185BE4EE4B28Cll, 0x550C7DC3D5FFB4E2ll, - 0x72BE5D74F27B896Fll, 0x80DEB1FE3B1696B1ll, 0x9BDC06A725C71235ll, - 0xC19BF174CF692694ll, 0xE49B69C19EF14AD2ll, 0xEFBE4786384F25E3ll, - 0x0FC19DC68B8CD5B5ll, 0x240CA1CC77AC9C65ll, 0x2DE92C6F592B0275ll, - 0x4A7484AA6EA6E483ll, 0x5CB0A9DCBD41FBD4ll, 0x76F988DA831153B5ll, - 0x983E5152EE66DFABll, 0xA831C66D2DB43210ll, 0xB00327C898FB213Fll, - 0xBF597FC7BEEF0EE4ll, 0xC6E00BF33DA88FC2ll, 0xD5A79147930AA725ll, - 0x06CA6351E003826Fll, 0x142929670A0E6E70ll, 0x27B70A8546D22FFCll, - 0x2E1B21385C26C926ll, 0x4D2C6DFC5AC42AEDll, 0x53380D139D95B3DFll, - 0x650A73548BAF63DEll, 0x766A0ABB3C77B2A8ll, 0x81C2C92E47EDAEE6ll, - 0x92722C851482353Bll, 0xA2BFE8A14CF10364ll, 0xA81A664BBC423001ll, - 0xC24B8B70D0F89791ll, 0xC76C51A30654BE30ll, 0xD192E819D6EF5218ll, - 0xD69906245565A910ll, 0xF40E35855771202All, 0x106AA07032BBD1B8ll, - 0x19A4C116B8D2D0C8ll, 0x1E376C085141AB53ll, 0x2748774CDF8EEB99ll, - 0x34B0BCB5E19B48A8ll, 0x391C0CB3C5C95A63ll, 0x4ED8AA4AE3418ACBll, - 0x5B9CCA4F7763E373ll, 0x682E6FF3D6B2B8A3ll, 0x748F82EE5DEFB2FCll, - 0x78A5636F43172F60ll, 0x84C87814A1F0AB72ll, 0x8CC702081A6439ECll, - 0x90BEFFFA23631E28ll, 0xA4506CEBDE82BDE9ll, 0xBEF9A3F7B2C67915ll, - 0xC67178F2E372532Bll, 0xCA273ECEEA26619Cll, 0xD186B8C721C0C207ll, - 0xEADA7DD6CDE0EB1Ell, 0xF57D4F7FEE6ED178ll, 0x06F067AA72176FBAll, - 0x0A637DC5A2C898A6ll, 0x113F9804BEF90DAEll, 0x1B710B35131C471Bll, - 0x28DB77F523047D84ll, 0x32CAAB7B40C72493ll, 0x3C9EBE0A15C9BEBCll, - 0x431D67C49C100D4Cll, 0x4CC5D4BECB3E42B6ll, 0x597F299CFC657E2All, - 0x5FCB6FAB3AD6FAECll, 0x6C44198C4A475817ll - }; - int t, t8; /* Loop counter */ - uint64_t temp1, temp2; /* Temporary word value */ - uint64_t W[80]; /* Word sequence */ - uint64_t A, B, C, D, E, F, G, H; /* Word buffers */ - - /* - * Initialize the first 16 words in the array W - */ - for (t = t8 = 0; t < 16; t++, t8 += 8) - W[t] = ((uint64_t)(context->Message_Block[t8 ]) << 56) | - ((uint64_t)(context->Message_Block[t8 + 1]) << 48) | - ((uint64_t)(context->Message_Block[t8 + 2]) << 40) | - ((uint64_t)(context->Message_Block[t8 + 3]) << 32) | - ((uint64_t)(context->Message_Block[t8 + 4]) << 24) | - ((uint64_t)(context->Message_Block[t8 + 5]) << 16) | - ((uint64_t)(context->Message_Block[t8 + 6]) << 8) | - ((uint64_t)(context->Message_Block[t8 + 7])); - - for (t = 16; t < 80; t++) - W[t] = SHA512_sigma1(W[t-2]) + W[t-7] + - SHA512_sigma0(W[t-15]) + W[t-16]; - A = context->Intermediate_Hash[0]; - B = context->Intermediate_Hash[1]; - C = context->Intermediate_Hash[2]; - D = context->Intermediate_Hash[3]; - E = context->Intermediate_Hash[4]; - F = context->Intermediate_Hash[5]; - G = context->Intermediate_Hash[6]; - H = context->Intermediate_Hash[7]; - - for (t = 0; t < 80; t++) { - temp1 = H + SHA512_SIGMA1(E) + SHA_Ch(E,F,G) + K[t] + W[t]; - temp2 = SHA512_SIGMA0(A) + SHA_Maj(A,B,C); - H = G; - G = F; - F = E; - E = D + temp1; - D = C; - C = B; - B = A; - A = temp1 + temp2; - } - - context->Intermediate_Hash[0] += A; - context->Intermediate_Hash[1] += B; - context->Intermediate_Hash[2] += C; - context->Intermediate_Hash[3] += D; - context->Intermediate_Hash[4] += E; - context->Intermediate_Hash[5] += F; - context->Intermediate_Hash[6] += G; - context->Intermediate_Hash[7] += H; -#endif /* USE_32BIT_ONLY */ - - context->Message_Block_Index = 0; -} - -/* - * SHA384_512Finalize - * - * Description: - * This helper function finishes off the digest calculations. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * Pad_Byte: [in] - * The last byte to add to the message block before the 0-padding - * and length. This will contain the last bits of the message - * followed by another single bit. If the message was an - * exact multiple of 8-bits long, Pad_Byte will be 0x80. - * - * Returns: - * sha Error Code. - * - */ -static void SHA384_512Finalize(SHA512Context *context, - uint8_t Pad_Byte) -{ - int_least16_t i; - SHA384_512PadMessage(context, Pad_Byte); - /* message may be sensitive, clear it out */ - for (i = 0; i < SHA512_Message_Block_Size; ++i) - context->Message_Block[i] = 0; -#ifdef USE_32BIT_ONLY /* and clear length */ - context->Length[0] = context->Length[1] = 0; - context->Length[2] = context->Length[3] = 0; -#else /* !USE_32BIT_ONLY */ - context->Length_High = context->Length_Low = 0; -#endif /* USE_32BIT_ONLY */ - context->Computed = 1; -} - -/* - * SHA384_512PadMessage - * - * Description: - * According to the standard, the message must be padded to the next - * even multiple of 1024 bits. The first padding bit must be a '1'. - * The last 128 bits represent the length of the original message. - * All bits in between should be 0. This helper function will - * pad the message according to those rules by filling the - * Message_Block array accordingly. When it returns, it can be - * assumed that the message digest has been computed. - * - * Parameters: - * context: [in/out] - * The context to pad. - * Pad_Byte: [in] - * The last byte to add to the message block before the 0-padding - * and length. This will contain the last bits of the message - * followed by another single bit. If the message was an - * exact multiple of 8-bits long, Pad_Byte will be 0x80. - * - * Returns: - * Nothing. - * - */ -static void SHA384_512PadMessage(SHA512Context *context, - uint8_t Pad_Byte) -{ - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second - * block. - */ - if (context->Message_Block_Index >= (SHA512_Message_Block_Size-16)) { - context->Message_Block[context->Message_Block_Index++] = Pad_Byte; - while (context->Message_Block_Index < SHA512_Message_Block_Size) - context->Message_Block[context->Message_Block_Index++] = 0; - - SHA384_512ProcessMessageBlock(context); - } else - context->Message_Block[context->Message_Block_Index++] = Pad_Byte; - - while (context->Message_Block_Index < (SHA512_Message_Block_Size-16)) - context->Message_Block[context->Message_Block_Index++] = 0; - - /* - * Store the message length as the last 16 octets - */ -#ifdef USE_32BIT_ONLY - context->Message_Block[112] = (uint8_t)(context->Length[0] >> 24); - context->Message_Block[113] = (uint8_t)(context->Length[0] >> 16); - context->Message_Block[114] = (uint8_t)(context->Length[0] >> 8); - context->Message_Block[115] = (uint8_t)(context->Length[0]); - context->Message_Block[116] = (uint8_t)(context->Length[1] >> 24); - context->Message_Block[117] = (uint8_t)(context->Length[1] >> 16); - context->Message_Block[118] = (uint8_t)(context->Length[1] >> 8); - context->Message_Block[119] = (uint8_t)(context->Length[1]); - - context->Message_Block[120] = (uint8_t)(context->Length[2] >> 24); - context->Message_Block[121] = (uint8_t)(context->Length[2] >> 16); - context->Message_Block[122] = (uint8_t)(context->Length[2] >> 8); - context->Message_Block[123] = (uint8_t)(context->Length[2]); - context->Message_Block[124] = (uint8_t)(context->Length[3] >> 24); - context->Message_Block[125] = (uint8_t)(context->Length[3] >> 16); - context->Message_Block[126] = (uint8_t)(context->Length[3] >> 8); - context->Message_Block[127] = (uint8_t)(context->Length[3]); -#else /* !USE_32BIT_ONLY */ - context->Message_Block[112] = (uint8_t)(context->Length_High >> 56); - context->Message_Block[113] = (uint8_t)(context->Length_High >> 48); - context->Message_Block[114] = (uint8_t)(context->Length_High >> 40); - context->Message_Block[115] = (uint8_t)(context->Length_High >> 32); - context->Message_Block[116] = (uint8_t)(context->Length_High >> 24); - context->Message_Block[117] = (uint8_t)(context->Length_High >> 16); - context->Message_Block[118] = (uint8_t)(context->Length_High >> 8); - context->Message_Block[119] = (uint8_t)(context->Length_High); - - context->Message_Block[120] = (uint8_t)(context->Length_Low >> 56); - context->Message_Block[121] = (uint8_t)(context->Length_Low >> 48); - context->Message_Block[122] = (uint8_t)(context->Length_Low >> 40); - context->Message_Block[123] = (uint8_t)(context->Length_Low >> 32); - context->Message_Block[124] = (uint8_t)(context->Length_Low >> 24); - context->Message_Block[125] = (uint8_t)(context->Length_Low >> 16); - context->Message_Block[126] = (uint8_t)(context->Length_Low >> 8); - context->Message_Block[127] = (uint8_t)(context->Length_Low); -#endif /* USE_32BIT_ONLY */ - - SHA384_512ProcessMessageBlock(context); -} - -/* - * SHA384_512ResultN - * - * Description: - * This helper function will return the 384-bit or 512-bit message - * digest into the Message_Digest array provided by the caller. - * NOTE: - * The first octet of hash is stored in the element with index 0, - * the last octet of hash in the element with index 47/63. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA hash. - * Message_Digest[ ]: [out] - * Where the digest is returned. - * HashSize: [in] - * The size of the hash, either 48 or 64. - * - * Returns: - * sha Error Code. - * - */ -static int SHA384_512ResultN(SHA512Context *context, - uint8_t Message_Digest[ ], int HashSize) -{ - int i; -#ifdef USE_32BIT_ONLY - int i2; -#endif /* USE_32BIT_ONLY */ - - if (!context) return shaNull; - if (!Message_Digest) return shaNull; - if (context->Corrupted) return context->Corrupted; - - if (!context->Computed) - SHA384_512Finalize(context, 0x80); - -#ifdef USE_32BIT_ONLY - for (i = i2 = 0; i < HashSize; ) { - Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>24); - Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>16); - Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>8); - Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2++]); - Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>24); - Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>16); - Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2]>>8); - Message_Digest[i++]=(uint8_t)(context->Intermediate_Hash[i2++]); - } -#else /* !USE_32BIT_ONLY */ - for (i = 0; i < HashSize; ++i) - Message_Digest[i] = (uint8_t) - (context->Intermediate_Hash[i>>3] >> 8 * ( 7 - ( i % 8 ) )); -#endif /* USE_32BIT_ONLY */ - - return shaSuccess; -} - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/shatest.c b/lib/libesp32_div/ESP32-HomeKit/src/shatest.c deleted file mode 100644 index f2c9232b3..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/shatest.c +++ /dev/null @@ -1,1530 +0,0 @@ -/************************** shatest.c **************************/ -/***************** See RFC 6234 for details. *******************/ -/* Copyright (c) 2011 IETF Trust and the persons identified as */ -/* authors of the code. All rights reserved. */ -/* See sha.h for terms of use and redistribution. */ - -/* - * Description: - * This file will exercise the SHA code performing - * the three tests documented in FIPS PUB 180-3 - * (http://csrc.nist.gov/publications/fips/ - * fips180-2/fips180-2withchangenotice.pdf) - * one that calls SHAInput with an exact multiple of 512 bits - * the seven tests documented for each algorithm in - * "The Secure Hash Algorithm Validation System (SHAVS)" - * (http://csrc.nist.gov/cryptval/shs/SHAVS.pdf), - * three of which are bit-level tests - * - * These tests have subsequently been moved to pages linked from - * http://csrc.nist.gov/groups/ST/toolkit/examples.html - * - * This file will exercise the HMAC SHA1 code performing - * the seven tests documented in RFCs [RFC 2202] and [RFC 4231]. - * - * This file will exercise the HKDF code performing - * the seven tests documented in RFC 4869. - * - * To run the tests and just see PASSED/FAILED, use the -p option. - * - * Other options exercise: - * hashing an arbitrary string - * hashing a file's contents - * a few error test checks - * printing the results in raw format - * - * Portability Issues: - * None. - * - */ - -#include -#include -#include -#include -#include -#include /* defines getopt() and optarg */ -#include "sha.h" - -static int scasecmp(const char *s1, const char *s2); - -/* - * Define patterns for testing - */ -#define TEST1 "abc" -#define TEST2_1 \ - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" -#define TEST2_2a \ - "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" -#define TEST2_2b \ - "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" -#define TEST2_2 TEST2_2a TEST2_2b -#define TEST3 "a" /* times 1000000 */ -#define TEST4a "01234567012345670123456701234567" -#define TEST4b "01234567012345670123456701234567" - /* an exact multiple of 512 bits */ -#define TEST4 TEST4a TEST4b /* times 10 */ -#define TEST7_1 \ - "\x49\xb2\xae\xc2\x59\x4b\xbe\x3a\x3b\x11\x75\x42\xd9\x4a\xc8" -#define TEST8_1 \ - "\x9a\x7d\xfd\xf1\xec\xea\xd0\x6e\xd6\x46\xaa\x55\xfe\x75\x71\x46" -#define TEST9_1 \ - "\x65\xf9\x32\x99\x5b\xa4\xce\x2c\xb1\xb4\xa2\xe7\x1a\xe7\x02\x20" \ - "\xaa\xce\xc8\x96\x2d\xd4\x49\x9c\xbd\x7c\x88\x7a\x94\xea\xaa\x10" \ - "\x1e\xa5\xaa\xbc\x52\x9b\x4e\x7e\x43\x66\x5a\x5a\xf2\xcd\x03\xfe" \ - "\x67\x8e\xa6\xa5\x00\x5b\xba\x3b\x08\x22\x04\xc2\x8b\x91\x09\xf4" \ - "\x69\xda\xc9\x2a\xaa\xb3\xaa\x7c\x11\xa1\xb3\x2a" -#define TEST10_1 \ - "\xf7\x8f\x92\x14\x1b\xcd\x17\x0a\xe8\x9b\x4f\xba\x15\xa1\xd5\x9f" \ - "\x3f\xd8\x4d\x22\x3c\x92\x51\xbd\xac\xbb\xae\x61\xd0\x5e\xd1\x15" \ - "\xa0\x6a\x7c\xe1\x17\xb7\xbe\xea\xd2\x44\x21\xde\xd9\xc3\x25\x92" \ - "\xbd\x57\xed\xea\xe3\x9c\x39\xfa\x1f\xe8\x94\x6a\x84\xd0\xcf\x1f" \ - "\x7b\xee\xad\x17\x13\xe2\xe0\x95\x98\x97\x34\x7f\x67\xc8\x0b\x04" \ - "\x00\xc2\x09\x81\x5d\x6b\x10\xa6\x83\x83\x6f\xd5\x56\x2a\x56\xca" \ - "\xb1\xa2\x8e\x81\xb6\x57\x66\x54\x63\x1c\xf1\x65\x66\xb8\x6e\x3b" \ - "\x33\xa1\x08\xb0\x53\x07\xc0\x0a\xff\x14\xa7\x68\xed\x73\x50\x60" \ - "\x6a\x0f\x85\xe6\xa9\x1d\x39\x6f\x5b\x5c\xbe\x57\x7f\x9b\x38\x80" \ - "\x7c\x7d\x52\x3d\x6d\x79\x2f\x6e\xbc\x24\xa4\xec\xf2\xb3\xa4\x27" \ - "\xcd\xbb\xfb" -#define TEST7_224 \ - "\xf0\x70\x06\xf2\x5a\x0b\xea\x68\xcd\x76\xa2\x95\x87\xc2\x8d" -#define TEST8_224 \ - "\x18\x80\x40\x05\xdd\x4f\xbd\x15\x56\x29\x9d\x6f\x9d\x93\xdf\x62" -#define TEST9_224 \ - "\xa2\xbe\x6e\x46\x32\x81\x09\x02\x94\xd9\xce\x94\x82\x65\x69\x42" \ - "\x3a\x3a\x30\x5e\xd5\xe2\x11\x6c\xd4\xa4\xc9\x87\xfc\x06\x57\x00" \ - "\x64\x91\xb1\x49\xcc\xd4\xb5\x11\x30\xac\x62\xb1\x9d\xc2\x48\xc7" \ - "\x44\x54\x3d\x20\xcd\x39\x52\xdc\xed\x1f\x06\xcc\x3b\x18\xb9\x1f" \ - "\x3f\x55\x63\x3e\xcc\x30\x85\xf4\x90\x70\x60\xd2" -#define TEST10_224 \ - "\x55\xb2\x10\x07\x9c\x61\xb5\x3a\xdd\x52\x06\x22\xd1\xac\x97\xd5" \ - "\xcd\xbe\x8c\xb3\x3a\xa0\xae\x34\x45\x17\xbe\xe4\xd7\xba\x09\xab" \ - "\xc8\x53\x3c\x52\x50\x88\x7a\x43\xbe\xbb\xac\x90\x6c\x2e\x18\x37" \ - "\xf2\x6b\x36\xa5\x9a\xe3\xbe\x78\x14\xd5\x06\x89\x6b\x71\x8b\x2a" \ - "\x38\x3e\xcd\xac\x16\xb9\x61\x25\x55\x3f\x41\x6f\xf3\x2c\x66\x74" \ - "\xc7\x45\x99\xa9\x00\x53\x86\xd9\xce\x11\x12\x24\x5f\x48\xee\x47" \ - "\x0d\x39\x6c\x1e\xd6\x3b\x92\x67\x0c\xa5\x6e\xc8\x4d\xee\xa8\x14" \ - "\xb6\x13\x5e\xca\x54\x39\x2b\xde\xdb\x94\x89\xbc\x9b\x87\x5a\x8b" \ - "\xaf\x0d\xc1\xae\x78\x57\x36\x91\x4a\xb7\xda\xa2\x64\xbc\x07\x9d" \ - "\x26\x9f\x2c\x0d\x7e\xdd\xd8\x10\xa4\x26\x14\x5a\x07\x76\xf6\x7c" \ - "\x87\x82\x73" -#define TEST7_256 \ - "\xbe\x27\x46\xc6\xdb\x52\x76\x5f\xdb\x2f\x88\x70\x0f\x9a\x73" -#define TEST8_256 \ - "\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3\x88\x7a\xb2\xcd\x68\x46\x52" -#define TEST9_256 \ - "\x3e\x74\x03\x71\xc8\x10\xc2\xb9\x9f\xc0\x4e\x80\x49\x07\xef\x7c" \ - "\xf2\x6b\xe2\x8b\x57\xcb\x58\xa3\xe2\xf3\xc0\x07\x16\x6e\x49\xc1" \ - "\x2e\x9b\xa3\x4c\x01\x04\x06\x91\x29\xea\x76\x15\x64\x25\x45\x70" \ - "\x3a\x2b\xd9\x01\xe1\x6e\xb0\xe0\x5d\xeb\xa0\x14\xeb\xff\x64\x06" \ - "\xa0\x7d\x54\x36\x4e\xff\x74\x2d\xa7\x79\xb0\xb3" -#define TEST10_256 \ - "\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1\x2b\x20\x52\x7a\xfe\xf0" \ - "\x4d\x8a\x05\x69\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76\x00\x00" \ - "\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08\x3a\xa3\x9d\x81\x0d\xb3\x10\x77" \ - "\x7d\xab\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32\x5f\x8b\x23\x74" \ - "\xde\x7a\x4b\x5a\x58\xcb\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b" \ - "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65\x92\xec\xed\xaa\x66\xca" \ - "\x82\xa2\x9d\x0c\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4\xc0\xa4" \ - "\x3f\x8d\x79\xa3\x0a\x16\x5c\xba\xbe\x45\x2b\x77\x4b\x9c\x71\x09" \ - "\xa9\x7d\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc\x10\x6a\xad\x5a" \ - "\x9f\xdd\x30\x82\x57\x69\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39" \ - "\x3d\x54\xd6" -#define TEST7_384 \ - "\x8b\xc5\x00\xc7\x7c\xee\xd9\x87\x9d\xa9\x89\x10\x7c\xe0\xaa" -#define TEST8_384 \ - "\xa4\x1c\x49\x77\x79\xc0\x37\x5f\xf1\x0a\x7f\x4e\x08\x59\x17\x39" -#define TEST9_384 \ - "\x68\xf5\x01\x79\x2d\xea\x97\x96\x76\x70\x22\xd9\x3d\xa7\x16\x79" \ - "\x30\x99\x20\xfa\x10\x12\xae\xa3\x57\xb2\xb1\x33\x1d\x40\xa1\xd0" \ - "\x3c\x41\xc2\x40\xb3\xc9\xa7\x5b\x48\x92\xf4\xc0\x72\x4b\x68\xc8" \ - "\x75\x32\x1a\xb8\xcf\xe5\x02\x3b\xd3\x75\xbc\x0f\x94\xbd\x89\xfe" \ - "\x04\xf2\x97\x10\x5d\x7b\x82\xff\xc0\x02\x1a\xeb\x1c\xcb\x67\x4f" \ - "\x52\x44\xea\x34\x97\xde\x26\xa4\x19\x1c\x5f\x62\xe5\xe9\xa2\xd8" \ - "\x08\x2f\x05\x51\xf4\xa5\x30\x68\x26\xe9\x1c\xc0\x06\xce\x1b\xf6" \ - "\x0f\xf7\x19\xd4\x2f\xa5\x21\xc8\x71\xcd\x23\x94\xd9\x6e\xf4\x46" \ - "\x8f\x21\x96\x6b\x41\xf2\xba\x80\xc2\x6e\x83\xa9" -#define TEST10_384 \ - "\x39\x96\x69\xe2\x8f\x6b\x9c\x6d\xbc\xbb\x69\x12\xec\x10\xff\xcf" \ - "\x74\x79\x03\x49\xb7\xdc\x8f\xbe\x4a\x8e\x7b\x3b\x56\x21\xdb\x0f" \ - "\x3e\x7d\xc8\x7f\x82\x32\x64\xbb\xe4\x0d\x18\x11\xc9\xea\x20\x61" \ - "\xe1\xc8\x4a\xd1\x0a\x23\xfa\xc1\x72\x7e\x72\x02\xfc\x3f\x50\x42" \ - "\xe6\xbf\x58\xcb\xa8\xa2\x74\x6e\x1f\x64\xf9\xb9\xea\x35\x2c\x71" \ - "\x15\x07\x05\x3c\xf4\xe5\x33\x9d\x52\x86\x5f\x25\xcc\x22\xb5\xe8" \ - "\x77\x84\xa1\x2f\xc9\x61\xd6\x6c\xb6\xe8\x95\x73\x19\x9a\x2c\xe6" \ - "\x56\x5c\xbd\xf1\x3d\xca\x40\x38\x32\xcf\xcb\x0e\x8b\x72\x11\xe8" \ - "\x3a\xf3\x2a\x11\xac\x17\x92\x9f\xf1\xc0\x73\xa5\x1c\xc0\x27\xaa" \ - "\xed\xef\xf8\x5a\xad\x7c\x2b\x7c\x5a\x80\x3e\x24\x04\xd9\x6d\x2a" \ - "\x77\x35\x7b\xda\x1a\x6d\xae\xed\x17\x15\x1c\xb9\xbc\x51\x25\xa4" \ - "\x22\xe9\x41\xde\x0c\xa0\xfc\x50\x11\xc2\x3e\xcf\xfe\xfd\xd0\x96" \ - "\x76\x71\x1c\xf3\xdb\x0a\x34\x40\x72\x0e\x16\x15\xc1\xf2\x2f\xbc" \ - "\x3c\x72\x1d\xe5\x21\xe1\xb9\x9b\xa1\xbd\x55\x77\x40\x86\x42\x14" \ - "\x7e\xd0\x96" -#define TEST7_512 \ - "\x08\xec\xb5\x2e\xba\xe1\xf7\x42\x2d\xb6\x2b\xcd\x54\x26\x70" -#define TEST8_512 \ - "\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81\x6e\x9d\x98\xbf\xf0\xa0" -#define TEST9_512 \ - "\x3a\xdd\xec\x85\x59\x32\x16\xd1\x61\x9a\xa0\x2d\x97\x56\x97\x0b" \ - "\xfc\x70\xac\xe2\x74\x4f\x7c\x6b\x27\x88\x15\x10\x28\xf7\xb6\xa2" \ - "\x55\x0f\xd7\x4a\x7e\x6e\x69\xc2\xc9\xb4\x5f\xc4\x54\x96\x6d\xc3" \ - "\x1d\x2e\x10\xda\x1f\x95\xce\x02\xbe\xb4\xbf\x87\x65\x57\x4c\xbd" \ - "\x6e\x83\x37\xef\x42\x0a\xdc\x98\xc1\x5c\xb6\xd5\xe4\xa0\x24\x1b" \ - "\xa0\x04\x6d\x25\x0e\x51\x02\x31\xca\xc2\x04\x6c\x99\x16\x06\xab" \ - "\x4e\xe4\x14\x5b\xee\x2f\xf4\xbb\x12\x3a\xab\x49\x8d\x9d\x44\x79" \ - "\x4f\x99\xcc\xad\x89\xa9\xa1\x62\x12\x59\xed\xa7\x0a\x5b\x6d\xd4" \ - "\xbd\xd8\x77\x78\xc9\x04\x3b\x93\x84\xf5\x49\x06" -#define TEST10_512 \ - "\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a\x50\x2d\x65\x82\x4e\x31" \ - "\xa2\x30\x54\x32\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d\xe1\xde" \ - "\x69\x74\xbf\x49\x54\x69\xfc\x7f\x33\x8f\x80\x54\xd5\x8c\x26\xc4" \ - "\x93\x60\xc3\xe8\x7a\xf5\x65\x23\xac\xf6\xd8\x9d\x03\xe5\x6f\xf2" \ - "\xf8\x68\x00\x2b\xc3\xe4\x31\xed\xc4\x4d\xf2\xf0\x22\x3d\x4b\xb3" \ - "\xb2\x43\x58\x6e\x1a\x7d\x92\x49\x36\x69\x4f\xcb\xba\xf8\x8d\x95" \ - "\x19\xe4\xeb\x50\xa6\x44\xf8\xe4\xf9\x5e\xb0\xea\x95\xbc\x44\x65" \ - "\xc8\x82\x1a\xac\xd2\xfe\x15\xab\x49\x81\x16\x4b\xbb\x6d\xc3\x2f" \ - "\x96\x90\x87\xa1\x45\xb0\xd9\xcc\x9c\x67\xc2\x2b\x76\x32\x99\x41" \ - "\x9c\xc4\x12\x8b\xe9\xa0\x77\xb3\xac\xe6\x34\x06\x4e\x6d\x99\x28" \ - "\x35\x13\xdc\x06\xe7\x51\x5d\x0d\x73\x13\x2e\x9a\x0d\xc6\xd3\xb1" \ - "\xf8\xb2\x46\xf1\xa9\x8a\x3f\xc7\x29\x41\xb1\xe3\xbb\x20\x98\xe8" \ - "\xbf\x16\xf2\x68\xd6\x4f\x0b\x0f\x47\x07\xfe\x1e\xa1\xa1\x79\x1b" \ - "\xa2\xf3\xc0\xc7\x58\xe5\xf5\x51\x86\x3a\x96\xc9\x49\xad\x47\xd7" \ - "\xfb\x40\xd2" -#define SHA1_SEED "\xd0\x56\x9c\xb3\x66\x5a\x8a\x43\xeb\x6e\xa2\x3d" \ - "\x75\xa3\xc4\xd2\x05\x4a\x0d\x7d" -#define SHA224_SEED "\xd0\x56\x9c\xb3\x66\x5a\x8a\x43\xeb\x6e\xa2" \ - "\x3d\x75\xa3\xc4\xd2\x05\x4a\x0d\x7d\x66\xa9\xca\x99\xc9\xce\xb0" \ - "\x27" -#define SHA256_SEED "\xf4\x1e\xce\x26\x13\xe4\x57\x39\x15\x69\x6b" \ - "\x5a\xdc\xd5\x1c\xa3\x28\xbe\x3b\xf5\x66\xa9\xca\x99\xc9\xce\xb0" \ - "\x27\x9c\x1c\xb0\xa7" -#define SHA384_SEED "\x82\x40\xbc\x51\xe4\xec\x7e\xf7\x6d\x18\xe3" \ - "\x52\x04\xa1\x9f\x51\xa5\x21\x3a\x73\xa8\x1d\x6f\x94\x46\x80\xd3" \ - "\x07\x59\x48\xb7\xe4\x63\x80\x4e\xa3\xd2\x6e\x13\xea\x82\x0d\x65" \ - "\xa4\x84\xbe\x74\x53" -#define SHA512_SEED "\x47\x3f\xf1\xb9\xb3\xff\xdf\xa1\x26\x69\x9a" \ - "\xc7\xef\x9e\x8e\x78\x77\x73\x09\x58\x24\xc6\x42\x55\x7c\x13\x99" \ - "\xd9\x8e\x42\x20\x44\x8d\xc3\x5b\x99\xbf\xdd\x44\x77\x95\x43\x92" \ - "\x4c\x1c\xe9\x3b\xc5\x94\x15\x38\x89\x5d\xb9\x88\x26\x1b\x00\x77" \ - "\x4b\x12\x27\x20\x39" - -#define TESTCOUNT 10 -#define HASHCOUNT 5 -#define RANDOMCOUNT 4 -#define HMACTESTCOUNT 7 -#define HKDFTESTCOUNT 7 - -#define PRINTNONE 0 -#define PRINTTEXT 1 -#define PRINTRAW 2 -#define PRINTHEX 3 -#define PRINTBASE64 4 - -#define PRINTPASSFAIL 1 -#define PRINTFAIL 2 - -#define length(x) (sizeof(x)-1) - -/* Test arrays for hashes. */ -struct hash { - const char *name; - SHAversion whichSha; - int hashsize; - struct { - const char *testarray; - int length; - long repeatcount; - int extrabits; - int numberExtrabits; - const char *resultarray; - } tests[TESTCOUNT]; - const char *randomtest; - const char *randomresults[RANDOMCOUNT]; -} hashes[HASHCOUNT] = { - { "SHA1", SHA1, SHA1HashSize, - { - /* 1 */ { TEST1, length(TEST1), 1, 0, 0, - "A9993E364706816ABA3E25717850C26C9CD0D89D" }, - /* 2 */ { TEST2_1, length(TEST2_1), 1, 0, 0, - "84983E441C3BD26EBAAE4AA1F95129E5E54670F1" }, - /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, - "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F" }, - /* 4 */ { TEST4, length(TEST4), 10, 0, 0, - "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452" }, - /* 5 */ { "", 0, 0, 0x98, 5, - "29826B003B906E660EFF4027CE98AF3531AC75BA" }, - /* 6 */ { "\x5e", 1, 1, 0, 0, - "5E6F80A34A9798CAFC6A5DB96CC57BA4C4DB59C2" }, - /* 7 */ { TEST7_1, length(TEST7_1), 1, 0x80, 3, - "6239781E03729919C01955B3FFA8ACB60B988340" }, - /* 8 */ { TEST8_1, length(TEST8_1), 1, 0, 0, - "82ABFF6605DBE1C17DEF12A394FA22A82B544A35" }, - /* 9 */ { TEST9_1, length(TEST9_1), 1, 0xE0, 3, - "8C5B2A5DDAE5A97FC7F9D85661C672ADBF7933D4" }, - /* 10 */ { TEST10_1, length(TEST10_1), 1, 0, 0, - "CB0082C8F197D260991BA6A460E76E202BAD27B3" } - }, SHA1_SEED, { "E216836819477C7F78E0D843FE4FF1B6D6C14CD4", - "A2DBC7A5B1C6C0A8BCB7AAA41252A6A7D0690DBC", - "DB1F9050BB863DFEF4CE37186044E2EEB17EE013", - "127FDEDF43D372A51D5747C48FBFFE38EF6CDF7B" - } }, - { "SHA224", SHA224, SHA224HashSize, - { - /* 1 */ { TEST1, length(TEST1), 1, 0, 0, - "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7" }, - /* 2 */ { TEST2_1, length(TEST2_1), 1, 0, 0, - "75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B1952522525" }, - /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, - "20794655980C91D8BBB4C1EA97618A4BF03F42581948B2EE4EE7AD67" }, - /* 4 */ { TEST4, length(TEST4), 10, 0, 0, - "567F69F168CD7844E65259CE658FE7AADFA25216E68ECA0EB7AB8262" }, - /* 5 */ { "", 0, 0, 0x68, 5, - "E3B048552C3C387BCAB37F6EB06BB79B96A4AEE5FF27F51531A9551C" }, - /* 6 */ { "\x07", 1, 1, 0, 0, - "00ECD5F138422B8AD74C9799FD826C531BAD2FCABC7450BEE2AA8C2A" }, - /* 7 */ { TEST7_224, length(TEST7_224), 1, 0xA0, 3, - "1B01DB6CB4A9E43DED1516BEB3DB0B87B6D1EA43187462C608137150" }, - /* 8 */ { TEST8_224, length(TEST8_224), 1, 0, 0, - "DF90D78AA78821C99B40BA4C966921ACCD8FFB1E98AC388E56191DB1" }, - /* 9 */ { TEST9_224, length(TEST9_224), 1, 0xE0, 3, - "54BEA6EAB8195A2EB0A7906A4B4A876666300EEFBD1F3B8474F9CD57" }, - /* 10 */ { TEST10_224, length(TEST10_224), 1, 0, 0, - "0B31894EC8937AD9B91BDFBCBA294D9ADEFAA18E09305E9F20D5C3A4" } - }, SHA224_SEED, { "100966A5B4FDE0B42E2A6C5953D4D7F41BA7CF79FD" - "2DF431416734BE", "1DCA396B0C417715DEFAAE9641E10A2E99D55A" - "BCB8A00061EB3BE8BD", "1864E627BDB2319973CD5ED7D68DA71D8B" - "F0F983D8D9AB32C34ADB34", "A2406481FC1BCAF24DD08E6752E844" - "709563FB916227FED598EB621F" - } }, - { "SHA256", SHA256, SHA256HashSize, - { - /* 1 */ { TEST1, length(TEST1), 1, 0, 0, "BA7816BF8F01CFEA4141" - "40DE5DAE2223B00361A396177A9CB410FF61F20015AD" }, - /* 2 */ { TEST2_1, length(TEST2_1), 1, 0, 0, "248D6A61D20638B8" - "E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1" }, - /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, "CDC76E5C9914FB92" - "81A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0" }, - /* 4 */ { TEST4, length(TEST4), 10, 0, 0, "594847328451BDFA" - "85056225462CC1D867D877FB388DF0CE35F25AB5562BFBB5" }, - /* 5 */ { "", 0, 0, 0x68, 5, "D6D3E02A31A84A8CAA9718ED6C2057BE" - "09DB45E7823EB5079CE7A573A3760F95" }, - /* 6 */ { "\x19", 1, 1, 0, 0, "68AA2E2EE5DFF96E3355E6C7EE373E3D" - "6A4E17F75F9518D843709C0C9BC3E3D4" }, - /* 7 */ { TEST7_256, length(TEST7_256), 1, 0x60, 3, "77EC1DC8" - "9C821FF2A1279089FA091B35B8CD960BCAF7DE01C6A7680756BEB972" }, - /* 8 */ { TEST8_256, length(TEST8_256), 1, 0, 0, "175EE69B02BA" - "9B58E2B0A5FD13819CEA573F3940A94F825128CF4209BEABB4E8" }, - /* 9 */ { TEST9_256, length(TEST9_256), 1, 0xA0, 3, "3E9AD646" - "8BBBAD2AC3C2CDC292E018BA5FD70B960CF1679777FCE708FDB066E9" }, - /* 10 */ { TEST10_256, length(TEST10_256), 1, 0, 0, "97DBCA7D" - "F46D62C8A422C941DD7E835B8AD3361763F7E9B2D95F4F0DA6E1CCBC" }, - }, SHA256_SEED, { "83D28614D49C3ADC1D6FC05DB5F48037C056F8D2A4CE44" - "EC6457DEA5DD797CD1", "99DBE3127EF2E93DD9322D6A07909EB33B6399" - "5E529B3F954B8581621BB74D39", "8D4BE295BB64661CA3C7EFD129A2F7" - "25B33072DBDDE32385B9A87B9AF88EA76F", "40AF5D3F9716B040DF9408" - "E31536B70FF906EC51B00447CA97D7DD97C12411F4" - } }, - { "SHA384", SHA384, SHA384HashSize, - { - /* 1 */ { TEST1, length(TEST1), 1, 0, 0, - "CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED163" - "1A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7" }, - /* 2 */ { TEST2_2, length(TEST2_2), 1, 0, 0, - "09330C33F71147E83D192FC782CD1B4753111B173B3B05D2" - "2FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039" }, - /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, - "9D0E1809716474CB086E834E310A4A1CED149E9C00F24852" - "7972CEC5704C2A5B07B8B3DC38ECC4EBAE97DDD87F3D8985" }, - /* 4 */ { TEST4, length(TEST4), 10, 0, 0, - "2FC64A4F500DDB6828F6A3430B8DD72A368EB7F3A8322A70" - "BC84275B9C0B3AB00D27A5CC3C2D224AA6B61A0D79FB4596" }, - /* 5 */ { "", 0, 0, 0x10, 5, - "8D17BE79E32B6718E07D8A603EB84BA0478F7FCFD1BB9399" - "5F7D1149E09143AC1FFCFC56820E469F3878D957A15A3FE4" }, - /* 6 */ { "\xb9", 1, 1, 0, 0, - "BC8089A19007C0B14195F4ECC74094FEC64F01F90929282C" - "2FB392881578208AD466828B1C6C283D2722CF0AD1AB6938" }, - /* 7 */ { TEST7_384, length(TEST7_384), 1, 0xA0, 3, - "D8C43B38E12E7C42A7C9B810299FD6A770BEF30920F17532" - "A898DE62C7A07E4293449C0B5FA70109F0783211CFC4BCE3" }, - /* 8 */ { TEST8_384, length(TEST8_384), 1, 0, 0, - "C9A68443A005812256B8EC76B00516F0DBB74FAB26D66591" - "3F194B6FFB0E91EA9967566B58109CBC675CC208E4C823F7" }, - /* 9 */ { TEST9_384, length(TEST9_384), 1, 0xE0, 3, - "5860E8DE91C21578BB4174D227898A98E0B45C4C760F0095" - "49495614DAEDC0775D92D11D9F8CE9B064EEAC8DAFC3A297" }, - /* 10 */ { TEST10_384, length(TEST10_384), 1, 0, 0, - "4F440DB1E6EDD2899FA335F09515AA025EE177A79F4B4AAF" - "38E42B5C4DE660F5DE8FB2A5B2FBD2A3CBFFD20CFF1288C0" } - }, SHA384_SEED, { "CE44D7D63AE0C91482998CF662A51EC80BF6FC68661A3C" - "57F87566112BD635A743EA904DEB7D7A42AC808CABE697F38F", "F9C6D2" - "61881FEE41ACD39E67AA8D0BAD507C7363EB67E2B81F45759F9C0FD7B503" - "DF1A0B9E80BDE7BC333D75B804197D", "D96512D8C9F4A7A4967A366C01" - "C6FD97384225B58343A88264847C18E4EF8AB7AEE4765FFBC3E30BD485D3" - "638A01418F", "0CA76BD0813AF1509E170907A96005938BC985628290B2" - "5FEF73CF6FAD68DDBA0AC8920C94E0541607B0915A7B4457F7" - } }, - { "SHA512", SHA512, SHA512HashSize, - { - /* 1 */ { TEST1, length(TEST1), 1, 0, 0, - "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2" - "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD" - "454D4423643CE80E2A9AC94FA54CA49F" }, - /* 2 */ { TEST2_2, length(TEST2_2), 1, 0, 0, - "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1" - "7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A" - "C7D329EEB6DD26545E96E55B874BE909" }, - /* 3 */ { TEST3, length(TEST3), 1000000, 0, 0, - "E718483D0CE769644E2E42C7BC15B4638E1F98B13B204428" - "5632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31B" - "EB009C5C2C49AA2E4EADB217AD8CC09B" }, - /* 4 */ { TEST4, length(TEST4), 10, 0, 0, - "89D05BA632C699C31231DED4FFC127D5A894DAD412C0E024" - "DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF33C765CB51" - "0813A39CD5A84C4ACAA64D3F3FB7BAE9" }, - /* 5 */ { "", 0, 0, 0xB0, 5, - "D4EE29A9E90985446B913CF1D1376C836F4BE2C1CF3CADA0" - "720A6BF4857D886A7ECB3C4E4C0FA8C7F95214E41DC1B0D2" - "1B22A84CC03BF8CE4845F34DD5BDBAD4" }, - /* 6 */ { "\xD0", 1, 1, 0, 0, - "9992202938E882E73E20F6B69E68A0A7149090423D93C81B" - "AB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA8306826C4A" - "D6E74CECE9631BFA8A549B4AB3FBBA15" }, - /* 7 */ { TEST7_512, length(TEST7_512), 1, 0x80, 3, - "ED8DC78E8B01B69750053DBB7A0A9EDA0FB9E9D292B1ED71" - "5E80A7FE290A4E16664FD913E85854400C5AF05E6DAD316B" - "7359B43E64F8BEC3C1F237119986BBB6" }, - /* 8 */ { TEST8_512, length(TEST8_512), 1, 0, 0, - "CB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75ACBD" - "D1C153C9828924C3DDEDAAFE669C5FDD0BC66F630F677398" - "8213EB1B16F517AD0DE4B2F0C95C90F8" }, - /* 9 */ { TEST9_512, length(TEST9_512), 1, 0x80, 3, - "32BA76FC30EAA0208AEB50FFB5AF1864FDBF17902A4DC0A6" - "82C61FCEA6D92B783267B21080301837F59DE79C6B337DB2" - "526F8A0A510E5E53CAFED4355FE7C2F1" }, - /* 10 */ { TEST10_512, length(TEST10_512), 1, 0, 0, - "C665BEFB36DA189D78822D10528CBF3B12B3EEF726039909" - "C1A16A270D48719377966B957A878E720584779A62825C18" - "DA26415E49A7176A894E7510FD1451F5" } - }, SHA512_SEED, { "2FBB1E7E00F746BA514FBC8C421F36792EC0E11FF5EFC3" - "78E1AB0C079AA5F0F66A1E3EDBAEB4F9984BE14437123038A452004A5576" - "8C1FD8EED49E4A21BEDCD0", "25CBE5A4F2C7B1D7EF07011705D50C62C5" - "000594243EAFD1241FC9F3D22B58184AE2FEE38E171CF8129E29459C9BC2" - "EF461AF5708887315F15419D8D17FE7949", "5B8B1F2687555CE2D7182B" - "92E5C3F6C36547DA1C13DBB9EA4F73EA4CBBAF89411527906D35B1B06C1B" - "6A8007D05EC66DF0A406066829EAB618BDE3976515AAFC", "46E36B007D" - "19876CDB0B29AD074FE3C08CDD174D42169D6ABE5A1414B6E79707DF5877" - "6A98091CF431854147BB6D3C66D43BFBC108FD715BDE6AA127C2B0E79F" - } - } -}; - -/* Test arrays for HMAC. */ -struct hmachash { - const char *keyarray[5]; - int keylength[5]; - const char *dataarray[5]; - int datalength[5]; - const char *resultarray[5]; - int resultlength[5]; -} hmachashes[HMACTESTCOUNT] = { - { /* 1 */ { - "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" - "\x0b\x0b\x0b\x0b\x0b" - }, { 20 }, { - "\x48\x69\x20\x54\x68\x65\x72\x65" /* "Hi There" */ - }, { 8 }, { - /* HMAC-SHA-1 */ - "B617318655057264E28BC0B6FB378C8EF146BE00", - /* HMAC-SHA-224 */ - "896FB1128ABBDF196832107CD49DF33F47B4B1169912BA4F53684B22", - /* HMAC-SHA-256 */ - "B0344C61D8DB38535CA8AFCEAF0BF12B881DC200C9833DA726E9376C2E32" - "CFF7", - /* HMAC-SHA-384 */ - "AFD03944D84895626B0825F4AB46907F15F9DADBE4101EC682AA034C7CEB" - "C59CFAEA9EA9076EDE7F4AF152E8B2FA9CB6", - /* HMAC-SHA-512 */ - "87AA7CDEA5EF619D4FF0B4241A1D6CB02379F4E2CE4EC2787AD0B30545E1" - "7CDEDAA833B7D6B8A702038B274EAEA3F4E4BE9D914EEB61F1702E696C20" - "3A126854" - }, { SHA1HashSize, SHA224HashSize, SHA256HashSize, - SHA384HashSize, SHA512HashSize } - }, - { /* 2 */ { - "\x4a\x65\x66\x65" /* "Jefe" */ - }, { 4 }, { - "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74" - "\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f" - /* "what do ya want for nothing?" */ - }, { 28 }, { - /* HMAC-SHA-1 */ - "EFFCDF6AE5EB2FA2D27416D5F184DF9C259A7C79", - /* HMAC-SHA-224 */ - "A30E01098BC6DBBF45690F3A7E9E6D0F8BBEA2A39E6148008FD05E44", - /* HMAC-SHA-256 */ - "5BDCC146BF60754E6A042426089575C75A003F089D2739839DEC58B964EC" - "3843", - /* HMAC-SHA-384 */ - "AF45D2E376484031617F78D2B58A6B1B9C7EF464F5A01B47E42EC3736322" - "445E8E2240CA5E69E2C78B3239ECFAB21649", - /* HMAC-SHA-512 */ - "164B7A7BFCF819E2E395FBE73B56E0A387BD64222E831FD610270CD7EA25" - "05549758BF75C05A994A6D034F65F8F0E6FDCAEAB1A34D4A6B4B636E070A" - "38BCE737" - }, { SHA1HashSize, SHA224HashSize, SHA256HashSize, - SHA384HashSize, SHA512HashSize } - }, - { /* 3 */ - { - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa" - }, { 20 }, { - "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" - "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" - "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd" - "\xdd\xdd\xdd\xdd\xdd" - }, { 50 }, { - /* HMAC-SHA-1 */ - "125D7342B9AC11CD91A39AF48AA17B4F63F175D3", - /* HMAC-SHA-224 */ - "7FB3CB3588C6C1F6FFA9694D7D6AD2649365B0C1F65D69D1EC8333EA", - /* HMAC-SHA-256 */ - "773EA91E36800E46854DB8EBD09181A72959098B3EF8C122D9635514CED5" - "65FE", - /* HMAC-SHA-384 */ - "88062608D3E6AD8A0AA2ACE014C8A86F0AA635D947AC9FEBE83EF4E55966" - "144B2A5AB39DC13814B94E3AB6E101A34F27", - /* HMAC-SHA-512 */ - "FA73B0089D56A284EFB0F0756C890BE9B1B5DBDD8EE81A3655F83E33B227" - "9D39BF3E848279A722C806B485A47E67C807B946A337BEE8942674278859" - "E13292FB" - }, { SHA1HashSize, SHA224HashSize, SHA256HashSize, - SHA384HashSize, SHA512HashSize } - }, - { /* 4 */ { - "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19" - }, { 25 }, { - "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" - "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" - "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd" - "\xcd\xcd\xcd\xcd\xcd" - }, { 50 }, { - /* HMAC-SHA-1 */ - "4C9007F4026250C6BC8414F9BF50C86C2D7235DA", - /* HMAC-SHA-224 */ - "6C11506874013CAC6A2ABC1BB382627CEC6A90D86EFC012DE7AFEC5A", - /* HMAC-SHA-256 */ - "82558A389A443C0EA4CC819899F2083A85F0FAA3E578F8077A2E3FF46729" - "665B", - /* HMAC-SHA-384 */ - "3E8A69B7783C25851933AB6290AF6CA77A9981480850009CC5577C6E1F57" - "3B4E6801DD23C4A7D679CCF8A386C674CFFB", - /* HMAC-SHA-512 */ - "B0BA465637458C6990E5A8C5F61D4AF7E576D97FF94B872DE76F8050361E" - "E3DBA91CA5C11AA25EB4D679275CC5788063A5F19741120C4F2DE2ADEBEB" - "10A298DD" - }, { SHA1HashSize, SHA224HashSize, SHA256HashSize, - SHA384HashSize, SHA512HashSize } - }, - { /* 5 */ { - "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" - "\x0c\x0c\x0c\x0c\x0c" - }, { 20 }, { - "Test With Truncation" - }, { 20 }, { - /* HMAC-SHA-1 */ - "4C1A03424B55E07FE7F27BE1", - /* HMAC-SHA-224 */ - "0E2AEA68A90C8D37C988BCDB9FCA6FA8", - /* HMAC-SHA-256 */ - "A3B6167473100EE06E0C796C2955552B", - /* HMAC-SHA-384 */ - "3ABF34C3503B2A23A46EFC619BAEF897", - /* HMAC-SHA-512 */ - "415FAD6271580A531D4179BC891D87A6" - }, { 12, 16, 16, 16, 16 } - }, - { /* 6 */ { - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - }, { 80, 131 }, { - "Test Using Larger Than Block-Size Key - Hash Key First" - }, { 54 }, { - /* HMAC-SHA-1 */ - "AA4AE5E15272D00E95705637CE8A3B55ED402112", - /* HMAC-SHA-224 */ - "95E9A0DB962095ADAEBE9B2D6F0DBCE2D499F112F2D2B7273FA6870E", - /* HMAC-SHA-256 */ - "60E431591EE0B67F0D8A26AACBF5B77F8E0BC6213728C5140546040F0EE3" - "7F54", - /* HMAC-SHA-384 */ - "4ECE084485813E9088D2C63A041BC5B44F9EF1012A2B588F3CD11F05033A" - "C4C60C2EF6AB4030FE8296248DF163F44952", - /* HMAC-SHA-512 */ - "80B24263C7C1A3EBB71493C1DD7BE8B49B46D1F41B4AEEC1121B013783F8" - "F3526B56D037E05F2598BD0FD2215D6A1E5295E64F73F63F0AEC8B915A98" - "5D786598" - }, { SHA1HashSize, SHA224HashSize, SHA256HashSize, - SHA384HashSize, SHA512HashSize } - }, - { /* 7 */ { - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" - }, { 80, 131 }, { - "Test Using Larger Than Block-Size Key and " - "Larger Than One Block-Size Data", - "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20" - "\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20" - "\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65" - "\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67" - "\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73" - "\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b" - "\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20" - "\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62" - "\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68" - "\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68" - "\x6d\x2e" - /* "This is a test using a larger than block-size key and a " - "larger than block-size data. The key needs to be hashed " - "before being used by the HMAC algorithm." */ - }, { 73, 152 }, { - /* HMAC-SHA-1 */ - "E8E99D0F45237D786D6BBAA7965C7808BBFF1A91", - /* HMAC-SHA-224 */ - "3A854166AC5D9F023F54D517D0B39DBD946770DB9C2B95C9F6F565D1", - /* HMAC-SHA-256 */ - "9B09FFA71B942FCB27635FBCD5B0E944BFDC63644F0713938A7F51535C3A" - "35E2", - /* HMAC-SHA-384 */ - "6617178E941F020D351E2F254E8FD32C602420FEB0B8FB9ADCCEBB82461E" - "99C5A678CC31E799176D3860E6110C46523E", - /* HMAC-SHA-512 */ - "E37B6A775DC87DBAA4DFA9F96E5E3FFDDEBD71F8867289865DF5A32D20CD" - "C944B6022CAC3C4982B10D5EEB55C3E4DE15134676FB6DE0446065C97440" - "FA8C6A58" - }, { SHA1HashSize, SHA224HashSize, SHA256HashSize, - SHA384HashSize, SHA512HashSize } - } -}; - -/* Test arrays for HKDF. */ -struct hkdfhash { - SHAversion whichSha; - int ikmlength; - const char *ikmarray; - int saltlength; - const char *saltarray; - int infolength; - const char *infoarray; - int prklength; - const char *prkarray; - int okmlength; - const char *okmarray; -} hkdfhashes[HKDFTESTCOUNT] = { - { /* RFC 5869 A.1. Test Case 1 */ - SHA256, - 22, "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" - "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", - 13, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c", - 10, "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", - 32, "077709362C2E32DF0DDC3F0DC47BBA6390B6C73BB50F9C3122EC844A" - "D7C2B3E5", - 42, "3CB25F25FAACD57A90434F64D0362F2A2D2D0A90CF1A5A4C5DB02D56" - "ECC4C5BF34007208D5B887185865" - }, - { /* RFC 5869 A.2. Test Case 2 */ - SHA256, - 80, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d" - "\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b" - "\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29" - "\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45" - "\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", - 80, "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d" - "\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b" - "\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89" - "\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5" - "\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf", - 80, "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd" - "\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb" - "\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9" - "\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5" - "\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - 32, "06A6B88C5853361A06104C9CEB35B45C" - "EF760014904671014A193F40C15FC244", - 82, "B11E398DC80327A1C8E7F78C596A4934" - "4F012EDA2D4EFAD8A050CC4C19AFA97C" - "59045A99CAC7827271CB41C65E590E09" - "DA3275600C2F09B8367793A9ACA3DB71" - "CC30C58179EC3E87C14C01D5C1F3434F" - "1D87" - }, - { /* RFC 5869 A.3. Test Case 3 */ - SHA256, - 22, "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" - "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", - 0, "", - 0, "", - 32, "19EF24A32C717B167F33A91D6F648BDF" - "96596776AFDB6377AC434C1C293CCB04", - 42, "8DA4E775A563C18F715F802A063C5A31" - "B8A11F5C5EE1879EC3454E5F3C738D2D" - "9D201395FAA4B61A96C8" - }, - { /* RFC 5869 A.4. Test Case 4 */ - SHA1, - 11, "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", - 13, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c", - 10, "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9", - 20, "9B6C18C432A7BF8F0E71C8EB88F4B30BAA2BA243", - 42, "085A01EA1B10F36933068B56EFA5AD81" - "A4F14B822F5B091568A9CDD4F155FDA2" - "C22E422478D305F3F896" - }, - { /* RFC 5869 A.5. Test Case 5 */ - SHA1, - 80, "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d" - "\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b" - "\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29" - "\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45" - "\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f", - 80, "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D" - "\x6E\x6F\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7A\x7B" - "\x7C\x7D\x7E\x7F\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89" - "\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5" - "\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF", - 80, "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD" - "\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB" - "\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9" - "\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7" - "\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5" - "\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF", - 20, "8ADAE09A2A307059478D309B26C4115A224CFAF6", - 82, "0BD770A74D1160F7C9F12CD5912A06EB" - "FF6ADCAE899D92191FE4305673BA2FFE" - "8FA3F1A4E5AD79F3F334B3B202B2173C" - "486EA37CE3D397ED034C7F9DFEB15C5E" - "927336D0441F4C4300E2CFF0D0900B52" - "D3B4" - }, - { /* RFC 5869 A.6. Test Case 6 */ - SHA1, - 22, "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" - "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", - 0, "", - 0, "", - 20, "DA8C8A73C7FA77288EC6F5E7C297786AA0D32D01", - 42, "0AC1AF7002B3D761D1E55298DA9D0506" - "B9AE52057220A306E07B6B87E8DF21D0" - "EA00033DE03984D34918" - }, - { /* RFC 5869 A.7. Test Case 7. */ - SHA1, - 22, "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c" - "\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c", - 0, 0, - 0, "", - 20, "2ADCCADA18779E7C2077AD2EB19D3F3E731385DD", - 42, "2C91117204D745F3500D636A62F64F0A" - "B3BAE548AA53D423B0D1F27EBBA6F5E5" - "673A081D70CCE7ACFC48" - } -}; - -/* - * Check the hash value against the expected string, expressed in hex - */ -static const char hexdigits[ ] = "0123456789ABCDEF"; -int checkmatch(const unsigned char *hashvalue, - const char *hexstr, int hashsize) -{ - int i; - for (i = 0; i < hashsize; ++i) { - if (*hexstr++ != hexdigits[(hashvalue[i] >> 4) & 0xF]) - return 0; - if (*hexstr++ != hexdigits[hashvalue[i] & 0xF]) return 0; - } - return 1; -} - -/* - * Print the string, converting non-printable characters to "." - */ -void printstr(const char *str, int len) -{ - for ( ; len-- > 0; str++) - putchar(isprint((unsigned char)*str) ? *str : '.'); -} - -/* - * Print the string, converting all characters to hex "## ". - */ -void printxstr(const char *str, int len) -{ - char sep[2] = {0}; - for ( ; len-- > 0; str++) { - printf("%s%c%c", sep, hexdigits[(*str >> 4) & 0xF], - hexdigits[*str & 0xF]); - sep[0] = ' '; - } -} - -/* - * Print a usage message. - */ -void usage(const char *argv0) -{ - fprintf(stderr, - "Usage:\n" - "Common options: [-h hash] [-w|-x|-6] [-H]\n" - "Hash a string:\n" - "\t%s [-S expectedresult] -s hashstr [-k key] " - "[-i info -L okm-len]\n" - "Hash a file:\n" - "\t%s [-S expectedresult] -f file [-k key] " - "[-i info -L okm-len]\n" - "Hash a file, ignoring whitespace:\n" - "\t%s [-S expectedresult] -F file [-k key] " - "[-i info -L okm-len]\n" - "Additional bits to add in: [-B bitcount -b bits]\n" - "(If -k,-i&-L are used, run HKDF-SHA###.\n" - " If -k is used, but not -i&-L, run HMAC-SHA###.\n" - " Otherwise, run SHA###.)\n" - "Standard tests:\n" - "\t%s [-m | -d] [-l loopcount] [-t test#] [-e]\n" - "\t\t[-r randomseed] [-R randomloop-count] " - "[-p] [-P|-X]\n" - "-h\thash to test: " - "0|SHA1, 1|SHA224, 2|SHA256, 3|SHA384, 4|SHA512\n" - "-m\tperform hmac standard tests\n" - "-k\tkey for hmac test\n" - "-d\tperform hkdf standard tests\n" - "-t\ttest case to run, 1-10\n" - "-l\thow many times to run the test\n" - "-e\ttest error returns\n" - "-p\tdo not print results\n" - "-P\tdo not print PASSED/FAILED\n" - "-X\tprint FAILED, but not PASSED\n" - "-r\tseed for random test\n" - "-R\thow many times to run random test\n" - "-s\tstring to hash\n" - "-S\texpected result of hashed string, in hex\n" - "-w\toutput hash in raw format\n" - "-x\toutput hash in hex format\n" - "-6\toutput hash in base64 format\n" - "-B\t# extra bits to add in after string or file input\n" - "-b\textra bits to add (high order bits of #, 0# or 0x#)\n" - "-H\tinput hashstr or randomseed is in hex\n" - , argv0, argv0, argv0, argv0); - exit(1); -} - -/* - * Print the results and PASS/FAIL. - */ -void printResult(uint8_t *Message_Digest, int hashsize, - const char *hashname, const char *testtype, const char *testname, - const char *resultarray, int printResults, int printPassFail) -{ - int i, k; - if (printResults == PRINTTEXT) { - printf("\nhashsize=%d\n", hashsize); - putchar('\t'); - for (i = 0; i < hashsize; ++i) { - putchar(hexdigits[(Message_Digest[i] >> 4) & 0xF]); - putchar(hexdigits[Message_Digest[i] & 0xF]); - putchar(' '); - } - putchar('\n'); - } else if (printResults == PRINTRAW) { - fwrite(Message_Digest, 1, hashsize, stdout); - } else if (printResults == PRINTHEX) { - for (i = 0; i < hashsize; ++i) { - putchar(hexdigits[(Message_Digest[i] >> 4) & 0xF]); - putchar(hexdigits[Message_Digest[i] & 0xF]); - } - putchar('\n'); - } else if (printResults == PRINTBASE64) { - unsigned char b; - const char *sm = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - for (i = 0; i < hashsize; i += 3) { - putchar(sm[Message_Digest[i] >> 2]); - b = (Message_Digest[i] & 0x03) << 4; - if (i+1 < hashsize) b |= Message_Digest[i+1] >> 4; - putchar(sm[b]); - if (i+1 < hashsize) { - b = (Message_Digest[i+1] & 0x0f) << 2; - if (i+2 < hashsize) b |= Message_Digest[i+2] >> 6; - putchar(sm[b]); - } else putchar('='); - if (i+2 < hashsize) putchar(sm[Message_Digest[i+2] & 0x3f]); - else putchar('='); - } - putchar('\n'); - } - - if (printResults && resultarray) { - printf(" Should match:\n\t"); - for (i = 0, k = 0; i < hashsize; i++, k += 2) { - putchar(resultarray[k]); - putchar(resultarray[k+1]); - putchar(' '); - } - putchar('\n'); - } - - if (printPassFail && resultarray) { - int ret = checkmatch(Message_Digest, resultarray, hashsize); - if ((printPassFail == PRINTPASSFAIL) || !ret) - printf("%s %s %s: %s\n", hashname, testtype, testname, - ret ? "PASSED" : "FAILED"); - } -} - -/* - * Exercise a hash series of functions. The input is the testarray, - * repeated repeatcount times, followed by the extrabits. If the - * result is known, it is in resultarray in uppercase hex. - */ -int hash(int testno, int loopno, int hashno, - const char *testarray, int length, long repeatcount, - int numberExtrabits, int extrabits, const unsigned char *keyarray, - int keylen, const unsigned char *info, int infolen, int okmlen, - const char *resultarray, int hashsize, int printResults, - int printPassFail) -{ - USHAContext sha; - HMACContext hmac; - HKDFContext hkdf; - int err, i; - uint8_t Message_Digest_Buf[USHAMaxHashSize]; - uint8_t *Message_Digest = Message_Digest_Buf; - char buf[20]; - - if (printResults == PRINTTEXT) { - printf("\nTest %d: Iteration %d, Repeat %ld\n\t'", testno+1, - loopno, repeatcount); - printstr(testarray, length); - printf("'\n\t'"); - printxstr(testarray, length); - printf("'\n"); - printf(" Length=%d bytes (%d bits), ", length, length * 8); - printf("ExtraBits %d: %2.2x\n", numberExtrabits, extrabits); - } - - if (info) Message_Digest = malloc(okmlen); - memset(&sha, '\343', sizeof(sha)); /* force bad data into struct */ - memset(&hmac, '\343', sizeof(hmac)); - memset(&hkdf, '\343', sizeof(hkdf)); - - err = info ? hkdfReset(&hkdf, hashes[hashno].whichSha, - keyarray, keylen) : - keyarray ? hmacReset(&hmac, hashes[hashno].whichSha, - keyarray, keylen) : - USHAReset(&sha, hashes[hashno].whichSha); - if (err != shaSuccess) { - fprintf(stderr, "hash(): %sReset Error %d.\n", - info ? "hkdf" : keyarray ? "hmac" : "sha", err); - return err; - } - - for (i = 0; i < repeatcount; ++i) { - err = info ? hkdfInput(&hkdf, (const uint8_t *)testarray, length) : - keyarray ? hmacInput(&hmac, (const uint8_t *) testarray, - length) : - USHAInput(&sha, (const uint8_t *) testarray, - length); - if (err != shaSuccess) { - fprintf(stderr, "hash(): %sInput Error %d.\n", - info ? "hkdf" : keyarray ? "hmac" : "sha", err); - return err; - } - } - - if (numberExtrabits > 0) { - err = info ? hkdfFinalBits(&hkdf, extrabits, numberExtrabits) : - keyarray ? hmacFinalBits(&hmac, (uint8_t) extrabits, - numberExtrabits) : - USHAFinalBits(&sha, (uint8_t) extrabits, - numberExtrabits); - if (err != shaSuccess) { - fprintf(stderr, "hash(): %sFinalBits Error %d.\n", - info ? "hkdf" : keyarray ? "hmac" : "sha", err); - return err; - } - } - - err = info ? hkdfResult(&hkdf, 0, info, infolen, - Message_Digest, okmlen) : - keyarray ? hmacResult(&hmac, Message_Digest) : - USHAResult(&sha, Message_Digest); - if (err != shaSuccess) { - fprintf(stderr, "hash(): %s Result Error %d, could not compute " - "message digest.\n", - info ? "hkdf" : keyarray ? "hmac" : "sha", err); - return err; - } - - sprintf(buf, "%d", testno+1); - printResult(Message_Digest, info ? okmlen : hashsize, - hashes[hashno].name, info ? "hkdf standard test" : - keyarray ? "hmac standard test" : "sha standard test", buf, - resultarray, printResults, printPassFail); - - return err; -} - -/* - * Exercise an HKDF series. The input is the testarray, - * repeated repeatcount times, followed by the extrabits. If the - * result is known, it is in resultarray in uppercase hex. - */ -int hashHkdf(int testno, int loopno, int hashno, - int printResults, int printPassFail) -{ - int err; - unsigned char prk[USHAMaxHashSize+1]; - uint8_t okm[255 * USHAMaxHashSize+1]; - char buf[24]; - - if (printResults == PRINTTEXT) { - printf("\nTest %d: Iteration %d\n\tSALT\t'", testno+1, loopno); - printxstr(hkdfhashes[testno].saltarray, - hkdfhashes[testno].saltlength); - printf("'\n\tIKM\t'"); - printxstr(hkdfhashes[testno].ikmarray, - hkdfhashes[testno].ikmlength); - printf("'\n\tINFO\t'"); - printxstr(hkdfhashes[testno].infoarray, - hkdfhashes[testno].infolength); - printf("'\n"); - printf(" L=%d bytes\n", hkdfhashes[testno].okmlength); - } - - /* Run hkdf() against the test vectors */ - err = hkdf(hkdfhashes[testno].whichSha, - (const uint8_t *) hkdfhashes[testno].saltarray, - hkdfhashes[testno].saltlength, - (const uint8_t *) hkdfhashes[testno].ikmarray, - hkdfhashes[testno].ikmlength, - (const uint8_t *) hkdfhashes[testno].infoarray, - hkdfhashes[testno].infolength, okm, - hkdfhashes[testno].okmlength); - if (err != shaSuccess) { - fprintf(stderr, "hashHkdf(): hkdf Error %d.\n", err); - return err; - } - sprintf(buf, "hkdf %d", testno+1); - printResult(okm, hkdfhashes[testno].okmlength, - USHAHashName(hkdfhashes[testno].whichSha), "hkdf standard test", - buf, hkdfhashes[testno].okmarray, printResults, printPassFail); - - /* Now run hkdfExtract() by itself against the test vectors */ - /* to verify the intermediate results. */ - err = hkdfExtract(hkdfhashes[testno].whichSha, - (const uint8_t *) hkdfhashes[testno].saltarray, - hkdfhashes[testno].saltlength, - (const uint8_t *) hkdfhashes[testno].ikmarray, - hkdfhashes[testno].ikmlength, prk); - if (err != shaSuccess) { - fprintf(stderr, "hashHkdf(): hkdfExtract Error %d.\n", err); - return err; - } - sprintf(buf, "hkdfExtract %d", testno+1); - printResult(prk, USHAHashSize(hkdfhashes[testno].whichSha), - USHAHashName(hkdfhashes[testno].whichSha), "hkdf standard test", - buf, hkdfhashes[testno].prkarray, printResults, printPassFail); - - /* Now run hkdfExpand() by itself against the test vectors */ - /* using the intermediate results from hkdfExtract. */ - err = hkdfExpand(hkdfhashes[testno].whichSha, prk, - USHAHashSize(hkdfhashes[testno].whichSha), - (const uint8_t *)hkdfhashes[testno].infoarray, - hkdfhashes[testno].infolength, okm, hkdfhashes[testno].okmlength); - if (err != shaSuccess) { - fprintf(stderr, "hashHkdf(): hkdfExpand Error %d.\n", err); - return err; - } - sprintf(buf, "hkdfExpand %d", testno+1); - printResult(okm, hkdfhashes[testno].okmlength, - USHAHashName(hkdfhashes[testno].whichSha), "hkdf standard test", - buf, hkdfhashes[testno].okmarray, printResults, printPassFail); - - return err; -} - -/* - * Exercise a hash series of functions. The input is a filename. - * If the result is known, it is in resultarray in uppercase hex. - */ -int hashfile(int hashno, const char *hashfilename, int bits, - int bitcount, int skipSpaces, const unsigned char *keyarray, - int keylen, const unsigned char *info, int infolen, int okmlen, - const char *resultarray, int hashsize, - int printResults, int printPassFail) -{ - USHAContext sha; - HMACContext hmac; - HKDFContext hkdf; - int err, nread, c; - unsigned char buf[4096]; - uint8_t Message_Digest_Buf[USHAMaxHashSize]; - uint8_t *Message_Digest = Message_Digest_Buf; - unsigned char cc; - FILE *hashfp = (strcmp(hashfilename, "-") == 0) ? stdin : - fopen(hashfilename, "r"); - - if (!hashfp) { - fprintf(stderr, "cannot open file '%s'\n", hashfilename); - return shaStateError; - } - - if (info) Message_Digest = malloc(okmlen); - memset(&sha, '\343', sizeof(sha)); /* force bad data into struct */ - memset(&hmac, '\343', sizeof(hmac)); - memset(&hkdf, '\343', sizeof(hkdf)); - err = info ? hkdfReset(&hkdf, hashes[hashno].whichSha, - keyarray, keylen) : - keyarray ? hmacReset(&hmac, hashes[hashno].whichSha, - keyarray, keylen) : - USHAReset(&sha, hashes[hashno].whichSha); - if (err != shaSuccess) { - fprintf(stderr, "hashfile(): %sReset Error %d.\n", - info ? "hkdf" : keyarray ? "hmac" : "sha", err); - return err; - } - - if (skipSpaces) - while ((c = getc(hashfp)) != EOF) { - if (!isspace(c)) { - cc = (unsigned char)c; - err = info ? hkdfInput(&hkdf, &cc, 1) : - keyarray ? hmacInput(&hmac, &cc, 1) : - USHAInput(&sha, &cc, 1); - if (err != shaSuccess) { - fprintf(stderr, "hashfile(): %sInput Error %d.\n", - info ? "hkdf" : keyarray ? "hmac" : "sha", err); - if (hashfp != stdin) fclose(hashfp); - return err; - } - } - } - else - while ((nread = fread(buf, 1, sizeof(buf), hashfp)) > 0) { - err = info ? hkdfInput(&hkdf, buf, nread) : - keyarray ? hmacInput(&hmac, buf, nread) : - USHAInput(&sha, buf, nread); - if (err != shaSuccess) { - fprintf(stderr, "hashfile(): %s Error %d.\n", - info ? "hkdf" : keyarray ? "hmacInput" : - "shaInput", err); - if (hashfp != stdin) fclose(hashfp); - return err; - } - } - - if (bitcount > 0) - err = info ? hkdfFinalBits(&hkdf, bits, bitcount) : - keyarray ? hmacFinalBits(&hmac, bits, bitcount) : - USHAFinalBits(&sha, bits, bitcount); - if (err != shaSuccess) { - fprintf(stderr, "hashfile(): %s Error %d.\n", - info ? "hkdf" : keyarray ? "hmacFinalBits" : - "shaFinalBits", err); - if (hashfp != stdin) fclose(hashfp); - return err; - } - - err = info ? hkdfResult(&hkdf, 0, info, infolen, - Message_Digest, okmlen) : - keyarray ? hmacResult(&hmac, Message_Digest) : - USHAResult(&sha, Message_Digest); - if (err != shaSuccess) { - fprintf(stderr, "hashfile(): %s Error %d.\n", - info ? "hkdf" : keyarray ? "hmacResult" : - "shaResult", err); - if (hashfp != stdin) fclose(hashfp); - return err; - } - - printResult(Message_Digest, info ? okmlen : hashsize, - hashes[hashno].name, "file", hashfilename, resultarray, - printResults, printPassFail); - - if (hashfp != stdin) fclose(hashfp); - if (info) free(Message_Digest); - return err; -} - -/* - * Exercise a hash series of functions through multiple permutations. - * The input is an initial seed. That seed is replicated 3 times. - * For 1000 rounds, the previous three results are used as the input. - * This result is then checked, and used to seed the next cycle. - * If the result is known, it is in resultarrays in uppercase hex. - */ -void randomtest(int hashno, const char *seed, int hashsize, - const char **resultarrays, int randomcount, - int printResults, int printPassFail) -{ - int i, j; char buf[20]; - unsigned char SEED[USHAMaxHashSize], MD[1003][USHAMaxHashSize]; - - /* INPUT: Seed - A random seed n bits long */ - memcpy(SEED, seed, hashsize); - if (printResults == PRINTTEXT) { - printf("%s random test seed= '", hashes[hashno].name); - printxstr(seed, hashsize); - printf("'\n"); - } - - for (j = 0; j < randomcount; j++) { - /* MD0 = MD1 = MD2 = Seed; */ - memcpy(MD[0], SEED, hashsize); - memcpy(MD[1], SEED, hashsize); - memcpy(MD[2], SEED, hashsize); - for (i=3; i<1003; i++) { - /* Mi = MDi-3 || MDi-2 || MDi-1; */ - USHAContext Mi; - memset(&Mi, '\343', sizeof(Mi)); /* force bad data into struct */ - USHAReset(&Mi, hashes[hashno].whichSha); - USHAInput(&Mi, MD[i-3], hashsize); - USHAInput(&Mi, MD[i-2], hashsize); - USHAInput(&Mi, MD[i-1], hashsize); - /* MDi = SHA(Mi); */ - USHAResult(&Mi, MD[i]); - } - - /* MDj = Seed = MDi; */ - memcpy(SEED, MD[i-1], hashsize); - - /* OUTPUT: MDj */ - sprintf(buf, "%d", j); - printResult(SEED, hashsize, hashes[hashno].name, "random test", - buf, resultarrays ? resultarrays[j] : 0, printResults, - (j < RANDOMCOUNT) ? printPassFail : 0); - } -} - -/* - * Look up a hash name. - */ -int findhash(const char *argv0, const char *opt) -{ - int i; - const char *names[HASHCOUNT][2] = { - { "0", "sha1" }, { "1", "sha224" }, { "2", "sha256" }, - { "3", "sha384" }, { "4", "sha512" } - }; - for (i = 0; i < HASHCOUNT; i++) - if ((strcmp(opt, names[i][0]) == 0) || - (scasecmp(opt, names[i][1]) == 0)) - return i; - - fprintf(stderr, "%s: Unknown hash name: '%s'\n", argv0, opt); - usage(argv0); - return 0; -} - -/* - * Run some tests that should invoke errors. - */ -void testErrors(int hashnolow, int hashnohigh, int printResults, - int printPassFail) -{ - USHAContext usha; - uint8_t Message_Digest[USHAMaxHashSize]; - int hashno, err; - - for (hashno = hashnolow; hashno <= hashnohigh; hashno++) { - memset(&usha, '\343', sizeof(usha)); /* force bad data */ - USHAReset(&usha, hashno); - USHAResult(&usha, Message_Digest); - err = USHAInput(&usha, (const unsigned char *)"foo", 3); - if (printResults == PRINTTEXT) - printf ("\nError %d. Should be %d.\n", err, shaStateError); - if ((printPassFail == PRINTPASSFAIL) || - ((printPassFail == PRINTFAIL) && (err != shaStateError))) - printf("%s se: %s\n", hashes[hashno].name, - (err == shaStateError) ? "PASSED" : "FAILED"); - - err = USHAFinalBits(&usha, 0x80, 3); - if (printResults == PRINTTEXT) - printf ("\nError %d. Should be %d.\n", err, shaStateError); - if ((printPassFail == PRINTPASSFAIL) || - ((printPassFail == PRINTFAIL) && (err != shaStateError))) - printf("%s se: %s\n", hashes[hashno].name, - (err == shaStateError) ? "PASSED" : "FAILED"); - - err = USHAReset(0, hashes[hashno].whichSha); - if (printResults == PRINTTEXT) - printf("\nError %d. Should be %d.\n", err, shaNull); - if ((printPassFail == PRINTPASSFAIL) || - ((printPassFail == PRINTFAIL) && (err != shaNull))) - printf("%s usha null: %s\n", hashes[hashno].name, - (err == shaNull) ? "PASSED" : "FAILED"); - - switch (hashno) { - case SHA1: err = SHA1Reset(0); break; - case SHA224: err = SHA224Reset(0); break; - case SHA256: err = SHA256Reset(0); break; - case SHA384: err = SHA384Reset(0); break; - case SHA512: err = SHA512Reset(0); break; - } - if (printResults == PRINTTEXT) - printf("\nError %d. Should be %d.\n", err, shaNull); - if ((printPassFail == PRINTPASSFAIL) || - ((printPassFail == PRINTFAIL) && (err != shaNull))) - printf("%s sha null: %s\n", hashes[hashno].name, - (err == shaNull) ? "PASSED" : "FAILED"); - } -} - -/* replace a hex string in place with its value */ -int unhexStr(char *hexstr) -{ - char *o = hexstr; - int len = 0, nibble1 = 0, nibble2 = 0; - if (!hexstr) return 0; - for ( ; *hexstr; hexstr++) { - if (isalpha((int)(unsigned char)(*hexstr))) { - nibble1 = tolower((int)(unsigned char)(*hexstr)) - 'a' + 10; - } else if (isdigit((int)(unsigned char)(*hexstr))) { - nibble1 = *hexstr - '0'; - } else { - printf("\nError: bad hex character '%c'\n", *hexstr); - } - if (!*++hexstr) break; - if (isalpha((int)(unsigned char)(*hexstr))) { - nibble2 = tolower((int)(unsigned char)(*hexstr)) - 'a' + 10; - } else if (isdigit((int)(unsigned char)(*hexstr))) { - nibble2 = *hexstr - '0'; - } else { - printf("\nError: bad hex character '%c'\n", *hexstr); - } - *o++ = (char)((nibble1 << 4) | nibble2); - len++; - } - return len; -} - -int main(int argc, char **argv) -{ - int i, err; - int loopno, loopnohigh = 1; - int hashno, hashnolow = 0, hashnohigh = HASHCOUNT - 1; - int testno, testnolow = 0, testnohigh; - int ntestnohigh = 0; - int printResults = PRINTTEXT; - int printPassFail = 1; - int checkErrors = 0; - char *hashstr = 0; - int hashlen = 0; - const char *resultstr = 0; - char *randomseedstr = 0; - int runHmacTests = 0; - int runHkdfTests = 0; - char *hmacKey = 0; - int hmaclen = 0; - char *info = 0; - int infolen = 0, okmlen = 0; - int randomcount = RANDOMCOUNT; - const char *hashfilename = 0; - const char *hashFilename = 0; - int extrabits = 0, numberExtrabits = 0; - int strIsHex = 0; - - if ('A' != 0x41) { - fprintf(stderr, "%s: these tests require ASCII\n", argv[0]); - } - - while ((i = getopt(argc, argv, - "6b:B:def:F:h:i:Hk:l:L:mpPr:R:s:S:t:wxX")) != -1) - switch (i) { - case 'b': extrabits = strtol(optarg, 0, 0); break; - case 'B': numberExtrabits = atoi(optarg); break; - case 'd': runHkdfTests = 1; break; - case 'e': checkErrors = 1; break; - case 'f': hashfilename = optarg; break; - case 'F': hashFilename = optarg; break; - case 'h': hashnolow = hashnohigh = findhash(argv[0], optarg); - break; - case 'H': strIsHex = 1; break; - case 'i': info = optarg; infolen = strlen(optarg); break; - case 'k': hmacKey = optarg; hmaclen = strlen(optarg); break; - case 'l': loopnohigh = atoi(optarg); break; - case 'L': okmlen = strtol(optarg, 0, 0); break; - case 'm': runHmacTests = 1; break; - case 'P': printPassFail = 0; break; - case 'p': printResults = PRINTNONE; break; - case 'R': randomcount = atoi(optarg); break; - case 'r': randomseedstr = optarg; break; - case 's': hashstr = optarg; hashlen = strlen(hashstr); break; - case 'S': resultstr = optarg; break; - case 't': testnolow = ntestnohigh = atoi(optarg) - 1; break; - case 'w': printResults = PRINTRAW; break; - case 'x': printResults = PRINTHEX; break; - case 'X': printPassFail = 2; break; - case '6': printResults = PRINTBASE64; break; - default: usage(argv[0]); - } - - if (strIsHex) { - hashlen = unhexStr(hashstr); - unhexStr(randomseedstr); - hmaclen = unhexStr(hmacKey); - infolen = unhexStr(info); - } - testnohigh = (ntestnohigh != 0) ? ntestnohigh: - runHmacTests ? (HMACTESTCOUNT-1) : - runHkdfTests ? (HKDFTESTCOUNT-1) : - (TESTCOUNT-1); - if ((testnolow < 0) || - (testnohigh >= (runHmacTests ? HMACTESTCOUNT : TESTCOUNT)) || - (hashnolow < 0) || (hashnohigh >= HASHCOUNT) || - (hashstr && (testnolow == testnohigh)) || - (randomcount < 0) || - (resultstr && (!hashstr && !hashfilename && !hashFilename)) || - ((runHmacTests || hmacKey) && randomseedstr) || - (hashfilename && hashFilename) || - (info && ((infolen <= 0) || (okmlen <= 0))) || - (info && !hmacKey)) - usage(argv[0]); - - /* - * Perform SHA/HMAC tests - */ - for (hashno = hashnolow; hashno <= hashnohigh; ++hashno) { - if (printResults == PRINTTEXT) - printf("Hash %s\n", hashes[hashno].name); - err = shaSuccess; - - for (loopno = 1; (loopno <= loopnohigh) && (err == shaSuccess); - ++loopno) { - if (hashstr) - err = hash(0, loopno, hashno, hashstr, hashlen, 1, - numberExtrabits, extrabits, (const unsigned char *)hmacKey, - hmaclen, (const uint8_t *) info, infolen, okmlen, resultstr, - hashes[hashno].hashsize, printResults, printPassFail); - - else if (randomseedstr) - randomtest(hashno, randomseedstr, hashes[hashno].hashsize, 0, - randomcount, printResults, printPassFail); - - else if (hashfilename) - err = hashfile(hashno, hashfilename, extrabits, - numberExtrabits, 0, - (const unsigned char *)hmacKey, hmaclen, - (const uint8_t *) info, infolen, okmlen, - resultstr, hashes[hashno].hashsize, - printResults, printPassFail); - - else if (hashFilename) - err = hashfile(hashno, hashFilename, extrabits, - numberExtrabits, 1, - (const unsigned char *)hmacKey, hmaclen, - (const uint8_t *) info, infolen, okmlen, - resultstr, hashes[hashno].hashsize, - printResults, printPassFail); - - else /* standard tests */ { - for (testno = testnolow; - (testno <= testnohigh) && (err == shaSuccess); ++testno) { - if (runHmacTests) { - err = hash(testno, loopno, hashno, - hmachashes[testno].dataarray[hashno] ? - hmachashes[testno].dataarray[hashno] : - hmachashes[testno].dataarray[1] ? - hmachashes[testno].dataarray[1] : - hmachashes[testno].dataarray[0], - hmachashes[testno].datalength[hashno] ? - hmachashes[testno].datalength[hashno] : - hmachashes[testno].datalength[1] ? - hmachashes[testno].datalength[1] : - hmachashes[testno].datalength[0], - 1, 0, 0, - (const unsigned char *)( - hmachashes[testno].keyarray[hashno] ? - hmachashes[testno].keyarray[hashno] : - hmachashes[testno].keyarray[1] ? - hmachashes[testno].keyarray[1] : - hmachashes[testno].keyarray[0]), - hmachashes[testno].keylength[hashno] ? - hmachashes[testno].keylength[hashno] : - hmachashes[testno].keylength[1] ? - hmachashes[testno].keylength[1] : - hmachashes[testno].keylength[0], - 0, 0, 0, - hmachashes[testno].resultarray[hashno], - hmachashes[testno].resultlength[hashno], - printResults, printPassFail); - } else if (runHkdfTests) { - err = hashHkdf(testno, loopno, hashno, - printResults, printPassFail); - } else { /* sha tests */ - err = hash(testno, loopno, hashno, - hashes[hashno].tests[testno].testarray, - hashes[hashno].tests[testno].length, - hashes[hashno].tests[testno].repeatcount, - hashes[hashno].tests[testno].numberExtrabits, - hashes[hashno].tests[testno].extrabits, - 0, 0, 0, 0, 0, - hashes[hashno].tests[testno].resultarray, - hashes[hashno].hashsize, - printResults, printPassFail); - } - } - if (!runHmacTests && !runHkdfTests) { - randomtest(hashno, hashes[hashno].randomtest, - hashes[hashno].hashsize, hashes[hashno].randomresults, - RANDOMCOUNT, printResults, printPassFail); - } - } - } - } - - /* Test some error returns */ - if (checkErrors) { - testErrors(hashnolow, hashnohigh, printResults, printPassFail); - } - - return 0; -} - -/* - * Compare two strings, case independently. - * Equivalent to strcasecmp() found on some systems. - */ -int scasecmp(const char *s1, const char *s2) -{ - for (;;) { - char u1 = tolower((int)(unsigned char)(*s1++)); - char u2 = tolower((int)(unsigned char)(*s2++)); - if (u1 != u2) - return u1 - u2; - if (u1 == '\0') - return 0; - } -} - diff --git a/lib/libesp32_div/ESP32-HomeKit/src/usha.c b/lib/libesp32_div/ESP32-HomeKit/src/usha.c deleted file mode 100644 index 08d857d99..000000000 --- a/lib/libesp32_div/ESP32-HomeKit/src/usha.c +++ /dev/null @@ -1,281 +0,0 @@ -/**************************** usha.c ***************************/ -/***************** See RFC 6234 for details. *******************/ -/* Copyright (c) 2011 IETF Trust and the persons identified as */ -/* authors of the code. All rights reserved. */ -/* See sha.h for terms of use and redistribution. */ - -/* - * Description: - * This file implements a unified interface to the SHA algorithms. - */ - -#include "sha.h" - -/* - * USHAReset - * - * Description: - * This function will initialize the SHA Context in preparation - * for computing a new SHA message digest. - * - * Parameters: - * context: [in/out] - * The context to reset. - * whichSha: [in] - * Selects which SHA reset to call - * - * Returns: - * sha Error Code. - * - */ -int USHAReset(USHAContext *context, enum SHAversion whichSha) -{ - if (!context) return shaNull; - context->whichSha = whichSha; - switch (whichSha) { - case SHA1: return SHA1Reset((SHA1Context*)&context->ctx); - case SHA224: return SHA224Reset((SHA224Context*)&context->ctx); - case SHA256: return SHA256Reset((SHA256Context*)&context->ctx); - case SHA384: return SHA384Reset((SHA384Context*)&context->ctx); - case SHA512: return SHA512Reset((SHA512Context*)&context->ctx); - default: return shaBadParam; - } -} - -/* - * USHAInput - * - * Description: - * This function accepts an array of octets as the next portion - * of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_array: [in] - * An array of octets representing the next portion of - * the message. - * length: [in] - * The length of the message in message_array. - * - * Returns: - * sha Error Code. - * - */ -int USHAInput(USHAContext *context, - const uint8_t *bytes, unsigned int bytecount) -{ - if (!context) return shaNull; - switch (context->whichSha) { - case SHA1: - return SHA1Input((SHA1Context*)&context->ctx, bytes, - bytecount); - case SHA224: - return SHA224Input((SHA224Context*)&context->ctx, bytes, - bytecount); - case SHA256: - return SHA256Input((SHA256Context*)&context->ctx, bytes, - bytecount); - case SHA384: - return SHA384Input((SHA384Context*)&context->ctx, bytes, - bytecount); - case SHA512: - return SHA512Input((SHA512Context*)&context->ctx, bytes, - bytecount); - default: return shaBadParam; - } -} - -/* - * USHAFinalBits - * - * Description: - * This function will add in any final bits of the message. - * - * Parameters: - * context: [in/out] - * The SHA context to update. - * message_bits: [in] - * The final bits of the message, in the upper portion of the - * byte. (Use 0b###00000 instead of 0b00000### to input the - * three bits ###.) - * length: [in] - * The number of bits in message_bits, between 1 and 7. - * - * Returns: - * sha Error Code. - */ -int USHAFinalBits(USHAContext *context, - uint8_t bits, unsigned int bit_count) -{ - if (!context) return shaNull; - switch (context->whichSha) { - case SHA1: - return SHA1FinalBits((SHA1Context*)&context->ctx, bits, - bit_count); - case SHA224: - return SHA224FinalBits((SHA224Context*)&context->ctx, bits, - bit_count); - case SHA256: - return SHA256FinalBits((SHA256Context*)&context->ctx, bits, - bit_count); - case SHA384: - return SHA384FinalBits((SHA384Context*)&context->ctx, bits, - bit_count); - case SHA512: - return SHA512FinalBits((SHA512Context*)&context->ctx, bits, - bit_count); - default: return shaBadParam; - } -} - -/* - * USHAResult - * - * Description: - * This function will return the message digest of the appropriate - * bit size, as returned by USHAHashSizeBits(whichSHA) for the - * 'whichSHA' value used in the preceeding call to USHAReset, - * into the Message_Digest array provided by the caller. - * - * Parameters: - * context: [in/out] - * The context to use to calculate the SHA-1 hash. - * Message_Digest: [out] - * Where the digest is returned. - * - * Returns: - * sha Error Code. - * - */ -int USHAResult(USHAContext *context, - uint8_t Message_Digest[USHAMaxHashSize]) -{ - if (!context) return shaNull; - switch (context->whichSha) { - case SHA1: - return SHA1Result((SHA1Context*)&context->ctx, Message_Digest); - case SHA224: - return SHA224Result((SHA224Context*)&context->ctx, - Message_Digest); - case SHA256: - return SHA256Result((SHA256Context*)&context->ctx, - Message_Digest); - case SHA384: - return SHA384Result((SHA384Context*)&context->ctx, - Message_Digest); - case SHA512: - return SHA512Result((SHA512Context*)&context->ctx, - Message_Digest); - default: return shaBadParam; - } -} - -/* - * USHABlockSize - * - * Description: - * This function will return the blocksize for the given SHA - * algorithm. - * - * Parameters: - * whichSha: - * which SHA algorithm to query - * - * Returns: - * block size - * - */ -int USHABlockSize(enum SHAversion whichSha) -{ - switch (whichSha) { - case SHA1: return SHA1_Message_Block_Size; - case SHA224: return SHA224_Message_Block_Size; - case SHA256: return SHA256_Message_Block_Size; - case SHA384: return SHA384_Message_Block_Size; - default: - case SHA512: return SHA512_Message_Block_Size; - } -} - -/* - * USHAHashSize - * - * Description: - * This function will return the hashsize for the given SHA - * algorithm. - * - * Parameters: - * whichSha: - * which SHA algorithm to query - * - * Returns: - * hash size - * - */ -int USHAHashSize(enum SHAversion whichSha) -{ - switch (whichSha) { - case SHA1: return SHA1HashSize; - case SHA224: return SHA224HashSize; - case SHA256: return SHA256HashSize; - case SHA384: return SHA384HashSize; - default: - case SHA512: return SHA512HashSize; - } -} - -/* - * USHAHashSizeBits - * - * Description: - * This function will return the hashsize for the given SHA - * algorithm, expressed in bits. - * - * Parameters: - * whichSha: - * which SHA algorithm to query - * - * Returns: - * hash size in bits - * - */ -int USHAHashSizeBits(enum SHAversion whichSha) -{ - switch (whichSha) { - case SHA1: return SHA1HashSizeBits; - case SHA224: return SHA224HashSizeBits; - case SHA256: return SHA256HashSizeBits; - case SHA384: return SHA384HashSizeBits; - default: - case SHA512: return SHA512HashSizeBits; - } -} - -/* - * USHAHashName - * - * Description: - * This function will return the name of the given SHA algorithm - * as a string. - * - * Parameters: - * whichSha: - * which SHA algorithm to query - * - * Returns: - * character string with the name in it - * - */ -const char *USHAHashName(enum SHAversion whichSha) -{ - switch (whichSha) { - case SHA1: return "SHA1"; - case SHA224: return "SHA224"; - case SHA256: return "SHA256"; - case SHA384: return "SHA384"; - default: - case SHA512: return "SHA512"; - } -} - diff --git a/lib/libesp32_div/NimBLE-Arduino/library.json b/lib/libesp32_div/NimBLE-Arduino/library.json index 348f77d3d..1f55748d6 100644 --- a/lib/libesp32_div/NimBLE-Arduino/library.json +++ b/lib/libesp32_div/NimBLE-Arduino/library.json @@ -2,7 +2,7 @@ "name": "NimBLE-Arduino", "keywords": "esp32, bluetooth", "description": "Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE", - "version": "1.4.0", + "version": "1.4.1", "frameworks": "arduino", "platforms": "espressif32" } diff --git a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp index 43ba21909..d2553b0e8 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp +++ b/lib/libesp32_div/NimBLE-Arduino/src/NimBLEDevice.cpp @@ -867,7 +867,7 @@ void NimBLEDevice::init(const std::string &deviceName) { esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); -#if defined (CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) +#if defined (CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32S3) bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE; #else bt_cfg.mode = ESP_BT_MODE_BLE; diff --git a/lib/libesp32_div/NimBLE-Arduino/src/nimconfig.h b/lib/libesp32_div/NimBLE-Arduino/src/nimconfig.h index 8214e1d9b..9d991ae21 100644 --- a/lib/libesp32_div/NimBLE-Arduino/src/nimconfig.h +++ b/lib/libesp32_div/NimBLE-Arduino/src/nimconfig.h @@ -149,6 +149,12 @@ End Arduino user-config **********************************/ +#ifndef CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE +#define CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE 4096 +#endif + +#ifndef CONFIG_BT_NIMBLE_ROLE_CENTRAL // means for Tasmota: nimble was already embedded into the Arduino framework + /* This section should not be altered */ #ifndef CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED #define CONFIG_BT_NIMBLE_ROLE_CENTRAL @@ -170,10 +176,6 @@ #define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0 #endif -#ifndef CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE -#define CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE 4096 -#endif - #ifndef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL #define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1 #endif @@ -284,7 +286,7 @@ #define CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE 2 #endif -#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) +#if !defined(CONFIG_IDF_TARGET_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32S3) #define CONFIG_IDF_TARGET_ESP32 1 #endif @@ -324,9 +326,12 @@ #define CONFIG_BT_NIMBLE_ROLE_BROADCASTER #endif +#endif //CONFIG_BT_NIMBLE_ROLE_CENTRAL + /* Enables the use of Arduino String class for attribute values */ #if defined __has_include # if __has_include () # define NIMBLE_CPP_ARDUINO_STRING_AVAILABLE # endif #endif + diff --git a/lib/libesp32_div/esp-nimble-cpp/.github/workflows/build.yml b/lib/libesp32_div/esp-nimble-cpp/.github/workflows/build.yml new file mode 100644 index 000000000..f256daaff --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/.github/workflows/build.yml @@ -0,0 +1,65 @@ +name: Build + +on: + workflow_dispatch: # Start a workflow + pull_request: + push: + +jobs: + build-esp-idf-component: + name: Build with ESP-IDF ${{ matrix.idf_ver }} for ${{ matrix.idf_target }} + runs-on: ubuntu-latest + strategy: + matrix: + # The version names here correspond to the versions of espressif/idf Docker image. + # See https://hub.docker.com/r/espressif/idf/tags and + # https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-docker-image.html + # for details. + idf_ver: ["release-v4.4", "release-v5.1"] + idf_target: ["esp32", "esp32s3", "esp32c2", "esp32c3", "esp32c6"] + example: + - Advanced/NimBLE_Client + - Advanced/NimBLE_Server + - basic/BLE_client + - basic/BLE_notify + - basic/BLE_scan + - basic/BLE_server + - basic/BLE_uart + - Bluetooth_5/NimBLE_extended_client + - Bluetooth_5/NimBLE_extended_server + - Bluetooth_5/NimBLE_multi_advertiser + exclude: + - idf_target: "esp32" + example: Bluetooth_5/NimBLE_extended_client + - idf_target: "esp32" + example: Bluetooth_5/NimBLE_extended_server + - idf_target: "esp32" + example: Bluetooth_5/NimBLE_multi_advertiser + - idf_ver: release-v4.4 + idf_target: "esp32c2" + - idf_ver: release-v4.4 + idf_target: "esp32c6" + + container: espressif/idf:${{ matrix.idf_ver }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: components/esp-nimble-cpp + - name: Build examples + env: + IDF_TARGET: ${{ matrix.idf_target }} + shell: bash + run: | + . ${IDF_PATH}/export.sh + cp -r components/esp-nimble-cpp/examples/* . + idf.py -C ${{ matrix.example }} -DEXTRA_COMPONENT_DIRS=$PWD/components build + + build_docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Doxygen Action + uses: mattnotmitt/doxygen-action@v1.9.5 + with: + working-directory: 'docs/' diff --git a/lib/libesp32_div/esp-nimble-cpp/.gitignore b/lib/libesp32_div/esp-nimble-cpp/.gitignore new file mode 100644 index 000000000..343d1f417 --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/.gitignore @@ -0,0 +1 @@ +docs/doxydocs \ No newline at end of file diff --git a/lib/libesp32_div/esp-nimble-cpp/CHANGELOG.md b/lib/libesp32_div/esp-nimble-cpp/CHANGELOG.md new file mode 100644 index 000000000..f8b6e42cb --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/CHANGELOG.md @@ -0,0 +1,280 @@ +# Changelog + +All notable changes to this project will be documented in this file. +## [Unreleased] + +### Changed +- NimBLESecurity class removed. + +### Added +- `NimBLEDevice::setDeviceName` to change the device name after initialization. +- `NimBLEHIDDevice::batteryLevel` returns the HID device battery level characteristic. + +## [1.4.0] - 2022-07-31 + +### Fixed +- Fixed missing data from long notification values. +- Fixed NimbleCharacteristicCallbacks::onRead not being called when a non-long read command is received. +- Prevent a potential crash when retrieving characteristics from a service if the result was successful but no characteristics found. +- logs/typos. + +### Changed +- AD flags are no longer set in the advertisements of non-connectable beacons, freeing up 3 bytes of advertisement room. +- Save resources when retrieving descriptors if the characteristic handle is the same as the end handle (no descriptors). +- Subscribing to characteristic notifications/indications will now always use write with response, as per BLE specifications. +- `NimBLEClient::discoverAttributes` now returns a bool value to indicate success/failure. +- Scan result callbacks are no longer called when the scan response data is updated in order to reduce duplicates. + +### Added +- Preliminary support for non-esp devices, NRF51 and NRF52 devices supported with [n-able arduino core](https://github.com/h2zero/n-able-Arduino) +- Alias added for `NimBLEServerCallbacks::onMTUChange` to `onMtuChanged` in order to support porting code from original library. +- `NimBLEAttValue` Class added to reduce and control RAM footprint of characteristic/descriptor values and support conversions from Arduino Strings and many other data types. +- Bluetooth 5 extended advertising support for capable devices. CODED Phy, 2M Phy, extended advertising data, and multi-advertising are supported, periodic advertising will be implemented in the future. + +## [1.3.3] - 2022-02-15 + +### Changed +- If attribute retrieval fails with a "not found" try again with the 16 bit version if a 128 bit base uuid is used. + +### Fixed +- Memory leak when deleting client instance. +- IDf version check for data length extension. +- Memory leak when server services changed. +- Compiler warnings for non-esp32 devices. + +## [1.3.2] - 2022-01-15 + +### Fixed +- Initialize advertising complete callback in NimBLEAdvertising constructor. +- Clear client disconnect timer in constructor before initializing. +- Fix missing data when reading large values. +- Fix missing data in notifications when using a large MTU size and more than 270 bytes of data are sent. +- Workaround fix added for cases when the task notification value is not cleared, causing various functions that should block not to block. + +### Added +- `NimBLEClient::getLastError` : Gets the error code of the last function call that produces a return code from the stack. +- `NimBLECharacteristic::notify` : Overload method to send notifications/indications with custom values. +- Added conditional checks for ESP32 specific functions/values to support use of the library on non-esp32 devices. +- Added an alias to use the callback name from the original library `onMtuChanged`. +- `NimBLEClient::setDataLen` and `NimBLEServer::setDataLen`: Data length extension support (IDF version >= 4.3.2 only) +- Config option to set logging level for esp-nimble-cpp + +### Changed +- Critical section calls now use the NimBLE API instead of FreeRTOS directly. This removes the need for a `portMUX_TYPE` variable in the class definitions. +- Removed unnecessary variables in `NimBLEService` and changed the constructor no no longer accept `numHandles` and `inst_id` parameters. + +## [1.3.1] - 2021-08-04 + +### Fixed +- Corrected a compiler/linker error when an application or a library uses bluetooth classic due to the redefinition of `btInUse`. + +## [1.3.0] - 2021-08-02 + +### Added +- `NimBLECharacteristic::removeDescriptor`: Dynamically remove a descriptor from a characterisic. Takes effect after all connections are closed and sends a service changed indication. +- `NimBLEService::removeCharacteristic`: Dynamically remove a characteristic from a service. Takes effect after all connections are closed and sends a service changed indication +- `NimBLEServerCallbacks::onMTUChange`: This is callback is called when the MTU is updated after connection with a client. +- ESP32C3 support + +- Whitelist API: + - `NimBLEDevice::whiteListAdd`: Add a device to the whitelist. + - `NimBLEDevice::whiteListRemove`: Remove a device from the whitelist. + - `NimBLEDevice::onWhiteList`: Check if the device is on the whitelist. + - `NimBLEDevice::getWhiteListCount`: Gets the size of the whitelist + - `NimBLEDevice::getWhiteListAddress`: Get the address of a device on the whitelist by index value. + +- Bond management API: + - `NimBLEDevice::getNumBonds`: Gets the number of bonds stored. + - `NimBLEDevice::isBonded`: Checks if the device is bonded. + - `NimBLEDevice::deleteAllBonds`: Deletes all bonds. + - `NimBLEDevice::getBondedAddress`: Gets the address of a bonded device by the index value. + +- `NimBLECharacteristic::getCallbacks` to retrieve the current callback handler. +- Connection Information class: `NimBLEConnInfo`. +- `NimBLEScan::clearDuplicateCache`: This can be used to reset the cache of advertised devices so they will be immediately discovered again. + +### Changed +- FreeRTOS files have been removed as they are not used by the library. +- Services, characteristics and descriptors can now be created statically and added after. +- Excess logging and some asserts removed. +- Use ESP_LOGx macros to enable using local log level filtering. + +### Fixed +- `NimBLECharacteristicCallbacks::onSubscribe` Is now called after the connection is added to the vector. +- Corrected bonding failure when reinitializing the BLE stack. +- Writing to a characterisic with a std::string value now correctly writes values with null characters. +- Retrieving remote descriptors now uses the characterisic end handle correctly. +- Missing data in long writes to remote descriptors. +- Hanging on task notification when sending an indication from the characteristic callback. +- BLE controller memory could be released when using Arduino as a component. +- Complile errors with NimBLE release 1.3.0. + +## [1.2.0] - 2021-02-08 + +### Added +- `NimBLECharacteristic::getDescriptorByHandle`: Return the BLE Descriptor for the given handle. + +- `NimBLEDescriptor::getStringValue`: Get the value of this descriptor as a string. + +- `NimBLEServer::getServiceByHandle`: Get a service by its handle. + +- `NimBLEService::getCharacteristicByHandle`: Get a pointer to the characteristic object with the specified handle. + +- `NimBLEService::getCharacteristics`: Get the vector containing pointers to each characteristic associated with this service. +Overloads to get a vector containing pointers to all the characteristics in a service with the UUID. (supports multiple same UUID's in a service) + - `NimBLEService::getCharacteristics(const char *uuid)` + - `NimBLEService::getCharacteristics(const NimBLEUUID &uuid)` + +- `NimBLEAdvertisementData` New methods: + - `NimBLEAdvertisementData::addTxPower`: Adds transmission power to the advertisement. + - `NimBLEAdvertisementData::setPreferredParams`: Adds connection parameters to the advertisement. + - `NimBLEAdvertisementData::setURI`: Adds URI data to the advertisement. + +- `NimBLEAdvertising` New methods: + - `NimBLEAdvertising::setName`: Set the name advertised. + - `NimBLEAdvertising::setManufacturerData`: Adds manufacturer data to the advertisement. + - `NimBLEAdvertising::setURI`: Adds URI data to the advertisement. + - `NimBLEAdvertising::setServiceData`: Adds service data to the advertisement. + - `NimBLEAdvertising::addTxPower`: Adds transmission power to the advertisement. + - `NimBLEAdvertising::reset`: Stops the current advertising and resets the advertising data to the default values. + +- `NimBLEDevice::setScanFilterMode`: Set the controller duplicate filter mode for filtering scanned devices. + +- `NimBLEDevice::setScanDuplicateCacheSize`: Sets the number of advertisements filtered before the cache is reset. + +- `NimBLEScan::setMaxResults`: This allows for setting a maximum number of advertised devices stored in the results vector. + +- `NimBLEAdvertisedDevice` New data retrieval methods added: + - `haveAdvInterval/getAdvInterval`: checks if the interval is advertised / gets the advertisement interval value. + + - `haveConnParams/getMinInterval/getMaxInterval`: checks if the parameters are advertised / get min value / get max value. + + - `haveURI/getURI`: checks if a URI is advertised / gets the URI data. + + - `haveTargetAddress/getTargetAddressCount/getTargetAddress(index)`: checks if a target address is present / gets a count of the addresses targeted / gets the address of the target at index. + +### Changed +- `nimconfig.h` (Arduino) is now easier to use. + +- `NimBLEServer::getServiceByUUID` Now takes an extra parameter of instanceID to support multiple services with the same UUID. + +- `NimBLEService::getCharacteristic` Now takes an extra parameter of instanceID to support multiple characteristics with the same UUID. + +- `NimBLEAdvertising` Transmission power is no longer advertised by default and can be added to the advertisement by calling `NimBLEAdvertising::addTxPower` + +- `NimBLEAdvertising` Custom scan response data can now be used without custom advertisment. + +- `NimBLEScan` Now uses the controller duplicate filter. + +- `NimBLEAdvertisedDevice` Has been refactored to store the complete advertisement payload and no longer parses the data from each advertisement. +Instead the data will be parsed on-demand when the user application asks for specific data. + +### Fixed +- `NimBLEHIDDevice` Characteristics now use encryption, this resolves an issue with communicating with devices requiring encryption for HID devices. + + +## [1.1.0] - 2021-01-20 + +### Added +- `NimBLEDevice::setOwnAddrType` added to enable the use of random and random-resolvable addresses, by asukiaaa + +- New examples for securing and authenticating client/server connections, by mblasee. + +- `NimBLEAdvertising::SetMinPreferred` and `NimBLEAdvertising::SetMinPreferred` re-added. + +- Conditional checks added for command line config options in `nimconfig.h` to support custom configuration in platformio. + +- `NimBLEClient::setValue` Now takes an extra bool parameter `response` to enable the use of write with response (default = false). + +- `NimBLEClient::getCharacteristic(uint16_t handle)` Enabling the use of the characteristic handle to be used to find +the NimBLERemoteCharacteristic object. + +- `NimBLEHIDDevice` class added by wakwak-koba. + +- `NimBLEServerCallbacks::onDisconnect` overloaded callback added to provide a ble_gap_conn_desc parameter for the application +to obtain information about the disconnected client. + +- Conditional checks in `nimconfig.h` for command line defined macros to support platformio config settings. + +### Changed +- `NimBLEAdvertising::start` now returns a bool value to indicate success/failure. + +- Some asserts were removed in `NimBLEAdvertising::start` and replaced with better return code handling and logging. + +- If a host reset event occurs, scanning and advertising will now only be restarted if their previous duration was indefinite. + +- `NimBLERemoteCharacteristic::subscribe` and `NimBLERemoteCharacteristic::registerForNotify` will now set the callback +regardless of the existance of the CCCD and return true unless the descriptor write operation failed. + +- Advertising tx power level is now sent in the advertisement packet instead of scan response. + +- `NimBLEScan` When the scan ends the scan stopped flag is now set before calling the scan complete callback (if used) +this allows the starting of a new scan from the callback function. + +### Fixed +- Sometimes `NimBLEClient::connect` would hang on the task block if no event arrived to unblock. +A time limit has been added to timeout appropriately. + +- When getting descriptors for a characterisic the end handle of the service was used as a proxy for the characteristic end +handle. This would be rejected by some devices and has been changed to use the next characteristic handle as the end when possible. + +- An exception could occur when deleting a client instance if a notification arrived while the attribute vectors were being +deleted. A flag has been added to prevent this. + +- An exception could occur after a host reset event when the host re-synced if the tasks that were stopped during the event did +not finish processing. A yield has been added after re-syncing to allow tasks to finish before proceeding. + +- Occasionally the controller would fail to send a disconnected event causing the client to indicate it is connected +and would be unable to reconnect. A timer has been added to reset the host/controller if it expires. + +- Occasionally the call to start scanning would get stuck in a loop on BLE_HS_EBUSY, this loop has been removed. + +- 16bit and 32bit UUID's in some cases were not discovered or compared correctly if the device +advertised them as 16/32bit but resolved them to 128bits. Both are now checked. + +- `FreeRTOS` compile errors resolved in latest Ardruino core and IDF v3.3. + +- Multiple instances of `time()` called inside critical sections caused sporadic crashes, these have been moved out of critical regions. + +- Advertisement type now correctly set when using non-connectable (advertiser only) mode. + +- Advertising payload length correction, now accounts for appearance. + +- (Arduino) Ensure controller mode is set to BLE Only. + + +## [1.0.2] - 2020-09-13 + +### Changed + +- `NimBLEAdvertising::start` Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a +callback that is invoked when advertsing ends and takes a pointer to a `NimBLEAdvertising` object (similar to the `NimBLEScan::start` API). + +- (Arduino) Maximum BLE connections can now be altered by only changing the value of `CONFIG_BT_NIMBLE_MAX_CONNECTIONS` in `nimconfig.h`. +Any changes to the controller max connection settings in `sdkconfig.h` will now have no effect when using this library. + +- (Arduino) Revert the previous change to fix the advertising start delay. Instead a replacement fix that routes all BLE controller commands from +a task running on core 0 (same as the controller) has been implemented. This improves response times and reliability for all BLE functions. + + +## [1.0.1] - 2020-09-02 + +### Added + +- Empty `NimBLEAddress` constructor: `NimBLEAddress()` produces an address of 00:00:00:00:00:00 type 0. +- Documentation of the difference of NimBLEAddress::getNative vs the original bluedroid library. + +### Changed + +- notify_callback typedef is now defined as std::function to enable the use of std::bind to call a class member function. + +### Fixed + +- Fix advertising start delay when first called. + + +## [1.0.0] - 2020-08-22 + +First stable release. + +All the original library functionality is complete and many extras added with full documentation. diff --git a/lib/libesp32_div/esp-nimble-cpp/CMakeLists.txt b/lib/libesp32_div/esp-nimble-cpp/CMakeLists.txt new file mode 100644 index 000000000..90c22bd19 --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/CMakeLists.txt @@ -0,0 +1,64 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +idf_build_get_property(__hack_component_targets __COMPONENT_TARGETS) + +if("esp-nimble-component" IN_LIST BUILD_COMPONENTS OR "__esp-nimble-component" IN_LIST __hack_component_targets) + list(APPEND ESP_NIMBLE_PRIV_REQUIRES + esp-nimble-component + ) +elseif("nimble" IN_LIST BUILD_COMPONENTS OR "__nimble" IN_LIST __hack_component_targets) + list(APPEND ESP_NIMBLE_PRIV_REQUIRES + nimble + ) +endif() + +if("arduino" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "__idf_arduino") + list(APPEND ESP_NIMBLE_PRIV_REQUIRES + arduino + ) +elseif("framework-arduinoespressif32" IN_LIST BUILD_COMPONENTS OR __hack_component_targets MATCHES "___idf_framework-arduinoespressif32") + list(APPEND ESP_NIMBLE_PRIV_REQUIRES + framework-arduinoespressif32 + ) +endif() + +idf_component_register( + REQUIRED_IDF_TARGETS + "esp32" + "esp32s3" + "esp32c2" + "esp32c3" + "esp32c6" + INCLUDE_DIRS + "src" + SRCS + "src/NimBLE2904.cpp" + "src/NimBLEAddress.cpp" + "src/NimBLEAdvertisedDevice.cpp" + "src/NimBLEAdvertising.cpp" + "src/NimBLEBeacon.cpp" + "src/NimBLECharacteristic.cpp" + "src/NimBLEClient.cpp" + "src/NimBLEDescriptor.cpp" + "src/NimBLEDevice.cpp" + "src/NimBLEEddystoneTLM.cpp" + "src/NimBLEEddystoneURL.cpp" + "src/NimBLEExtAdvertising.cpp" + "src/NimBLEHIDDevice.cpp" + "src/NimBLERemoteCharacteristic.cpp" + "src/NimBLERemoteDescriptor.cpp" + "src/NimBLERemoteService.cpp" + "src/NimBLEScan.cpp" + "src/NimBLEServer.cpp" + "src/NimBLEService.cpp" + "src/NimBLEUtils.cpp" + "src/NimBLEUUID.cpp" + REQUIRES + bt + nvs_flash + PRIV_REQUIRES + ${ESP_NIMBLE_PRIV_REQUIRES} +) + diff --git a/lib/libesp32_div/esp-nimble-cpp/CMakeLists.txt_idf3 b/lib/libesp32_div/esp-nimble-cpp/CMakeLists.txt_idf3 new file mode 100644 index 000000000..c548f9021 --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/CMakeLists.txt_idf3 @@ -0,0 +1,56 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(SUPPORTED_TARGETS esp32) + +set(COMPONENT_SRCS + "src/NimBLE2904.cpp" + "src/NimBLEAddress.cpp" + "src/NimBLEAdvertisedDevice.cpp" + "src/NimBLEAdvertising.cpp" + "src/NimBLEBeacon.cpp" + "src/NimBLECharacteristic.cpp" + "src/NimBLEClient.cpp" + "src/NimBLEDescriptor.cpp" + "src/NimBLEDevice.cpp" + "src/NimBLEEddystoneTLM.cpp" + "src/NimBLEEddystoneURL.cpp" + "src/NimBLEHIDDevice.cpp" + "src/NimBLERemoteCharacteristic.cpp" + "src/NimBLERemoteDescriptor.cpp" + "src/NimBLERemoteService.cpp" + "src/NimBLEScan.cpp" + "src/NimBLESecurity.cpp" + "src/NimBLEServer.cpp" + "src/NimBLEService.cpp" + "src/NimBLEUtils.cpp" + "src/NimBLEUUID.cpp" +) + +set(COMPONENT_ADD_INCLUDEDIRS + src +) + +set(COMPONENT_PRIV_REQUIRES + nvs_flash + bt +) + +if(COMPONENTS MATCHES "esp-nimble-component") + list(APPEND COMPONENT_PRIV_REQUIRES + esp-nimble-component + ) +elseif(COMPONENTS MATCHES "nimble") + list(APPEND COMPONENT_PRIV_REQUIRES + nimble + ) +endif() + +if(COMPONENTS MATCHES "arduino") + list(APPEND COMPONENT_PRIV_REQUIRES + arduino + ) +endif() + +register_component() diff --git a/lib/libesp32_div/esp-nimble-cpp/Kconfig b/lib/libesp32_div/esp-nimble-cpp/Kconfig new file mode 100644 index 000000000..730f8cd96 --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/Kconfig @@ -0,0 +1,72 @@ +menu "ESP-NimBLE-CPP configuration" + +choice NIMBLE_CPP_LOG_LEVEL + prompt "NimBLE CPP log verbosity" + default NIMBLE_CPP_LOG_LEVEL_NONE + help + Select NimBLE CPP log verbosity level. + + config NIMBLE_CPP_LOG_LEVEL_NONE + bool "No logs" + config NIMBLE_CPP_LOG_LEVEL_ERROR + bool "Error logs" + config NIMBLE_CPP_LOG_LEVEL_WARNING + bool "Warning logs" + config NIMBLE_CPP_LOG_LEVEL_INFO + bool "Info logs" + config NIMBLE_CPP_LOG_LEVEL_DEBUG + bool "Debug logs" +endchoice #NIMBLE_CPP_LOG_LEVEL + +config NIMBLE_CPP_LOG_LEVEL + int + default 0 if NIMBLE_CPP_LOG_LEVEL_NONE + default 1 if NIMBLE_CPP_LOG_LEVEL_ERROR + default 2 if NIMBLE_CPP_LOG_LEVEL_WARNING + default 3 if NIMBLE_CPP_LOG_LEVEL_INFO + default 4 if NIMBLE_CPP_LOG_LEVEL_DEBUG + +config NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT + bool "Show NimBLE return codes as text in debug log." + default "n" + help + Enabling this option will display return code values as text + messages in the debug log. This will use approximately 8kB + of flash memory. + +config NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT + bool "Show NimBLE gap events as text in debug log." + default "n" + help + Enabling this option will display gap event codes as text + messages in the debug log. This will use approximately 1kB + of flash memory. + +config NIMBLE_CPP_ENABLE_ADVERTISEMENT_TYPE_TEXT + bool "Show advertisment types as text in debug log." + default "n" + help + Enabling this option will display advertisment types recieved + while scanning as text messages in the debug log. + This will use approximately 250 bytes of flash memory. + +config NIMBLE_CPP_ATT_VALUE_TIMESTAMP_ENABLED + bool "Enable timestamps to be stored with attribute values." + default "n" + help + Enabling this option will store the timestamp when an attribute value is updated. + This allows for checking the last update time using getTimeStamp() + or getValue(time_t*). If disabled, the timestamp returned from these functions will be 0. + Disabling timestamps will reduce the memory used for each value. + +config NIMBLE_CPP_ATT_VALUE_INIT_LENGTH + int "Initial attribute value size (bytes) for empty values." + range 1 512 + default 20 + help + Sets the default allocation size (bytes) for each attribute if not specified + when the constructor is called. This is also the size used when a remote + characteristic or descriptor is constructed before a value is read/notifed. + Increasing this will reduce reallocations but increase memory footprint. + +endmenu diff --git a/lib/libesp32_div/esp-nimble-cpp/LICENSE b/lib/libesp32_div/esp-nimble-cpp/LICENSE new file mode 100644 index 000000000..ff162769f --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/LICENSE @@ -0,0 +1,203 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {2020} {Ryan Powell} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + This product partly derives from esp32-snippets; Copyright 2017 Neil Kolban. \ No newline at end of file diff --git a/lib/libesp32_div/esp-nimble-cpp/README.md b/lib/libesp32_div/esp-nimble-cpp/README.md new file mode 100644 index 000000000..7f37effad --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/README.md @@ -0,0 +1,70 @@ +[Latest release ![Release Version](https://img.shields.io/github/release/h2zero/esp-nimble-cpp.svg?style=plastic) +![Release Date](https://img.shields.io/github/release-date/h2zero/esp-nimble-cpp.svg?style=plastic)](https://github.com/h2zero/esp-nimble-cpp/releases/latest/) + +Need help? Have questions or suggestions? Join the [![Gitter](https://badges.gitter.im/NimBLE-Arduino/community.svg)](https://gitter.im/NimBLE-Arduino/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +
+ +# esp-nimble-cpp + +NimBLE CPP library for use with ESP32 that attempts to maintain compatibility with the [nkolban cpp_uitls BLE API](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils). + +**An Arduino version of this library, including NimBLE, can be [found here.](https://github.com/h2zero/NimBLE-Arduino)** + +This library **significantly** reduces resource usage and improves performance for ESP32 BLE applications as compared +with the bluedroid based library. The goal is to maintain, as much as reasonable, compatibility with the original +library but refactored to use the NimBLE stack. In addition, this library will be more actively developed and maintained +to provide improved capabilites and stability over the original. + +**Testing shows a nearly 50% reduction in flash use and approx. 100kB less ram consumed vs the original!** +*Your results may vary* +
+ +# What is NimBLE? +NimBLE is a completely open source Bluetooth Low Energy stack produced by [Apache](https://github.com/apache/mynewt-nimble). +It is more suited to resource constrained devices than bluedroid and has now been ported to the ESP32 by Espressif. +
+ +# Installation + +### ESP-IDF v4.0+ +Download as .zip and extract or clone into the components folder in your esp-idf project. + +Run menuconfig, go to `Component config->Bluetooth` enable Bluetooth and in `Bluetooth host` NimBLE. +Configure settings in `NimBLE Options`. +`#include "NimBLEDevice.h"` in main.cpp. +Call `NimBLEDevice::init("");` in `app_main`. +
+ +### ESP-IDF v3.2 & v3.3 +The NimBLE component does not come with these versions of IDF (now included in 3.3.2 and above). +A backport that works in these versions has been created and is [available here](https://github.com/h2zero/esp-nimble-component). +Download or clone that repo into your project/components folder and run menuconfig. +Configure settings in `main menu -> NimBLE Options`. + +`#include "NimBLEDevice.h"` in main.cpp. +Call `NimBLEDevice::init("");` in `app_main`. +
+ +# Using +This library is intended to be compatible with the original ESP32 BLE functions and types with minor changes. + +If you have not used the original Bluedroid library please refer to the [New user guide](docs/New_user_guide.md). + +If you are familiar with the original library, see: [The migration guide](docs/Migration_guide.md) for details about breaking changes and migration. + +Also see [Improvements_and_updates](docs/Improvements_and_updates.md) for information about non-breaking changes. + +[Full API documentation and class list can be found here.](https://h2zero.github.io/esp-nimble-cpp/) +
+ +## Using with Arduino as an IDF component and CMake +When using this library along with Arduino and compiling with *CMake* you must add `add_compile_definitions(ARDUINO_ARCH_ESP32=1)` +in your project/CMakeLists.txt after the line `include($ENV{IDF_PATH}/tools/cmake/project.cmake)` to prevent Arduino from releasing BLE memory. +
+ +# Acknowledgments +* [nkolban](https://github.com/nkolban) and [chegewara](https://github.com/chegewara) for the [original esp32 BLE library](https://github.com/nkolban/esp32-snippets/tree/master/cpp_utils) this project was derived from. +* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples. +* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code. +
+ diff --git a/lib/libesp32_div/esp-nimble-cpp/component.mk b/lib/libesp32_div/esp-nimble-cpp/component.mk new file mode 100644 index 000000000..563436815 --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/component.mk @@ -0,0 +1,2 @@ +COMPONENT_ADD_INCLUDEDIRS := src +COMPONENT_SRCDIRS := src \ No newline at end of file diff --git a/lib/libesp32_div/esp-nimble-cpp/docs/Bluetooth 5 features.md b/lib/libesp32_div/esp-nimble-cpp/docs/Bluetooth 5 features.md new file mode 100644 index 000000000..3737b0d7e --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/docs/Bluetooth 5 features.md @@ -0,0 +1,28 @@ +# Bluetooth 5.x features + +## About extended advertising +Extended advertising allows for much more capability and flexibility. + +* Allows for 251 bytes of advertisement data and up to 1650 bytes when chained (configuration dependant) vs 31. + +* New PHY's (physical layers) that allow for faster data rate (2M PHY) or long range/slower data rates (CODED PHY) as well as the original 1M PHY. + +* New periodic advertising, allowing the scanning device to sync with the advertisements of a beacon. This allows for the scanning device to sleep or perform other tasks before the next expected advertisement is sent, preserving cpu cycles and power (To be implemented). +
+ +## Enabling extended advertising +Extended advertising is supported when enabled with the config option `CONFIG_BT_NIMBLE_EXT_ADV` set to a value of 1. This is done in menuconfig under `Component config > Bluetooth > NimBLE options > Enable extended advertising`, or set in `nimconfig.h` for Arduino, or in `build_flags` in PlatformIO. + +When enabled the following will occur: +* `NimBLEScan::start` method will scan on both the 1M PHY and the coded PHY standards automatically. + +* `NimBLEClient::connect` will use the primary PHY the device is listening on, unless specified (see below). + +* `NimBLEClient::setConnectPhy` becomes available to specify the PHY's to connect with (default is all). + +* `NimBLEAdvertising` is no longer available for use and is replaced by `NimBLEExtAdvertising`. `NimBLEDevice::getAdvertising` will now return an instance of `NimBLEExtAdvertising`. + +* `NimBLEAdvertisementData` is no longer available for use and is replaced by `NimBLEExtAdvertisement`. This new class is where everything about the advertisement is configured, including the advertisement intervals and advertisement ended callback. + + + diff --git a/lib/libesp32_div/esp-nimble-cpp/docs/Doxyfile b/lib/libesp32_div/esp-nimble-cpp/docs/Doxyfile new file mode 100644 index 000000000..c67e49f5a --- /dev/null +++ b/lib/libesp32_div/esp-nimble-cpp/docs/Doxyfile @@ -0,0 +1,2778 @@ +# Doxyfile 1.9.5 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = esp-nimble-cpp + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 1.4.1 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doxydocs + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# numer of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = YES + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = NO + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../CHANGELOG.md \ + . \ + ../src + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.doc \ + *.txt \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = ../src/nimconfig_rename.h + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = index.md + +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. Default setting AUTO_LIGHT +# enables light output unless the user preference is dark output. Other options +# are DARK to always use dark mode, LIGHT to always use light mode, AUTO_DARK to +# default to dark mode unless the user prefers light mode, and TOGGLE to let the +# user toggle between dark and light mode via a button. +# Possible values are: LIGHT Always generate light output., DARK Always generate +# dark output., AUTO_LIGHT Automatically set the mode according to the user +# preference, use light mode if no preference is set (the default)., AUTO_DARK +# Automatically set the mode according to the user preference, use dark mode if +# no preference is set. and TOGGLE Allow to user to switch between light and +# dark mode via a button.. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html +# #tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /